From b623f5953691b2a0614e6f1f4def86bdbb9a4113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sat, 8 Aug 2020 11:53:00 +0200 Subject: New upstream version 5.2.0Beta2.1 --- .hgtags | 27 + CMake/FindCMocka.cmake | 9 +- CMake/FindFreeImage.cmake | 58 + CMake/FindLibzip.cmake | 61 + CMake/FindZlib.cmake | 43 + CMake/NSIS.template.in | 988 + CMakeLists.txt | 42 +- app/CMakeLists.txt | 5 +- app/bin/CMakeLists.txt | 110 +- app/bin/acclkeys.h | 12 +- app/bin/appdefaults.c | 25 +- app/bin/archive.c | 454 + app/bin/archive.h | 15 + app/bin/bdf2xtp.c | 9 +- app/bin/bitmaps/SVG/star.svg | 124 + app/bin/bitmaps/XCF/bluedot.xcf | Bin 0 -> 2124 bytes app/bin/bitmaps/XCF/greendot.xcf | Bin 0 -> 2024 bytes app/bin/bitmaps/XCF/greydot.xcf | Bin 0 -> 2022 bytes app/bin/bitmaps/XCF/reddot.xcf | Bin 0 -> 2124 bytes app/bin/bitmaps/XCF/yellowdot.xcf | Bin 0 -> 1854 bytes app/bin/bitmaps/arrow0.xbm | 14 +- app/bin/bitmaps/arrow0_ctl.xbm | 9 + app/bin/bitmaps/arrow0_shift.xbm | 9 + app/bin/bitmaps/arrow3.xbm | 2 +- app/bin/bitmaps/arrow3_ctl.xbm | 9 + app/bin/bitmaps/arrow3_shift.xbm | 9 + app/bin/bitmaps/arrowr3.xbm | 9 + app/bin/bitmaps/arrowr3_ctl.xbm | 9 + app/bin/bitmaps/arrowr3_shift.xbm | 9 + app/bin/bitmaps/arrows.xbm | 2 +- app/bin/bitmaps/background.xpm | 155 + app/bin/bitmaps/bluedot.xpm | 26 + app/bin/bitmaps/bma0.xbm | 2 +- app/bin/bitmaps/bma135.xbm | 2 +- app/bin/bitmaps/bma45.xbm | 2 +- app/bin/bitmaps/bma90.xbm | 2 +- app/bin/bitmaps/bmendpt.xbm | 2 +- app/bin/bitmaps/bridge.xpm | 22 + app/bin/bitmaps/clip.xbm | 6 + app/bin/bitmaps/convertfr.xpm | 23 + app/bin/bitmaps/convertto.xpm | 23 + app/bin/bitmaps/cornu.xpm | 23 + app/bin/bitmaps/cross0.xbm | 2 +- app/bin/bitmaps/delete.xpm | 39 +- app/bin/bitmaps/document-export.xpm | 90 + app/bin/bitmaps/document-exportdxf.xpm | 84 + app/bin/bitmaps/document-import.xpm | 92 + app/bin/bitmaps/document-importmod.xpm | 71 + app/bin/bitmaps/dpolyline.xpm | 23 + app/bin/bitmaps/export.xpm | 21 - app/bin/bitmaps/flash.xbm | 2 +- app/bin/bitmaps/greendot.xpm | 23 + app/bin/bitmaps/greenstar.xpm | 69 + app/bin/bitmaps/greydot.xpm | 25 + app/bin/bitmaps/greystar.xpm | 69 + app/bin/bitmaps/import.xpm | 21 - app/bin/bitmaps/joinline.xpm | 22 + app/bin/bitmaps/link.xbm | 6 + app/bin/bitmaps/magnet.xpm | 22 + app/bin/bitmaps/magnifier.xpm | 89 + app/bin/bitmaps/note.xbm | 8 +- app/bin/bitmaps/pan.xpm | 2 +- app/bin/bitmaps/parallel-line.xpm | 22 + app/bin/bitmaps/parallel.xpm | 15 +- app/bin/bitmaps/reddot.xpm | 26 + app/bin/bitmaps/redstar.xpm | 67 + app/bin/bitmaps/sticky-note-chain.xpm | 84 + app/bin/bitmaps/sticky-note-clip.xpm | 99 + app/bin/bitmaps/sticky-note-text.xpm | 86 + app/bin/bitmaps/tunnel.xpm | 19 +- app/bin/bitmaps/yellowdot.xpm | 27 + app/bin/bitmaps/yellowstar.xpm | 67 + app/bin/cJSON.c | 2932 ++ app/bin/cJSON.h | 285 + app/bin/cbezier.c | 233 +- app/bin/cbezier.h | 7 +- app/bin/cblock.c | 184 +- app/bin/ccontrol.c | 42 +- app/bin/ccornu.c | 2515 +- app/bin/ccornu.h | 11 + app/bin/ccurve.c | 637 +- app/bin/ccurve.h | 8 +- app/bin/cdraw.c | 1814 +- app/bin/celev.c | 364 +- app/bin/cgroup.c | 495 +- app/bin/chndldto.c | 14 +- app/bin/chotbar.c | 119 +- app/bin/cjoin.c | 610 +- app/bin/cmisc.c | 114 +- app/bin/cmodify.c | 490 +- app/bin/cnote.c | 430 +- app/bin/common.h | 22 + app/bin/compound.c | 285 +- app/bin/compound.h | 24 +- app/bin/cparalle.c | 370 +- app/bin/cprint.c | 516 +- app/bin/cprofile.c | 2314 +- app/bin/cpull.c | 263 +- app/bin/cruler.c | 22 +- app/bin/cselect.c | 2250 +- app/bin/cselect.h | 12 +- app/bin/csensor.c | 42 +- app/bin/csignal.c | 47 +- app/bin/csnap.c | 32 +- app/bin/csplit.c | 89 +- app/bin/cstraigh.c | 77 +- app/bin/cstruct.c | 421 +- app/bin/cswitchmotor.c | 108 +- app/bin/ctext.c | 71 +- app/bin/ctodesgn.c | 1515 +- app/bin/ctrain.c | 139 +- app/bin/ctrain.h | 20 +- app/bin/cturnout.c | 1186 +- app/bin/cturntbl.c | 115 +- app/bin/custom.c | 51 +- app/bin/custom.h | 14 +- app/bin/dbench.c | 2 +- app/bin/dbitmap.c | 14 +- app/bin/dcar.c | 625 +- app/bin/dcmpnd.c | 33 + app/bin/dcontmgm.c | 5 +- app/bin/dcustmgm.c | 73 +- app/bin/dease.c | 2 + app/bin/directory.c | 162 + app/bin/directory.h | 6 + app/bin/dlayer.c | 143 +- app/bin/doption.c | 90 +- app/bin/dpricels.c | 2 +- app/bin/dprmfile.c | 757 +- app/bin/draw.c | 1612 +- app/bin/draw.h | 262 +- app/bin/drawgeom.c | 2413 +- app/bin/drawgeom.h | 65 +- app/bin/dxfoutput.c | 16 +- app/bin/elev.c | 42 +- app/bin/file2uri.c | 83 + app/bin/file2uri.h | 27 + app/bin/fileio.c | 963 +- app/bin/fileio.h | 68 +- app/bin/filenoteui.c | 330 + app/bin/helphelper.c | 1 + app/bin/include/dirent.h | 1254 + app/bin/include/paramfile.h | 26 + app/bin/include/paramfilelist.h | 32 + app/bin/include/partcatalog.h | 70 + app/bin/include/stringxtc.h | 8 + app/bin/include/utf8convert.h | 24 + app/bin/layout.c | 364 +- app/bin/layout.h | 20 +- app/bin/linknoteui.c | 260 + app/bin/macro.c | 501 +- app/bin/manifest.c | 176 + app/bin/manifest.h | 6 + app/bin/misc.c | 2972 +- app/bin/misc.h | 87 +- app/bin/misc2.c | 16 +- app/bin/misc2.h | 14 +- app/bin/note.h | 110 + app/bin/param.c | 213 +- app/bin/param.h | 2 + app/bin/paramfile.c | 393 + app/bin/paramfilelist.c | 496 + app/bin/paramfilesearch_ui.c | 426 + app/bin/partcatalog.c | 846 + app/bin/paths.c | 39 +- app/bin/paths.h | 2 + app/bin/shortentext.c | 92 + app/bin/shortentext.h | 28 + app/bin/smalldlg.c | 17 +- app/bin/stringxtc.c | 106 + app/bin/tbezier.c | 389 +- app/bin/tbezier.h | 6 +- app/bin/tcornu.c | 377 +- app/bin/tcornu.h | 6 +- app/bin/tcurve.c | 231 +- app/bin/tease.c | 232 +- app/bin/textnoteui.c | 243 + app/bin/tocornu.src | 21 + app/bin/tocornu3way.src | 33 + app/bin/tocornuwye.src | 24 + app/bin/track.c | 900 +- app/bin/track.h | 161 +- app/bin/trackx.h | 2 +- app/bin/trknote.c | 720 + app/bin/trkseg.c | 558 +- app/bin/tstraigh.c | 108 +- app/bin/unittest/CMakeLists.txt | 36 +- app/bin/unittest/catalogtest.c | 124 + app/bin/unittest/defaultstest.c | 8 +- app/bin/unittest/pathstest.c | 5 + app/bin/unittest/shortentest.c | 152 + app/bin/unittest/testfiles/HO-Peco-Code83.xtp | 236 + app/bin/unittest/testfiles/atl83ho.xtp | 561 + app/bin/unittest/testfiles/atlasn.xtp | 697 + app/bin/utf8convert.c | 96 + app/bin/utility.c | 171 + app/bin/utility.h | 4 + app/bin/validator.c | 87 + app/bin/validator.h | 29 + app/cornu/bezctx_xtrkcad.c | 13 +- app/cornu/bezctx_xtrkcad.h | 2 +- app/doc/CMakeLists.txt | 11 +- app/doc/addm.but | 312 +- app/doc/appendix.but | 26 +- app/doc/changem.but | 679 +- app/doc/drawm.but | 436 +- app/doc/editm.but | 58 +- app/doc/filem.but | 184 +- app/doc/helpm.but | 16 +- app/doc/hotbar.but | 38 +- app/doc/intro.but.in | 192 +- app/doc/managem.but | 27 +- app/doc/navigation.but | 156 +- app/doc/optionm.but | 67 +- app/doc/png.d/bcornu.png | Bin 0 -> 4346 bytes app/doc/png.d/bfile.png | Bin 0 -> 681 bytes app/doc/png.d/bjoin.png | Bin 277 -> 4433 bytes app/doc/png.d/bjoinline.png | Bin 0 -> 4329 bytes app/doc/png.d/blayer.png | Bin 1620 -> 70247 bytes app/doc/png.d/blink.png | Bin 0 -> 626 bytes app/doc/png.d/bnote.png | Bin 250 -> 600 bytes app/doc/png.d/bparalle.png | Bin 239 -> 0 bytes app/doc/png.d/bparallel.png | Bin 0 -> 4402 bytes app/doc/png.d/bparalleline.png | Bin 0 -> 4357 bytes app/doc/png.d/cmdopt.png | Bin 19624 -> 7407 bytes app/doc/png.d/convertfrom.png | Bin 0 -> 4169 bytes app/doc/png.d/convertto.png | Bin 0 -> 4169 bytes app/doc/png.d/cornuendanchor.png | Bin 0 -> 5312 bytes app/doc/png.d/dcprofile.png | Bin 8234 -> 11508 bytes app/doc/png.d/displayopt.png | Bin 68298 -> 86476 bytes app/doc/png.d/dprmfile.png | Bin 24735 -> 13308 bytes app/doc/png.d/greendot.png | Bin 0 -> 301 bytes app/doc/png.d/greenstar.png | Bin 0 -> 415 bytes app/doc/png.d/greydot.png | Bin 0 -> 262 bytes app/doc/png.d/greystar.png | Bin 0 -> 431 bytes app/doc/png.d/iconfile.png | Bin 0 -> 165 bytes app/doc/png.d/iconlink.PNG | Bin 0 -> 230 bytes app/doc/png.d/iconnote.png | Bin 479 -> 211 bytes app/doc/png.d/layout.png | Bin 13213 -> 72958 bytes app/doc/png.d/madd.png | Bin 7895 -> 13693 bytes app/doc/png.d/main.png | Bin 36744 -> 397486 bytes app/doc/png.d/maintagged.png | Bin 0 -> 400969 bytes app/doc/png.d/mmovedraw.png | Bin 1037 -> 0 bytes app/doc/png.d/mnote.png | Bin 0 -> 1392 bytes app/doc/png.d/notefile.png | Bin 0 -> 6830 bytes app/doc/png.d/notelink.png | Bin 0 -> 6780 bytes app/doc/png.d/notetext.png | Bin 0 -> 6928 bytes app/doc/png.d/paramsearch.png | Bin 0 -> 14516 bytes app/doc/png.d/print.png | Bin 14306 -> 46869 bytes app/doc/png.d/printmargin.png | Bin 0 -> 10613 bytes app/doc/png.d/reddot.png | Bin 0 -> 301 bytes app/doc/png.d/redstar.png | Bin 0 -> 364 bytes app/doc/png.d/satusbarparallel.png | Bin 1617 -> 0 bytes app/doc/png.d/statusbarparallel.png | Bin 0 -> 12964 bytes app/doc/png.d/yellowdot.png | Bin 0 -> 326 bytes app/doc/png.d/yellowstar.png | Bin 0 -> 414 bytes app/doc/statusbar.but | 13 +- app/doc/upgrade.but | 74 +- app/doc/view_winm.but | 25 +- app/dynstring/dynstring.c | 17 + app/dynstring/dynstring.h | 89 +- app/help/CMakeLists.txt | 5 +- app/help/cJSON.c | 2932 ++ app/help/cJSON.h | 285 + app/help/genhelp.c | 286 +- app/help/genhelp.in | 728 - app/help/genhelp.json | 681 + app/help/messages.in | 244 +- app/help/xtrkcad.info | 1123 - app/help/xtrkcad.tip | 65 +- app/i18n/CMakeLists.txt | 12 +- app/i18n/de_DE.po | 29324 ++++++++++--------- app/i18n/fi.po | 28654 ++++++++++-------- app/i18n/fr_FR.po | 16142 ++++++++++ app/i18n/pt_BR.po | 26391 +++++++++-------- app/i18n/stripmsg.c | 23 +- app/lib/CHANGELOG.md | 360 +- app/lib/CMakeLists.txt | 6 +- app/lib/Readme.md | 45 +- app/lib/demos/dmadjend.xtr | 622 +- app/lib/demos/dmbench.xtr | 8 + app/lib/demos/dmcancel.xtr | 52 +- app/lib/demos/dmcircle.xtr | 9 + app/lib/demos/dmconn1.xtr | 336 +- app/lib/demos/dmconn2.xtr | 236 +- app/lib/demos/dmcrvtrk.xtr | 32 + app/lib/demos/dmctlpnl.xtr | 1082 +- app/lib/demos/dmdelund.xtr | 10 + app/lib/demos/dmdialog.xtr | 13 + app/lib/demos/dmdimlin.xtr | 138 +- app/lib/demos/dmease.xtr | 162 +- app/lib/demos/dmelev.xtr | 239 +- app/lib/demos/dmexcept.xtr | 52 +- app/lib/demos/dmextend.xtr | 49 +- app/lib/demos/dmflip.xtr | 3 + app/lib/demos/dmgroup.xtr | 158 +- app/lib/demos/dmhelix.xtr | 33 +- app/lib/demos/dmhndld.xtr | 66 +- app/lib/demos/dmintro.xtr | 24 +- app/lib/demos/dmjcir.xtr | 34 +- app/lib/demos/dmjnabut.xtr | 16 +- app/lib/demos/dmjncs.xtr | 44 +- app/lib/demos/dmjnmove.xtr | 27 +- app/lib/demos/dmjnss.xtr | 225 +- app/lib/demos/dmjntt.xtr | 34 +- app/lib/demos/dmlines.xtr | 132 +- app/lib/demos/dmlines2.xtr | 149 +- app/lib/demos/dmmouse.xtr | 232 +- app/lib/demos/dmmovabt.xtr | 3 +- app/lib/demos/dmnotes.xtr | 7 +- app/lib/demos/dmparall.xtr | 41 +- app/lib/demos/dmplymod.xtr | 88 +- app/lib/demos/dmprof.xtr | 164 +- app/lib/demos/dmrescal.xtr | 129 +- app/lib/demos/dmrotate.xtr | 913 +- app/lib/demos/dmruler.xtr | 3 + app/lib/demos/dmselect.xtr | 468 +- app/lib/demos/dmsplit.xtr | 42 + app/lib/demos/dmstrtrk.xtr | 6 + app/lib/demos/dmtbledg.xtr | 59 +- app/lib/demos/dmtosel.xtr | 99 +- app/lib/demos/dmtotrim.xtr | 28 +- app/lib/demos/dmtoyard.xtr | 159 +- app/lib/demos/dmtrkwid.xtr | 134 +- app/lib/demos/dmtrntab.xtr | 4 + app/lib/examples/psr.xtc | 14 +- app/lib/params/Any-AtlasControllers.xtp | 571 + app/lib/params/Any-CTC_panel.xtp | 24 +- app/lib/params/BachmannEZ-N.xtp | 2 +- app/lib/params/CMakeLists.txt | 11 +- app/lib/params/FastTrack-HO.xtp | 4 +- app/lib/params/FastTrack_n.xtp | 2 +- app/lib/params/G-MicroEngineeringTrack.xtp | 142 + app/lib/params/G-NQD-AMAX Plastic.xtp | 4 +- app/lib/params/G-Peco G45 Track.xtp | 46 + app/lib/params/G-aristo.xtp | 2 +- app/lib/params/Gn15-nmra.xtp | 2 +- app/lib/params/H0_ncb-Roads.xtp | 1098 - app/lib/params/HO-CentralValley Bridges.xtp | 407 + app/lib/params/HO-DapolHOOO.xtp | 8 +- app/lib/params/HO-EndoRailwayTrackSystem.xtp | 228 + app/lib/params/HO-HornbyHO.xtp | 271 +- app/lib/params/HO-Marklin C-Track.xtp | 569 + app/lib/params/HO-Marklin K-track.xtp | 527 + app/lib/params/HO-Marklin M-Track.xtp | 1072 + app/lib/params/HO-MetcalfeHOOO.xtp | 4 +- app/lib/params/HO-MicroEngineering-Bridges.xtp | 736 + app/lib/params/HO-MicroEngineering.xtp | 2 +- app/lib/params/HO-Peco-Code100Streamline.xtp | 130 +- app/lib/params/HO-Peco-Code75Finescale.xtp | 101 +- app/lib/params/HO-RatioHOOO.xtp | 6 +- app/lib/params/HO-Roco HO Code 83.xtp | 469 + app/lib/params/HO-Slot-Car-AFX-Track.xtp | 46 +- app/lib/params/HO-Slot-Cars.xtp | 5 +- ...lthers Cornerstone Engineered Bridge System.xtp | 624 + app/lib/params/HO-Weinert-Code75.xtp | 42 +- app/lib/params/HO-WillsHOOO.xtp | 8 +- app/lib/params/HO-atl100ho.xtp | 72 +- app/lib/params/HO-cmr-ho.xtp | 2 +- app/lib/params/HO_toolkit-Roads.xtp | 2 +- app/lib/params/HOn3-MicroEngineering-Bridges.xtp | 377 + app/lib/params/HOn3-MicroEngineering.xtp | 50 +- app/lib/params/HOn30_Minitrains.xtp | 2 +- app/lib/params/Hornby Dublo 2 Rail.xtp | 2 +- .../params/Hornby Dublo 3 Rail with Turntable.xtp | 4 +- app/lib/params/Hornby Dublo Signals.xtp | 2 +- app/lib/params/Hornby Dublo Wood Buildings.xtp | 2 +- app/lib/params/HornbyOO.xtp | 221 - app/lib/params/LifeLike-N.xtp | 66 - app/lib/params/Lionel-O.xtp | 6 +- app/lib/params/Lionel27.xtp | 6 +- app/lib/params/N-AtlasTrueTrack.xtp | 26 +- .../N-Bonus Generic Industrial Structures.xtp | 3 +- app/lib/params/N-CentralValley Bridges.xtp | 123 + app/lib/params/N-Kato Track and Structures.xtp | 1741 ++ app/lib/params/N-Kato-Unitram.xtp | 7 +- app/lib/params/N-Katocn.xtp | 2 +- app/lib/params/N-LifeLike Power-Loc.xtp | 2 +- app/lib/params/N-ME Structures.xtp | 3 +- app/lib/params/N-MicroEngineering-Bridges.xtp | 318 + app/lib/params/N-NULINE.xtp | 2 +- app/lib/params/N-PecoCode55Finescale.xtp | 50 +- app/lib/params/N-PecoCode80Streamline.xtp | 50 +- app/lib/params/N-Rix-Pikestuff.xtp | 2 +- app/lib/params/N-Shinohara70.xtp | 4 +- app/lib/params/N-Tomix Track.xtp | 1705 ++ app/lib/params/N-atlasn55.xtp | 27 +- app/lib/params/N-atlasn80.xtp | 845 + app/lib/params/N-cmr.xtp | 2 +- app/lib/params/N-kato-n-gl-trk.xtp | 567 - app/lib/params/N-kato-turntable.xtp | 16 +- app/lib/params/N-kato.xtp | 1704 -- app/lib/params/N-me.xtp | 2 +- app/lib/params/Newqida.xtp | 43 + app/lib/params/Nn3-FastTrack.xtp | 2 +- app/lib/params/O-Atlas2Rail.xtp | 296 + app/lib/params/O-Atlas2RailObsolete.xtp | 120 + app/lib/params/O-Atlas3Rail Roadbed.xtp | 340 + app/lib/params/O-Atlas3Rrail.xtp | 617 + app/lib/params/O-AtlasIndustrial3Rail.xtp | 151 + app/lib/params/O-Bassett-Lowke (discontinued).xtp | 6 +- app/lib/params/O-ETS TramTrack.xtp | 2 +- app/lib/params/O-Lehnhardt Tramrails.xtp | 2 +- app/lib/params/O-atlaso3rail.xtp | 6 +- app/lib/params/On30-FastTrack.xtp | 2 +- app/lib/params/On30-MicroEngineering.xtp | 50 + app/lib/params/Proto-AmSlotCar.xtp | 2 +- app/lib/params/RemcoMightyCasey.xtp | 42 + app/lib/params/S-Lionel AF Fastrack.xtp | 306 + app/lib/params/S_ACG_18.824in Radius Track.xtp | 2 +- app/lib/params/S_ACG_20.000 Track.xtp | 2 +- app/lib/params/TT-Kuehn.xtp | 20 +- app/lib/params/TT-TilligAdvBeddingTrack.xtp | 9 +- app/lib/params/TT-Trak Modules.xtp | 3 +- app/lib/params/TilligAdvTT.xtp | 9 +- app/lib/params/TilligH0EliteCode83.xtp | 2 +- app/lib/params/TilligH0e.xtp | 2 +- app/lib/params/TilligH0m.xtp | 2 +- app/lib/params/USA-G.xtp | 2 +- app/lib/params/Z-Fasttrack.xtp | 4 +- app/lib/params/Z-Rokuhan.xtp | 21 +- app/lib/params/Z-T-Trak.xtp | 9 +- app/lib/params/arnold.xtp | 5 +- app/lib/params/atl83ho.xtp | 2 +- app/lib/params/atlasn.xtp | 697 - app/lib/params/atlaso2rail.xtp | 3 + app/lib/params/br.xtp | 2 +- app/lib/params/dpm-ho.xtp | 2 +- app/lib/params/eu.xtp | 2 +- app/lib/params/ho-amb.xtp | 4 +- app/lib/params/ho-ncb-roads.xtp | 2 +- app/lib/params/hon3cars.xtp | 9 + app/lib/params/hubner1.xtp | 6 +- app/lib/params/kato-ho.xtp | 4 +- app/lib/params/kato-n-DblTrk.xtp | 369 - app/lib/params/kato-n.xtp | 1639 -- app/lib/params/lgb.xtp | 2 +- app/lib/params/me-ho.xtp | 47 - app/lib/params/minitrix.xtp | 2 +- app/lib/params/mrkhomde.xtp | 2 +- app/lib/params/mrkln1.xtp | 2 +- app/lib/params/mrklnhoc-de.xtp | 4 +- app/lib/params/mrklnhoc.xtp | 495 - app/lib/params/mrklnhok.xtp | 401 - app/lib/params/mrklnhom.xtp | 906 - app/lib/params/mrklnz.xtp | 4 +- app/lib/params/nmra-0-lapped.xtp | 76 - app/lib/params/nmra-ho.xtp | 2 +- app/lib/params/nmra-ho3.xtp | 2 +- app/lib/params/nmra-n.xtp | 4 +- app/lib/params/nmra-o.xtp | 2 +- app/lib/params/nmra-s.xtp | 2 +- app/lib/params/nmra-tt.to | 2 +- app/lib/params/nmra-tt.xtp | 2 +- app/lib/params/nmra-z.xtp | 2 +- app/lib/params/pecohom.xtp | 2 +- app/lib/params/pecohon30.xtp | 2 +- app/lib/params/proto-ng.xtp | 29 + app/lib/params/protoam.xtp | 2 +- app/lib/params/protosteam.xtp | 2 +- app/lib/params/rocho100.xtp | 5 +- app/lib/params/rocho83.xtp | 293 - app/lib/params/supero.xtp | 2 +- app/lib/params/tomix-n.xtp | 1689 -- app/lib/params/toolkit-n.xtp | 2 +- app/lib/params/walth-n.xtp | 2686 -- app/lib/params/wlthho10.xtp | 2 +- app/lib/params/wlthho83.xtp | 4 +- app/lib/xtrkcad.xtq | 18 +- app/tools/HACKING | 4 +- app/wlib/gtklib/CMakeLists.txt | 48 +- app/wlib/gtklib/browserhelp.c | 59 +- app/wlib/gtklib/button.c | 44 +- app/wlib/gtklib/color.c | 11 +- app/wlib/gtklib/control.c | 59 +- app/wlib/gtklib/droplist.c | 75 +- app/wlib/gtklib/filesel.c | 238 +- app/wlib/gtklib/font.c | 17 +- app/wlib/gtklib/gtkdraw-cairo.c | 995 +- app/wlib/gtklib/gtkint.h | 24 +- app/wlib/gtklib/help.c | 16 + app/wlib/gtklib/ixhelp.c | 10 + app/wlib/gtklib/list.c | 5 +- app/wlib/gtklib/liststore.c | 2 + app/wlib/gtklib/menu.c | 8 +- app/wlib/gtklib/notice.c | 18 +- app/wlib/gtklib/opendocument.c | 117 + app/wlib/gtklib/osxhelp.c | 67 +- app/wlib/gtklib/print.c | 233 +- app/wlib/gtklib/single.c | 82 +- app/wlib/gtklib/splash.c | 12 +- app/wlib/gtklib/statusbar.c | 6 +- app/wlib/gtklib/text.c | 24 +- app/wlib/gtklib/timer.c | 3 + app/wlib/gtklib/util.c | 88 +- app/wlib/gtklib/window.c | 204 +- app/wlib/gtklib/wpref.c | 10 +- app/wlib/include/mswlib.h | 2 - app/wlib/include/wlib.h | 103 +- app/wlib/mswlib/CMakeLists.txt | 19 +- app/wlib/mswlib/backgnd.c | 220 + app/wlib/mswlib/mswbitmap.c | 46 +- app/wlib/mswlib/mswbutt.c | 21 +- app/wlib/mswlib/mswchksm.c | 125 - app/wlib/mswlib/mswdraw.c | 833 +- app/wlib/mswlib/mswedit.c | 210 +- app/wlib/mswlib/mswint.h | 23 +- app/wlib/mswlib/mswlist.c | 2 +- app/wlib/mswlib/mswmenu.c | 8 +- app/wlib/mswlib/mswmisc.c | 266 +- app/wlib/mswlib/mswmsg.c | 9 +- app/wlib/mswlib/mswpref.c | 1 + app/wlib/mswlib/mswprint.c | 46 +- app/wlib/mswlib/mswsplash.c | 8 +- app/wlib/mswlib/mswtext.c | 63 +- app/wlib/mswlib/simple-gettext.c | 3 +- app/wlib/mswlib/unittest/CMakeLists.txt | 11 + app/wlib/mswlib/unittest/utf8test.c | 65 + app/wlib/mswlib/utf8conv.c | 210 + distribution/CMakeLists.txt | 3 +- distribution/osx/CMakeLists.txt | 2 +- distribution/osx/gtk-bundle/xtrkcad-launcher.sh | 4 +- .../osx/gtk-bundle/xtrkcad-template.dmg.zip | Bin 3990654 -> 2641265 bytes distribution/posix/CMakeLists.txt | 42 +- distribution/win32/nsis/CMakeLists.txt | 12 +- distribution/win32/nsis/install.nsh | 27 +- distribution/win32/nsis/uninstall.nsh | 29 +- xtrkcad-config.h.in | 4 +- 528 files changed, 128846 insertions(+), 66629 deletions(-) create mode 100644 CMake/FindFreeImage.cmake create mode 100644 CMake/FindLibzip.cmake create mode 100644 CMake/FindZlib.cmake create mode 100644 CMake/NSIS.template.in create mode 100644 app/bin/archive.c create mode 100644 app/bin/archive.h create mode 100644 app/bin/bitmaps/SVG/star.svg create mode 100644 app/bin/bitmaps/XCF/bluedot.xcf create mode 100644 app/bin/bitmaps/XCF/greendot.xcf create mode 100644 app/bin/bitmaps/XCF/greydot.xcf create mode 100644 app/bin/bitmaps/XCF/reddot.xcf create mode 100644 app/bin/bitmaps/XCF/yellowdot.xcf create mode 100644 app/bin/bitmaps/arrow0_ctl.xbm create mode 100644 app/bin/bitmaps/arrow0_shift.xbm create mode 100644 app/bin/bitmaps/arrow3_ctl.xbm create mode 100644 app/bin/bitmaps/arrow3_shift.xbm create mode 100644 app/bin/bitmaps/arrowr3.xbm create mode 100644 app/bin/bitmaps/arrowr3_ctl.xbm create mode 100644 app/bin/bitmaps/arrowr3_shift.xbm create mode 100644 app/bin/bitmaps/background.xpm create mode 100644 app/bin/bitmaps/bluedot.xpm create mode 100644 app/bin/bitmaps/bridge.xpm create mode 100644 app/bin/bitmaps/clip.xbm create mode 100644 app/bin/bitmaps/convertfr.xpm create mode 100644 app/bin/bitmaps/convertto.xpm create mode 100644 app/bin/bitmaps/cornu.xpm create mode 100644 app/bin/bitmaps/document-export.xpm create mode 100644 app/bin/bitmaps/document-exportdxf.xpm create mode 100644 app/bin/bitmaps/document-import.xpm create mode 100644 app/bin/bitmaps/document-importmod.xpm create mode 100644 app/bin/bitmaps/dpolyline.xpm delete mode 100644 app/bin/bitmaps/export.xpm create mode 100644 app/bin/bitmaps/greendot.xpm create mode 100644 app/bin/bitmaps/greenstar.xpm create mode 100644 app/bin/bitmaps/greydot.xpm create mode 100644 app/bin/bitmaps/greystar.xpm delete mode 100644 app/bin/bitmaps/import.xpm create mode 100644 app/bin/bitmaps/joinline.xpm create mode 100644 app/bin/bitmaps/link.xbm create mode 100644 app/bin/bitmaps/magnet.xpm create mode 100644 app/bin/bitmaps/magnifier.xpm create mode 100644 app/bin/bitmaps/parallel-line.xpm create mode 100644 app/bin/bitmaps/reddot.xpm create mode 100644 app/bin/bitmaps/redstar.xpm create mode 100644 app/bin/bitmaps/sticky-note-chain.xpm create mode 100644 app/bin/bitmaps/sticky-note-clip.xpm create mode 100644 app/bin/bitmaps/sticky-note-text.xpm create mode 100644 app/bin/bitmaps/yellowdot.xpm create mode 100644 app/bin/bitmaps/yellowstar.xpm create mode 100755 app/bin/cJSON.c create mode 100755 app/bin/cJSON.h create mode 100644 app/bin/directory.c create mode 100644 app/bin/directory.h create mode 100644 app/bin/file2uri.c create mode 100644 app/bin/file2uri.h create mode 100644 app/bin/filenoteui.c create mode 100644 app/bin/include/dirent.h create mode 100644 app/bin/include/paramfile.h create mode 100644 app/bin/include/paramfilelist.h create mode 100644 app/bin/include/partcatalog.h create mode 100644 app/bin/include/stringxtc.h create mode 100644 app/bin/include/utf8convert.h create mode 100644 app/bin/linknoteui.c create mode 100644 app/bin/manifest.c create mode 100644 app/bin/manifest.h create mode 100644 app/bin/note.h create mode 100644 app/bin/paramfile.c create mode 100644 app/bin/paramfilelist.c create mode 100644 app/bin/paramfilesearch_ui.c create mode 100644 app/bin/partcatalog.c create mode 100644 app/bin/shortentext.c create mode 100644 app/bin/shortentext.h create mode 100644 app/bin/stringxtc.c create mode 100644 app/bin/textnoteui.c create mode 100644 app/bin/tocornu.src create mode 100644 app/bin/tocornu3way.src create mode 100644 app/bin/tocornuwye.src create mode 100644 app/bin/trknote.c create mode 100644 app/bin/unittest/catalogtest.c create mode 100644 app/bin/unittest/shortentest.c create mode 100644 app/bin/unittest/testfiles/HO-Peco-Code83.xtp create mode 100644 app/bin/unittest/testfiles/atl83ho.xtp create mode 100644 app/bin/unittest/testfiles/atlasn.xtp create mode 100644 app/bin/utf8convert.c create mode 100644 app/bin/validator.c create mode 100644 app/bin/validator.h create mode 100644 app/doc/png.d/bcornu.png create mode 100644 app/doc/png.d/bfile.png create mode 100644 app/doc/png.d/bjoinline.png create mode 100644 app/doc/png.d/blink.png delete mode 100644 app/doc/png.d/bparalle.png create mode 100644 app/doc/png.d/bparallel.png create mode 100644 app/doc/png.d/bparalleline.png create mode 100644 app/doc/png.d/convertfrom.png create mode 100644 app/doc/png.d/convertto.png create mode 100644 app/doc/png.d/cornuendanchor.png create mode 100644 app/doc/png.d/greendot.png create mode 100644 app/doc/png.d/greenstar.png create mode 100644 app/doc/png.d/greydot.png create mode 100644 app/doc/png.d/greystar.png create mode 100644 app/doc/png.d/iconfile.png create mode 100644 app/doc/png.d/iconlink.PNG create mode 100644 app/doc/png.d/maintagged.png delete mode 100644 app/doc/png.d/mmovedraw.png create mode 100644 app/doc/png.d/mnote.png create mode 100644 app/doc/png.d/notefile.png create mode 100644 app/doc/png.d/notelink.png create mode 100644 app/doc/png.d/notetext.png create mode 100644 app/doc/png.d/paramsearch.png create mode 100644 app/doc/png.d/printmargin.png create mode 100644 app/doc/png.d/reddot.png create mode 100644 app/doc/png.d/redstar.png delete mode 100644 app/doc/png.d/satusbarparallel.png create mode 100644 app/doc/png.d/statusbarparallel.png create mode 100644 app/doc/png.d/yellowdot.png create mode 100644 app/doc/png.d/yellowstar.png create mode 100644 app/help/cJSON.c create mode 100644 app/help/cJSON.h delete mode 100644 app/help/genhelp.in create mode 100644 app/help/genhelp.json delete mode 100644 app/help/xtrkcad.info create mode 100644 app/i18n/fr_FR.po create mode 100644 app/lib/params/Any-AtlasControllers.xtp create mode 100644 app/lib/params/G-MicroEngineeringTrack.xtp create mode 100644 app/lib/params/G-Peco G45 Track.xtp delete mode 100644 app/lib/params/H0_ncb-Roads.xtp create mode 100644 app/lib/params/HO-CentralValley Bridges.xtp create mode 100644 app/lib/params/HO-EndoRailwayTrackSystem.xtp create mode 100644 app/lib/params/HO-Marklin C-Track.xtp create mode 100644 app/lib/params/HO-Marklin K-track.xtp create mode 100644 app/lib/params/HO-Marklin M-Track.xtp create mode 100644 app/lib/params/HO-MicroEngineering-Bridges.xtp create mode 100644 app/lib/params/HO-Roco HO Code 83.xtp create mode 100644 app/lib/params/HO-Walthers Cornerstone Engineered Bridge System.xtp create mode 100644 app/lib/params/HOn3-MicroEngineering-Bridges.xtp delete mode 100644 app/lib/params/HornbyOO.xtp delete mode 100644 app/lib/params/LifeLike-N.xtp create mode 100644 app/lib/params/N-CentralValley Bridges.xtp create mode 100644 app/lib/params/N-Kato Track and Structures.xtp create mode 100644 app/lib/params/N-MicroEngineering-Bridges.xtp create mode 100644 app/lib/params/N-Tomix Track.xtp create mode 100644 app/lib/params/N-atlasn80.xtp delete mode 100644 app/lib/params/N-kato-n-gl-trk.xtp delete mode 100644 app/lib/params/N-kato.xtp create mode 100644 app/lib/params/Newqida.xtp create mode 100644 app/lib/params/O-Atlas2Rail.xtp create mode 100644 app/lib/params/O-Atlas2RailObsolete.xtp create mode 100644 app/lib/params/O-Atlas3Rail Roadbed.xtp create mode 100644 app/lib/params/O-Atlas3Rrail.xtp create mode 100644 app/lib/params/O-AtlasIndustrial3Rail.xtp create mode 100644 app/lib/params/On30-MicroEngineering.xtp create mode 100644 app/lib/params/RemcoMightyCasey.xtp create mode 100644 app/lib/params/S-Lionel AF Fastrack.xtp delete mode 100644 app/lib/params/atlasn.xtp create mode 100644 app/lib/params/hon3cars.xtp delete mode 100644 app/lib/params/kato-n-DblTrk.xtp delete mode 100644 app/lib/params/kato-n.xtp delete mode 100644 app/lib/params/me-ho.xtp delete mode 100644 app/lib/params/mrklnhoc.xtp delete mode 100644 app/lib/params/mrklnhok.xtp delete mode 100644 app/lib/params/mrklnhom.xtp delete mode 100644 app/lib/params/nmra-0-lapped.xtp create mode 100644 app/lib/params/proto-ng.xtp delete mode 100644 app/lib/params/rocho83.xtp delete mode 100644 app/lib/params/tomix-n.xtp delete mode 100644 app/lib/params/walth-n.xtp create mode 100644 app/wlib/gtklib/opendocument.c create mode 100644 app/wlib/mswlib/backgnd.c delete mode 100644 app/wlib/mswlib/mswchksm.c create mode 100644 app/wlib/mswlib/unittest/CMakeLists.txt create mode 100644 app/wlib/mswlib/unittest/utf8test.c create mode 100644 app/wlib/mswlib/utf8conv.c diff --git a/.hgtags b/.hgtags index 52dcbcb..5c1cc48 100644 --- a/.hgtags +++ b/.hgtags @@ -46,3 +46,30 @@ ff3eb7eadadae951cb63fe770ca51cf89ec3d53d Release_5_1_0 e93612ade2a32f2ba0fe8fdcfb92e59c14265466 Release_5_1_2 e93612ade2a32f2ba0fe8fdcfb92e59c14265466 Release_5_1_2 4562e9b122b2b2e58ce9355a83b9cd23e17ed138 Release_5_1_2 +0000000000000000000000000000000000000000 Release_5_1_2a +41d5525d954622bedb12bc9eb9516e3d8848a9d6 Release_5_1_2a +fc632b33222d1cd00c15342fe2ce91466a27a2b4 V5.2 Beta 1.0 Release +2111ec67392603645062dff2b3b2c76ff9d6e1a7 V5.2 Beta 2.0 Release +2111ec67392603645062dff2b3b2c76ff9d6e1a7 V5.2 Beta 2.0 Release +7b4f25593473721116c49a4cd426482eb8cf1655 V5.2 Beta 2.0 Release +7b4f25593473721116c49a4cd426482eb8cf1655 V5.2 Beta 2.0 Release +a7fd6e03aa2680a5c958d103e13aa38ef5b0dde3 V5.2 Beta 2.0 Release +a7fd6e03aa2680a5c958d103e13aa38ef5b0dde3 V5.2 Beta 2.0 Release +f47114e7bba8af38f1a9228ff619ba88cee01709 V5.2 Beta 2.0 Release +f47114e7bba8af38f1a9228ff619ba88cee01709 V5.2 Beta 2.0 Release +f605edb2081daf4882dd8eb2d25b1830e4521400 V5.2 Beta 2.0 Release +f605edb2081daf4882dd8eb2d25b1830e4521400 V5.2 Beta 2.0 Release +3e5f9ebcc29acb009fd3a04950761bef568ee8bf V5.2 Beta 2.0 Release +3e5f9ebcc29acb009fd3a04950761bef568ee8bf V5.2 Beta 2.0 Release +a5a2221e59d57cb7227de4df566fb49643c4799b V5.2 Beta 2.0 Release +a5a2221e59d57cb7227de4df566fb49643c4799b V5.2 Beta 2.0 Release +1f1e18e8765d75150651a0cf33fadaf1050c8f16 V5.2 Beta 2.0 Release +1f1e18e8765d75150651a0cf33fadaf1050c8f16 V5.2 Beta 2.0 Release +4541599c0b238eb62d848c65f340bfa7059e8d4f V5.2 Beta 2.0 Release +2959e327915b2c1573da0bd817f9cc5a27f0e9d6 V5.2 Beta 2.1 Release +2959e327915b2c1573da0bd817f9cc5a27f0e9d6 V5.2 Beta 2.1 Release +19b72cf126d107f3f499d3bff0f231a6089b7115 V5.2 Beta 2.1 Release +19b72cf126d107f3f499d3bff0f231a6089b7115 V5.2 Beta 2.1 Release +a9688ed807416e3a239268e05f2a26940f96eea7 V5.2 Beta 2.1 Release +a9688ed807416e3a239268e05f2a26940f96eea7 V5.2 Beta 2.1 Release +33627b1df2f6f96acecb26f402c918dd4c9ff3e0 V5.2 Beta 2.1 Release diff --git a/CMake/FindCMocka.cmake b/CMake/FindCMocka.cmake index bec2905..6a5484e 100644 --- a/CMake/FindCMocka.cmake +++ b/CMake/FindCMocka.cmake @@ -23,24 +23,23 @@ set (CMOCKA_ROOT_DIR - "C:/Users/Martin/Documents/CMocka") + "../../external/x86/cmocka") find_path(CMOCKA_INCLUDE_DIR NAMES cmocka.h PATHS ${CMOCKA_ROOT_DIR}/include - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Andreas Schneider\\cmocka]/include" ) find_library(CMOCKA_LIBRARY NAMES - cmocka + cmocka-static PATHS ${CMOCKA_ROOT_DIR}/lib - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Andreas Schneider\\cmocka]/lib" ) + if (CMOCKA_LIBRARY) set(CMOCKA_LIBRARIES ${CMOCKA_LIBRARIES} @@ -52,4 +51,4 @@ include(FindPackageHandleStandardArgs) find_package_handle_standard_args(CMocka DEFAULT_MSG CMOCKA_LIBRARY CMOCKA_INCLUDE_DIR) # show the CMOCKA_INCLUDE_DIR and CMOCKA_LIBRARIES variables only in the advanced view -mark_as_advanced(CMOCKA_INCLUDE_DIR CMOCKA_LIBRARY CMOCKA_LIBRARIES) \ No newline at end of file +mark_as_advanced(CMOCKA_INCLUDE_DIR CMOCKA_LIBRARY CMOCKA_LIBRARIES) diff --git a/CMake/FindFreeImage.cmake b/CMake/FindFreeImage.cmake new file mode 100644 index 0000000..6073916 --- /dev/null +++ b/CMake/FindFreeImage.cmake @@ -0,0 +1,58 @@ +# +# Try to find the FreeImage library and include path. +# Once done this will define +# +# FREEIMAGE_FOUND +# FREEIMAGE_INCLUDE_PATH +# FREEIMAGE_LIBRARY +# FREEIMAGE_SHAREDLIB (Win32 only) +# +# There is no default installation for FreeImage on Windows so a +# XTrackCAD specific directory tree is assumed +# + +if (WIN32) + find_path( FREEIMAGE_INCLUDE_PATH FreeImage.h + PATHS + $ENV{XTCEXTERNALROOT}/x86/FreeImage + DOC "The directory where FreeImage.h resides") + find_library( FREEIMAGE_LIBRARY + NAMES FreeImage freeimage + PATHS + $ENV{XTCEXTERNALROOT}/x86/FreeImage + DOC "The FreeImage library") + find_file( FREEIMAGE_SHAREDLIB + NAMES freeimage.DLL + PATHS + $ENV{XTCEXTERNALROOT}/x86/FreeImage + ) +else (WIN32) + find_path( FREEIMAGE_INCLUDE_PATH FreeImage.h + /usr/include + /usr/local/include + /sw/include + /opt/local/include + DOC "The directory where FreeImage.h resides") + find_library( FREEIMAGE_LIBRARY + NAMES FreeImage freeimage + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + DOC "The FreeImage library") +endif (WIN32) + +find_package_handle_standard_args( FreeImage + DEFAULT_MSG + FREEIMAGE_LIBRARY + FREEIMAGE_INCLUDE_PATH +) + +mark_as_advanced( + FREEIMAGE_FOUND + FREEIMAGE_LIBRARY + FREEIMAGE_INCLUDE_PATH + FREEIMAGE_SHAREDLIB) diff --git a/CMake/FindLibzip.cmake b/CMake/FindLibzip.cmake new file mode 100644 index 0000000..b6f1a9e --- /dev/null +++ b/CMake/FindLibzip.cmake @@ -0,0 +1,61 @@ +# Finds libzip. +# +# This module defines: +# LIBZIP_INCLUDE_DIR_ZIP +# LIBZIP_INCLUDE_DIR_ZIPCONF +# LIBZIP_LIBRARY +# +# There is no default installation for libzip on Windows so a +# XTrackCAD specific directory tree is assumed +# + +if(WIN32) + find_path( LIBZIP_INCLUDE_DIR_ZIP zip.h + PATHS + $ENV{XTCEXTERNALROOT}/x86/libzip + DOC "The directory where zip.h resides") + find_path( LIBZIP_INCLUDE_DIR_ZIPCONF zipconf.h + PATHS + $ENV{XTCEXTERNALROOT}/x86/libzip + DOC "The directory where zip.h resides") + find_library( LIBZIP_LIBRARY + NAMES zip Zip + PATHS + $ENV{XTCEXTERNALROOT}/x86/libzip + DOC "The libzip library") + find_file( LIBZIP_SHAREDLIB + NAMES zip.dll Zip.dll + PATHS + $ENV{XTCEXTERNALROOT}/x86/libzip) +else(WIN32) + find_package(PkgConfig) + pkg_check_modules(PC_LIBZIP QUIET libzip) + + find_path(LIBZIP_INCLUDE_DIR_ZIP + NAMES zip.h + HINTS ${PC_LIBZIP_INCLUDE_DIRS}) + + find_path(LIBZIP_INCLUDE_DIR_ZIPCONF + NAMES zipconf.h + HINTS ${PC_LIBZIP_INCLUDE_DIRS}) + + find_library(LIBZIP_LIBRARY + NAMES zip) +endif(WIN32) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( + LIBZIP DEFAULT_MSG + LIBZIP_LIBRARY LIBZIP_INCLUDE_DIR_ZIP LIBZIP_INCLUDE_DIR_ZIPCONF) + +set(LIBZIP_VERSION 0) + +if (LIBZIP_INCLUDE_DIR_ZIPCONF) + FILE(READ "${LIBZIP_INCLUDE_DIR_ZIPCONF}/zipconf.h" _LIBZIP_VERSION_CONTENTS) + if (_LIBZIP_VERSION_CONTENTS) + STRING(REGEX REPLACE ".*#define LIBZIP_VERSION \"([0-9a-z.]+)\".*" "\\1" LIBZIP_VERSION "${_LIBZIP_VERSION_CONTENTS}") + endif () +endif () + +set(LIBZIP_VERSION ${LIBZIP_VERSION} CACHE STRING "Version number of libzip") +mark_as_advanced(LIBZIP_LIBRARY LIBZIP_INCLUDE_DIR_ZIP LIBZIP_INCLUDE_DIR_ZIPCONF LIBZIP_SHAREDLIB) diff --git a/CMake/FindZlib.cmake b/CMake/FindZlib.cmake new file mode 100644 index 0000000..3305ee3 --- /dev/null +++ b/CMake/FindZlib.cmake @@ -0,0 +1,43 @@ +# Finds zlib. +# +# This module defines: +# zlib_INCLUDE_DIR_ZIP +# zlib_INCLUDE_DIR_ZIPCONF +# zlib_LIBRARY +# +# There is no default installation for zlib on Windows so a +# XTrackCAD specific directory tree is assumed +# + +if(WIN32) + find_path( ZLIB_INCLUDE_DIR zlib.h + PATHS + $ENV{XTCEXTERNALROOT}/x86/zlib + DOC "The directory where zip.h resides") + find_library( ZLIB_LIBRARY + NAMES zlib Zlib + PATHS + $ENV{XTCEXTERNALROOT}/x86/zlib + DOC "The zlib library") + find_file( ZLIB_SHAREDLIB + NAMES zlib.dll Zlib.dll + PATHS + $ENV{XTCEXTERNALROOT}/x86/zlib) +else(WIN32) + find_package(PkgConfig) + pkg_check_modules(PC_ZLIB QUIET zlib) + + find_path(ZLIB_INCLUDE_DIR + NAMES zlib.h + HINTS ${PC_ZLIB_INCLUDE_DIRS}) + + find_library(ZLIB_LIBRARY + NAMES z) +endif(WIN32) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( + ZLIB DEFAULT_MSG + ZLIB_LIBRARY ZLIB_INCLUDE_DIR) + +mark_as_advanced(ZLIB_LIBRARY ZLIB_INCLUDE_DIR) diff --git a/CMake/NSIS.template.in b/CMake/NSIS.template.in new file mode 100644 index 0000000..ebadf87 --- /dev/null +++ b/CMake/NSIS.template.in @@ -0,0 +1,988 @@ +; CPack install script designed for a nmake build + +;-------------------------------- +; You must define these values + + !define VERSION "@CPACK_PACKAGE_VERSION@" + !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" + !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" + +;-------------------------------- +;Variables + + Var MUI_TEMP + Var STARTMENU_FOLDER + Var SV_ALLUSERS + Var START_MENU + Var DO_NOT_ADD_TO_PATH + Var ADD_TO_PATH_ALL_USERS + Var ADD_TO_PATH_CURRENT_USER + Var INSTALL_DESKTOP + Var IS_DEFAULT_INSTALLDIR +;-------------------------------- +;Include Modern UI + + !include "MUI.nsh" + + ;Default installation folder + InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" + +;-------------------------------- +;General + + ;Name and file + Name "@CPACK_NSIS_PACKAGE_NAME@" + OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" + + ;Set compression + SetCompressor @CPACK_NSIS_COMPRESSOR@ + + ;Require administrator access + RequestExecutionLevel admin + +@CPACK_NSIS_DEFINES@ + + !include Sections.nsh + +;--- Component support macros: --- +; The code for the add/remove functionality is from: +; http://nsis.sourceforge.net/Add/Remove_Functionality +; It has been modified slightly and extended to provide +; inter-component dependencies. +Var AR_SecFlags +Var AR_RegFlags +@CPACK_NSIS_SECTION_SELECTED_VARS@ + +; Loads the "selected" flag for the section named SecName into the +; variable VarName. +!macro LoadSectionSelectedIntoVar SecName VarName + SectionGetFlags ${${SecName}} $${VarName} + IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits +!macroend + +; Loads the value of a variable... can we get around this? +!macro LoadVar VarName + IntOp $R0 0 + $${VarName} +!macroend + +; Sets the value of a variable +!macro StoreVar VarName IntValue + IntOp $${VarName} 0 + ${IntValue} +!macroend + +!macro InitSection SecName + ; This macro reads component installed flag from the registry and + ;changes checked state of the section on the components page. + ;Input: section index constant name specified in Section command. + + ClearErrors + ;Reading component status from registry + ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed" + IfErrors "default_${SecName}" + ;Status will stay default if registry value not found + ;(component was never installed) + IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits + SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags + IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off + IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit + + ; Note whether this component was installed before + !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags + IntOp $R0 $AR_RegFlags & $AR_RegFlags + + ;Writing modified flags + SectionSetFlags ${${SecName}} $AR_SecFlags + + "default_${SecName}:" + !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected +!macroend + +!macro FinishSection SecName + ; This macro reads section flag set by user and removes the section + ;if it is not selected. + ;Then it writes component installed flag to registry + ;Input: section index constant name specified in Section command. + + SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags + ;Checking lowest bit: + IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} + IntCmp $AR_SecFlags 1 "leave_${SecName}" + ;Section is not selected: + ;Calling Section uninstall macro and writing zero installed flag + !insertmacro "Remove_${${SecName}}" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ + "Installed" 0 + Goto "exit_${SecName}" + + "leave_${SecName}:" + ;Section is selected: + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ + "Installed" 1 + + "exit_${SecName}:" +!macroend + +!macro RemoveSection_CPack SecName + ; This macro is used to call section's Remove_... macro + ;from the uninstaller. + ;Input: section index constant name specified in Section command. + + !insertmacro "Remove_${${SecName}}" +!macroend + +; Determine whether the selection of SecName changed +!macro MaybeSelectionChanged SecName + !insertmacro LoadVar ${SecName}_selected + SectionGetFlags ${${SecName}} $R1 + IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits + + ; See if the status has changed: + IntCmp $R0 $R1 "${SecName}_unchanged" + !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected + + IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected" + !insertmacro "Deselect_required_by_${SecName}" + goto "${SecName}_unchanged" + + "${SecName}_was_selected:" + !insertmacro "Select_${SecName}_depends" + + "${SecName}_unchanged:" +!macroend +;--- End of Add/Remove macros --- + +;-------------------------------- +;Interface Settings + + !define MUI_HEADERIMAGE + !define MUI_ABORTWARNING + +;---------------------------------------- +; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" +;---------------------------------------- +!verbose 3 +!include "WinMessages.NSH" +!verbose 4 +;==================================================== +; get_NT_environment +; Returns: the selected environment +; Output : head of the stack +;==================================================== +!macro select_NT_profile UN +Function ${UN}select_NT_profile + StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single + DetailPrint "Selected environment for all users" + Push "all" + Return + environment_single: + DetailPrint "Selected environment for current user only." + Push "current" + Return +FunctionEnd +!macroend +!insertmacro select_NT_profile "" +!insertmacro select_NT_profile "un." +;---------------------------------------------------- +!define NT_current_env 'HKCU "Environment"' +!define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' + +!ifndef WriteEnvStr_RegKey + !ifdef ALL_USERS + !define WriteEnvStr_RegKey \ + 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' + !else + !define WriteEnvStr_RegKey 'HKCU "Environment"' + !endif +!endif + +; AddToPath - Adds the given dir to the search path. +; Input - head of the stack +; Note - Win9x systems requires reboot + +Function AddToPath + Exch $0 + Push $1 + Push $2 + Push $3 + + # don't add if the path doesn't exist + IfFileExists "$0\*.*" "" AddToPath_done + + ReadEnvStr $1 PATH + ; if the path is too long for a NSIS variable NSIS will return a 0 + ; length string. If we find that, then warn and skip any path + ; modification as it will trash the existing path. + StrLen $2 $1 + IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done + CheckPathLength_ShowPathWarning: + Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!" + Goto AddToPath_done + CheckPathLength_Done: + Push "$1;" + Push "$0;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$0\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + GetFullPathName /SHORT $3 $0 + Push "$1;" + Push "$3;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$3\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + + Call IsNT + Pop $1 + StrCmp $1 1 AddToPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" a + FileSeek $1 -1 END + FileReadByte $1 $2 + IntCmp $2 26 0 +2 +2 # DOS EOF + FileSeek $1 -1 END # write over EOF + FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" + FileClose $1 + SetRebootFlag true + Goto AddToPath_done + + AddToPath_NT: + StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey + ReadRegStr $1 ${NT_current_env} "PATH" + Goto DoTrim + ReadAllKey: + ReadRegStr $1 ${NT_all_env} "PATH" + DoTrim: + StrCmp $1 "" AddToPath_NTdoIt + Push $1 + Call Trim + Pop $1 + StrCpy $0 "$1;$0" + AddToPath_NTdoIt: + StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey + WriteRegExpandStr ${NT_current_env} "PATH" $0 + Goto DoSend + WriteAllKey: + WriteRegExpandStr ${NT_all_env} "PATH" $0 + DoSend: + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + AddToPath_done: + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + + +; RemoveFromPath - Remove a given dir from the path +; Input: head of the stack + +Function un.RemoveFromPath + Exch $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + + IntFmt $6 "%c" 26 # DOS EOF + + Call un.IsNT + Pop $1 + StrCmp $1 1 unRemoveFromPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" r + GetTempFileName $4 + FileOpen $2 $4 w + GetFullPathName /SHORT $0 $0 + StrCpy $0 "SET PATH=%PATH%;$0" + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoop: + FileRead $1 $3 + StrCpy $5 $3 1 -1 # read last char + StrCmp $5 $6 0 +2 # if DOS EOF + StrCpy $3 $3 -1 # remove DOS EOF so we can compare + StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "" unRemoveFromPath_dosLoopEnd + FileWrite $2 $3 + Goto unRemoveFromPath_dosLoop + unRemoveFromPath_dosLoopRemoveLine: + SetRebootFlag true + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoopEnd: + FileClose $2 + FileClose $1 + StrCpy $1 $WINDIR 2 + Delete "$1\autoexec.bat" + CopyFiles /SILENT $4 "$1\autoexec.bat" + Delete $4 + Goto unRemoveFromPath_done + + unRemoveFromPath_NT: + StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey + ReadRegStr $1 ${NT_current_env} "PATH" + Goto unDoTrim + unReadAllKey: + ReadRegStr $1 ${NT_all_env} "PATH" + unDoTrim: + StrCpy $5 $1 1 -1 # copy last char + StrCmp $5 ";" +2 # if last char != ; + StrCpy $1 "$1;" # append ; + Push $1 + Push "$0;" + Call un.StrStr ; Find `$0;` in $1 + Pop $2 ; pos of our dir + StrCmp $2 "" unRemoveFromPath_done + ; else, it is in path + # $0 - path to add + # $1 - path var + StrLen $3 "$0;" + StrLen $4 $2 + StrCpy $5 $1 -$4 # $5 is now the part before the path to remove + StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove + StrCpy $3 $5$6 + + StrCpy $5 $3 1 -1 # copy last char + StrCmp $5 ";" 0 +2 # if last char == ; + StrCpy $3 $3 -1 # remove last char + + StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey + WriteRegExpandStr ${NT_current_env} "PATH" $3 + Goto unDoSend + unWriteAllKey: + WriteRegExpandStr ${NT_all_env} "PATH" $3 + unDoSend: + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + unRemoveFromPath_done: + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Uninstall sutff +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +########################################### +# Utility Functions # +########################################### + +;==================================================== +; IsNT - Returns 1 if the current system is NT, 0 +; otherwise. +; Output: head of the stack +;==================================================== +; IsNT +; no input +; output, top of the stack = 1 if NT or 0 if not +; +; Usage: +; Call IsNT +; Pop $R0 +; ($R0 at this point is 1 or 0) + +!macro IsNT un +Function ${un}IsNT + Push $0 + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + StrCmp $0 "" 0 IsNT_yes + ; we are not NT. + Pop $0 + Push 0 + Return + + IsNT_yes: + ; NT!!! + Pop $0 + Push 1 +FunctionEnd +!macroend +!insertmacro IsNT "" +!insertmacro IsNT "un." + +; StrStr +; input, top of stack = string to search for +; top of stack-1 = string to search in +; output, top of stack (replaces with the portion of the string remaining) +; modifies no other variables. +; +; Usage: +; Push "this is a long ass string" +; Push "ass" +; Call StrStr +; Pop $R0 +; ($R0 at this point is "ass string") + +!macro StrStr un +Function ${un}StrStr +Exch $R1 ; st=haystack,old$R1, $R1=needle + Exch ; st=old$R1,haystack + Exch $R2 ; st=old$R1,old$R2, $R2=haystack + Push $R3 + Push $R4 + Push $R5 + StrLen $R3 $R1 + StrCpy $R4 0 + ; $R1=needle + ; $R2=haystack + ; $R3=len(needle) + ; $R4=cnt + ; $R5=tmp + loop: + StrCpy $R5 $R2 $R3 $R4 + StrCmp $R5 $R1 done + StrCmp $R5 "" done + IntOp $R4 $R4 + 1 + Goto loop +done: + StrCpy $R1 $R2 "" $R4 + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Exch $R1 +FunctionEnd +!macroend +!insertmacro StrStr "" +!insertmacro StrStr "un." + +Function Trim ; Added by Pelaca + Exch $R1 + Push $R2 +Loop: + StrCpy $R2 "$R1" 1 -1 + StrCmp "$R2" " " RTrim + StrCmp "$R2" "$\n" RTrim + StrCmp "$R2" "$\r" RTrim + StrCmp "$R2" ";" RTrim + GoTo Done +RTrim: + StrCpy $R1 "$R1" -1 + Goto Loop +Done: + Pop $R2 + Exch $R1 +FunctionEnd + +Function ConditionalAddToRegisty + Pop $0 + Pop $1 + StrCmp "$0" "" ConditionalAddToRegisty_EmptyString + WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \ + "$1" "$0" + ;MessageBox MB_OK "Set Registry: '$1' to '$0'" + DetailPrint "Set install registry entry: '$1' to '$0'" + ConditionalAddToRegisty_EmptyString: +FunctionEnd + +;-------------------------------- + +!ifdef CPACK_USES_DOWNLOAD +Function DownloadFile + IfFileExists $INSTDIR\* +2 + CreateDirectory $INSTDIR + Pop $0 + + ; Skip if already downloaded + IfFileExists $INSTDIR\$0 0 +2 + Return + + StrCpy $1 "@CPACK_DOWNLOAD_SITE@" + + try_again: + NSISdl::download "$1/$0" "$INSTDIR\$0" + + Pop $1 + StrCmp $1 "success" success + StrCmp $1 "Cancelled" cancel + MessageBox MB_OK "Download failed: $1" + cancel: + Return + success: +FunctionEnd +!endif + +;-------------------------------- +; Create desktop icon + +Function finishpageaction + CreateShortcut "$desktop\@CPACK_NSIS_DISPLAY_NAME@.lnk" "$instdir\@CPACK_NSIS_EXECUTABLE_NAME@" +FunctionEnd + +;-------------------------------- +; Installation types +@CPACK_NSIS_INSTALLATION_TYPES@ + +;-------------------------------- +; Component sections +@CPACK_NSIS_COMPONENT_SECTIONS@ + +;-------------------------------- +; Define some macro setting for the gui +@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@ +@CPACK_NSIS_INSTALLER_ICON_CODE@ +@CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE@ +@CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE@ +@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@ +@CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@ + +;-------------------------------- +;Pages + !insertmacro MUI_PAGE_WELCOME + + !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" + Page custom InstallOptionsPage + !insertmacro MUI_PAGE_DIRECTORY + + ;Start Menu Folder Page Configuration + !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" + !define MUI_STARTMENUPAGE_DEFAULTFOLDER "@CPACK_NSIS_STARTMENU_FOLDER@" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" + !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER + + ; Finish page + !define MUI_FINISHPAGE_SHOWREADME "" + !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED + !define MUI_FINISHPAGE_SHOWREADME_TEXT "Create Desktop Shortcut" + !define MUI_FINISHPAGE_SHOWREADME_FUNCTION finishpageaction + + @CPACK_NSIS_PAGE_COMPONENTS@ + + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" ;first language is the default language + !insertmacro MUI_LANGUAGE "Albanian" + !insertmacro MUI_LANGUAGE "Arabic" + !insertmacro MUI_LANGUAGE "Basque" + !insertmacro MUI_LANGUAGE "Belarusian" + !insertmacro MUI_LANGUAGE "Bosnian" + !insertmacro MUI_LANGUAGE "Breton" + !insertmacro MUI_LANGUAGE "Bulgarian" + !insertmacro MUI_LANGUAGE "Croatian" + !insertmacro MUI_LANGUAGE "Czech" + !insertmacro MUI_LANGUAGE "Danish" + !insertmacro MUI_LANGUAGE "Dutch" + !insertmacro MUI_LANGUAGE "Estonian" + !insertmacro MUI_LANGUAGE "Farsi" + !insertmacro MUI_LANGUAGE "Finnish" + !insertmacro MUI_LANGUAGE "French" + !insertmacro MUI_LANGUAGE "German" + !insertmacro MUI_LANGUAGE "Greek" + !insertmacro MUI_LANGUAGE "Hebrew" + !insertmacro MUI_LANGUAGE "Hungarian" + !insertmacro MUI_LANGUAGE "Icelandic" + !insertmacro MUI_LANGUAGE "Indonesian" + !insertmacro MUI_LANGUAGE "Irish" + !insertmacro MUI_LANGUAGE "Italian" + !insertmacro MUI_LANGUAGE "Japanese" + !insertmacro MUI_LANGUAGE "Korean" + !insertmacro MUI_LANGUAGE "Kurdish" + !insertmacro MUI_LANGUAGE "Latvian" + !insertmacro MUI_LANGUAGE "Lithuanian" + !insertmacro MUI_LANGUAGE "Luxembourgish" + !insertmacro MUI_LANGUAGE "Macedonian" + !insertmacro MUI_LANGUAGE "Malay" + !insertmacro MUI_LANGUAGE "Mongolian" + !insertmacro MUI_LANGUAGE "Norwegian" + !insertmacro MUI_LANGUAGE "Polish" + !insertmacro MUI_LANGUAGE "Portuguese" + !insertmacro MUI_LANGUAGE "PortugueseBR" + !insertmacro MUI_LANGUAGE "Romanian" + !insertmacro MUI_LANGUAGE "Russian" + !insertmacro MUI_LANGUAGE "Serbian" + !insertmacro MUI_LANGUAGE "SerbianLatin" + !insertmacro MUI_LANGUAGE "SimpChinese" + !insertmacro MUI_LANGUAGE "Slovak" + !insertmacro MUI_LANGUAGE "Slovenian" + !insertmacro MUI_LANGUAGE "Spanish" + !insertmacro MUI_LANGUAGE "Swedish" + !insertmacro MUI_LANGUAGE "Thai" + !insertmacro MUI_LANGUAGE "TradChinese" + !insertmacro MUI_LANGUAGE "Turkish" + !insertmacro MUI_LANGUAGE "Ukrainian" + !insertmacro MUI_LANGUAGE "Welsh" + + +;-------------------------------- +;Reserve Files + + ;These files should be inserted before other files in the data block + ;Keep these lines before any File command + ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) + + ReserveFile "NSIS.InstallOptions.ini" + !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS + +;-------------------------------- +;Installer Sections + +Section "-Core installation" + ;Use the entire tree produced by the INSTALL target. Keep the + ;list of directories here in sync with the RMDir commands below. + SetOutPath "$INSTDIR" + @CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@ + @CPACK_NSIS_FULL_INSTALL@ + + SetShellVarContext all + + ;Store installation folder + WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR + + ;Create uninstaller + WriteUninstaller "$INSTDIR\Uninstall.exe" + Push "DisplayName" + Push "@CPACK_NSIS_DISPLAY_NAME@" + Call ConditionalAddToRegisty + Push "DisplayVersion" + Push "@CPACK_PACKAGE_VERSION@" + Call ConditionalAddToRegisty + Push "Publisher" + Push "@CPACK_PACKAGE_VENDOR@" + Call ConditionalAddToRegisty + Push "UninstallString" + Push "$INSTDIR\Uninstall.exe" + Call ConditionalAddToRegisty + Push "NoRepair" + Push "1" + Call ConditionalAddToRegisty + + !ifdef CPACK_NSIS_ADD_REMOVE + ;Create add/remove functionality + Push "ModifyPath" + Push "$INSTDIR\AddRemove.exe" + Call ConditionalAddToRegisty + !else + Push "NoModify" + Push "1" + Call ConditionalAddToRegisty + !endif + + ; Optional registration + Push "DisplayIcon" + Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" + Call ConditionalAddToRegisty + Push "HelpLink" + Push "@CPACK_NSIS_HELP_LINK@" + Call ConditionalAddToRegisty + Push "URLInfoAbout" + Push "@CPACK_NSIS_URL_INFO_ABOUT@" + Call ConditionalAddToRegisty + Push "Contact" + Push "@CPACK_NSIS_CONTACT@" + Call ConditionalAddToRegisty + !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + + ;Create shortcuts + CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" +@CPACK_NSIS_CREATE_ICONS@ +@CPACK_NSIS_CREATE_ICONS_EXTRA@ + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + + ;Read a value from an InstallOptions INI file + !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" + !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" + !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" + + ; Write special uninstall registry entries + Push "StartMenu" + Push "$STARTMENU_FOLDER" + Call ConditionalAddToRegisty + Push "DoNotAddToPath" + Push "$DO_NOT_ADD_TO_PATH" + Call ConditionalAddToRegisty + Push "AddToPathAllUsers" + Push "$ADD_TO_PATH_ALL_USERS" + Call ConditionalAddToRegisty + Push "AddToPathCurrentUser" + Push "$ADD_TO_PATH_CURRENT_USER" + Call ConditionalAddToRegisty + Push "InstallToDesktop" + Push "$INSTALL_DESKTOP" + Call ConditionalAddToRegisty + + !insertmacro MUI_STARTMENU_WRITE_END + +@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ + +SectionEnd + +Section "-Add to path" + Push $INSTDIR\bin + StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath + StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0 + Call AddToPath + doNotAddToPath: +SectionEnd + +;-------------------------------- +; Create custom pages +Function InstallOptionsPage + !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" + !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" + +FunctionEnd + +;-------------------------------- +; determine admin versus local install +Function un.onInit + + ClearErrors + UserInfo::GetName + IfErrors noLM + Pop $0 + UserInfo::GetAccountType + Pop $1 + StrCmp $1 "Admin" 0 +3 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Admin group' + Goto done + StrCmp $1 "Power" 0 +3 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Power Users group' + Goto done + + noLM: + ;Get installation folder from registry if available + + done: + +FunctionEnd + +;--- Add/Remove callback functions: --- +!macro SectionList MacroName + ;This macro used to perform operation on multiple sections. + ;List all of your components in following manner here. +@CPACK_NSIS_COMPONENT_SECTION_LIST@ +!macroend + +Section -FinishComponents + ;Removes unselected components and writes component status to registry + !insertmacro SectionList "FinishSection" + +!ifdef CPACK_NSIS_ADD_REMOVE + ; Get the name of the installer executable + System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1' + StrCpy $R3 $R0 + + ; Strip off the last 13 characters, to see if we have AddRemove.exe + StrLen $R1 $R0 + IntOp $R1 $R0 - 13 + StrCpy $R2 $R0 13 $R1 + StrCmp $R2 "AddRemove.exe" addremove_installed + + ; We're not running AddRemove.exe, so install it + CopyFiles $R3 $INSTDIR\AddRemove.exe + + addremove_installed: +!endif +SectionEnd +;--- End of Add/Remove callback functions --- + +;-------------------------------- +; Component dependencies +Function .onSelChange + !insertmacro SectionList MaybeSelectionChanged +FunctionEnd + +;-------------------------------- +;Uninstaller Section + +Section "Uninstall" + ReadRegStr $START_MENU SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" + ;MessageBox MB_OK "Start menu is in: $START_MENU" + ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath" + ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers" + ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser" + ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS" + ReadRegStr $INSTALL_DESKTOP SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop" + ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP " + +@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@ + + ;Remove files we installed. + ;Keep the list of directories here in sync with the File commands above. +@CPACK_NSIS_DELETE_FILES@ +@CPACK_NSIS_DELETE_DIRECTORIES@ + +!ifdef CPACK_NSIS_ADD_REMOVE + ;Remove the add/remove program + Delete "$INSTDIR\AddRemove.exe" +!endif + + ;Remove the uninstaller itself. + Delete "$INSTDIR\Uninstall.exe" + DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + + ;Remove the installation directory if it is empty. + RMDir "$INSTDIR" + + ; Remove the registry entries. + DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + + ; Removes all optional components + !insertmacro SectionList "RemoveSection_CPack" + + !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP + + Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" +@CPACK_NSIS_DELETE_ICONS@ +@CPACK_NSIS_DELETE_ICONS_EXTRA@ + + ;Delete empty start menu parent diretories + StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" + + startMenuDeleteLoop: + ClearErrors + RMDir $MUI_TEMP + GetFullPathName $MUI_TEMP "$MUI_TEMP\.." + + IfErrors startMenuDeleteLoopDone + + StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop + startMenuDeleteLoopDone: + + ; If the user changed the shortcut, then untinstall may not work. This should + ; try to fix it. + StrCpy $MUI_TEMP "$START_MENU" + Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" +@CPACK_NSIS_DELETE_ICONS_EXTRA@ + + ;Delete empty start menu parent diretories + StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" + + secondStartMenuDeleteLoop: + ClearErrors + RMDir $MUI_TEMP + GetFullPathName $MUI_TEMP "$MUI_TEMP\.." + + IfErrors secondStartMenuDeleteLoopDone + + StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop + secondStartMenuDeleteLoopDone: + + DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + + Push $INSTDIR\bin + StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0 + Call un.RemoveFromPath + doNotRemoveFromPath: +SectionEnd + +;-------------------------------- +; determine admin versus local install +; Is install for "AllUsers" or "JustMe"? +; Default to "JustMe" - set to "AllUsers" if admin or on Win9x +; This function is used for the very first "custom page" of the installer. +; This custom page does not show up visibly, but it executes prior to the +; first visible page and sets up $INSTDIR properly... +; Choose different default installation folder based on SV_ALLUSERS... +; "Program Files" for AllUsers, "My Documents" for JustMe... + +Function .onInit + StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst + + ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" + StrCmp $0 "" inst + + MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \ + "@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \ + /SD IDYES IDYES uninst IDNO inst + Abort + +;Run the uninstaller +uninst: + ClearErrors + StrLen $2 "\Uninstall.exe" + StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path + ExecWait '"$0" /S _?=$3' ;Do not copy the uninstaller to a temp file + + IfErrors uninst_failed inst +uninst_failed: + MessageBox MB_OK|MB_ICONSTOP "Uninstall failed." + Abort + + +inst: + ; Reads components status for registry + !insertmacro SectionList "InitSection" + + ; check to see if /D has been used to change + ; the install directory by comparing it to the + ; install directory that is expected to be the + ; default + StrCpy $IS_DEFAULT_INSTALLDIR 0 + StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2 + StrCpy $IS_DEFAULT_INSTALLDIR 1 + + StrCpy $SV_ALLUSERS "JustMe" + ; if default install dir then change the default + ; if it is installed for JustMe + StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 + StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@" + + ClearErrors + UserInfo::GetName + IfErrors noLM + Pop $0 + UserInfo::GetAccountType + Pop $1 + StrCmp $1 "Admin" 0 +4 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Admin group' + StrCpy $SV_ALLUSERS "AllUsers" + Goto done + StrCmp $1 "Power" 0 +4 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Power Users group' + StrCpy $SV_ALLUSERS "AllUsers" + Goto done + + noLM: + StrCpy $SV_ALLUSERS "AllUsers" + ;Get installation folder from registry if available + + done: + StrCmp $SV_ALLUSERS "AllUsers" 0 +3 + StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 + StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" + + StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage + !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" + + noOptionsPage: +FunctionEnd diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d07364..0128295 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ PROJECT(XTrkCAD) enable_testing() cmake_minimum_required(VERSION 2.8) +set(CMAKE_MACOSX_RPATH 0) # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked @@ -11,20 +12,23 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMake") if(UNIX) include(FindPkgConfig) set(XTRKCAD_USE_GTK_DEFAULT ON) - if(APPLE) + if(APPLE) SET(XTRKCAD_USE_GETTEXT_DEFAULT OFF) - else() - set(XTRKCAD_USE_GETTEXT_DEFAULT ON) - add_compile_options("-std=gnu99") - PKG_CHECK_MODULES(GTK_WEBKIT "webkit-1.0") + SET(XTRKCAD_USE_APPLEHELP_DEFAULT ON) + PKG_CHECK_MODULES(GTK_WEBKIT "webkit-1.0" QUIET) if(GTK_WEBKIT_FOUND) set(XTRKCAD_USE_BROWSER_DEFAULT OFF) else() set(XTRKCAD_USE_BROWSER_DEFAULT ON) endif() - endif(APPLE) + else() + set(XTRKCAD_USE_BROWSER_DEFAULT ON) + endif(APPLE) endif(UNIX) +find_package(Libzip) +find_package(Zlib) + IF(WIN32) SET(XTRKCAD_USE_GTK_DEFAULT OFF) SET(XTRKCAD_USE_GETTEXT_DEFAULT ON) @@ -41,7 +45,7 @@ ENDIF(WIN32) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) if( POLICY CMP0026 ) - cmake_policy(SET CMP0026 OLD) + cmake_policy(SET CMP0026 NEW) endif( POLICY CMP0026 ) endif(COMMAND cmake_policy) @@ -54,6 +58,11 @@ if(UNIX AND NOT APPLE) option(XTRKCAD_USE_BROWSER "Show help in default browser" ${XTRKCAD_USE_BROWSER_DEFAULT}) endif() +if(APPLE) + option(XTRKCAD_USE_APPLEHELP "Show help in Apple Help" ${XTRKCAD_USE_APPLEHELP_DEFAULT}) + option(XTRKCAD_USE_BROWSER "Show help in default browser" ${XTRKCAD_USE_BROWSER_DEFAULT}) +endif() + IF(UNIX) PKG_CHECK_MODULES(GTK REQUIRED "gtk+-2.0") ENDIF() @@ -85,9 +94,9 @@ ENDIF(XTRKCAD_USE_PACKAGEMAKER) # Find unit testing framework find_package(CMocka) if(CMOCKA_FOUND) - include_directories(${CMOCKA_INCLUDE_DIR}) - set(LIBS ${LIBS} ${CMOCKA_LIBRARIES}) - option( XTRKCAD_TESTING "Build unittests" ON) + include_directories(${CMOCKA_INCLUDE_DIR}) + set(LIBS ${LIBS} ${CMOCKA_LIBRARIES}) + option( XTRKCAD_TESTING "Build unittests" ON) endif() # Find document conversion tool @@ -100,9 +109,9 @@ CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H) # Setup some global options for installation ... SET(XTRKCAD_MAJOR_VERSION "5") -SET(XTRKCAD_MINOR_VERSION "1") -SET(XTRKCAD_RELEASE_VERSION "2") -SET(XTRKCAD_VERSION_MODIFIER "a") +SET(XTRKCAD_MINOR_VERSION "2") +SET(XTRKCAD_RELEASE_VERSION "0") +SET(XTRKCAD_VERSION_MODIFIER "Beta2.1") SET(XTRKCAD_VERSION "${XTRKCAD_MAJOR_VERSION}.${XTRKCAD_MINOR_VERSION}.${XTRKCAD_RELEASE_VERSION}${XTRKCAD_VERSION_MODIFIER}") IF(WIN32) @@ -136,6 +145,13 @@ IF(XTRKCAD_USE_GETTEXT) endif(INTL_PATH) endif() ENDIF(WIN32) + iF(APPLE) + find_path ( INTL_PATH libintl.h ) + if(INTL_PATH) + message( STATUS "Use installed gettext module" ) + INCLUDE_DIRECTORIES(${INTL_PATH}) + endif(INTL_PATH) + ENDIF(APPLE) ELSE(XTRKCAD_USE_GETTEXT) SET(GENHELP_OPTS "-bh") ENDIF(XTRKCAD_USE_GETTEXT) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 5791fa2..72ca170 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,7 +1,9 @@ + # "bin/i18n.h" is widely used INCLUDE_DIRECTORIES(bin) include_directories(dynstring) include_directories(cornu) +include_directories(libzip) # Setup the rest of the build ... add_subdirectory(dynstring) @@ -15,5 +17,4 @@ ADD_SUBDIRECTORY(cornu) IF(XTRKCAD_USE_GETTEXT) ADD_SUBDIRECTORY(i18n) -ENDIF(XTRKCAD_USE_GETTEXT) - +ENDIF(XTRKCAD_USE_GETTEXT) \ No newline at end of file diff --git a/app/bin/CMakeLists.txt b/app/bin/CMakeLists.txt index 74b1bc8..2dea1bc 100644 --- a/app/bin/CMakeLists.txt +++ b/app/bin/CMakeLists.txt @@ -1,5 +1,6 @@ +include( CheckSymbolExists ) + ADD_EXECUTABLE(cnvdsgn cnvdsgn.c utility.c) -GET_TARGET_PROPERTY(cnvdsgn_EXE cnvdsgn LOCATION) IF(NOT WIN32) TARGET_LINK_LIBRARIES(cnvdsgn m) ENDIF(NOT WIN32) @@ -8,7 +9,7 @@ MACRO(GENERATE_LIN lin_name) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${lin_name}.lin DEPENDS cnvdsgn ${CMAKE_CURRENT_SOURCE_DIR}/${lin_name}.src - COMMAND ${cnvdsgn_EXE} < ${CMAKE_CURRENT_SOURCE_DIR}/${lin_name}.src > ${CMAKE_CURRENT_BINARY_DIR}/${lin_name}.lin + COMMAND cnvdsgn < ${CMAKE_CURRENT_SOURCE_DIR}/${lin_name}.src > ${CMAKE_CURRENT_BINARY_DIR}/${lin_name}.lin ) ENDMACRO(GENERATE_LIN) @@ -24,6 +25,9 @@ GENERATE_LIN(tosslip) GENERATE_LIN(tostrsct) GENERATE_LIN(towye) GENERATE_LIN(toxing) +GENERATE_LIN(tocornu) +GENERATE_LIN(tocornuwye) +GENERATE_LIN(tocornu3way) SET(LIN_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/to3way.lin @@ -38,19 +42,21 @@ SET(LIN_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/tostrsct.lin ${CMAKE_CURRENT_BINARY_DIR}/towye.lin ${CMAKE_CURRENT_BINARY_DIR}/toxing.lin + ${CMAKE_CURRENT_BINARY_DIR}/tocornu.lin + ${CMAKE_CURRENT_BINARY_DIR}/tocornuwye.lin + ${CMAKE_CURRENT_BINARY_DIR}/tocornu3way.lin ) -GET_TARGET_PROPERTY(genhelp_EXE genhelp LOCATION) - ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bllnhlp.c - DEPENDS genhelp ${help_SOURCE_DIR}/genhelp.in - COMMAND ${genhelp_EXE} ${GENHELP_OPTS} ${help_SOURCE_DIR}/genhelp.in ${CMAKE_CURRENT_BINARY_DIR}/bllnhlp.c + DEPENDS genhelp ${help_SOURCE_DIR}/genhelp.json + COMMAND genhelp ${GENHELP_OPTS} ${help_SOURCE_DIR}/genhelp.json ${CMAKE_CURRENT_BINARY_DIR}/bllnhlp.c ) SET(SOURCES ${LIN_SOURCES} appdefaults.c + archive.c bllnhlp.c cbezier.c cblock.c @@ -95,6 +101,7 @@ SET(SOURCES dcontmgm.c dease.c denum.c + directory.c dlayer.c doption.c dpricels.c @@ -104,33 +111,72 @@ SET(SOURCES dxfformat.c dxfoutput.c elev.c + file2uri.c + file2uri.h fileio.c + filenoteui.c i18n.c layout.c + linknoteui.c lprintf.c macro.c + manifest.c misc2.c param.c + paramfile.c + paramfilelist.c + paramfilesearch_ui.c + partcatalog.c paths.c + shortentext.c shrtpath.c smalldlg.c + stringxtc.c tbezier.c tcornu.c tcurve.c tease.c + textnoteui.c track.c + trknote.c trkseg.c tstraigh.c utility.c + validator.c + cJSON.c + archive.h + directory.h + manifest.h + validator.h ) +# add UTF-8 conversion utilities on Windows +if(WIN32) + set( SOURCES + ${SOURCES} + utf8convert.c + include/utf8convert.h + ) +endif(WIN32) + +set (SOURCES + ${SOURCES} + include/dirent.h + include/paramfile.h + include/paramfilelist.h +) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) INCLUDE_DIRECTORIES(${XTrkCAD_BINARY_DIR}) INCLUDE_DIRECTORIES(${help_BINARY_DIR}) INCLUDE_DIRECTORIES(${wlib_SOURCE_DIR}/include) +include_directories(${FREEIMAGE_INCLUDE_PATH}) +INCLUDE_DIRECTORIES(${LIBZIP_INCLUDE_DIR_ZIP}) +INCLUDE_DIRECTORIES(${CJSON_INCLUDE}) LINK_DIRECTORIES(${GTK_LIBRARY_DIRS}) LINK_DIRECTORIES(${GTK_WEBKIT_LIBRARY_DIRS}) +LINK_DIRECTORIES(${LIBZIP_LIBZIP_LIBRARY}) ADD_LIBRARY(xtrkcad-lib ${SOURCES}) @@ -145,18 +191,22 @@ TARGET_LINK_LIBRARIES(xtrkcad xtrkcad-lib) TARGET_LINK_LIBRARIES(xtrkcad xtrkcad-wlib) TARGET_LINK_LIBRARIES(xtrkcad xtrkcad-cornu) TARGET_LINK_LIBRARIES(xtrkcad dynstring) +target_link_libraries(xtrkcad ${LIBZIP_LIBRARY} ${LIBZIP_LIBRARIES}) ADD_EXECUTABLE(mkturnout ${LIN_SOURCES} ctodesgn.c utility.c + ) SET_TARGET_PROPERTIES(mkturnout PROPERTIES COMPILE_FLAGS -DMKTURNOUT) +TARGET_LINK_LIBRARIES(mkturnout xtrkcad-cornu) + IF(NOT WIN32) TARGET_LINK_LIBRARIES(mkturnout m) TARGET_LINK_LIBRARIES(xtrkcad m) - + # Link libintl for systems where it is a separate library find_library( INTL_LIBRARY intl ) if(INTL_LIBRARY) @@ -164,25 +214,57 @@ IF(NOT WIN32) endif(INTL_LIBRARY) ELSE(NOT WIN32) TARGET_LINK_LIBRARIES(mkturnout xtrkcad-wlib) -ENDIF(NOT WIN32) + + # copy dlls into the build dir for easier debugging + add_custom_command( + TARGET xtrkcad POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${FREEIMAGE_SHAREDLIB} + ${CMAKE_CURRENT_BINARY_DIR} + ) + + add_custom_command( + TARGET xtrkcad POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${LIBZIP_SHAREDLIB} + ${CMAKE_CURRENT_BINARY_DIR} + ) + + add_custom_command( + TARGET xtrkcad POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${ZLIB_SHAREDLIB} + ${CMAKE_CURRENT_BINARY_DIR} + ) + + # add dll to install package + install(FILES + ${LIBZIP_SHAREDLIB} + DESTINATION ${XTRKCAD_BIN_INSTALL_DIR} + ) + install(FILES + ${ZLIB_SHAREDLIB} + DESTINATION ${XTRKCAD_BIN_INSTALL_DIR} + ) +ENDIF(NOT WIN32) # for testing only, should be IF(APPLE) ... IF(APPLE) - ADD_EXECUTABLE( helphelper helphelper.c ) + ADD_EXECUTABLE( helphelper helphelper.c ) FIND_LIBRARY(COREFOUNDATION_LIBRARY CoreFoundation) - FIND_LIBRARY(CARBON_LIBRARY Carbon) + FIND_LIBRARY(CARBON_LIBRARY Carbon) TARGET_lINK_LIBRARIES(helphelper ${COREFOUNDATION_LIBRARY} ${CARBON_LIBRARY}) INSTALL( TARGETS helphelper RUNTIME DESTINATION ${XTRKCAD_BIN_INSTALL_DIR} ) ENDIF(APPLE) - + INSTALL( TARGETS xtrkcad RUNTIME DESTINATION ${XTRKCAD_BIN_INSTALL_DIR} ) - -if(XTRKCAD_TESTING AND CMOCKA_FOUND) + +if(XTRKCAD_TESTING AND CMOCKA_FOUND) add_subdirectory( unittest ) -endif() +endif() diff --git a/app/bin/acclkeys.h b/app/bin/acclkeys.h index 1cbdf00..4dd80fc 100644 --- a/app/bin/acclkeys.h +++ b/app/bin/acclkeys.h @@ -40,6 +40,9 @@ #define ACCL_CIRCLE2 (WCTL+'9') #define ACCL_CIRCLE3 (WCTL+'0') #define ACCL_BEZIER (0) +#define ACCL_CORNU (0) +#define ACCL_CONVERTTO (0) +#define ACCL_CONVERTFR (0) #define ACCL_TURNOUT (WCTL+'t') #define ACCL_TURNTABLE (WCTL+WSHIFT+'n') #define ACCL_PARALLEL (WCTL+WSHIFT+'p') @@ -56,6 +59,8 @@ #define ACCL_PROFILE (WCTL+WSHIFT+'f') #define ACCL_DELETE (WCTL+'d') #define ACCL_TUNNEL (WCTL+WSHIFT+'t') +#define ACCL_BRIDGE (0) +#define ACCL_TIES (0) #define ACCL_HNDLDTO (WCTL+WSHIFT+'i') #define ACCL_TEXT (WCTL+WSHIFT+'x') #define ACCL_DRAWLINE (WCTL+WSHIFT+'1') @@ -75,8 +80,10 @@ #define ACCL_DRAWBEZLINE (0) #define ACCL_DRAWBOX (WCTL+WSHIFT+'[') #define ACCL_DRAWFILLBOX (WALT+WCTL+'[') -#define ACCL_DRAWPOLYLINE (WCTL+WSHIFT+'2') +#define ACCL_DRAWPOLYLINE (0) #define ACCL_DRAWPOLYGON (WALT+WCTL+'2') +#define ACCL_DRAWPOLY (0) +#define ACCL_DRAWFILLPOLYGON (WCTL+WSHIFT+'2') #define ACCL_NOTE (WALT+WCTL+'n') #define ACCL_STRUCTURE (WCTL+WSHIFT+'c') #define ACCL_ABOVE (WCTL+WSHIFT+'b') @@ -104,6 +111,7 @@ #define ACCL_COPY (WCTL+'c') #define ACCL_CUT (WCTL+'x') #define ACCL_PASTE (WCTL+'v') +#define ACCL_CLONE (0) #define ACCL_SELECTALL (WCTL+WSHIFT+'a') #define ACCL_DESELECTALL (0) #define ACCL_THIN (WCTL+'1') @@ -111,6 +119,7 @@ #define ACCL_THICK (WCTL+'3') #define ACCL_EXPORT (WALT+WCTL+'x') #define ACCL_IMPORT (WALT+WCTL+'i') +#define ACCL_IMPORT_MOD (0) #define ACCL_EXPORTDXF (0) #define ACCL_LOOSEN (WCTL+WSHIFT+'k') #define ACCL_GROUP (WCTL+WSHIFT+'g') @@ -149,6 +158,7 @@ #define ACCL_PLAYBACK (WALT+WCTL+'b') #define ACCL_BRIDGE (0) +#define ACCL_TIES (0) /* Blocks */ #define ACCL_BLOCK1 (0) diff --git a/app/bin/appdefaults.c b/app/bin/appdefaults.c index a2dd885..55a2201 100644 --- a/app/bin/appdefaults.c +++ b/app/bin/appdefaults.c @@ -82,7 +82,10 @@ static char *GetParamPrototype(struct appDefault *ptrDefault, */ struct appDefault xtcDefaults[] = { - { "DialogItem.cmdopt-preselect", 0, INTEGERCONSTANT,{ .intValue = 1 } }, /**< default command is select */ + { "DialogItem.cmdopt-preselect", 0, INTEGERCONSTANT,{ .intValue = 1 } }, /**< default command is select */ + { "DialogItem.cmdopt-rightclickmode", 0, INTEGERCONSTANT,{ .intValue = 1 } }, /**< swap default to context */ + { "DialogItem.cmdopt-selectmode", 0, INTEGERCONSTANT,{ .intValue = 0 } }, /**< 'Only' mode */ + { "DialogItem.cmdopt-selectzero", 0, INTEGERCONSTANT,{ .intValue = 1 } }, /**< 'On' mode */ { "DialogItem.grid-horzenable", 0, INTEGERCONSTANT, { .intValue = 0 }}, { "DialogItem.grid-vertenable", 0, INTEGERCONSTANT,{ .intValue = 0 } }, { "DialogItem.pref-dstfmt", 0, INTEGERFUNCTION,{ .intFunction = GetLocalDistanceFormat } }, /**< number format for distances */ @@ -226,6 +229,14 @@ InitializeRegionCode(void) #endif } +/** + * Use Metric measures everywhere except United States and Canada\ + */ +static bool UseMetric() +{ + return ( strcmp( regionCode, "US" ) != 0 && + strcmp( regionCode, "CA" ) != 0 ); +} /** * For the US the classical 4x8 sheet is used as default size. in the metric world 1,25x2,0m is used. */ @@ -234,11 +245,11 @@ static double GetLocalRoomSize(struct appDefault *ptrDefault, void *data) { if (!strcmp(ptrDefault->defaultKey, "draw.roomsizeY")) { - return (strcmp(regionCode, "US") ? 125.0/2.54 : 48); + return (UseMetric() ? 125.0/2.54 : 48); } if (!strcmp(ptrDefault->defaultKey, "draw.roomsizeX")) { - return (strcmp(regionCode, "US") ? 200.0 / 2.54 : 96); + return (UseMetric() ? 200.0 / 2.54 : 96); } return (0.0); // should never get here @@ -255,21 +266,21 @@ GetLocalPopularScale(struct appDefault *ptrDefault, void *data) } /** - * The measurement system is english for the US and metric elsewhere + * The measurement system is english for the US and Canada and metric elsewhere */ static int GetLocalMeasureSystem(struct appDefault *ptrDefault, void *data) { - return (strcmp(regionCode, "US") ? 1 : 0); + return (UseMetric() ? 1 : 0); } /** -* The distance format is 999.9 cm for metric and ?? for english +* The distance format is 999.9 cm for metric and 999.99 for english */ static int GetLocalDistanceFormat(struct appDefault *ptrDefault, void *data) { - return (strcmp(regionCode, "US") ? 8 : 5); + return (UseMetric() ? 8 : 4); } /** diff --git a/app/bin/archive.c b/app/bin/archive.c new file mode 100644 index 0000000..4e82bd3 --- /dev/null +++ b/app/bin/archive.c @@ -0,0 +1,454 @@ +/** \file archive.c + * ARCHIVE PROCESSING + */ + +/* XTrkCad - Model Railroad CAD + * Copyright (C) 2018 Adam Richards and Martin Fischer + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include +#include +#include +#include + +#include + +#ifdef WINDOWS + #include "include/dirent.h" + #include + #include + #include + #define unlink(a) _unlink((a)) + #define rmdir(a) _rmdir((a)) + #define open(name, flag, mode) _open((name), (flag), (mode)) + #define write(file, buffer, count) _write((file),(buffer), (count)) + #define close(file) _close((file)) + #define getpid() _getpid() +#else + #include + #include +#endif + +#include +#include "archive.h" +#include "directory.h" +#include "dynstring.h" +#include "i18n.h" +#include "messages.h" +#include "misc.h" +#include "misc2.h" +#include "paths.h" +#include "include/utf8convert.h" + +int log_zip = 0; + +//char * +//NativeToUtf8(const char *nativeString) +//{ +// +//#ifdef WINDOWS +// +// int cnt = 2 * (strlen(nativeString) + 1); +// char *tempBuffer = MyMalloc( cnt ); +// char *destBuffer = MyMalloc( cnt ); +// +// //// find the +// //cnt = MultiByteToWideChar(CP_ACP, +// // 0, +// // nativeString, +// // -1, +// // tempBuffer, +// // 0); +// +// //tempBuffer = realloc(tempBuffer, cnt * 2 + 4); +// +// // convert to wide character (UTF16) +// MultiByteToWideChar(CP_ACP, +// 0, +// nativeString, +// -1, +// (LPWSTR)tempBuffer, +// cnt); +// +// // convert from wide char to UTF-8 +// WideCharToMultiByte(CP_UTF8, +// 0, +// (LPCWCH)tempBuffer, +// -1, +// (LPSTR)destBuffer, +// cnt, +// NULL, +// NULL); +// +// MyFree(tempBuffer); +//#else +// char * destBuffer = MyStrdup(nativeString); +//#endif +// +// return(destBuffer); +//} + +/** + * Create the full path for temporary directories used in zip archive operations + * + * \param archive operation + * \return pointer to full path, must be free'd by caller + */ + +char * +GetZipDirectoryName(enum ArchiveOps op) +{ + char *opDesc; + char *directory; + DynString zipDirectory; + + DynStringMalloc(&zipDirectory, 0); + + switch (op) { + case ARCHIVE_READ: + opDesc = "in"; + break; + case ARCHIVE_WRITE: + opDesc = "out"; + break; + default: + opDesc = "err"; + break; + } + + DynStringPrintf(&zipDirectory, + "%s" FILE_SEP_CHAR "zip_%s.%d", + workingDir, + opDesc, + getpid()); + + directory = strdup(DynStringToCStr(&zipDirectory)); + DynStringFree(&zipDirectory); + return (directory); +} + +/***************************************************************************** + * Add directory to archive + * + * \param IN zip The open zip archive handle + * \param IN dir_path The path to add + * \param IN prefix The prefix in the archive + * + * \returns TRUE if OK + */ + +BOOL_T AddDirectoryToArchive( + struct zip * za, + const char * dir_path, + const char * prefix) +{ + + char *full_path; + char *arch_path; + DIR *dir; + const char * buf; + struct stat stat_path, stat_entry; + struct dirent *entry; + + zip_source_t * zt; + + // stat for the path + stat(dir_path, &stat_path); + + // if path does not exists or is not dir - exit with status -1 + if (S_ISDIR(stat_path.st_mode) == 0) { + NoticeMessage(MSG_NOT_DIR_FAIL, + _("Continue"), NULL, dir_path); + return FALSE; + } + + // if not possible to read the directory for this user + if ((dir = opendir(dir_path)) == NULL) { + NoticeMessage(MSG_OPEN_DIR_FAIL, + _("Continue"), NULL, dir_path); + return FALSE; + } + + // iteration through entries in the directory + while ((entry = readdir(dir)) != NULL) { + // skip entries "." and ".." + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { + continue; + } + + // determinate a full path of an entry + MakeFullpath(&full_path, dir_path, entry->d_name, NULL); + + // stat for the entry + stat(full_path, &stat_entry); + + if (prefix && prefix[0]) { + MakeFullpath(&arch_path, prefix, entry->d_name, NULL); + } else { + MakeFullpath(&arch_path, entry->d_name, NULL); + } + + // recursively add a nested directory + if (S_ISDIR(stat_entry.st_mode) != 0) { + if (zip_dir_add(za, arch_path, 0) < 0) { + zip_error_t *ziperr = zip_get_error(za); + buf = zip_error_strerror(ziperr); + NoticeMessage(MSG_ZIP_DIR_ADD_FAIL, + _("Continue"), NULL, arch_path, buf); +#if DEBUG + printf("Added Directory %s \n", arch_path); +#endif + } + + if (AddDirectoryToArchive(za, full_path, arch_path) != TRUE) { + free(full_path); + free(arch_path); + return FALSE; + } + free(arch_path); + continue; + } else { + char *archPathUtf8 = MyStrdup(arch_path); + char *fullPathUtf8 = MyStrdup(full_path); +#ifdef WINDOWS + archPathUtf8 = Convert2UTF8(archPathUtf8); + fullPathUtf8 = Convert2UTF8(fullPathUtf8); + ConvertPathForward(archPathUtf8); +#endif // WINDOWS + zt = zip_source_file(za, fullPathUtf8, 0, -1); + if (zip_file_add(za, archPathUtf8, zt, ZIP_FL_ENC_UTF_8) == -1) { + zip_error_t *ziperr = zip_get_error(za); + buf = zip_error_strerror(ziperr); + NoticeMessage(MSG_ZIP_FILE_ADD_FAIL, _("Continue"), NULL, full_path, arch_path, + buf); + free(full_path); + free(arch_path); + MyFree(fullPathUtf8); + MyFree(archPathUtf8); + return FALSE; + } + MyFree(fullPathUtf8); + MyFree(archPathUtf8); +#if DEBUG + printf("Added File %s", full_path); +#endif + } + free(arch_path); + free(full_path); + } + + closedir(dir); + return TRUE; +} + +/*********************************************************************** + * Create Archive + * + * \param IN dir_path The place to create the archive + * \param IN fileName The name of the archive + * + * \return TRUE if ok + */ + +BOOL_T CreateArchive( + const char * dir_path, + const char * fileName) +{ + struct zip *za; + int err; + char buf[100]; + + char * archive = MyStrdup(fileName); // Because of const char + char * archive_name = FindFilename(archive); + char * archive_path; + char * archiveUtf8; + + MakeFullpath(&archive_path, workingDir, archive_name, NULL); + + archiveUtf8 = MyStrdup(archive_path); +#ifdef WINDOWS + archiveUtf8 = Convert2UTF8(archiveUtf8); +#endif // WINDOWS + + MyFree(archive); + + if ((za = zip_open(archiveUtf8, ZIP_CREATE, &err)) == NULL) { + zip_error_to_str(buf, sizeof(buf), err, errno); + NoticeMessage(MSG_ZIP_CREATE_FAIL, _("Continue"), NULL, archiveUtf8, buf); + MyFree(archiveUtf8); + return FALSE; + } +#if DEBUG + printf("====================== \n"); + printf("Started Archive %s", archive_path); +#endif + + AddDirectoryToArchive(za, dir_path, ""); + + if (zip_close(za) == -1) { + zip_error_to_str(buf, sizeof(buf), err, errno); + NoticeMessage(MSG_ZIP_CLOSE_FAIL, _("Continue"), NULL, archiveUtf8, buf); + free(archive_path); + MyFree(archiveUtf8); + return FALSE; + } + + unlink(fileName); //Delete Old + if (rename(archive_path, fileName) == -1) { //Move zip into place + NoticeMessage(MSG_ZIP_RENAME_FAIL, _("Continue"), NULL, archiveUtf8, fileName, + strerror(errno)); + free(archive_path); + MyFree(archiveUtf8); + return FALSE; + } + free(archive_path); + MyFree(archiveUtf8); + +#if DEBUG + printf("Moved Archive to %s", fileName); + printf("====================== \n"); +#endif + return TRUE; +} + +/************************************************************************** + * Unpack_Archive_for + * + * \param IN pathName the name of the archive + * \param IN fileName just the filename and extension of the layout + * \param IN tempDir The directory to use to unpack into + * + * \returns TRUE if all worked + */ +BOOL_T UnpackArchiveFor( + const char * pathName, /*Full name of archive*/ + const char * fileName, /*Layout name and extension */ + const char * tempDir, /*Directory to unpack into */ + BOOL_T file_only) +{ + char *dirName; + struct zip *za; + struct zip_file *zf; + struct zip_stat sb; + char buf[100]; + int err; + int i; + int64_t len; + FILE *fd; + long long sum; + + char *destBuffer = MyStrdup(pathName); +#ifdef WINDOWS + destBuffer = Convert2UTF8(destBuffer); +#endif // WINDOWS + + + if ((za = zip_open(destBuffer, 0, &err)) == NULL) { + zip_error_to_str(buf, sizeof(buf), err, errno); + NoticeMessage(MSG_ZIP_OPEN_FAIL, _("Continue"), NULL, pathName, buf); + fprintf(stderr, "xtrkcad: can't open xtrkcad zip archive `%s': %s \n", + pathName, buf); + + MyFree(destBuffer); + return FALSE; + } + + for (i = 0; i < zip_get_num_entries(za, 0); i++) { + if (zip_stat_index(za, i, 0, &sb) == 0) { + len = strlen(sb.name); + +#if DEBUG + printf("==================\n"); + printf("Name: [%s], ", sb.name); + printf("Size: [%llu], ", sb.size); + printf("mtime: [%u]\n", (unsigned int)sb.mtime); + printf("mtime: [%u]\n", (unsigned int)sb.mtime); +#endif + + LOG(log_zip, 1, ("================= \n")) + LOG(log_zip, 1, ("Zip-Name [%s] \n", sb.name)) + LOG(log_zip, 1, ("Zip-Size [%llu] \n", sb.size)) + LOG(log_zip, 1, ("Zip-mtime [%u] \n", (unsigned int)sb.mtime)) + + if (sb.name[len - 1] == '/' && !file_only) { + MakeFullpath(&dirName, tempDir, &sb.name[0], NULL); + if (SafeCreateDir(dirName) != TRUE) { + free(dirName); + return FALSE; + } + free(dirName); + } else { + zf = zip_fopen_index(za, i, 0); + if (!zf) { + NoticeMessage(MSG_ZIP_INDEX_FAIL, _("Continue"), NULL); + fprintf(stderr, "xtrkcad zip archive open index error \n"); + return FALSE; + } + + if (file_only) { + if (strncmp(sb.name, fileName, strlen(fileName)) != 0) { + continue; /* Ignore any other files than the one we asked for */ + } + } + MakeFullpath(&dirName, tempDir, &sb.name[0], NULL); +#ifdef WINDOWS + ConvertUTF8ToSystem(dirName); +#endif // WINDOWS + fd = fopen(dirName, "wb"); + if (!fd) { + NoticeMessage(MSG_ZIP_FILE_OPEN_FAIL, _("Continue"), NULL, dirName, + strerror(errno)); + free(dirName); + return FALSE; + } + + sum = 0; + while (sum != sb.size) { + len = zip_fread(zf, buf, 100); + if (len < 0) { + NoticeMessage(MSG_ZIP_READ_FAIL, _("Continue"), NULL, dirName, &sb.name[0]); + free(dirName); + fclose(fd); + return FALSE; + } + fwrite(buf, 1, (unsigned int)len, fd); + sum += len; + } + fclose(fd); + free(dirName); + zip_fclose(zf); + } + } else { + LOG(log_zip, 1, ("Zip-Unknown File[%s] Line[%d] \n", __FILE__, __LINE__)) +#if DEBUG + printf("File[%s] Line[%d]\n", __FILE__, __LINE__); +#endif + } + } + + MyFree(destBuffer); + + if (zip_close(za) == -1) { + NoticeMessage(MSG_ZIP_CLOSE_FAIL, _("Continue"), NULL, dirName, &sb.name[0]); + return FALSE; + } + return TRUE; +} + diff --git a/app/bin/archive.h b/app/bin/archive.h new file mode 100644 index 0000000..cfbb642 --- /dev/null +++ b/app/bin/archive.h @@ -0,0 +1,15 @@ +#ifndef HAVE_ARCHIVE_H +#define HAVE_ARCHIVE_H +#include +#include "common.h" + +enum ArchiveOps { ARCHIVE_READ, ARCHIVE_WRITE }; // has to be contiguous, see CleanupFiles()! + +extern int log_zip; +extern const char *workingDir; + +char *GetZipDirectoryName(enum ArchiveOps op); +BOOL_T AddDirectoryToArchive(struct zip * za, const char * dir_path, const char * prefix); +BOOL_T CreateArchive(const char * dir_path, const char * fileName); +BOOL_T UnpackArchiveFor(const char * pathName, const char * fileName, const char * tempDir, BOOL_T file_only); +#endif diff --git a/app/bin/bdf2xtp.c b/app/bin/bdf2xtp.c index 76fb31a..c979aa3 100644 --- a/app/bin/bdf2xtp.c +++ b/app/bin/bdf2xtp.c @@ -9,6 +9,7 @@ #include #ifndef _MSDOS #include +#include "fileio.h" #else #define M_PI 3.14159265358979323846 #define strncasecmp strnicmp @@ -563,7 +564,7 @@ void generateTurnout( void ) fprintf( fout, "\tC 0 0 %0.6f %0.6f %0.6f %0.6f %0.6f\n", X(sp->radius), X(center.x), X(center.y), X(a0), X(a1) ); } - fprintf( fout, "\tEND\n" ); + fprintf( fout, "\t%s\n", END_SEGS ); } @@ -875,7 +876,7 @@ void process( tokenDesc_t * tp, arg_t *args ) break; } } - fprintf( fout, "\tEND\n" ); + fprintf( fout, "\t%s\n", END_SEGS ); break; case ACT_TRANSFERTABLE: @@ -928,7 +929,7 @@ void process( tokenDesc_t * tp, arg_t *args ) } offset += length2; } - fprintf( fout, "\tEND\n"); + fprintf( fout, "\t%s\n", END_SEGS); break; case ACT_ENDTRANSFERTABLE: @@ -956,7 +957,7 @@ void process( tokenDesc_t * tp, arg_t *args ) break; } } - fprintf( fout, "\tEND\n" ); + fprintf( fout, "\t%s\n", END_SEGS ); break; case ACT_FILL_POINT: diff --git a/app/bin/bitmaps/SVG/star.svg b/app/bin/bitmaps/SVG/star.svg new file mode 100644 index 0000000..13f0914 --- /dev/null +++ b/app/bin/bitmaps/SVG/star.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/app/bin/bitmaps/XCF/bluedot.xcf b/app/bin/bitmaps/XCF/bluedot.xcf new file mode 100644 index 0000000..30d323e Binary files /dev/null and b/app/bin/bitmaps/XCF/bluedot.xcf differ diff --git a/app/bin/bitmaps/XCF/greendot.xcf b/app/bin/bitmaps/XCF/greendot.xcf new file mode 100644 index 0000000..f59311a Binary files /dev/null and b/app/bin/bitmaps/XCF/greendot.xcf differ diff --git a/app/bin/bitmaps/XCF/greydot.xcf b/app/bin/bitmaps/XCF/greydot.xcf new file mode 100644 index 0000000..7e795a5 Binary files /dev/null and b/app/bin/bitmaps/XCF/greydot.xcf differ diff --git a/app/bin/bitmaps/XCF/reddot.xcf b/app/bin/bitmaps/XCF/reddot.xcf new file mode 100644 index 0000000..449581f Binary files /dev/null and b/app/bin/bitmaps/XCF/reddot.xcf differ diff --git a/app/bin/bitmaps/XCF/yellowdot.xcf b/app/bin/bitmaps/XCF/yellowdot.xcf new file mode 100644 index 0000000..9395645 Binary files /dev/null and b/app/bin/bitmaps/XCF/yellowdot.xcf differ diff --git a/app/bin/bitmaps/arrow0.xbm b/app/bin/bitmaps/arrow0.xbm index 60fb2aa..f07a9e4 100644 --- a/app/bin/bitmaps/arrow0.xbm +++ b/app/bin/bitmaps/arrow0.xbm @@ -1,9 +1,9 @@ #define arrow0_width 24 #define arrow0_height 24 -static char arrow0_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x04, 0x02, - 0x00, 0x04, 0x01, 0x00, 0x84, 0x00, 0x00, 0x04, 0x01, 0x00, 0x24, 0x02, - 0x00, 0x54, 0x04, 0x00, 0x8c, 0x08, 0x00, 0x04, 0x11, 0x00, 0x00, 0x22, - 0x00, 0x00, 0x44, 0x00, 0x00, 0x88, 0x00, 0x00, 0x50, 0x00, 0x00, 0x20}; +static unsigned char arrow0_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x24, 0x00, +0x00, 0x42, 0x00, 0x00, 0x81, 0x00, 0x80, 0x00, 0x01, 0xc0, 0xe7, 0x03, +0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, +0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x3c, 0x00}; diff --git a/app/bin/bitmaps/arrow0_ctl.xbm b/app/bin/bitmaps/arrow0_ctl.xbm new file mode 100644 index 0000000..3b535c4 --- /dev/null +++ b/app/bin/bitmaps/arrow0_ctl.xbm @@ -0,0 +1,9 @@ +#define arrow0_ctl_width 24 +#define arrow0_ctl_height 24 +static unsigned char arrow0_ctl_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x3c, 0x00, +0x00, 0x7e, 0x00, 0x00, 0xff, 0x00, 0x80, 0xff, 0x01, 0xc0, 0xff, 0x03, +0x00, 0x24, 0x00, 0x00, 0x24, 0x06, 0x00, 0x24, 0x09, 0x00, 0x24, 0x01, +0x00, 0x24, 0x01, 0x00, 0x24, 0x09, 0x00, 0x24, 0x06, 0x00, 0x3c, 0x00}; \ No newline at end of file diff --git a/app/bin/bitmaps/arrow0_shift.xbm b/app/bin/bitmaps/arrow0_shift.xbm new file mode 100644 index 0000000..683f7e3 --- /dev/null +++ b/app/bin/bitmaps/arrow0_shift.xbm @@ -0,0 +1,9 @@ +#define arrow0_shift_width 24 +#define arrow0_shift_height 24 +static unsigned char arrow0_shift_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x00, 0x00, 0x24, 0x00, 0x00, 0x5a, 0x00, 0x00, 0xa5, 0x00, +0x80, 0x42, 0x01, 0x40, 0x81, 0x02, 0xa0, 0x00, 0x05, 0xd0, 0xe7, 0x0b, +0x10, 0x24, 0x08, 0xe0, 0xa5, 0x67, 0x00, 0xa5, 0x90, 0x00, 0xa5, 0x10, +0x00, 0xa5, 0x60, 0x00, 0xa5, 0x80, 0x00, 0xa5, 0x90, 0x00, 0xbd, 0x60}; \ No newline at end of file diff --git a/app/bin/bitmaps/arrow3.xbm b/app/bin/bitmaps/arrow3.xbm index 5f85bc0..aeac91f 100644 --- a/app/bin/bitmaps/arrow3.xbm +++ b/app/bin/bitmaps/arrow3.xbm @@ -1,6 +1,6 @@ #define arrow3_width 24 #define arrow3_height 24 -static char arrow3_bits[] = { +static unsigned char arrow3_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0xfc, 0x03, diff --git a/app/bin/bitmaps/arrow3_ctl.xbm b/app/bin/bitmaps/arrow3_ctl.xbm new file mode 100644 index 0000000..e87279a --- /dev/null +++ b/app/bin/bitmaps/arrow3_ctl.xbm @@ -0,0 +1,9 @@ +#define arrow3_ctl_width 24 +#define arrow3_ctl_height 24 +static unsigned char arrow3_ctl_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x04, 0x02, +0x00, 0x04, 0x01, 0x00, 0x84, 0x00, 0x00, 0xc4, 0x01, 0x00, 0xe4, 0x03, +0xc0, 0xd4, 0x07, 0x20, 0x8d, 0x0f, 0x20, 0x04, 0x1f, 0x20, 0x00, 0x3e, +0x20, 0x00, 0x7c, 0x20, 0x01, 0xf8, 0xc0, 0x00, 0x70, 0x00, 0x00, 0x20 }; \ No newline at end of file diff --git a/app/bin/bitmaps/arrow3_shift.xbm b/app/bin/bitmaps/arrow3_shift.xbm new file mode 100644 index 0000000..d2ee571 --- /dev/null +++ b/app/bin/bitmaps/arrow3_shift.xbm @@ -0,0 +1,9 @@ +#define arrow3_shift_width 24 +#define arrow3_shift_height 24 +static unsigned char arrow3_shift_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x0f, 0x00, 0x01, 0x10, 0x00, 0xfd, 0x17, 0x00, 0xfd, 0x0b, +0x00, 0xfd, 0x05, 0x00, 0xfd, 0x02, 0x00, 0xfd, 0x05, 0x00, 0xfd, 0x0b, +0x30, 0xdd, 0x17, 0x48, 0xad, 0x2f, 0x08, 0x55, 0x5f, 0x30, 0x89, 0xbe, +0x40, 0x06, 0x7d, 0x48, 0x00, 0xfa, 0x30, 0x00, 0x74, 0x00, 0x00, 0xa8}; \ No newline at end of file diff --git a/app/bin/bitmaps/arrowr3.xbm b/app/bin/bitmaps/arrowr3.xbm new file mode 100644 index 0000000..e63a39b --- /dev/null +++ b/app/bin/bitmaps/arrowr3.xbm @@ -0,0 +1,9 @@ +#define arrowr3_width 24 +#define arrowr3_height 24 +static unsigned char arrowr3_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0x3f, 0x00, +0x80, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x80, 0x3f, 0x00, 0xc0, 0x3f, 0x00, +0xe0, 0x3b, 0x00, 0xf0, 0x31, 0x00, 0xf8, 0x20, 0x00, 0x7c, 0x00, 0x00, +0x3e, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x04, 0x00, 0x00}; \ No newline at end of file diff --git a/app/bin/bitmaps/arrowr3_ctl.xbm b/app/bin/bitmaps/arrowr3_ctl.xbm new file mode 100644 index 0000000..f7bd770 --- /dev/null +++ b/app/bin/bitmaps/arrowr3_ctl.xbm @@ -0,0 +1,9 @@ +#define arrowr3_ctl_width 24 +#define arrowr3_ctl_height 24 +static unsigned char arrowr3_ctl_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x40, 0x20, 0x00, +0x80, 0x20, 0x00, 0x00, 0x21, 0x00, 0x80, 0x23, 0x00, 0xc0, 0x27, 0x00, +0xe0, 0x2b, 0x00, 0xf0, 0x31, 0x06, 0xf8, 0x20, 0x09, 0x7c, 0x00, 0x01, +0x3e, 0x00, 0x01, 0x1f, 0x00, 0x09, 0x0e, 0x00, 0x06, 0x04, 0x00, 0x00}; \ No newline at end of file diff --git a/app/bin/bitmaps/arrowr3_shift.xbm b/app/bin/bitmaps/arrowr3_shift.xbm new file mode 100644 index 0000000..1b10ea9 --- /dev/null +++ b/app/bin/bitmaps/arrowr3_shift.xbm @@ -0,0 +1,9 @@ +#define arrowr3_shift_width 24 +#define arrowr3_shift_height 24 +static unsigned char arrowr3_shift_bits[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xf0, 0xff, 0x00, 0x08, 0x80, 0x00, 0xe8, 0xbf, 0x00, 0xd0, 0xbf, 0x00, +0xa0, 0xbf, 0x00, 0x40, 0xbf, 0x00, 0xa0, 0xbf, 0x00, 0xd0, 0xbf, 0x00, +0xe8, 0xbb, 0x00, 0xf4, 0xb5, 0x0c, 0xfa, 0xaa, 0x12, 0x7d, 0x91, 0x02, +0xbe, 0x60, 0x0c, 0x5f, 0x00, 0x10, 0x2e, 0x00, 0x12, 0x15, 0x00, 0x0c}; \ No newline at end of file diff --git a/app/bin/bitmaps/arrows.xbm b/app/bin/bitmaps/arrows.xbm index 494b8de..7ac3113 100644 --- a/app/bin/bitmaps/arrows.xbm +++ b/app/bin/bitmaps/arrows.xbm @@ -1,7 +1,7 @@ #define arrows_width 24 #define arrows_height 24 // static unsigned char arrows_bits[] = { -static char arrows_bits[] = { +static unsigned char arrows_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x00, 0x01, 0x10, 0x00, 0xfd, 0x17, 0x00, 0xfd, 0x13, diff --git a/app/bin/bitmaps/background.xpm b/app/bin/bitmaps/background.xpm new file mode 100644 index 0000000..4859734 --- /dev/null +++ b/app/bin/bitmaps/background.xpm @@ -0,0 +1,155 @@ +/* XPM */ +static char *background[] = { +/* columns rows colors chars-per-pixel */ +"16 16 133 2 ", +" c #0B2B2B", +". c #183A3A", +"X c #789757", +"o c #799358", +"O c #7E9068", +"+ c #86A068", +"@ c #9BA77A", +"# c #99B073", +"$ c #9DB777", +"% c #98B67E", +"& c #A6BD7F", +"* c #A4BE7E", +"= c #77AAA8", +"- c #5FA7D7", +"; c #58A1DB", +": c #59A2DB", +"> c #5AA3DA", +", c #5BA4DB", +"< c #5CA4D9", +"1 c #5DA5DB", +"2 c #66ACD3", +"3 c #62A9D5", +"4 c #69AED1", +"5 c #60A9DB", +"6 c #63ACDB", +"7 c #64ACDA", +"8 c #66AFDB", +"9 c #62ACDE", +"0 c #67B0DC", +"q c #67B0DE", +"w c #68B1DB", +"e c #6BB4DB", +"r c #6EB7DB", +"t c #6FBADF", +"y c #71B9DB", +"u c #71BADB", +"i c #74BEDE", +"p c #6FBAE0", +"a c #6EB9E3", +"s c #73BEE3", +"d c #74BEE0", +"f c #72BEE4", +"g c #70BCE7", +"h c #6BBFFF", +"j c #7CC9E9", +"k c #7CCAEC", +"l c #6EC2FF", +"z c #6FC4FF", +"x c #73C8FF", +"c c #74C9FF", +"v c #78CDFF", +"b c #79CEFF", +"n c #7DD2FF", +"m c #7ED3FF", +"M c #809786", +"N c #84AC98", +"B c #93A492", +"V c #A1AD8E", +"C c #A3B587", +"Z c #A7B787", +"A c #ABB584", +"S c #A2B389", +"D c #A3B988", +"F c #A8BA94", +"G c #ACBD97", +"H c #B5BC90", +"J c #8EA8A8", +"K c #97BEAB", +"L c #8BADB7", +"P c #80B2B8", +"I c #91B5B6", +"U c #AFBFA9", +"Y c #A4C182", +"T c #B5C987", +"R c #B2C088", +"E c #BAD08E", +"W c #AFC491", +"Q c #B6CB97", +"! c #BED190", +"~ c #AFCEAA", +"^ c #BBCAA0", +"/ c #BECFA1", +"( c #BDCEA7", +") c #B5C7A9", +"_ c #BFD0AE", +"` c #BFD1AF", +"' c #A8CDBF", +"] c #C2CC95", +"[ c #C7D798", +"{ c #C3D19D", +"} c #C6D898", +"| c #CDD8A6", +" . c #D0DDA6", +".. c #C4DCB6", +"X. c #D3E0A2", +"o. c #D0E4B9", +"O. c #DBE5B9", +"+. c #D9E5BD", +"@. c #E2ECB3", +"#. c #E4EDB0", +"$. c #87B8C5", +"%. c #96CFDB", +"&. c #9CD1D5", +"*. c #98D1DF", +"=. c #A4CDC4", +"-. c #ADD7D0", +";. c #B0D1D5", +":. c #82D6FF", +">. c #83D7FF", +",. c #83D8FF", +"<. c #8CDEFF", +"1. c #95DEFC", +"2. c #99E1F6", +"3. c #A8E4ED", +"4. c #B6E6E2", +"5. c #BDEAE6", +"6. c #ADE7F8", +"7. c #E2EBCA", +"8. c #E2F3F3", +"9. c #E4F4F4", +"0. c #E6F5F5", +"q. c #E9F6F6", +"w. c #EBF7F7", +"e. c #E9F9F9", +"r. c #EEF8F8", +"t. c #F1F9F9", +"y. c #F4FBFB", +"u. c #F7FCFC", +"i. c #F9FDFD", +"p. c #FCFEFE", +"a. c #FEFFFF", +"s. c #FFFFFF", +"d. c None", +/* pixels */ +"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.", +"d.s.s.s.s.s.s.s.s.s.s.s.s.s.d.d.", +"d.s.; ; , < 5 6 7 w e r r s.d.d.", +"d.s.; l l 9 x v a m ,.1.k s.d.d.", +"d.i.< z x q b m j ,.3.5.-.i.d.d.", +"d.u.- 7 q g p s %.*.%.=.{ u.d.d.", +"d.y.3 b m t :.5.| @.o...K u.d.d.", +"d.t.2 m :.i 2.#._ .} ! = t.d.d.", +"d.w.4 u i k ' ] / W * $ = w.d.d.", +"d.q.$.<.6.;.7.+.^ ~ D % N q.d.d.", +"d.w.H O. .R T * D _ ) F I q.d.d.", +"d.q.A [ ! # Q ( F F ) V L 0.d.d.", +"d.0.@ Z C S + X o O B M J 0.d.d.", +". e.8.8.8.8.8.8.8.8.8.8.8.e.. d.", +"d. d.d.", +"d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d." +}; diff --git a/app/bin/bitmaps/bluedot.xpm b/app/bin/bitmaps/bluedot.xpm new file mode 100644 index 0000000..5c1df4c --- /dev/null +++ b/app/bin/bitmaps/bluedot.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char * bluedot[] = { +"16 16 7 1", +" c None", +". c #000000", +"+ c #3465A4", +"@ c #3565A4", +"# c #4465A1", +"$ c #5A649B", +"% c #4C79BA", +" ", +" ", +" .... ", +" ..#@@#.. ", +" .$%%%+++$. ", +" .%%%%%+++. ", +" .#%%%%%+++#. ", +" .@%%%%%+++@. ", +" .@+%%%++++@. ", +" .#++++++++#. ", +" .++++++++. ", +" .$++++++$. ", +" ..#@@#.. ", +" .... ", +" ", +" "}; diff --git a/app/bin/bitmaps/bma0.xbm b/app/bin/bitmaps/bma0.xbm index e0a2815..6986b0f 100644 --- a/app/bin/bitmaps/bma0.xbm +++ b/app/bin/bitmaps/bma0.xbm @@ -1,6 +1,6 @@ #define bma0_width 16 #define bma0_height 16 -static char bma0_bits[] = { +static unsigned char bma0_bits[] = { 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bma135.xbm b/app/bin/bitmaps/bma135.xbm index e0c5f4a..5a3ffcb 100644 --- a/app/bin/bitmaps/bma135.xbm +++ b/app/bin/bitmaps/bma135.xbm @@ -1,6 +1,6 @@ #define bma135_width 16 #define bma135_height 16 -static char bma135_bits[] = { +static unsigned char bma135_bits[] = { 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bma45.xbm b/app/bin/bitmaps/bma45.xbm index c4717b4..6a943f0 100644 --- a/app/bin/bitmaps/bma45.xbm +++ b/app/bin/bitmaps/bma45.xbm @@ -1,6 +1,6 @@ #define bma45_width 16 #define bma45_height 16 -static char bma45_bits[] = { +static unsigned char bma45_bits[] = { 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bma90.xbm b/app/bin/bitmaps/bma90.xbm index cf03ee3..007a8d5 100644 --- a/app/bin/bitmaps/bma90.xbm +++ b/app/bin/bitmaps/bma90.xbm @@ -1,6 +1,6 @@ #define bma90_width 16 #define bma90_height 16 -static char bma90_bits[] = { +static unsigned char bma90_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bmendpt.xbm b/app/bin/bitmaps/bmendpt.xbm index 1bea7b7..7572d17 100644 --- a/app/bin/bitmaps/bmendpt.xbm +++ b/app/bin/bitmaps/bmendpt.xbm @@ -1,6 +1,6 @@ #define bmendpt_width 16 #define bmendpt_height 16 -static char bmendpt_bits[] = { +static unsigned char bmendpt_bits[] = { 0x81, 0x40, 0x82, 0x20, 0x84, 0x10, 0x88, 0x08, 0x90, 0x04, 0xa0, 0x02, 0xc0, 0x01, 0xff, 0x7f, 0xc0, 0x01, 0xa0, 0x02, 0x90, 0x04, 0x88, 0x08, 0x84, 0x10, 0x82, 0x20, 0x81, 0x40, 0x00, 0x00}; diff --git a/app/bin/bitmaps/bridge.xpm b/app/bin/bitmaps/bridge.xpm new file mode 100644 index 0000000..446f055 --- /dev/null +++ b/app/bin/bitmaps/bridge.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * bridge_xpm[] = { +"16 16 3 1", +" c None", +". c #00FFFF", +"+ c #000000", +".. ..", +" .. .. ", +" ............ ", +" .......... ", +"+ + + + ", +"+++++++++++++++ ", +"+ + + + ", +"+ + + + ", +"+ + + + ", +"+++++++++++++++ ", +"+ + + + ", +" .......... ", +" ............ ", +" .. .. ", +".. ..", +" "}; diff --git a/app/bin/bitmaps/clip.xbm b/app/bin/bitmaps/clip.xbm new file mode 100644 index 0000000..6bffd55 --- /dev/null +++ b/app/bin/bitmaps/clip.xbm @@ -0,0 +1,6 @@ +#define clip_width 16 +#define clip_height 16 +static unsigned char clip_bits[] = { + 0xff, 0x03, 0x01, 0x06, 0x01, 0x0a, 0x01, 0x12, 0x01, 0x22, 0x01, 0x7e, + 0x01, 0x40, 0xf9, 0x5f, 0x05, 0x60, 0x13, 0x60, 0xf3, 0x7f, 0x05, 0x60, + 0xf9, 0x5f, 0x01, 0x40, 0x01, 0x40, 0xff, 0x7f }; diff --git a/app/bin/bitmaps/convertfr.xpm b/app/bin/bitmaps/convertfr.xpm new file mode 100644 index 0000000..7f141c8 --- /dev/null +++ b/app/bin/bitmaps/convertfr.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static char * convertfr_xpm[] = { +"16 16 4 1", +" c None", +"! c #000000000000", +"# c #FFFF00000000", +"$ c #808080000000", +" !!! !!!! ", +" !! !!! !!", +" !! !! !! ", +" !!!! # !!! ", +" # ", +" ## # ## ", +" ####### ", +" ### ", +" # ", +" ", +" !!!!!! ", +" !! ", +" !!!! ", +" !! ", +" !! ", +" "}; \ No newline at end of file diff --git a/app/bin/bitmaps/convertto.xpm b/app/bin/bitmaps/convertto.xpm new file mode 100644 index 0000000..f0fead2 --- /dev/null +++ b/app/bin/bitmaps/convertto.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static char * convertto_xpm[] = { +"16 16 4 1", +" c None", +"! c #000000000000", +"# c #FFFF00000000", +"$ c #808080000000", +" !!! !!!! ", +" !! !!! !!", +" !! !! !! ", +" !!!! # !!! ", +" ### ", +" ####### ", +" ## # ## ", +" # ", +" # ", +" ", +" !!!!!! ", +" !! ", +" !!!! ", +" !! ", +" !! ", +" "}; \ No newline at end of file diff --git a/app/bin/bitmaps/cornu.xpm b/app/bin/bitmaps/cornu.xpm new file mode 100644 index 0000000..bd3a2ed --- /dev/null +++ b/app/bin/bitmaps/cornu.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static char * cornu_xpm[] = { +"16 16 4 1", +" c None", +"! c #000000000000", +"# c #FFFF00000000", +"$ c #808080000000", +" !!$!!!! ", +" !! $ !! ", +" !! $!!! $$$", +" $! !!$ $$ !!", +" !! $! ! !!", +"!! !! !! !! ", +"! !! $###$ ", +"$$$$ # # ", +"! !! ### ", +"! !! ", +"! !$ ", +"!!$$! ", +"!$ !! ", +"$! $!!!$!!$###", +" !! $ $ # #", +" $!!!!!$!!$###"}; diff --git a/app/bin/bitmaps/cross0.xbm b/app/bin/bitmaps/cross0.xbm index 373d897..8f2e35d 100644 --- a/app/bin/bitmaps/cross0.xbm +++ b/app/bin/bitmaps/cross0.xbm @@ -1,5 +1,5 @@ #define cross0_width 8 #define cross0_height 8 //static unsigned char cross0_bits[] = { -static char cross0_bits[] = { +static unsigned char cross0_bits[] = { 0x04, 0x04, 0x1f, 0x04, 0x04, 0x00, 0x00, 0x00}; diff --git a/app/bin/bitmaps/delete.xpm b/app/bin/bitmaps/delete.xpm index 1e88b80..63b875a 100644 --- a/app/bin/bitmaps/delete.xpm +++ b/app/bin/bitmaps/delete.xpm @@ -1,21 +1,22 @@ /* XPM */ static char * delete_xpm[] = { -"16 16 2 1", -". c None", -" c #000000000000", -" ............ .", -" ......... ..", -".. ...... ...", -"... .... ....", -".. .. .. .. ..", -" .. . ", -".. ... ... ..", -".. .... .... ..", -".. ... ... ..", -" . . . ", -".. . .... . ..", -"... ...... ...", -".. ........ ..", -". ........... .", -" .............", -". ............. "}; +"16 16 3 1", +" c None", +". c #FF0000", +"+ c #000000", +" .. .. ", +" .. .. ", +" .. .. ", +" .. .. ", +" + .. .. + ", +"++++++....++++++", +" + +..+ + ", +" + +..+ + ", +" + .... + ", +"+++++..++..+++++", +" + .. .. + ", +" .. .. ", +" .. .. ", +" .. .. ", +".. ..", +" "}; diff --git a/app/bin/bitmaps/document-export.xpm b/app/bin/bitmaps/document-export.xpm new file mode 100644 index 0000000..8d632de --- /dev/null +++ b/app/bin/bitmaps/document-export.xpm @@ -0,0 +1,90 @@ +/* XPM */ +static char * export_xpm[] = { +"16 16 71 1", +" c None", +". c #406C98", +"+ c #DDF0FB", +"@ c #D4E9F7", +"# c #D1E7F5", +"$ c #CEE4F4", +"% c #CCE2F3", +"& c #CCE1F2", +"* c #A7C2DC", +"= c #D6EBF7", +"- c #C5DFEF", +"; c #C1DBED", +"> c #BCD6EA", +", c #B6D0E8", +"' c #B3CDE6", +") c #B2CCE5", +"! c #9AB6D2", +"~ c #E5F6FF", +"{ c #D7ECF8", +"] c #C7E1EF", +"^ c #85A4C2", +"/ c #D7EDF8", +"( c #C8E2F0", +"_ c #D8EEF8", +": c #CAE4F1", +"< c #D9EEF9", +"[ c #CBE5F2", +"} c #8FAFCF", +"| c #83A5C7", +"1 c #DAEFF9", +"2 c #CDE7F2", +"3 c #81A3C5", +"4 c #105293", +"5 c #DAF0F9", +"6 c #CEE8F3", +"7 c #C0DAEB", +"8 c #AFCCE0", +"9 c #9AB9D4", +"0 c #88A9C9", +"a c #7FA1C3", +"b c #CCE1F0", +"c c #155493", +"d c #DBF0FA", +"e c #D0EAF4", +"f c #CFE8F3", +"g c #D4EAF6", +"h c #E1F3FD", +"i c #195793", +"j c #DBF1FA", +"k c #D1EBF4", +"l c #C1DCEB", +"m c #AFCBE0", +"n c #98B7D1", +"o c #84A4C4", +"p c #799BBD", +"q c #CBE0EF", +"r c #1E5993", +"s c #DCF1FA", +"t c #D2ECF5", +"u c #7597B9", +"v c #275D94", +"w c #DCF2FB", +"x c #D3EDF5", +"y c #84A4C0", +"z c #6B8DAF", +"A c #3D71A5", +"B c #DDF2FB", +"C c #D4EEF6", +"D c #D8EDF8", +"E c #E1F4FD", +"F c #DFF2FC", +" ......... ", +" .+@#$%&&*. ", +" .=-;>,')!~. ", +" .{]-;>,'^^^. ", +" ./(]-;>,')&. ", +" ._:(]-;>,'&. ", +" .<[:(]-;>}| ", +" .12[:(]-;3~4 ", +" .562[7890ab~c ", +" .de62fg1h~~~~i", +" .jke6lmnopq~r ", +" .stke62[:u~v ", +" .wxtke62[yzA ", +" .BCxtke62[D. ", +" .EBwsjd51 c #B6D0E8", +", c #B3CDE6", +"' c #9AB6D2", +") c #E5F6FF", +"! c #D7ECF8", +"~ c #C7E1EF", +"{ c #C1DBED", +"] c #85A4C2", +"^ c #D8EEF8", +"/ c #CAE4F1", +"( c #D9EEF9", +"_ c #CBE5F2", +": c #C8E2F0", +"< c #8FAFCF", +"[ c #83A5C7", +"} c #DAEFF9", +"| c #CDE7F2", +"1 c #81A3C5", +"2 c #105293", +"3 c #AFCCE0", +"4 c #9AB9D4", +"5 c #88A9C9", +"6 c #7FA1C3", +"7 c #CCE1F0", +"8 c #155493", +"9 c #DBF0FA", +"0 c #D0EAF4", +"a c #CFE8F3", +"b c #D4EAF6", +"c c #E1F3FD", +"d c #195793", +"e c #DBF1FA", +"f c #D1EBF4", +"g c #CEE8F3", +"h c #C1DCEB", +"i c #AFCBE0", +"j c #98B7D1", +"k c #84A4C4", +"l c #799BBD", +"m c #CBE0EF", +"n c #1E5993", +"o c #DCF1FA", +"p c #D2ECF5", +"q c #7597B9", +"r c #275D94", +"s c #84A4C0", +"t c #6B8DAF", +"u c #3D71A5", +"v c #DDF2FB", +"w c #D4EEF6", +"x c #D8EDF8", +"y c #E1F4FD", +"z c #DFF2FC", +" ......... ", +" .+@#$%&#*. ", +" .=-#;>,#'). ", +" .!~#{;>#]]]. ", +" .##########. ", +" .^/#~-{#>,&. ", +" .(_#:~-#;<[ ", +" .}|#/:~#{1)2 ", +" .#####34567)8 ", +" .90#|ab}c))))d", +" .ef#ghijklm)n ", +" .op#0g|#/q)r ", +" .########stu ", +" .vw#pf0#|_x. ", +" .yv#oe9#}(z. ", +" ............ "}; diff --git a/app/bin/bitmaps/document-import.xpm b/app/bin/bitmaps/document-import.xpm new file mode 100644 index 0000000..28dc3c8 --- /dev/null +++ b/app/bin/bitmaps/document-import.xpm @@ -0,0 +1,92 @@ +/* XPM */ +static char * import_xpm[] = { +"16 16 73 1", +" c None", +". c #406C98", +"+ c #DDF0FB", +"@ c #D4E9F7", +"# c #D1E7F5", +"$ c #CEE4F4", +"% c #CCE2F3", +"& c #CCE1F2", +"* c #A7C2DC", +"= c #D6EBF7", +"- c #C5DFEF", +"; c #C1DBED", +"> c #BCD6EA", +", c #B6D0E8", +"' c #B3CDE6", +") c #B2CCE5", +"! c #9AB6D2", +"~ c #E5F6FF", +"{ c #D7ECF8", +"] c #C7E1EF", +"^ c #85A4C2", +"/ c #D7EDF8", +"( c #C8E2F0", +"_ c #D8EEF8", +": c #94B4D1", +"< c #86A7C9", +"[ c #AECBE1", +"} c #D9EEF9", +"| c #81A3C5", +"1 c #E4F6FF", +"2 c #93B2D0", +"3 c #B6D2E6", +"4 c #155493", +"5 c #7FA1C3", +"6 c #CBE1F0", +"7 c #DEF2FC", +"8 c #A5C3DA", +"9 c #BED9EA", +"0 c #195793", +"a c #DFF2FC", +"b c #CFE7F4", +"c c #1E5993", +"d c #799BBD", +"e c #CAE0EF", +"f c #A4C2D9", +"g c #C0DBEB", +"h c #D4EAF7", +"i c #DBF1FA", +"j c #7597B9", +"k c #8BABC7", +"l c #B8D4E6", +"m c #CBE5F2", +"n c #CAE4F1", +"o c #D5EBF7", +"p c #DCF1FA", +"q c #86A6C1", +"r c #6F91B2", +"s c #ACC9DC", +"t c #CEE8F3", +"u c #CDE7F2", +"v c #D6ECF7", +"w c #DCF2FB", +"x c #D3EDF5", +"y c #D2ECF5", +"z c #D1EBF4", +"A c #D0EAF4", +"B c #DDF2FB", +"C c #D4EEF6", +"D c #D8EDF8", +"E c #E1F4FD", +"F c #DBF0FA", +"G c #DAF0F9", +"H c #DAEFF9", +" ......... ", +" .+@#$%&&* ", +" .=-;>,')!~ ", +" .{]-;>,'^^^. ", +" ./(]-;>,')&. ", +" ._:<[-;>,'&. ", +" .}|123-;>,%. ", +" 44556789-;>$. ", +"0~~~~1a/b]-;#. ", +" ccddeafg(]-h. ", +" .ij1klmn(]o. ", +" .pqrstumn(v. ", +" .wxyzAtumn{. ", +" .BCxyzAtumD. ", +" .EBwpiFGH}a. ", +" ............ "}; diff --git a/app/bin/bitmaps/document-importmod.xpm b/app/bin/bitmaps/document-importmod.xpm new file mode 100644 index 0000000..d0efd02 --- /dev/null +++ b/app/bin/bitmaps/document-importmod.xpm @@ -0,0 +1,71 @@ +/* XPM */ +static char *importmod_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 49 1 ", +" c #27795F", +". c #305173", +"X c #1A6878", +"o c #07900F", +"O c #0E8E14", +"+ c #0B9C17", +"@ c #10971E", +"# c #0BA619", +"$ c #10A51D", +"% c #0DB61C", +"& c #159E22", +"* c #209E2D", +"= c #18A727", +"- c #16B627", +"; c #27AB35", +": c #30AF3B", +"> c #2AB437", +", c #31B63E", +"< c #36BD46", +"1 c #3CC44C", +"2 c #40C94E", +"3 c #44CB54", +"4 c #54DB64", +"5 c #195793", +"6 c #3B6D8D", +"7 c #39798B", +"8 c #3F6E9C", +"9 c #377C97", +"0 c #3D77A6", +"q c #3F7FBC", +"w c #37878B", +"e c #38938E", +"r c #378399", +"t c #3983A7", +"y c #6F91B2", +"u c #789ABC", +"i c #7FA1C3", +"p c #86A6C4", +"a c #96B4D1", +"s c #A7C4DB", +"d c #AECBE1", +"f c #B9D5E7", +"g c #C0DBEB", +"h c #C9E1EF", +"j c #CDE4F2", +"k c #D7EDF8", +"l c #DFF2FC", +"z c #E5F6FF", +"x c None", +/* pixels */ +"xxqqqqqqqqqxxxxx", +"xxt3111;<>sqxxxx", +"xxq1<<:O;#xxxx", +"xxq=aid=$=,1>txx", +"xxq=ilaf->44>txx", +"x5qiijlsg-31=0xx", +"5zzzzzzkjh1,#rxx", +"x5Xuuhlsf1111exx", +"xxw c #305A07", +", c #3A700A", +"' c #4D960E", +") c #4A900D", +"! c #356508", +"~ c #264806", +"{ c #203B07", +"] c #1C3508", +"^ c #203C07", +"/ c #42800C", +"( c #478B0D", +"_ c #529E0F", +": c #4C940E", +"< c #46890D", +"[ c #417E0B", +"} c #3C730A", +"| c #1B3208", +"1 c #346208", +"2 c #4B920E", +"3 c #498F0D", +"4 c #45850C", +"5 c #407C0B", +"6 c #315B07", +"7 c #336108", +"8 c #44840C", +"9 c #2E5507", +"0 c #3F7A0B", +"a c #3F790B", +"b c #3C740A", +"c c #2B5106", +"d c #1F3808", +"e c #386B09", +"f c #234107", +"g c #2A4F06", +"h c #182C09", +"i c #2E5707", +"j c #1A3008", +"k c #172B09", +" ", +" ", +" ", +" .+ ", +" @# ", +" $%& ", +" *=-;>,')!~={] ", +" ^#/('_:<[}@| ", +" 1%)23456 ", +" 74%8[9 ", +" ,05abc ", +" deef;e1 ", +" &gh di| ", +" j k ", +" ", +" "}; diff --git a/app/bin/bitmaps/greydot.xpm b/app/bin/bitmaps/greydot.xpm new file mode 100644 index 0000000..771a096 --- /dev/null +++ b/app/bin/bitmaps/greydot.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char * greydot[] = { +"16 16 6 1", +" c None", +". c #000000", +"+ c #30312F", +"@ c #959792", +"# c #888A85", +"$ c #A2A49F", +" ", +" ", +" .... ", +" .+@@@@+. ", +" .#$$$@@@#. ", +" +$$$$$@@@+ ", +" .@$$$$$@@@@. ", +" .@$$$$$@@@@. ", +" .@@$$$@@@@@. ", +" .@@@@@@@@@@. ", +" +@@@@@@@@+ ", +" .#@@@@@@#. ", +" .+@@@@+. ", +" .... ", +" ", +" "}; diff --git a/app/bin/bitmaps/greystar.xpm b/app/bin/bitmaps/greystar.xpm new file mode 100644 index 0000000..e7c5300 --- /dev/null +++ b/app/bin/bitmaps/greystar.xpm @@ -0,0 +1,69 @@ +/* XPM */ +static char * greystar[] = { +"16 16 50 1", +" c None", +". c #5A5B57", +"+ c #5B5D59", +"@ c #6D6F6A", +"# c #73756F", +"$ c #878984", +"% c #868882", +"& c #555652", +"* c #3D3F3C", +"= c #565854", +"- c #5C5E59", +"; c #62645F", +"> c #676964", +", c #757772", +"' c #8F918C", +") c #8B8D88", +"! c #6E706A", +"~ c #5A5C58", +"{ c #51534F", +"] c #4D4F4B", +"^ c #525450", +"/ c #81837D", +"( c #888A84", +"_ c #959792", +": c #8E908A", +"< c #868983", +"[ c #7F817B", +"} c #787A74", +"| c #4C4D49", +"1 c #6C6E69", +"2 c #8D8F8A", +"3 c #8B8D87", +"4 c #848680", +"5 c #7D807A", +"6 c #686A65", +"7 c #6B6D68", +"8 c #83857F", +"9 c #646561", +"0 c #7D7F79", +"a c #7C7E78", +"b c #787B75", +"c c #60625D", +"d c #50514D", +"e c #72746E", +"f c #565753", +"g c #5F615D", +"h c #474945", +"i c #646661", +"j c #4A4B48", +"k c #474844", +" ", +" ", +" ", +" .+ ", +" @# ", +" $%& ", +" *=-;>,')!~={] ", +" ^#/('_:<[}@| ", +" 1%)23456 ", +" 74%8[9 ", +" ,05abc ", +" deef;e1 ", +" &gh di| ", +" j k ", +" ", +" "}; diff --git a/app/bin/bitmaps/import.xpm b/app/bin/bitmaps/import.xpm deleted file mode 100644 index f048333..0000000 --- a/app/bin/bitmaps/import.xpm +++ /dev/null @@ -1,21 +0,0 @@ -/* XPM */ -static char * import_xpm[] = { -"16 16 2 1", -" c None", -". c #FFFFFFFFFFFF", -" .......", -" ....... .......", -" ....... ... ...", -" ....... .... ..", -" ....... . .", -" ....... ...... ", -" ....... ...... ", -" ....... . .", -" . .... .... ..", -" .. .. ... ...", -" .... .........", -"................", -".. . . . .....", -"... ... .. .....", -" . . .. .. .....", -"................"}; diff --git a/app/bin/bitmaps/joinline.xpm b/app/bin/bitmaps/joinline.xpm new file mode 100644 index 0000000..06e22f8 --- /dev/null +++ b/app/bin/bitmaps/joinline.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * joinline_xpm[] = { +"16 16 3 1", +" c None", +". c #000000000000", +"X c #FFFF00000000", +" ", +" ", +" ", +" .", +" ..", +" ...", +" ... ", +" ... ", +" XXX ", +" X X ", +" X X X ", +".....X X ", +".....XXXX ", +"..... X ", +" X ", +" "}; \ No newline at end of file diff --git a/app/bin/bitmaps/link.xbm b/app/bin/bitmaps/link.xbm new file mode 100644 index 0000000..199256e --- /dev/null +++ b/app/bin/bitmaps/link.xbm @@ -0,0 +1,6 @@ +#define link_width 16 +#define link_height 16 +static unsigned char link_bits[] = { + 0xff, 0x03, 0x01, 0x06, 0x01, 0x0a, 0x01, 0x12, 0x01, 0x22, 0x01, 0x7e, + 0x01, 0x40, 0x01, 0x40, 0x3d, 0x5e, 0x43, 0x61, 0xf3, 0x67, 0x43, 0x61, + 0x3d, 0x5e, 0x01, 0x40, 0x01, 0x40, 0xff, 0x7f }; diff --git a/app/bin/bitmaps/magnet.xpm b/app/bin/bitmaps/magnet.xpm new file mode 100644 index 0000000..99a31db --- /dev/null +++ b/app/bin/bitmaps/magnet.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * magnet_xpm[] = { +"16 16 3 1", +" c #FF0000", +". c None", +"X c #FFFF00", +"................", +"........ ......", +"....... ....", +"...... ...", +"..... ..", +"..... . .", +".... ... .", +"... ... .", +"..XXX ... ..", +".XXXXX... ..", +"..XXXX.. ...", +"...XX..XX ....", +"......XXXXX ....", +"......XXXXX.....", +"........XX......", +"................"}; diff --git a/app/bin/bitmaps/magnifier.xpm b/app/bin/bitmaps/magnifier.xpm new file mode 100644 index 0000000..69a3faa --- /dev/null +++ b/app/bin/bitmaps/magnifier.xpm @@ -0,0 +1,89 @@ +/* XPM */ +static char * magnifier_xpm[] = { +"16 16 70 1", +" c None", +". c #545454", +"+ c #555555", +"@ c #515151", +"# c #5E6063", +"$ c #94A3B1", +"% c #C5D5E6", +"& c #DFEAF4", +"* c #D9E3ED", +"= c #A2ACB6", +"- c #4D4D4D", +"; c #5A5D5F", +"> c #AEC1D5", +", c #C4D8EB", +"' c #E2ECF6", +") c #E4EDF6", +"! c #B8C8D9", +"~ c #5B5D60", +"{ c #494949", +"] c #919FAD", +"^ c #BBD2E8", +"/ c #D5E3F1", +"( c #D6E4F2", +"_ c #97A4B0", +": c #434343", +"< c #B6CBE0", +"[ c #C1D3E4", +"} c #3E3E3E", +"| c #BED4E9", +"1 c #C8DBED", +"2 c #383838", +"3 c #BCCFE1", +"4 c #CAD8E7", +"5 c #313131", +"6 c #939DA8", +"7 c #BFD5EA", +"8 c #DFE9F5", +"9 c #9EA6AD", +"0 c #373737", +"a c #444647", +"b c #C4D1DE", +"c c #D9E6F3", +"d c #E6EFF7", +"e c #D3D9DF", +"f c #3B3C3D", +"g c #262626", +"h c #3B3B3B", +"i c #3C3C3C", +"j c #ADADAF", +"k c #28292B", +"l c #91979D", +"m c #E3E8EE", +"n c #EDF3F9", +"o c #E5EAEF", +"p c #9EA0A3", +"q c #282829", +"r c #464647", +"s c #B8B8BC", +"t c #151516", +"u c #141414", +"v c #3D3D3D", +"w c #515153", +"x c #C4C4CC", +"y c #212122", +"z c #606064", +"A c #D1D1DD", +"B c #2E2E30", +"C c #DADAEA", +"D c #3F3F43", +"E c #151515", +" .+++++. ", +" @#$%&*=#@ ", +" -;>,'))'!~-", +" {]^/))))(_{", +" :<^^^^^^^[:", +" }|^^)))))1}", +" 23^))))))42", +" 5678))))'95", +" 0abc)))defg", +" hijklmnopq ", +" irst uuuuu ", +" vwxy ", +" }zAB ", +" 0CD ", +" Eu ", +" "}; diff --git a/app/bin/bitmaps/note.xbm b/app/bin/bitmaps/note.xbm index 7ca281a..3d2cac9 100644 --- a/app/bin/bitmaps/note.xbm +++ b/app/bin/bitmaps/note.xbm @@ -1,6 +1,6 @@ #define note_width 16 #define note_height 16 -static char note_bits[] = { - 0xff, 0x03, 0x01, 0x06, 0x81, 0x0a, 0x81, 0x12, 0x81, 0x22, 0x81, 0x7e, - 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x81, 0x40, 0x01, 0x40, - 0x81, 0x40, 0x01, 0x40, 0x01, 0x40, 0xff, 0x7f}; +static unsigned char note_bits[] = { + 0xff, 0x03, 0x01, 0x06, 0x01, 0x0a, 0x01, 0x12, 0x01, 0x22, 0x01, 0x7e, + 0x01, 0x40, 0xbd, 0x43, 0x01, 0x40, 0x01, 0x40, 0xfd, 0x5e, 0x01, 0x40, + 0x01, 0x40, 0xbd, 0x4f, 0x01, 0x40, 0xff, 0x7f }; diff --git a/app/bin/bitmaps/pan.xpm b/app/bin/bitmaps/pan.xpm index 8782714..9575ec5 100644 --- a/app/bin/bitmaps/pan.xpm +++ b/app/bin/bitmaps/pan.xpm @@ -14,7 +14,7 @@ static char * pan_xpm[] = { " XXXXXXXXXXXXXX ", " XXXXXXXXXXXXXX ", " XX XX XX ", -" XX ", +" XX ", " XX XX XX ", " XXXXXX ", " XXXX ", diff --git a/app/bin/bitmaps/parallel-line.xpm b/app/bin/bitmaps/parallel-line.xpm new file mode 100644 index 0000000..4ac471d --- /dev/null +++ b/app/bin/bitmaps/parallel-line.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static char * parallel_line_xpm[] = { +"16 16 3 1", +" c None", +". c #000000000000", +"X c #FFFF00000000", +" ", +" ", +" ", +"................", +" X ", +" X X ", +" X X ", +" ", +" ", +" . . . ", +"................", +" . . . ", +" . . . ", +" . . . ", +"................", +" . . . "}; diff --git a/app/bin/bitmaps/parallel.xpm b/app/bin/bitmaps/parallel.xpm index 3fe5591..eb816dc 100644 --- a/app/bin/bitmaps/parallel.xpm +++ b/app/bin/bitmaps/parallel.xpm @@ -1,15 +1,16 @@ /* XPM */ static char * parallel_xpm[] = { -"16 16 2 1", +"16 16 3 1", " c None", ". c #000000000000", -" ", -" ", -" ", +"X c #FFFF00000000", +"................", +" . . . ", +" . . . ", "................", -" . ", -" . . ", -" . . ", +" . X . ", +" X X ", +" X X ", " ", " ", " . . . ", diff --git a/app/bin/bitmaps/reddot.xpm b/app/bin/bitmaps/reddot.xpm new file mode 100644 index 0000000..14529bf --- /dev/null +++ b/app/bin/bitmaps/reddot.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static char * reddot[] = { +"16 16 7 1", +" c None", +". c #000000", +"+ c #CC0000", +"@ c #CA1F1E", +"# c #E62E16", +"$ c #C04E4B", +"% c #B25F5B", +" ", +" ", +" .... ", +" ..$@@$.. ", +" .%###+++%. ", +" .#####+++. ", +" .$#####+++$. ", +" .@#####+++@. ", +" .@+###++++@. ", +" .$++++++++$. ", +" .++++++++. ", +" .%++++++%. ", +" ..$@@$.. ", +" .... ", +" ", +" "}; diff --git a/app/bin/bitmaps/redstar.xpm b/app/bin/bitmaps/redstar.xpm new file mode 100644 index 0000000..b9f51f9 --- /dev/null +++ b/app/bin/bitmaps/redstar.xpm @@ -0,0 +1,67 @@ +/* XPM */ +static char * redstar[] = { +"16 16 48 1", +" c None", +". c #950800", +"+ c #980800", +"@ c #B50A00", +"# c #BF0A00", +"$ c #E00C00", +"% c #DE0C00", +"& c #8D0800", +"* c #670600", +"= c #900800", +"- c #990800", +"; c #A30900", +"> c #AC0900", +", c #C30B00", +"' c #ED0D00", +") c #E70C00", +"! c #B70A00", +"~ c #960800", +"{ c #870700", +"] c #810700", +"^ c #890700", +"/ c #D60C00", +"( c #E20C00", +"_ c #F70D00", +": c #EC0D00", +"< c #D30B00", +"[ c #C70B00", +"} c #7E0700", +"| c #B40A00", +"1 c #EA0D00", +"2 c #DB0C00", +"3 c #D10B00", +"4 c #AD0900", +"5 c #B20A00", +"6 c #D90C00", +"7 c #A50900", +"8 c #D00B00", +"9 c #CE0B00", +"0 c #C90B00", +"a c #A00900", +"b c #850700", +"c c #BE0A00", +"d c #8E0800", +"e c #9E0900", +"f c #770600", +"g c #A70900", +"h c #7B0700", +"i c #760600", +" ", +" ", +" ", +" .+ ", +" @# ", +" $%& ", +" *=-;>,')!~={] ", +" ^#/('_:$<[@} ", +" |%)1)234 ", +" 52%6<7 ", +" ,8390a ", +" bccd;c| ", +" &ef bg} ", +" h i ", +" ", +" "}; diff --git a/app/bin/bitmaps/sticky-note-chain.xpm b/app/bin/bitmaps/sticky-note-chain.xpm new file mode 100644 index 0000000..aa9445a --- /dev/null +++ b/app/bin/bitmaps/sticky-note-chain.xpm @@ -0,0 +1,84 @@ +/* XPM */ +static char * sticky_note_chain_bits[] = { +"16 16 65 1", +" c None", +". c #CCB301", +"+ c #CAB101", +"@ c #FBEF9C", +"# c #F9EB8F", +"$ c #F8EA8D", +"% c #F8E98A", +"& c #F6E785", +"* c #F3E37C", +"= c #F0E074", +"- c #EEDD6F", +"; c #D5C44D", +"> c #C8AF01", +", c #FBED95", +"' c #F7E67E", +") c #F6E57C", +"! c #F5E47B", +"~ c #F4E379", +"{ c #F1E075", +"] c #ECDB70", +"^ c #E8D76A", +"/ c #E6D567", +"( c #CDBC45", +"_ c #FFF6BB", +": c #C6AD01", +"< c #FCEB84", +"[ c #B7A73A", +"} c #BFAE37", +"| c #AC9401", +"1 c #C3AA01", +"2 c #FBED97", +"3 c #EEDD7B", +"4 c #9D96F6", +"5 c #E1D26F", +"6 c #C0A701", +"7 c #006E6E", +"8 c #00FFFF", +"9 c #BCA401", +"0 c #AFA358", +"a c #ADA054", +"b c #B9A101", +"c c #B59E01", +"d c #FEF19E", +"e c #EDDD7C", +"f c #E5D575", +"g c #E5D571", +"h c #B29A01", +"i c #FFF2A1", +"j c #FEED87", +"k c #FDEC86", +"l c #FDEC85", +"m c #FBEA82", +"n c #FAE981", +"o c #F8E77F", +"p c #A89100", +"q c #FFF4AF", +"r c #FFF1A0", +"s c #FDF09C", +"t c #FDEF9B", +"u c #FCEE99", +"v c #FAEC92", +"w c #F9EA90", +"x c #FAEC96", +"y c #9D8600", +"z c #9C8500", +" ", +" ", +" ........... ", +" +@#$%&*=--;+ ", +" >,')!~{]^/(_> ", +" :<<<<<<<<<[}}| ", +" 1234445444''-1 ", +" 647887478874-6 ", +" 94800878a084=9 ", +" b47887478874*b ", +" cde444f444g{&c ", +" hijkl c #C8AF01", +", c #FBED95", +"' c #F7E67E", +") c #F6E57C", +"! c #F6E68A", +"~ c #ECE0A0", +"{ c #BABDB6", +"] c #EFE3A7", +"^ c #CDBC45", +"/ c #FFF6BB", +"( c #C6AD01", +"_ c #FBED97", +": c #F8E77F", +"< c #F8E88D", +"[ c #EDE0A0", +"} c #F5E68F", +"| c #F0E39B", +"1 c #888A85", +"2 c #BFAE37", +"3 c #AC9401", +"4 c #C3AA01", +"5 c #FCEE99", +"6 c #F7E78B", +"7 c #EBDE9C", +"8 c #F8EBA2", +"9 c #ECDB70", +"0 c #E8D76A", +"a c #E6D567", +"b c #EEDD6F", +"c c #C0A701", +"d c #FDF0A5", +"e c #DCD695", +"f c #EAE29B", +"g c #E8E098", +"h c #DACB69", +"i c #BCA401", +"j c #FDF3B6", +"k c #B9A101", +"l c #FEF4B7", +"m c #E0D986", +"n c #F5E47B", +"o c #F4E379", +"p c #F1E075", +"q c #F3E37C", +"r c #B59E01", +"s c #FFF3B4", +"t c #DECF6F", +"u c #F4E47D", +"v c #F5E47C", +"w c #F6E785", +"x c #B29A01", +"y c #FFF2A3", +"z c #FBEDA4", +"A c #F0E07C", +"B c #F3E27C", +"C c #F5E47D", +"D c #A89100", +"E c #FFF4AF", +"F c #FFF2A1", +"G c #FFF1A0", +"H c #FEF19E", +"I c #FDF09C", +"J c #FDEF9B", +"K c #FAEC92", +"L c #F9EA90", +"M c #FAEC96", +"N c #9D8600", +"O c #9C8500", +" ", +" ", +" ........... ", +" +@#$%&*==-;+ ", +" >,')!~={]=^/> ", +" (_:<[=}=|1{223 ", +" 4567=8=8=90ab4 ", +" cde=f=g=}h90bc ", +" ij1818=8={)))i ", +" kl=m=1f={nopqk ", +" rs1t)8={uvnowr ", +" xyz1=1{ABC)n%x ", +" DEFGHIJ5_,KLMD ", +" NOOOOOOOOOOOON ", +" ", +" "}; diff --git a/app/bin/bitmaps/sticky-note-text.xpm b/app/bin/bitmaps/sticky-note-text.xpm new file mode 100644 index 0000000..119f39b --- /dev/null +++ b/app/bin/bitmaps/sticky-note-text.xpm @@ -0,0 +1,86 @@ +/* XPM */ +static char * sticky_note_text_bits[] = { +"16 16 67 1", +" c None", +". c #CCB301", +"+ c #CAB101", +"@ c #FBEF9C", +"# c #F9EB8F", +"$ c #F8EA8D", +"% c #F8E98A", +"& c #F6E785", +"* c #F3E37C", +"= c #F0E074", +"- c #EEDD6F", +"; c #D5C44D", +"> c #C8AF01", +", c #FBED95", +"' c #F7E67E", +") c #F6E57C", +"! c #F5E47B", +"~ c #F4E379", +"{ c #F1E075", +"] c #ECDB70", +"^ c #E8D76A", +"/ c #E6D567", +"( c #CDBC45", +"_ c #FFF6BB", +": c #C6AD01", +"< c #FBED97", +"[ c #F8E77F", +"} c #BFAE37", +"| c #AC9401", +"1 c #C3AA01", +"2 c #FCEE99", +"3 c #7E7E7E", +"4 c #979797", +"5 c #C0A701", +"6 c #FDEF9B", +"7 c #E5DC75", +"8 c #E4DB73", +"9 c #E4DA70", +"0 c #E3D86D", +"a c #E2D769", +"b c #EBDC70", +"c c #BCA401", +"d c #FDF09D", +"e c #B9A101", +"f c #FEF19E", +"g c #E5DD77", +"h c #EDDF75", +"i c #B59E01", +"j c #FFF1A0", +"k c #DED273", +"l c #E1D078", +"m c #B29A01", +"n c #FFF2A1", +"o c #FEED87", +"p c #FDEC86", +"q c #FDEC85", +"r c #FCEB84", +"s c #FBEA82", +"t c #FAE981", +"u c #A89100", +"v c #FFF4AF", +"w c #FDF09C", +"x c #FAEC92", +"y c #F9EA90", +"z c #FAEC96", +"A c #9D8600", +"B c #9C8500", +" ", +" ", +" ........... ", +" +@#$%&*=--;+ ", +" >,')!~{]^/(_> ", +" :<[')!~{]^}}}| ", +" 12334344{]^/-1 ", +" 567890ab~{]^-5 ", +" cd3334333443=c ", +" efgg789h)!~{*e ", +" ij3343kl')!~&i ", +" mnopqrst[')!%m ", +" uvnjfw62<,xyzu ", +" ABBBBBBBBBBBBA ", +" ", +" "}; diff --git a/app/bin/bitmaps/tunnel.xpm b/app/bin/bitmaps/tunnel.xpm index 79aed20..449080e 100644 --- a/app/bin/bitmaps/tunnel.xpm +++ b/app/bin/bitmaps/tunnel.xpm @@ -1,19 +1,20 @@ /* XPM */ static char * tunnel_xpm[] = { -"16 16 2 1", +"16 16 3 1", " c None", -". c #000000000000", +". c #00FFFF", +"+ c #000000", " .. ", " .. ", " .. ", " .. ", -". . .. ", -".......... . . ", -". . .. ", -". . .. ", -". . .. ", -".......... . . ", -". . .. ", +"+ + .. ", +"++++++++.. + + ", +"+ + .. ", +"+ + .. ", +"+ + .. ", +"++++++++.. + + ", +"+ + .. ", " .. ", " .. ", " .. ", diff --git a/app/bin/bitmaps/yellowdot.xpm b/app/bin/bitmaps/yellowdot.xpm new file mode 100644 index 0000000..da0dddf --- /dev/null +++ b/app/bin/bitmaps/yellowdot.xpm @@ -0,0 +1,27 @@ +/* XPM */ +static char * yellowdot[] = { +"16 16 8 1", +" c None", +". c #000000", +"+ c #B69A19", +"@ c #E0C504", +"# c #EBD200", +"$ c #CFB410", +"% c #EFD947", +"& c #EDD400", +" ", +" ", +" .... ", +" .+@##@+. ", +" .$%%%&&&$. ", +" +%%%%%&&&+ ", +" .@%%%%%&&&@. ", +" .#%%%%%&&&#. ", +" .#&%%%&&&&#. ", +" .@&&&&&&&&@. ", +" +&&&&&&&&+ ", +" .$&&&&&&$. ", +" .+@##@+. ", +" .... ", +" ", +" "}; diff --git a/app/bin/bitmaps/yellowstar.xpm b/app/bin/bitmaps/yellowstar.xpm new file mode 100644 index 0000000..637ad9c --- /dev/null +++ b/app/bin/bitmaps/yellowstar.xpm @@ -0,0 +1,67 @@ +/* XPM */ +static char * yellowstar[] = { +"16 16 48 1", +" c None", +". c #AB9600", +"+ c #AE9900", +"@ c #D0B600", +"# c #DBC000", +"$ c #FFDF02", +"% c #FFDF00", +"& c #A28D00", +"* c #766700", +"= c #A59000", +"- c #B09A00", +"; c #BBA400", +"> c #C5AC00", +", c #DFC300", +"' c #FFE111", +") c #FFE00A", +"! c #D2B800", +"~ c #AC9700", +"{ c #9B8800", +"] c #948100", +"^ c #9D8A00", +"/ c #F6D700", +"( c #FFE004", +"_ c #FFE31D", +": c #FFE10F", +"< c #F2D400", +"[ c #E5C800", +"} c #917F00", +"| c #CEB500", +"1 c #FFE10E", +"2 c #FCDC00", +"3 c #F0D200", +"4 c #C7AE00", +"5 c #CCB300", +"6 c #FADB00", +"7 c #BEA600", +"8 c #EED100", +"9 c #ECCF00", +"0 c #E6CA00", +"a c #B8A100", +"b c #988500", +"c c #DABE00", +"d c #A38F00", +"e c #B69F00", +"f c #897800", +"g c #BFA700", +"h c #8D7B00", +"i c #877600", +" ", +" ", +" ", +" .+ ", +" @# ", +" $%& ", +" *=-;>,')!~={] ", +" ^#/('_:$<[@} ", +" |%)1)234 ", +" 52%6<7 ", +" ,8390a ", +" bccd;c| ", +" &ef bg} ", +" h i ", +" ", +" "}; diff --git a/app/bin/cJSON.c b/app/bin/cJSON.c new file mode 100755 index 0000000..1733811 --- /dev/null +++ b/app/bin/cJSON.c @@ -0,0 +1,2932 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { + if (!cJSON_IsString(item)) { + return NULL; + } + + return item->valuestring; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 8) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occured */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = strlen((const char*)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((len < 0) || (buf == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buf; + p.length = (size_t)len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* faile to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL)) + { + return false; + } + + child = array->child; + + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + } + else + { + /* append to the end */ + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return; + } + + add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return; + } + + add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item->prev != NULL) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + add_item_to_array(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (parent->child == item) + { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return; + } + + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0;a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + unsigned char *into = (unsigned char*)json; + + if (json == NULL) + { + return; + } + + while (*json) + { + if (*json == ' ') + { + json++; + } + else if (*json == '\t') + { + /* Whitespace characters. */ + json++; + } + else if (*json == '\r') + { + json++; + } + else if (*json=='\n') + { + json++; + } + else if ((*json == '/') && (json[1] == '/')) + { + /* double-slash comments, to end of line. */ + while (*json && (*json != '\n')) + { + json++; + } + } + else if ((*json == '/') && (json[1] == '*')) + { + /* multiline comments. */ + while (*json && !((*json == '*') && (json[1] == '/'))) + { + json++; + } + json += 2; + } + else if (*json == '\"') + { + /* string literals, which are \" sensitive. */ + *into++ = (unsigned char)*json++; + while (*json && (*json != '\"')) + { + if (*json == '\\') + { + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + else + { + /* All other characters. */ + *into++ = (unsigned char)*json++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (a->valuedouble == b->valuedouble) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/app/bin/cJSON.h b/app/bin/cJSON.h new file mode 100755 index 0000000..8d45390 --- /dev/null +++ b/app/bin/cJSON.h @@ -0,0 +1,285 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 8 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check if the item is a string and return its valuestring */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/arrray that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + + +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/bin/cbezier.c b/app/bin/cbezier.c index b91a81e..7f90a27 100644 --- a/app/bin/cbezier.c +++ b/app/bin/cbezier.c @@ -104,7 +104,8 @@ static struct { DIST_T trackGauge; } Da; - +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) /** * Draw a ControlArm. @@ -233,17 +234,16 @@ double BezErrorLine(coOrd pos[4], coOrd start_point, coOrd end_point, double sta /* * Add element to DYNARR pointed to by caller from segment handed in */ -void addSegBezier(dynArr_t * const array_p, trkSeg_p seg) { +void addSegBezier(dynArr_t * array_p, trkSeg_p seg) { trkSeg_p s; - DYNARR_APPEND(trkSeg_t, * array_p, 1); //Adds 1 to cnt - s = &DYNARR_N(trkSeg_t,* array_p,array_p->cnt-1); + DYNARR_APPEND(trkSeg_t,* array_p, 1); //Adds 1 to cnt + s = &DYNARR_N(trkSeg_t,*array_p,(array_p->cnt)-1); s->type = seg->type; s->color = seg->color; s->width = seg->width; s->bezSegs.cnt = 0; - if (s->bezSegs.ptr) MyFree(s->bezSegs.ptr); s->bezSegs.ptr=NULL; s->bezSegs.max = 0; if ((s->type == SEG_BEZLIN || s->type == SEG_BEZTRK) && seg->bezSegs.cnt) { @@ -394,15 +394,15 @@ EXPORT BOOL_T ConvertToArcs (coOrd pos[4], dynArr_t * segs, BOOL_T track, wDrawC if (arc.curveData.type == curveTypeStraight) { double error = BezErrorLine(pos,start_point,end_point, t_s, t_e); - curr_good = (error <= errorThreshold/2); - arc.curveData.a0 = FindAngle(start_point,end_point); - arc.curveData.a1 = FindAngle(end_point,start_point); + curr_good = (error <= errorThreshold/4); + //arc.curveData.a0 = FindAngle(start_point,end_point); + //arc.curveData.a1 = FindAngle(end_point,start_point); } else if (arc.curveData.type == curveTypeNone) { return FALSE; //Something wrong } else { double error = BezError(pos, arc.curveData.curvePos, start_point, t_s, t_e); - curr_good = (error <= errorThreshold/2); + curr_good = (error <= errorThreshold/4); }; done = prev_good && !curr_good; //Was better than this last time? @@ -449,7 +449,7 @@ EXPORT BOOL_T ConvertToArcs (coOrd pos[4], dynArr_t * segs, BOOL_T track, wDrawC curveSeg.width = track?0:width; if ( prev_arc.curveData.type == curveTypeCurve ) { if (track) - curveSeg.color = (fabs(prev_arc.curveData.curveRadius)<(GetLayoutMinTrackRadius()-EPSILON))?wDrawColorRed:wDrawColorBlack; + curveSeg.color = (fabs(prev_arc.curveData.curveRadius)<(GetLayoutMinTrackRadius()-EPSILON))?exceptionColor:normalColor; else curveSeg.color = color; curveSeg.type = track?SEG_CRVTRK:SEG_CRVLIN; @@ -466,7 +466,7 @@ EXPORT BOOL_T ConvertToArcs (coOrd pos[4], dynArr_t * segs, BOOL_T track, wDrawC curveSeg.color = wDrawColorBlack; else curveSeg.color = color; - curveSeg.u.l.angle = prev_arc.curveData.a1; + curveSeg.u.l.angle = FindAngle(prev_arc.pos0,prev_arc.pos1); curveSeg.u.l.pos[0] = prev_arc.pos0; curveSeg.u.l.pos[1] = prev_arc.pos1; curveSeg.u.l.option = 0; @@ -483,7 +483,7 @@ EXPORT BOOL_T ConvertToArcs (coOrd pos[4], dynArr_t * segs, BOOL_T track, wDrawC * */ -EXPORT void DrawBezCurve(trkSeg_p control_arm1, +static void DrawBezCurve(trkSeg_p control_arm1, int cp1Segs_cnt, trkSeg_p control_arm2, int cp2Segs_cnt, @@ -491,28 +491,24 @@ EXPORT void DrawBezCurve(trkSeg_p control_arm1, int crvSegs_cnt, wDrawColor color ) { - long oldDrawOptions = tempD.funcs->options; - tempD.funcs->options = wDrawOptTemp; - long oldOptions = tempD.options; - tempD.options = DC_TICKS; - tempD.orig = mainD.orig; - tempD.angle = mainD.angle; if (crvSegs_cnt && curveSegs) DrawSegs( &tempD, zero, 0.0, curveSegs, crvSegs_cnt, Da.trackGauge, color ); if (cp1Segs_cnt && control_arm1) DrawSegs( &tempD, zero, 0.0, control_arm1, cp1Segs_cnt, Da.trackGauge, drawColorBlack ); if (cp2Segs_cnt && control_arm2) DrawSegs( &tempD, zero, 0.0, control_arm2, cp2Segs_cnt, Da.trackGauge, drawColorBlack ); - tempD.funcs->options = oldDrawOptions; - tempD.options = oldOptions; } +/* + * Undraw the temp Bezier + */ + /* * If Track, make it red if the radius is below minimum */ void DrawTempBezier(BOOL_T track) { - if (track) DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,Da.cp2Segs_da,Da.cp2Segs_da_cnt, (trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da_cnt,Da.minRadius<(GetLayoutMinTrackRadius()-EPSILON)?drawColorRed:drawColorBlack); + if (track) DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,Da.cp2Segs_da,Da.cp2Segs_da_cnt, (trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da_cnt,fabs(Da.minRadius)<(GetLayoutMinTrackRadius()-EPSILON)?exceptionColor:normalColor); else DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,Da.cp2Segs_da,Da.cp2Segs_da_cnt, (trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da_cnt,drawColorBlack); //Add Second Arm } @@ -542,6 +538,19 @@ void CreateBothControlArms(int selectPoint, BOOL_T track) { } } +void CreateMoveAnchor(coOrd pos,BOOL_T fill) { + double d = tempD.scale*0.15; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int inx = anchors_da.cnt-1; + anchors(inx).type = fill?SEG_FILCRCL:SEG_CRVLIN; + anchors(inx).u.c.a0 = 0.0; + anchors(inx).u.c.a1 = 360.0; + anchors(inx).width = 0; + anchors(inx).color = wDrawColorBlue; + anchors(inx).u.c.radius = d/4; + anchors(inx).u.c.center = pos; +} + /* * AdjustBezCurve * @@ -590,14 +599,24 @@ EXPORT STATUS_T AdjustBezCurve( InfoMessage( _("Select End-Point - Ctrl unlocks end-point") ); else InfoMessage( _("Select End-Point") ); - DrawTempBezier(Da.track); return C_CONTINUE; + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if (Da.state != PICK_POINT) return C_CONTINUE; + if (Da.state != PICK_POINT) return C_CONTINUE; + for (int i=0;i<4;i++) { + if (i==0 && Da.trk[0]) continue; + if (i==3 && Da.trk[1]) continue; //ignore locked points + d = FindDistance(Da.pos[i],pos); + if (IsClose(d)) CreateMoveAnchor(Da.pos[i],TRUE); + } + break; + case C_DOWN: if (Da.state != PICK_POINT) return C_CONTINUE; dd = 10000.0; Da.selectPoint = -1; - DrawTempBezier(Da.track); //wipe out for (int i=0;i<4;i++) { d = FindDistance(Da.pos[i],pos); if (d < dd) { @@ -609,19 +628,19 @@ EXPORT STATUS_T AdjustBezCurve( } if (!IsClose(dd) ) Da.selectPoint = -1; + DYNARR_RESET(trkSeg_t,anchors_da); if (Da.selectPoint == -1) { InfoMessage( _("Not close enough to any valid, selectable point, reselect") ); - DrawTempBezier(Da.track); return C_CONTINUE; } else { pos = Da.pos[Da.selectPoint]; + CreateMoveAnchor(pos,TRUE); Da.state = POINT_PICKED; InfoMessage( _("Drag point %d to new location and release it"),Da.selectPoint+1 ); } CreateBothControlArms(Da.selectPoint, track); if (ConvertToArcs(Da.pos, &Da.crvSegs_da, track, color,Da.width)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; Da.minRadius = BezierMinRadius(Da.pos, Da.crvSegs_da); - DrawTempBezier(Da.track); return C_CONTINUE; case C_MOVE: @@ -629,8 +648,8 @@ EXPORT STATUS_T AdjustBezCurve( InfoMessage(_("Pick any circle to adjust it - Enter to confirm, ESC to abort")); return C_CONTINUE; } + DYNARR_RESET(trkSeg_t,anchors_da); //If locked, reset pos to be on line from other track - DrawTempBezier(Da.track); //wipe out if (Da.selectPoint == 1 || Da.selectPoint == 2) { //CPs int controlArm = Da.selectPoint-1; //Snap to direction of track if (Da.trk[controlArm]) { @@ -642,6 +661,7 @@ EXPORT STATUS_T AdjustBezCurve( } // Dont Snap control points } else SnapPos(&pos); Da.pos[Da.selectPoint] = pos; + CreateMoveAnchor(pos,TRUE); CreateBothControlArms(Da.selectPoint, track); if (ConvertToArcs(Da.pos,&Da.crvSegs_da,track, color, Da.width)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; Da.minRadius = BezierMinRadius(Da.pos,Da.crvSegs_da); @@ -666,7 +686,6 @@ EXPORT STATUS_T AdjustBezCurve( InfoMessage( _("Bezier %s : Min Radius=%s Length=%s"),track?"Track":"Line", FormatDistance(Da.minRadius>=100000?0:Da.minRadius), FormatDistance(BezierLength(Da.pos,Da.crvSegs_da))); - DrawTempBezier(Da.track); return C_CONTINUE; case C_UP: @@ -674,11 +693,8 @@ EXPORT STATUS_T AdjustBezCurve( //Take last pos and decide if it should be snapped to a track because SHIFT is held (pos0 and pos3) ep = 0; BOOL_T found = FALSE; - - DrawTempBezier(Da.track); //wipe out - + DYNARR_RESET(trkSeg_t,anchors_da); p = pos; - if (track && (Da.selectPoint == 0 || Da.selectPoint == 3)) { //EPs if ((MyGetKeyState() & WKEY_SHIFT) != 0) { //Snap Track if ((t = OnTrackIgnore(&p, FALSE, TRUE, Da.selectTrack)) != NULL) { //Snap to endPoint @@ -701,6 +717,7 @@ EXPORT STATUS_T AdjustBezCurve( angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1); Translate(&Da.pos[Da.selectPoint==0?1:2], Da.pos[Da.selectPoint==0?0:3], angle1, FindDistance(Da.pos[Da.selectPoint==0?1:2],pos)*cos(D2R(angle2))); } + Da.selectPoint = -1; CreateBothControlArms(Da.selectPoint,track); if (ConvertToArcs(Da.pos,&Da.crvSegs_da,track,color,Da.width)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; @@ -722,7 +739,6 @@ EXPORT STATUS_T AdjustBezCurve( InfoMessage(_("Pick any circle to adjust it - Enter to confirm, ESC to abort")); } else InfoMessage(_("Pick any circle to adjust it - Enter to confirm, ESC to abort")); - DrawTempBezier(Da.track); Da.state = PICK_POINT; return C_CONTINUE; @@ -751,7 +767,6 @@ EXPORT STATUS_T AdjustBezCurve( } } Da.minRadius = BezierMinRadius(Da.pos,Da.crvSegs_da); - DrawTempBezier(Da.track); UndoStart( _("Create Bezier"), "newBezier - CR" ); if (Da.track) { t = NewBezierTrack( Da.pos, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt); @@ -761,26 +776,30 @@ EXPORT STATUS_T AdjustBezCurve( else t = NewBezierLine(Da.pos, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt,color,width); UndoEnd(); if (Da.crvSegs_da.ptr) MyFree(Da.crvSegs_da.ptr); + DYNARR_RESET(trkSeg_t,anchors_da); Da.crvSegs_da.ptr = NULL; Da.crvSegs_da.cnt = 0; Da.crvSegs_da.max = 0; DrawNewTrack(t); Da.state = NONE; - MainRedraw(); - MapRedraw(); return C_TERMINATE; } return C_CONTINUE; case C_REDRAW: - DrawTempBezier(Da.track); + if (Da.state != NONE) + DrawTempBezier(Da.track); + if (anchors_da.cnt>0) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); return C_CONTINUE; default: return C_CONTINUE; } + return C_CONTINUE; + } @@ -824,14 +843,16 @@ STATUS_T CmdBezModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG) Da.selectPoint = -1; Da.selectTrack = NULL; - if (IsTrack(trk)) Da.track = TRUE; + if (IsTrack(trk)) { + Da.track = TRUE; + Da.trk[0] = GetTrkEndTrk( trk, 0 ); + if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],trk); + Da.trk[1] = GetTrkEndTrk( trk, 1 ); + if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk); + } else Da.track = FALSE; Da.selectTrack = trk; - Da.trk[0] = GetTrkEndTrk( trk, 0 ); - if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],trk); - Da.trk[1] = GetTrkEndTrk( trk, 1 ); - if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk); for (int i=0;i<4;i++) Da.pos[i] = xx->bezierData.pos[i]; //Copy parms from old trk InfoMessage(_("%s picked - now select a Point"),track?"Track":"Line"); @@ -839,8 +860,12 @@ STATUS_T CmdBezModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG) DrawTrack(Da.selectTrack,&mainD,wDrawColorWhite); //Wipe out real track, draw replacement return AdjustBezCurve(C_START, pos, Da.track, xx->bezierData.segsColor, xx->bezierData.segsWidth, InfoMessage); + case wActionMove: + if (Da.state == NONE) return C_CONTINUE; + return AdjustBezCurve(wActionMove, pos, Da.track, xx->bezierData.segsColor, xx->bezierData.segsWidth, InfoMessage); case C_DOWN: if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up + UndrawNewTrack( Da.selectTrack ); return AdjustBezCurve(C_DOWN, pos, Da.track, xx->bezierData.segsColor, xx->bezierData.segsWidth, InfoMessage); @@ -867,9 +892,10 @@ STATUS_T CmdBezModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG) UndoStart( _("Modify Bezier"), "newBezier - CR" ); if (Da.track) t = NewBezierTrack( Da.pos, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt); else t = NewBezierLine(Da.pos, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt,xx->bezierData.segsColor,xx->bezierData.segsWidth); - + if (Da.track) CopyAttributes( trk, t ); + Da.state = NONE; //Must do before Delete for redraw DeleteTrack(trk, TRUE); if (Da.track) { @@ -879,16 +905,14 @@ STATUS_T CmdBezModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG) } } } + DrawNewTrack( t ); UndoEnd(); - InfoMessage(_("Modify Bezier Complete - select another")); - Da.state = NONE; + InfoMessage(_("Modify Bezier Complete")); return C_TERMINATE; case C_CANCEL: InfoMessage(_("Modify Bezier Cancelled")); Da.state = NONE; - MainRedraw(); - MapRedraw(); return C_TERMINATE; case C_REDRAW: @@ -919,6 +943,23 @@ DIST_T BezierLength(coOrd pos[4],dynArr_t segs) { return dd; } +DIST_T BezierOffsetLength(dynArr_t segs, double offset) { + DIST_T dd = 0.0; + if (segs.cnt == 0 ) return dd; + for (int i = 0;i0?offset:-offset))*D2R(t.u.c.a1)); + } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) { + dd +=BezierOffsetLength(t.bezSegs,offset); + } else if (t.type == SEG_STRLIN || t.type == SEG_STRTRK ) { + dd += FindDistance(t.u.l.pos[0],t.u.l.pos[1]); + } + } + return dd; +} + + DIST_T BezierMinRadius(coOrd pos[4],dynArr_t segs) { DIST_T r = 100000.0, rr; if (segs.cnt == 0 ) return r; @@ -934,6 +975,20 @@ DIST_T BezierMinRadius(coOrd pos[4],dynArr_t segs) { return r; } +static void CreateEndAnchor(coOrd p, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; +} + /* * Create a Bezier Curve (Track or Line) * Sequence is @@ -955,7 +1010,6 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) cmd = action>>8; } else cmd = (long)commandContext; - Da.color = lineColor; Da.width = (double)lineWidth/mainD.dpi; Da.trackGauge = trackGauge; @@ -965,6 +1019,10 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) case C_START: Da.track = (cmd == bezCmdModifyTrack || cmd == bezCmdCreateTrack)?TRUE:FALSE; + if (Da.track ) + Da.color = wDrawColorBlack; + else + Da.color = lineColor; Da.state = POS_1; Da. selectPoint = -1; @@ -977,44 +1035,43 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) DYNARR_RESET(trkSeg_t,Da.crvSegs_da); Da.cp1Segs_da_cnt = 0; Da.cp2Segs_da_cnt = 0; - InfoMessage( _("Place 1st end point of Bezier + Shift -> snap to %s end"), Da.track?"Unconnected Track":"Line" ); + InfoMessage( _("Place 1st endpoint of Bezier - snap to %s"), Da.track?"unconnected Track":"line" ); return C_CONTINUE; case C_DOWN: + DYNARR_RESET(trkSeg_t,anchors_da); if ( Da.state == POS_1 || Da.state == POS_2) { //Set the first or third point coOrd p = pos; BOOL_T found = FALSE; int end = Da.state==POS_1?0:1; EPINX_T ep; if (Da.track) { - if ((MyGetKeyState() & WKEY_SHIFT) != 0) { //Snap Track + if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == 0) { //Snap Track if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) { ep = PickUnconnectedEndPointSilent(p, t); if (ep != -1) { - Da.trk[end] = t; - Da.ep[end] = ep; - pos = GetTrkEndPos(t, ep); - found = TRUE; + if (GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) { + wBeep(); + InfoMessage(_("Track is different gauge")); + ep = -1; + t = NULL; + } else { + Da.trk[end] = t; + Da.ep[end] = ep; + pos = GetTrkEndPos(t, ep); + found = TRUE; + } } } - if (!found) { - wBeep(); - InfoMessage(_("Shift used, but no Unconnected Track End there")); - return C_CONTINUE; - } } } else { //Snap Bez Line to Lines - if ((MyGetKeyState() & WKEY_SHIFT) != 0) { + if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == 0) { if ((t = OnTrack(&p,FALSE, FALSE)) != NULL) { if (GetClosestEndPt(t,&p)) { pos = p; found = TRUE; } - } else { - wBeep(); - InfoMessage(_("Shift used, but no Line End there")); - return C_CONTINUE; } } } @@ -1024,37 +1081,58 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) Da.pos[1] = pos; Da.state = CONTROL_ARM_1; //Draw the first control arm Da.selectPoint = 1; - InfoMessage( _("Drag end of first Control Arm") ); + InfoMessage( _("Drag end of first control arm") ); Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0], Da.pos[1], Da.track,TRUE,Da.trk[1]!=NULL,1,wDrawColorBlack); - DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack); - } else { + } else { Da.pos[3] = pos; //2nd End Point Da.pos[2] = pos; //2nd Ctl Point Da.state = POINT_PICKED; // Drag out the second control arm Da.selectPoint = 2; - InfoMessage( _("Drag end of second Control Arm") ); - DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack); //Wipe out initial Arm + InfoMessage( _("Drag end of second control arm") ); Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0], Da.pos[1], Da.track,FALSE,Da.trk[0]!=NULL,-1,wDrawColorBlack); Da.cp2Segs_da_cnt = createControlArm(Da.cp2Segs_da, Da.pos[3], Da.pos[2], Da.track,TRUE,Da.trk[1]!=NULL,1,wDrawColorBlack); if (ConvertToArcs(Da.pos,&Da.crvSegs_da,Da.track,Da.color,Da.width)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; - DrawTempBezier(Da.track); } return C_CONTINUE; } else { return AdjustBezCurve( action&0xFF, pos, Da.track, Da.color, Da.width, InfoMessage ); } return C_CONTINUE; + + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if ( Da.state != POS_1 && Da.state != POS_2) return C_CONTINUE; + if (Da.track) { + if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == 0) { + if ((t = OnTrack(&pos, FALSE, TRUE)) != NULL) { + EPINX_T ep = PickUnconnectedEndPointSilent(pos, t); + if (ep != -1) { + if (GetTrkGauge(t) == GetScaleTrackGauge(GetLayoutCurScale())) { + pos = GetTrkEndPos(t, ep); + CreateEndAnchor(pos,FALSE); + } + } + } + } + } else { + if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == 0) { + if ((t = OnTrack(&pos,FALSE, FALSE)) != NULL) { + CreateEndAnchor(pos,TRUE); + } + } + } + if (anchors_da.cnt) + return C_CONTINUE; case C_MOVE: if (Da.state == POS_1) { - InfoMessage( _("Place 1st end point of Bezier + Shift -> snap to %s end"), Da.track?"Unconnected Track":"Line" ); + InfoMessage( _("Place 1st endpoint of Bezier - snap to %s"), Da.track?"unconnected track":"line" ); return C_CONTINUE; } if (Da.state == POS_2) { - InfoMessage( _("Select other end of Bezier, +Shift -> snap to %s end"), Da.track?"Unconnected Track":"Line" ); + InfoMessage( _("Select other end of Bezier - snap to %s end"), Da.track?"unconnected track":"line" ); } if (Da.state == CONTROL_ARM_1 ) { - DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack); if (Da.trk[0]) { EPINX_T ep = 0; ANGLE_T angle1,angle2; @@ -1066,7 +1144,6 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) } // Don't Snap control points Da.pos[1] = pos; Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0], Da.pos[1], Da.track, TRUE, Da.trk[0]!=NULL, 1, wDrawColorBlack); - DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack); } else { return AdjustBezCurve( action&0xFF, pos, Da.track, Da.color, Da.width, InfoMessage ); } @@ -1074,7 +1151,6 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) case C_UP: if (Da.state == CONTROL_ARM_1) { - DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack); if (Da.trk[0]) { EPINX_T ep = Da.ep[0]; ANGLE_T angle1,angle2; @@ -1091,9 +1167,8 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) return C_CONTINUE; } Da.state = POS_2; - InfoMessage( _("Select other end of Bezier, +Shift -> snap to %s end"), Da.track?"Unconnected Track":"Line" ); + InfoMessage( _("Select other end of Bezier - snap to %s end"), Da.track?"Unconnected Track":"Line" ); Da.cp1Segs_da_cnt = createControlArm(Da.cp1Segs_da, Da.pos[0], Da.pos[1], Da.track, FALSE, Da.trk[0]!=NULL, -1, wDrawColorBlack); - DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,NULL,0,NULL,0,drawColorBlack); return C_CONTINUE; } else { return AdjustBezCurve( action&0xFF, pos, Da.track, Da.color, Da.width, InfoMessage ); @@ -1108,14 +1183,14 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) case C_REDRAW: if ( Da.state != NONE ) { - DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,Da.cp2Segs_da,Da.cp2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, Da.color); } + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); return C_CONTINUE; case C_CANCEL: if (Da.state != NONE) { - DrawBezCurve(Da.cp1Segs_da,Da.cp1Segs_da_cnt,Da.cp2Segs_da,Da.cp2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, Da.color); Da.cp1Segs_da_cnt = 0; Da.cp2Segs_da_cnt = 0; Da.crvSegs_da_cnt = 0; @@ -1139,13 +1214,13 @@ STATUS_T CmdBezCurve( wAction_t action, coOrd pos ) } void UpdateParms(wDrawColor color,long width) { - DrawTempBezier(Da.track); Da.color = lineColor; Da.width = (double)lineWidth/mainD.dpi; if (Da.crvSegs_da.cnt) { ConvertToArcs(Da.pos,&Da.crvSegs_da,Da.track,Da.color,Da.width); } DrawTempBezier(Da.track); + } diff --git a/app/bin/cbezier.h b/app/bin/cbezier.h index 8d0dde8..49b818f 100644 --- a/app/bin/cbezier.h +++ b/app/bin/cbezier.h @@ -25,7 +25,7 @@ #include "utility.h" -dynArr_t tempEndPts_da; +extern dynArr_t tempEndPts_da; #define BezSegs(N) DYNARR_N( trkEndPt_t, tempEndPts_da, N ) #define bezCmdNone (0) @@ -42,12 +42,15 @@ STATUS_T CmdBezCurve( wAction_t, coOrd); STATUS_T CmdBezModify(track_p, wAction_t, coOrd, DIST_T); STATUS_T CreateBezier( wAction_t, coOrd, BOOL_T, wDrawColor, DIST_T, long, bezMessageProc ); -DIST_T BezierDescriptionDistance( coOrd, track_p ); +DIST_T BezierDescriptionDistance( coOrd, track_p, coOrd *, BOOL_T, BOOL_T * ); STATUS_T BezierDescriptionMove( track_p, wAction_t, coOrd ); BOOL_T GetBezierMiddle( track_p, coOrd * ); BOOL_T ConvertToArcs (coOrd[4], dynArr_t *, BOOL_T, wDrawColor, DIST_T); track_p NewBezierTrack(coOrd[4], trkSeg_t *, int); double BezierLength(coOrd[4], dynArr_t); +double BezierOffsetLength(dynArr_t,double offset); double BezierMinRadius(coOrd[4],dynArr_t); void UpdateParms(wDrawColor color,long width); +void addSegBezier(dynArr_t * array_p, trkSeg_p seg); + diff --git a/app/bin/cblock.c b/app/bin/cblock.c index 4c4895c..b395306 100644 --- a/app/bin/cblock.c +++ b/app/bin/cblock.c @@ -61,6 +61,10 @@ #include "trackx.h" #include "utility.h" +#ifdef WINDOWS +#include "include/utf8convert.h" +#endif // WINDOWS + EXPORT TRKTYP_T T_BLOCK = -1; static int log_block = 0; @@ -74,8 +78,8 @@ static void NoDrawString( drawCmd_p d, coOrd p, ANGLE_T a, char * s, wFont_p fp, FONTSIZE_T fontSize, wDrawColor color ) {} static void NoDrawBitMap( drawCmd_p d, coOrd p, wDrawBitMap_p bm, wDrawColor color) {} -static void NoDrawFillPoly( drawCmd_p d, int cnt, coOrd * pts, - wDrawColor color ) {} +static void NoDrawFillPoly( drawCmd_p d, int cnt, coOrd * pts, int * types, + wDrawColor color, wDrawWidth width, int fill, int open) {} static void NoDrawFillCircle( drawCmd_p d, coOrd p, DIST_T r, wDrawColor color ) {} @@ -100,6 +104,8 @@ static drawCmd_t blockD = { static char blockName[STR_SHORT_SIZE]; static char blockScript[STR_LONG_SIZE]; static long blockElementCount; +static track_p first_block; +static track_p last_block; static paramData_t blockPLs[] = { /*0*/ { PD_STRING, blockName, "name", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)200, N_("Name"), 0, 0, sizeof( blockName )}, @@ -116,7 +122,7 @@ static track_p blockEditTrack; static paramData_t blockEditPLs[] = { /*0*/ { PD_STRING, blockEditName, "name", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)200, N_("Name"), 0, 0, sizeof(blockEditName)}, /*1*/ { PD_STRING, blockEditScript, "script", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)350, N_("Script"), 0, 0, sizeof(blockEditScript)}, -/*2*/ { PD_STRING, blockEditSegs, "segments", PDO_NOPREF, (void*)350, N_("Segments"), BO_READONLY }, +/*2*/ { PD_STRING, blockEditSegs, "segments", PDO_NOPREF, (void*)350, N_("Segments"), BO_READONLY }, }; static paramGroup_t blockEditPG = { "block", 0, blockEditPLs, sizeof blockEditPLs/sizeof blockEditPLs[0] }; static wWin_p blockEditW; @@ -129,12 +135,14 @@ typedef struct btrackinfo_t { static dynArr_t blockTrk_da; #define blockTrk(N) DYNARR_N( btrackinfo_t , blockTrk_da, N ) +#define tracklist(N) (&(xx->trackList))[N] typedef struct blockData_t { char * name; char * script; BOOL_T IsHilite; + track_p next_block; wIndex_t numTracks; btrackinfo_t trackList; } blockData_t, *blockData_p; @@ -221,10 +229,11 @@ static DIST_T DistanceBlock (track_p t, coOrd * p ) DIST_T closest, current; int iTrk = 1; coOrd pos = *p; - closest = GetTrkDistance ((&(xx->trackList))[0].t, &pos); + closest = 99999.0; coOrd best_pos = pos; - for (; iTrk < xx->numTracks; iTrk++) { + for (iTrk = 0; iTrk < xx->numTracks; iTrk++) { pos = *p; + if ((&(xx->trackList))[iTrk].t == NULL) continue; current = GetTrkDistance ((&(xx->trackList))[iTrk].t, &pos); if (current < closest) { closest = current; @@ -252,22 +261,25 @@ static void DescribeBlock (track_p trk, char * str, CSIZE_T len ) *str = tolower((unsigned char)*str); str++; } - sprintf( str, _("(%d): Layer=%d %s"), + sprintf( str, _("(%d): Layer=%u %s"), GetTrkIndex(trk), GetTrkLayer(trk)+1, message ); blockData.name[0] = '\0'; strncat(blockData.name,xx->name,STR_SHORT_SIZE-1); blockData.script[0] = '\0'; strncat(blockData.script,xx->script,STR_LONG_SIZE-1); blockData.length = 0; - if (xx->numTracks > 0) { - blockData.endPt[0] = GetTrkEndPos((&(xx->trackList))[0].t,0); - } + BOOL_T first = TRUE; for (tcount = 0; tcount < xx->numTracks; tcount++) { - if ((&(xx->trackList))[tcount].t == NULL) continue; - blockData.length += GetTrkLength((&(xx->trackList))[tcount].t,0,1); - lastTrk = (&(xx->trackList))[tcount].t; + if ((&(xx->trackList))[tcount].t == NULL) continue; + if (first) { + blockData.endPt[0] = GetTrkEndPos((&(xx->trackList))[tcount].t,0); + first = FALSE; + } + blockData.endPt[1] = GetTrkEndPos((&(xx->trackList))[tcount].t,1); + blockData.length += GetTrkLength((&(xx->trackList))[tcount].t,0,1); + tcount++; + break; } - if (lastTrk != NULL) blockData.endPt[1] = GetTrkEndPos(lastTrk,1); blockDesc[E0].mode = blockDesc[E1].mode = blockDesc[LN].mode = DESC_RO; @@ -347,13 +359,31 @@ static BOOL_T blockCheckContigiousPath() static void DeleteBlock ( track_p t ) { - LOG( log_block, 1, ("*** DeleteBlock(%p)\n",t)) - blockData_p xx = GetblockData(t); - LOG( log_block, 1, ("*** DeleteBlock(): index is %d\n",GetTrkIndex(t))) - LOG( log_block, 1, ("*** DeleteBlock(): xx = %p, xx->name = %p, xx->script = %p\n", + track_p trk1; + blockData_p xx1; + + LOG( log_block, 1, ("*** DeleteBlock(%p)\n",t)) + blockData_p xx = GetblockData(t); + LOG( log_block, 1, ("*** DeleteBlock(): index is %d\n",GetTrkIndex(t))) + LOG( log_block, 1, ("*** DeleteBlock(): xx = %p, xx->name = %p, xx->script = %p\n", xx,xx->name,xx->script)) MyFree(xx->name); xx->name = NULL; MyFree(xx->script); xx->script = NULL; + + if (first_block == t) + first_block = xx->next_block; + trk1 = first_block; + while(trk1) { + xx1 = GetblockData (trk1); + if (xx1->next_block == t) { + xx1->next_block = xx->next_block; + break; + } + trk1 = xx1->next_block; + } + if (t == last_block) + last_block = trk1; + } static BOOL_T WriteBlock ( track_p t, FILE * f ) @@ -361,25 +391,31 @@ static BOOL_T WriteBlock ( track_p t, FILE * f ) BOOL_T rc = TRUE; wIndex_t iTrack; blockData_p xx = GetblockData(t); + char *blockName = MyStrdup(xx->name); + +#ifdef WINDOWS + blockName = Convert2UTF8(blockName); +#endif // WINDOWS rc &= fprintf(f, "BLOCK %d \"%s\" \"%s\"\n", - GetTrkIndex(t), xx->name, xx->script)>0; + GetTrkIndex(t), blockName, xx->script)>0; for (iTrack = 0; iTrack < xx->numTracks && rc; iTrack++) { if ((&(xx->trackList))[iTrack].t == NULL) continue; rc &= fprintf(f, "\tTRK %d\n", GetTrkIndex((&(xx->trackList))[iTrack].t))>0; } - rc &= fprintf( f, "\tEND\n" )>0; + rc &= fprintf( f, "\t%s\n", END_BLOCK )>0; + MyFree(blockName); return rc; } -static void ReadBlock ( char * line ) +static BOOL_T ReadBlock ( char * line ) { TRKINX_T trkindex; wIndex_t index; - track_p trk; + track_p trk, trk1; char * cp = NULL; - blockData_p xx; + blockData_p xx,xx1; wIndex_t iTrack; EPINX_T ep; trkEndPt_p endPtP; @@ -387,19 +423,24 @@ static void ReadBlock ( char * line ) LOG( log_block, 1, ("*** ReadBlock: line is '%s'\n",line)) if (!GetArgs(line+6,"dqq",&index,&name,&script)) { - return; + return FALSE; } + +#ifdef WINDOWS + ConvertUTF8ToSystem(name); +#endif // WINDOWS + DYNARR_RESET( btrackinfo_p , blockTrk_da ); while ( (cp = GetNextLine()) != NULL ) { - while (isspace((unsigned char)*cp)) cp++; - if ( strncmp( cp, "END", 3 ) == 0 ) { + if ( IsEND( END_BLOCK ) ) { break; } + while (isspace((unsigned char)*cp)) cp++; if ( *cp == '\n' || *cp == '#' ) { continue; } if ( strncmp( cp, "TRK", 3 ) == 0 ) { - if (!GetArgs(cp+4,"d",&trkindex)) return; + if (!GetArgs(cp+4,"d",&trkindex)) return FALSE; /*trk = FindTrack(trkindex);*/ DYNARR_APPEND( btrackinfo_p *, blockTrk_da, 10 ); blockTrk(blockTrk_da.cnt-1).i = trkindex; @@ -411,18 +452,28 @@ static void ReadBlock ( char * line ) endPtP = &tempEndPts(ep); SetTrkEndPoint( trk, ep, endPtP->pos, endPtP->angle ); } - xx = GetblockData( trk ); - LOG( log_block, 1, ("*** ReadBlock(): trk = %p (%d), xx = %p\n",trk,GetTrkIndex(trk),xx)) - LOG( log_block, 1, ("*** ReadBlock(): name = %p, script = %p\n",name,script)) - xx->name = name; - xx->script = script; - xx->IsHilite = FALSE; + xx = GetblockData( trk ); + LOG( log_block, 1, ("*** ReadBlock(): trk = %p (%d), xx = %p\n",trk,GetTrkIndex(trk),xx)) + LOG( log_block, 1, ("*** ReadBlock(): name = %p, script = %p\n",name,script)) + xx->name = name; + xx->script = script; + xx->IsHilite = FALSE; xx->numTracks = blockTrk_da.cnt; + trk1 = last_block; + if (!trk1) first_block = trk; + else { + xx1 = GetblockData(trk1); + xx1->next_block = trk; + } + xx->next_block = NULL; + last_block = trk; for (iTrack = 0; iTrack < blockTrk_da.cnt; iTrack++) { - LOG( log_block, 1, ("*** ReadBlock(): copying track T%d\n",GetTrkIndex(blockTrk(iTrack).t))) - memcpy((void*)&((&(xx->trackList))[iTrack]),(void*)&(blockTrk(iTrack)),sizeof(btrackinfo_t)); + LOG( log_block, 1, ("*** ReadBlock(): copying track T%d\n",blockTrk(iTrack).i)) + tracklist(iTrack).i = blockTrk(iTrack).i; + tracklist(iTrack).t = NULL; // Not resolved yet!! // } blockDebug(trk); + return TRUE; } EXPORT void ResolveBlockTrack ( track_p trk ) @@ -435,12 +486,12 @@ EXPORT void ResolveBlockTrack ( track_p trk ) LOG( log_block, 1, ("*** ResolveBlockTrack(%d)\n",GetTrkIndex(trk))) xx = GetblockData(trk); for (iTrack = 0; iTrack < xx->numTracks; iTrack++) { - t_trk = FindTrack((&(xx->trackList))[iTrack].i); + t_trk = FindTrack(tracklist(iTrack).i); if (t_trk == NULL) { - NoticeMessage( _("resolveBlockTrack: T%d[%d]: T%d doesn't exist"), _("Continue"), NULL, GetTrkIndex(trk), iTrack, (&(xx->trackList))[iTrack].i ); + NoticeMessage( _("resolveBlockTrack: T%d[%d]: T%d doesn't exist"), _("Continue"), NULL, GetTrkIndex(trk), iTrack, tracklist(iTrack).i,t_trk ); } - (&(xx->trackList))[iTrack].t = t_trk; - LOG( log_block, 1, ("*** ResolveBlockTrack(): %d (%d): %p\n",iTrack,(&(xx->trackList))[iTrack].i,t_trk)) + tracklist(iTrack).t = t_trk; + LOG( log_block, 1, ("*** ResolveBlockTrack(): %d (%d): %p\n",iTrack,tracklist(iTrack).i,t_trk)) } } @@ -494,17 +545,24 @@ static BOOL_T TrackInBlock (track_p trk, track_p blk) { static track_p FindBlock (track_p trk) { track_p a_trk; - for (a_trk = NULL; TrackIterate( &a_trk ) ;) { - if (GetTrkType(a_trk) == T_BLOCK && - TrackInBlock(trk,a_trk)) return a_trk; + blockData_p xx; + if (!first_block) return NULL; + a_trk = first_block; + while (a_trk) { + if (!IsTrackDeleted(a_trk)) { + if (GetTrkType(a_trk) == T_BLOCK && + TrackInBlock(trk,a_trk)) return a_trk; + } + xx = GetblockData(a_trk); + a_trk = xx->next_block; } return NULL; } static void BlockOk ( void * junk ) { - blockData_p xx; - track_p trk; + blockData_p xx,xx1; + track_p trk,trk1; wIndex_t iTrack; EPINX_T ep; trkEndPt_p endPtP; @@ -525,10 +583,11 @@ static void BlockOk ( void * junk ) while ( TrackIterate( &trk ) ) { if ( GetTrkSelected( trk ) ) { if ( IsTrack(trk) ) { - DYNARR_APPEND( btrackinfo_p *, blockTrk_da, 10 ); + DYNARR_APPEND( btrackinfo_t, blockTrk_da, 10 ); + blockTrk(blockTrk_da.cnt - 1).t = trk; + blockTrk(blockTrk_da.cnt - 1).i = GetTrkIndex(trk); LOG( log_block, 1, ("*** BlockOk(): adding track T%d\n",GetTrkIndex(trk))) - blockTrk(blockTrk_da.cnt-1).t = trk; - blockTrk(blockTrk_da.cnt-1).i = GetTrkIndex(trk); + } } } @@ -556,15 +615,26 @@ static void BlockOk ( void * junk ) SetTrkEndPoint( trk, ep, endPtP->pos, endPtP->angle ); } - xx = GetblockData( trk ); - LOG(log_block, 1, ("*** BlockOk(): trk = %p (%d), xx = %p\n", trk, GetTrkIndex(trk), xx)) + xx = GetblockData( trk ); + LOG(log_block, 1, ("*** BlockOk(): trk = %p (%d), xx = %p\n", trk, GetTrkIndex(trk), xx)) xx->name = MyStrdup(blockName); xx->script = MyStrdup(blockScript); - xx->IsHilite = FALSE; + xx->IsHilite = FALSE; xx->numTracks = blockTrk_da.cnt; + trk1 = last_block; + if (!trk1) { + first_block = trk; + } + else { + xx1 = GetblockData(trk1); + xx1->next_block = trk; + } + xx->next_block = NULL; + last_block = trk; for (iTrack = 0; iTrack < blockTrk_da.cnt; iTrack++) { - LOG( log_block, 1, ("*** BlockOk(): copying track T%d\n",GetTrkIndex(blockTrk(iTrack).t))) - memcpy((void*)&(&(xx->trackList))[iTrack],(void*)&blockTrk(iTrack),sizeof(btrackinfo_t)); + LOG( log_block, 1, ("*** BlockOk(): copying track T%d\n",tracklist(iTrack).i)) + tracklist(iTrack).i = blockTrk(iTrack).i; + tracklist(iTrack).t = blockTrk(iTrack).t; } blockDebug(trk); UndoEnd(); @@ -710,13 +780,17 @@ static STATUS_T CmdBlock (wAction_t action, coOrd pos ) } #endif -EXPORT void CheckDeleteBlock (track_p t) +void CheckDeleteBlock(track_p t) { track_p blk; blockData_p xx; - + if (!IsTrack(t)) { + return; + } blk = FindBlock(t); - if (blk == NULL) return; + if (blk == NULL) { + return; + } xx = GetblockData(blk); NoticeMessage(_("Deleting block %s"),_("Ok"),NULL,xx->name); DeleteTrack(blk,FALSE); @@ -789,7 +863,7 @@ static void DrawBlockTrackHilite( void ) w = (wPos_t)((blkhiliteSize.x/mainD.scale)*mainD.dpi+0.5); h = (wPos_t)((blkhiliteSize.y/mainD.scale)*mainD.dpi+0.5); mainD.CoOrd2Pix(&mainD,blkhiliteOrig,&x,&y); - wDrawFilledRectangle( mainD.d, x, y, w, h, blkhiliteColor, wDrawOptTemp ); + wDrawFilledRectangle( mainD.d, x, y, w, h, blkhiliteColor, wDrawOptTemp|wDrawOptTransparent ); } diff --git a/app/bin/ccontrol.c b/app/bin/ccontrol.c index fb02fdf..793acc3 100644 --- a/app/bin/ccontrol.c +++ b/app/bin/ccontrol.c @@ -58,6 +58,9 @@ static const char rcsid[] = "@(#) : $Id$"; #include "param.h" #include "track.h" #include "trackx.h" +#ifdef WINDOWS +#include "include/utf8convert.h" +#endif // WINDOWS #include "utility.h" #include "messages.h" @@ -276,7 +279,7 @@ static void DescribeControl (track_p trk, char * str, CSIZE_T len ) *str = tolower((unsigned char)*str); str++; } - sprintf( str, _("(%d [%s]): Layer=%d, at %0.3f,%0.3f"), + sprintf( str, _("(%d [%s]): Layer=%u, at %0.3f,%0.3f"), GetTrkIndex(trk), xx->name,GetTrkLayer(trk)+1, xx->orig.x, xx->orig.y); strncpy(controlProperties.name,xx->name,STR_SHORT_SIZE-1); @@ -305,14 +308,22 @@ static BOOL_T WriteControl ( track_p t, FILE * f ) { BOOL_T rc = TRUE; controlData_p xx = GetcontrolData(t); - rc &= fprintf(f, "CONTROL %d %d %s %d %0.6f %0.6f \"%s\" \"%s\" \"%s\"\n", + char *controlName = MyStrdup(xx->name); + +#ifdef WINDOWS + controlName = Convert2UTF8(controlName); +#endif // WINDOWS + + rc &= fprintf(f, "CONTROL %d %u %s %d %0.6f %0.6f \"%s\" \"%s\" \"%s\"\n", GetTrkIndex(t), GetTrkLayer(t), GetTrkScaleName(t), - GetTrkVisible(t), xx->orig.x, xx->orig.y, xx->name, + GetTrkVisible(t), xx->orig.x, xx->orig.y, controlName, xx->onscript, xx->offscript)>0; + + MyFree(controlName); return rc; } -static void ReadControl ( char * line ) +static BOOL_T ReadControl ( char * line ) { wIndex_t index; /*TRKINX_T trkindex;*/ @@ -326,8 +337,13 @@ static void ReadControl ( char * line ) wIndex_t layer; controlData_p xx; if (!GetArgs(line+7,"dLsdpqqq",&index,&layer,scale, &visible, &orig,&name,&onscript,&offscript)) { - return; + return FALSE; } + +#ifdef WINDOWS + ConvertUTF8ToSystem(name); +#endif // WINDOWS + trk = NewTrack(index, T_CONTROL, 0, sizeof(controlData_t)); SetTrkVisible(trk, visible); SetTrkScale(trk, LookupScale( scale )); @@ -338,6 +354,7 @@ static void ReadControl ( char * line ) xx->onscript = onscript; xx->offscript = offscript; ComputeControlBoundingBox(trk); + return TRUE; } static void MoveControl (track_p trk, coOrd orig ) @@ -502,24 +519,29 @@ static void CreateNewControl (coOrd orig) static STATUS_T CmdControl ( wAction_t action, coOrd pos ) { - + static coOrd control_pos; + static BOOL_T create; switch (action) { case C_START: InfoMessage(_("Place control")); + create = FALSE; return C_CONTINUE; case C_DOWN: + create = TRUE; + /* no break */ case C_MOVE: SnapPos(&pos); - DDrawControl( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack ); + control_pos = pos; return C_CONTINUE; case C_UP: SnapPos(&pos); - DDrawControl( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack ); CreateNewControl(pos); return C_TERMINATE; case C_REDRAW: + if (create) + DDrawControl( &tempD, control_pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack ); + return C_CONTINUE; case C_CANCEL: - DDrawControl( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack ); return C_CONTINUE; default: return C_CONTINUE; @@ -537,7 +559,7 @@ static void DrawControlTrackHilite( void ) w = (wPos_t)((ctlhiliteSize.x/mainD.scale)*mainD.dpi+0.5); h = (wPos_t)((ctlhiliteSize.y/mainD.scale)*mainD.dpi+0.5); mainD.CoOrd2Pix(&mainD,ctlhiliteOrig,&x,&y); - wDrawFilledRectangle( mainD.d, x, y, w, h, ctlhiliteColor, wDrawOptTemp ); + wDrawFilledRectangle( mainD.d, x, y, w, h, ctlhiliteColor, wDrawOptTemp|wDrawOptTransparent ); } static int ControlMgmProc ( int cmd, void * data ) diff --git a/app/bin/ccornu.c b/app/bin/ccornu.c index 9bdb0d0..fd51755 100644 --- a/app/bin/ccornu.c +++ b/app/bin/ccornu.c @@ -1,3 +1,7 @@ + + + + /** \file ccornu.c * Cornu Command. Draw or modify a Cornu Easement Track. */ @@ -71,6 +75,7 @@ #include "ccurve.h" #include "ccornu.h" #include "tcornu.h" +#include "tbezier.h" #include "cstraigh.h" #include "drawgeom.h" #include "cjoin.h" @@ -83,12 +88,24 @@ #include "cundo.h" #include "messages.h" #include "cselect.h" +#include "fileio.h" + +#include extern drawCmd_t tempD; extern TRKTYP_T T_BEZIER; extern TRKTYP_T T_CORNU; - +typedef struct { + coOrd end_center; + coOrd end_curve; + DIST_T mid_disp; + BOOL_T end_valid; + BOOL_T angle_selected; + BOOL_T radius_selected; + BOOL_T last_selected; + ANGLE_T arc_angle; +} endHandle; /* * STATE INFO @@ -101,11 +118,18 @@ enum Cornu_States { NONE, POINT_PICKED, TRACK_SELECTED }; +typedef enum {CORNU_MODIFY, CORNU_CREATE} cornuCmdType_e; + + static struct { enum Cornu_States state; coOrd pos[2]; - int selectPoint; - wDrawColor color; + int number_of_points; + int selectEndPoint; + int selectMidPoint; + int selectEndHandle; + int prevSelected; + int prevEndPoint; DIST_T width; track_p trk[2]; EPINX_T ep[2]; @@ -119,9 +143,9 @@ static struct { BOOL_T extend[2]; trkSeg_t extendSeg[2]; - trkSeg_t ep1Segs[2]; + trkSeg_t ep1Segs[11]; int ep1Segs_da_cnt; - trkSeg_t ep2Segs[2]; + trkSeg_t ep2Segs[11]; int ep2Segs_da_cnt; dynArr_t crvSegs_da; int crvSegs_da_cnt; @@ -132,9 +156,143 @@ static struct { BOOL_T circleorHelix[2]; DIST_T trackGauge; + int cmdType; + + dynArr_t midSegs; + + dynArr_t mid_points; + dynArr_t tracks; + BOOL_T ends[2]; + + endHandle endHandle[2]; + bezctx * bezc; + + cornuCmdType_e commandType; + } Da; +static trkSeg_p curCornu; +static wIndex_t cornuHotBarCmdInx; + +static struct { + trkSeg_t st; + trkSeg_t back; + trkSeg_t txt; + int count; +} hotB; + + +static char * CmdCornuHotBarProc( + hotBarProc_e op, + void * data, + drawCmd_p d, + coOrd * origP ) +{ + trkSeg_p trkseg = &hotB.st; + switch ( op ) { + case HB_SELECT: + CmdCornu( C_CANCEL, zero ); + curCornu = trkseg; + DoCommandB( (void*)(intptr_t)cornuHotBarCmdInx ); + return NULL; + case HB_LISTTITLE: + sprintf(message,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale())); + return message; + case HB_BARTITLE: + sprintf(message,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale())); + return message; + case HB_FULLTITLE: + sprintf(message,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale())); + return message; + case HB_DRAW: + DrawSegs( d, *origP, 0.0, trkseg, hotB.count, trackGauge, wDrawColorBlack ); + return NULL; + } + return NULL; +} + +static pts_t pts[4]; + + +EXPORT void AddHotBarCornu( void ) +{ + hotB.st.type = SEG_STRTRK; + hotB.st.color = wDrawColorBlack; + hotB.st.u.l.pos[0] = zero; + DIST_T ratio = 75.0/curScaleRatio; + Translate(&hotB.st.u.l.pos[1],zero,45.0,15.0*ratio); + hotB.st.u.l.angle = 45.0; + + pts[0].pt_type = wPolyLineStraight; + pts[0].pt.x = 1.0*ratio; + pts[0].pt.y = 5.0*ratio; + pts[1].pt_type = wPolyLineStraight; + pts[1].pt.x = 1.0*ratio; + pts[1].pt.y = 8.0*ratio; + pts[2].pt_type = wPolyLineStraight; + pts[2].pt.x = 13.0*ratio; + pts[2].pt.y = 8.0*ratio; + pts[3].pt_type = wPolyLineStraight; + pts[3].pt.x = 13.0*ratio; + pts[3].pt.y = 5.0*ratio; + + hotB.back.type = SEG_FILPOLY; + hotB.back.color = wDrawColorWhite; + hotB.back.u.p.orig.x = 0.0; + hotB.back.u.p.orig.y = 0.0; + hotB.back.u.p.cnt = 4; + hotB.back.u.p.angle = 0.0; + hotB.back.u.p.polyType = RECTANGLE; + hotB.back.u.p.pts = &pts[0]; + + hotB.txt.type = SEG_TEXT; + hotB.txt.color = wDrawColorBlack; + hotB.txt.u.t.pos.x = 1.0*ratio; + hotB.txt.u.t.pos.y = 5.0*ratio; + hotB.txt.u.t.boxed = TRUE; + hotB.txt.u.t.string = MyStrdup(_(" FLEX ")); + hotB.txt.u.t.fontP = NULL; + hotB.txt.u.t.fontSize = 160.0*ratio; + hotB.txt.u.t.angle = 0.0; + + char * label = MyMalloc(256); + sprintf(label,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale())); + coOrd end; + end = hotB.st.u.l.pos[1]; + //end.x = 21.25; + //end.y = 21.25; + hotB.count = 3; + //hotB.st.u.l.pos[1] = end; + AddHotBarElement( label, end, zero, TRUE, TRUE, curBarScale>0?curBarScale:-1, &hotB, CmdCornuHotBarProc ); +} + +int createMidPoint(dynArr_t * ap, + coOrd pos0, //end on curve + BOOL_T point_selected, + BOOL_T point_selectable, + BOOL_T track_modifyable + ) +{ + DIST_T d, w; + d = tempD.scale*0.25; + w = tempD.scale/tempD.dpi; /*double width*/ + + DYNARR_APPEND(trkSeg_t,*ap,1); + + trkSeg_p sp = &DYNARR_LAST(trkSeg_t,*ap); + + sp->u.c.center = pos0; + sp->u.c.a0 = 0.0; + sp->u.c.a1 = 360.0; + sp->u.c.radius = d/2; + sp->type = point_selected?SEG_FILCRCL:SEG_CRVLIN; + sp->width = w; + sp->color = drawColorBlack; + + return 1; + +} /** @@ -146,35 +304,208 @@ int createEndPoint( coOrd pos0, //end on curve BOOL_T point_selected, BOOL_T point_selectable, - BOOL_T track_modifyable + BOOL_T track_modifyable, + BOOL_T track_present, + ANGLE_T angle, + DIST_T radius, + coOrd centert, + endHandle * endHandle ) { DIST_T d, w; + int num =0; d = tempD.scale*0.25; w = tempD.scale/tempD.dpi; /*double width*/ + num = 1; + if (point_selectable) { + sp[1].u.c.center = pos0; + sp[1].u.c.a0 = 0.0; + sp[1].u.c.a1 = 360.0; + sp[1].u.c.radius = d/2; + sp[1].type = SEG_CRVLIN; + sp[1].width = w; + sp[1].color = point_selected?drawColorBlue:drawColorRed; + num = 2; + } sp[0].u.c.center = pos0; sp[0].u.c.a0 = 0.0; sp[0].u.c.a1 = 360.0; sp[0].width = w; sp[0].u.c.radius = d/4; - sp[0].color = (point_selected>=0)?drawColorRed:drawColorBlack; + sp[0].color = point_selected?drawColorBlue:drawColorRed; if (track_modifyable) sp[0].type = SEG_CRVLIN; else sp[0].type = SEG_FILCRCL; - if (point_selectable) { - sp[1].u.c.center = pos0; - sp[1].u.c.a0 = 0.0; - sp[1].u.c.a1 = 360.0; - sp[1].u.c.radius = d/2; - sp[1].type = SEG_CRVLIN; - sp[1].width = w; - sp[1].color = drawColorRed; - return 2; + if (!track_present && endHandle ) { + endHandle->end_center = zero; + endHandle->end_curve = zero; + endHandle->end_valid = TRUE; + endHandle->mid_disp = 0.0; + DIST_T end_length = 20*trackGauge; + Translate(&endHandle->end_curve,pos0,angle,end_length); + Translate(&endHandle->end_center,pos0,angle,end_length/2); + if (radius>0.0) { + ANGLE_T a1 = R2D(end_length/radius); + if (DifferenceBetweenAngles(angle,FindAngle(centert,pos0))>0.0) { + a1 = -a1; + } + PointOnCircle( &endHandle->end_curve, centert,radius,NormalizeAngle(FindAngle(centert,pos0)+a1)); + PointOnCircle( &endHandle->end_center,centert,radius,NormalizeAngle(FindAngle(centert,pos0)+(a1/2.0))); + coOrd cm; + cm = endHandle->end_center; + ANGLE_T a = FindAngle(endHandle->end_curve,pos0); + Rotate(&cm,endHandle->end_curve,-a ); + endHandle->mid_disp = cm.x-endHandle->end_curve.x; + curveData_t curveData; + PlotCurve(crvCmdFromCenter,pos0,endHandle->end_center, endHandle->end_curve, &curveData, FALSE); + if (curveData.type == curveTypeStraight) { + coOrd pos_line[2]; + Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2); + Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2); + Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + pos_line[0]= pos0; + Translate(&pos_line[1],pos0,-FindAngle(pos0,endHandle->end_curve),end_length); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = drawColorRed; + num++; + } else { + DIST_T pos_rad; + pos_rad = radius+trackGauge/2; + sp[num].type = SEG_CRVLIN; + sp[num].width = w; + sp[num].u.c.center = centert; + sp[num].u.c.radius = pos_rad; + ANGLE_T an0 = FindAngle(centert,pos0); + ANGLE_T an1 = FindAngle(centert,endHandle->end_curve); + if (DifferenceBetweenAngles(an0,an1)>0) { + sp[num].u.c.a1 = DifferenceBetweenAngles(an0,an1); + sp[num].u.c.a0 = an0; + } else { + sp[num].u.c.a1 = -DifferenceBetweenAngles(an0,an1); + sp[num].u.c.a0 = an1; + } + endHandle->arc_angle = sp[num].u.c.a1; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + pos_rad = radius-trackGauge/2; + sp[num].type = SEG_CRVLIN; + sp[num].width = w; + sp[num].u.c.center = centert; + sp[num].u.c.radius = pos_rad; + sp[num].u.c.a1 = sp[num-1].u.c.a1; + sp[num].u.c.a0 = sp[num-1].u.c.a0; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + } + } else { + coOrd pos_line[2]; + Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2); + Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2); + Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed; + num++; + + } + coOrd pos_line[2]; + pos_line[0]= pos0; + Translate(&pos_line[1],pos0,angle+180,end_length); + sp[num].type = SEG_STRLIN; + sp[num].width = w; + sp[num].u.l.pos[0] = pos_line[0]; + sp[num].u.l.pos[1] = pos_line[1]; + sp[num].color = drawColorRed; + num++; + sp[num].type = SEG_CRVLIN; + sp[num].u.c.center = endHandle->end_curve; + sp[num].u.c.a0 = 0.0; + sp[num].u.c.a1 = 360.0; + sp[num].width = w; + sp[num].u.c.radius = d/4; + sp[num].color = endHandle->angle_selected?drawColorBlue:drawColorRed; + num++; + if (radius<=0.0) + DrawArrowHeads(&sp[num],endHandle->end_center,angle+90.0,TRUE,endHandle->radius_selected?drawColorBlue:drawColorRed); + else + DrawArrowHeads(&sp[num],endHandle->end_center,FindAngle(centert,endHandle->end_center),TRUE,endHandle->radius_selected?drawColorBlue:drawColorRed); + num=num+5; + } else if (endHandle) { + endHandle->end_valid=FALSE; } - return 1; + return num; +} + +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) + +static void CreateCornuEndAnchor(coOrd p, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; + +} + +static void CreateCornuExtendAnchor(coOrd p, ANGLE_T a, wBool_t selected) { + DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),p,a,FALSE,wDrawColorBlue); } +static void CreateCornuAnchor(coOrd p, wBool_t open) { + DIST_T d = tempD.scale*0.15; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = open?SEG_CRVLIN:SEG_FILCRCL; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; +} /* * Add element to DYNARR pointed to by caller from segment handed in @@ -182,7 +513,6 @@ int createEndPoint( void addSegCornu(dynArr_t * const array_p, trkSeg_p seg) { trkSeg_p s; - DYNARR_APPEND(trkSeg_t, * array_p, 10); //Adds 1 to cnt s = &DYNARR_N(trkSeg_t,* array_p,array_p->cnt-1); s->type = seg->type; @@ -206,20 +536,105 @@ void addSegCornu(dynArr_t * const array_p, trkSeg_p seg) { s->u = seg->u; } } -EXPORT void SetKnots(spiro_cp knots[6], coOrd posk[6]) { - for (int i = 0; i < 6; i++) { +EXPORT void SetKnots(spiro_cp knots[], coOrd posk[], char type[], int count) { + for (int i = 0; i < count; i++) { knots[i].x = posk[i].x; knots[i].y = posk[i].y; + knots[i].ty = type[i]; + } +} + +typedef struct { + coOrd pos; + char ty; +} points_t; + +// Take in extra points within Cornu +// G2 (position only k1'' = k2'' = 0); Also Cornu <-> Cornu +// G4 (position only - splitable for Cornu - a G4 point) k1''= k2'' + +BOOL_T CallCornuM(dynArr_t extra_points, BOOL_T end[2], coOrd pos[2], cornuParm_t * cp, dynArr_t * array_p, BOOL_T spots) { + array_p->cnt = 0; + //Create LH knots + //Find remote end point of track, create start knot + int ends[2]; + ends[0] = (end[0]?2:0); ends[1] = (end[0]?3:1)+extra_points.cnt; + spiro_cp * knots; + coOrd * posk; + char * type; + posk = MyMalloc((6+extra_points.cnt)*sizeof(coOrd)); + knots = MyMalloc((6+extra_points.cnt)*sizeof(spiro_cp)); + type = MyMalloc((6+extra_points.cnt)*sizeof(char)); + BOOL_T back; + ANGLE_T angle1; + + if (Da.bezc) free(Da.bezc); + + Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots,tempD.scale*0.15/4); + + coOrd pos0 = pos[0]; + + if (end[0]) { + type[0] = SPIRO_OPEN_CONTOUR; + type[1] = SPIRO_G2; + type[2] = SPIRO_RIGHT; + if (cp->radius[0] == 0.0) { + Translate(&posk[0],pos0,cp->angle[0],10); + Translate(&posk[1],pos0,cp->angle[0],5); + } else { + angle1 = FindAngle(cp->center[0],pos[0]); + if (NormalizeAngle(angle1 - cp->angle[0])<180) back = TRUE; + else back = FALSE; + posk[0] = pos[0]; + Rotate(&posk[0],cp->center[0],(back)?-10:10); + posk[1] = pos[0]; + Rotate(&posk[1],cp->center[0],(back)?-5:5); + } + posk[2] = pos[0]; + } else { + type[0] = SPIRO_OPEN_CONTOUR; + posk[0] = pos[0]; + } + + for (int i=0;iradius[1] == 0.0) { + Translate(&posk[(end[0]?3:1)+extra_points.cnt+1],pos1,cp->angle[1],5); + Translate(&posk[(end[0]?3:1)+extra_points.cnt+2],pos1,cp->angle[1],10); + } else { + angle1 = FindAngle(cp->center[1],pos[1]); + if (NormalizeAngle(angle1 - cp->angle[1])>180) back = TRUE; + else back = FALSE; + posk[(end[0]?3:1)+extra_points.cnt+1] = pos[1]; + Rotate(&posk[(end[0]?3:1)+extra_points.cnt+1],cp->center[1],(back)?5:-5); + posk[(end[0]?3:1)+extra_points.cnt+2] = pos[1]; + Rotate(&posk[(end[0]?3:1)+extra_points.cnt+2],cp->center[1],(back)?10:-10); + } + } else { + type[(end[0]?3:1)+extra_points.cnt] = SPIRO_END_OPEN_CONTOUR; } - knots[0].ty = SPIRO_OPEN_CONTOUR; - knots[1].ty = SPIRO_G2; - knots[2].ty = SPIRO_RIGHT; - knots[3].ty = SPIRO_LEFT; - knots[4].ty = SPIRO_G2; - knots[5].ty = SPIRO_END_OPEN_CONTOUR; + SetKnots(knots, posk, type, ((end[0]?3:1)+(end[1]?3:1)+extra_points.cnt)); + TaggedSpiroCPsToBezier(knots,Da.bezc); + MyFree(posk); + MyFree(knots); + MyFree(type); + if (!bezctx_xtrkcad_close(Da.bezc)) { + return FALSE; + } + return TRUE; } -BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p, BOOL_T spots) { +EXPORT BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p, BOOL_T spots) { array_p->cnt = 0; //Create LH knots //Find remote end point of track, create start knot @@ -227,14 +642,17 @@ BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius ends[0] = 2; ends[1] = 3; spiro_cp knots[6]; coOrd posk[6]; + char type[6]; BOOL_T back; ANGLE_T angle1; if (Da.bezc) free(Da.bezc); - Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots); + Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots,tempD.scale*0.15/4); coOrd pos0 = pos[0]; + type[0] = SPIRO_OPEN_CONTOUR; + if (radius[0] == 0.0) { Translate(&posk[0],pos0,angle[0],10); @@ -248,9 +666,12 @@ BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius posk[1] = pos[0]; Rotate(&posk[1],center[0],(back)?-5:5); } + type[1] = SPIRO_G2; posk[2] = pos[0]; + type[2] = SPIRO_RIGHT; posk[3] = pos[1]; + type[3] = SPIRO_LEFT; coOrd pos1 = pos[1]; @@ -266,7 +687,10 @@ BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius posk[5] = pos[1]; Rotate(&posk[5],center[1],(back)?10:-10); } - SetKnots(knots,posk); + type[4] = SPIRO_G2; + type[5] = SPIRO_END_OPEN_CONTOUR; + + SetKnots(knots, posk, type, 6); TaggedSpiroCPsToBezier(knots,Da.bezc); if (!bezctx_xtrkcad_close(Da.bezc)) { return FALSE; @@ -290,19 +714,19 @@ BOOL_T CallCornu(coOrd pos[2], track_p trk[2], EPINX_T ep[2], dynArr_t * array_p if (Da.circleorHelix[i]) { //Helix/Circle only cp->radius[i] = params.arcR; cp->center[i] = params.arcP; - cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); + if (ep && ep[i]>=0) cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); } else if (params.type == curveTypeStraight) { cp->angle[i] = NormalizeAngle(angle+180); //Because end always backwards cp->radius[i] = 0.0; } else if ((params.type == curveTypeCornu || params.type == curveTypeBezier) && params.arcR == 0.0 ) { cp->radius[i] = 0.0; - cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); //Use point not end + if (ep && ep[i]>=0) cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); //Use point not end } else if (params.type == curveTypeCurve) { - cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); + if (ep && ep[i]>=0) cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); cp->radius[i] = params.arcR; cp->center[i] = params.arcP; } else if ((params.type == curveTypeCornu || params.type == curveTypeBezier) && params.arcR != 0.0 ){ - cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); + if (ep && ep[i]>=0) cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); cp->radius[i] = params.arcR; cp->center[i] = params.arcP; } else { @@ -317,6 +741,7 @@ BOOL_T CallCornu(coOrd pos[2], track_p trk[2], EPINX_T ep[2], dynArr_t * array_p } + /* * Draw Cornu while editing it. It consists of up to five elements - the ends, the curve and one or two End Points. * @@ -333,30 +758,26 @@ EXPORT void DrawCornuCurve( trkSeg_p second_trk, trkSeg_p extend1_trk, trkSeg_p extend2_trk, + trkSeg_p mids, + int midSegs_cnt, wDrawColor color ) { - long oldDrawOptions = tempD.funcs->options; - tempD.funcs->options = wDrawOptTemp; - long oldOptions = tempD.options; - tempD.options = DC_TICKS; - tempD.orig = mainD.orig; - tempD.angle = mainD.angle; if (first_trk) DrawSegs( &tempD, zero, 0.0, first_trk, 1, Da.trackGauge, drawColorBlack ); - if (crvSegs_cnt && curveSegs) + if (crvSegs_cnt>0 && curveSegs) DrawSegs( &tempD, zero, 0.0, curveSegs, crvSegs_cnt, Da.trackGauge, color ); if (second_trk) DrawSegs( &tempD, zero, 0.0, second_trk, 1, Da.trackGauge, drawColorBlack ); - if (ep1Segs_cnt && point1) + if (ep1Segs_cnt>0 && point1) DrawSegs( &tempD, zero, 0.0, point1, ep1Segs_cnt, Da.trackGauge, drawColorBlack ); - if (ep2Segs_cnt && point2) + if (ep2Segs_cnt>0 && point2) DrawSegs( &tempD, zero, 0.0, point2, ep2Segs_cnt, Da.trackGauge, drawColorBlack ); + if (midSegs_cnt>0 && mids) + DrawSegs( &tempD, zero, 0.0, mids, midSegs_cnt, Da.trackGauge, drawColorBlack ); if (extend1_trk) DrawSegs( &tempD, zero, 0.0, extend1_trk, 1, Da.trackGauge, drawColorBlack); if (extend2_trk) DrawSegs( &tempD, zero, 0.0, extend2_trk, 1, Da.trackGauge, drawColorBlack); - tempD.funcs->options = oldDrawOptions; - tempD.options = oldOptions; } @@ -373,35 +794,53 @@ void DrawTempCornu() { &Da.trk2Seg, Da.extend[0]?&Da.extendSeg[0]:NULL, Da.extend[1]?&Da.extendSeg[1]:NULL, - Da.minRadius<(GetLayoutMinTrackRadius()-EPSILON)?drawColorRed:drawColorBlack); + (trkSeg_t *)Da.midSegs.ptr,Da.midSegs.cnt, + fabs(Da.minRadius)<(GetLayoutMinTrackRadius()-EPSILON)?exceptionColor:normalColor); } -void CreateBothEnds(int selectPoint) { +void CreateBothEnds(int selectEndPoint, int selectMidPoint, int selectEndHandle, int lastSelected ) { BOOL_T selectable[2],modifyable[2]; selectable[0] = !Da.trk[0] || ( Da.trk[0] && !QueryTrack(Da.trk[0],Q_IS_CORNU) && !QueryTrack(Da.trk[0],Q_CAN_MODIFY_CONTROL_POINTS)); modifyable[0] = !Da.trk[0] || ( Da.trk[0] && QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY)); selectable[1] = !Da.trk[1] || ( - Da.trk[1] && !QueryTrack(Da.trk[1],Q_IS_CORNU) && !QueryTrack(Da.trk[0],Q_CAN_MODIFY_CONTROL_POINTS)); + Da.trk[1] && !QueryTrack(Da.trk[1],Q_IS_CORNU) && !QueryTrack(Da.trk[1],Q_CAN_MODIFY_CONTROL_POINTS)); modifyable[1] = !Da.trk[1] || ( Da.trk[1] && QueryTrack(Da.trk[1],Q_CORNU_CAN_MODIFY)); - if (selectPoint == -1) { - Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,selectable[0],modifyable[0]); - Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],FALSE,selectable[1],modifyable[1]); - } else if (selectPoint == 0 || selectPoint == 1) { - Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],selectPoint == 0,selectable[0],modifyable[0]); - Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],selectPoint == 1,selectable[1],modifyable[1]); + + Da.endHandle[0].angle_selected = (selectEndHandle==1)?TRUE:FALSE; + Da.endHandle[0].radius_selected = (selectEndHandle==0)?TRUE:FALSE; + Da.endHandle[1].angle_selected = (selectEndHandle==3)?TRUE:FALSE; + Da.endHandle[1].radius_selected = (selectEndHandle==2)?TRUE:FALSE; + Da.endHandle[0].last_selected = lastSelected==0?TRUE:FALSE; + Da.endHandle[1].last_selected = lastSelected==1?TRUE:FALSE; + if (selectEndPoint == -1) { + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,selectable[0],modifyable[0],Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],Da.extend[0]?NULL:&Da.endHandle[0]); + Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],FALSE,selectable[1],modifyable[1],Da.trk[1]!=NULL,Da.angle[1],Da.radius[1],Da.center[1],Da.extend[1]?NULL:&Da.endHandle[1]); } else { - Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,selectable[0],modifyable[0]); - Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],FALSE,selectable[1],modifyable[1]); + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],selectEndPoint == 0,selectable[0],modifyable[0],Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],Da.extend[0]?NULL:&Da.endHandle[0]); + Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],selectEndPoint == 1,selectable[1],modifyable[1],Da.trk[1]!=NULL,Da.angle[1],Da.radius[1],Da.center[1],Da.extend[1]?NULL:&Da.endHandle[1]); } + Da.endHandle[0].end_valid = !Da.extend[0]; + Da.endHandle[1].end_valid = !Da.extend[1]; + DYNARR_RESET(trkSeg_t,Da.midSegs); + for (int i=0;i=0.0) Da.ends[0] = TRUE; + else Da.ends[0] = FALSE; + if (Da.radius[1] >=0.0) Da.ends[1] = TRUE; + else Da.ends[1] = FALSE; } -BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track_end) { +BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track_end, wBool_t extend) { trackParams_t trackParams; - if (!GetTrackParams(PARAMS_CORNU, t, pos, &trackParams)) return FALSE; + coOrd pos1; + if ((track_end>=0) && extend) pos1 = GetTrkEndPos(t,track_end); + else pos1 = pos; + if (!GetTrackParams(PARAMS_CORNU, t, pos1, &trackParams)) return FALSE; Da.radius[end] = 0.0; Da.center[end] = zero; Da.circleorHelix[end] = FALSE; @@ -415,7 +854,8 @@ BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track Da.circleorHelix[end] = TRUE; Da.angle[end] = trackParams.track_angle; //For Now } else { - Da.angle[end] = NormalizeAngle(trackParams.track_angle + (track_end?180:0)); + Da.angle[end] = NormalizeAngle(GetTrkEndAngle(t,track_end)+180); + //Da.angle[end] = NormalizeAngle(trackParams.track_angle + (track_end?180:0)); } } else if (trackParams.type == curveTypeBezier) { Da.angle[end] = NormalizeAngle(trackParams.track_angle+(track_end?180:0)); @@ -430,12 +870,12 @@ BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track } } else if (trackParams.type == curveTypeCornu) { int ep = trackParams.ep; - Da.angle[end] = NormalizeAngle(trackParams.cornuAngle[ep]+(track_end?180:0)); + Da.angle[end] = NormalizeAngle(trackParams.cornuAngle[ep]+180); Da.radius[end] = trackParams.cornuRadius[ep]; Da.pos[end] = trackParams.cornuEnd[ep]; Da.center[end] = trackParams.cornuCenter[ep]; } else if (trackParams.type == curveTypeStraight) { - if (Da.ep[end]>=0) + if (trackParams.ep>=0) Da.angle[end] = NormalizeAngle(GetTrkEndAngle(t,track_end)+180); //Ignore params.angle because it gives from nearest end else { Da.angle[end] = NormalizeAngle(trackParams.angle+180); //Turntable @@ -483,11 +923,106 @@ void SetUpCornuParms(cornuParm_t * cp) { cp->radius[1] = Da.radius[1]; } +track_p CreateCornuFromPoints(coOrd pos[2],BOOL_T track_end[2]) { + coOrd center[2]; + DIST_T radius[2]; + ANGLE_T angle[2]; + BOOL_T back, neg; + cornuParm_t new; + int inx,subinx; + coOrd pos_temp[2]; + + for (int i=0;i<2;i++) { + pos_temp[i] = pos[i]; + + if (!track_end[i] || (Da.radius[i]==-1.0)) { + + angle[i] = GetAngleSegs(Da.crvSegs_da.cnt,(trkSeg_t *)(Da.crvSegs_da.ptr),&pos_temp[i],&inx,NULL,&back,&subinx,&neg); + + trkSeg_p segPtr = &DYNARR_N(trkSeg_t, Da.crvSegs_da, inx); + + if (segPtr->type == SEG_BEZTRK) + segPtr = &DYNARR_N(trkSeg_t, segPtr->bezSegs, subinx); + + if (i==0) { + if (neg==back) angle[i] = NormalizeAngle(angle[i]+180); + } else { + if (!(neg==back)) angle[i] = NormalizeAngle(angle[i]+180); + } + + if (segPtr->type == SEG_STRTRK) { + radius[i] = 0.0; + center[i] = zero; + } else if (segPtr->type == SEG_CRVTRK) { + center[i] = segPtr->u.c.center; + radius[i] = fabs(segPtr->u.c.radius); + } + } else { + pos[i] = Da.pos[i]; + radius[i] = Da.radius[i]; + center[i] = Da.center[i]; + angle[i] = Da.angle[i]; + neg = FALSE; + back = FALSE; + } + } + new.pos[0] = pos[0]; + new.pos[1] = pos[1]; + new.angle[0] = angle[0]; + new.angle[1] = angle[1]; + new.center[0] = center[0]; + new.center[1] = center[1]; + new.radius[0] = radius[0]; + new.radius[1] = radius[1]; + + track_p trk1 = NewCornuTrack(new.pos,new.center,new.angle,new.radius,NULL,0); + if (trk1==NULL) { + wBeep(); + InfoMessage(_("Cornu Create Failed for p1[%0.3f,%0.3f] p2[%0.3f,%0.3f], c1[%0.3f,%0.3f] c2[%0.3f,%0.3f], a1=%0.3f a2=%0.3f, r1=%s r2=%s"), + new.pos[0].x,new.pos[0].y, + new.pos[1].x,new.pos[1].y, + new.center[0].x,new.center[0].y, + new.center[1].x,new.center[1].y, + new.angle[0],new.angle[1], + FormatDistance(new.radius[0]),FormatDistance(new.radius[1])); + UndoEnd(); + return NULL; + } + return trk1; +} + struct extraData { cornuData_t cornuData; }; +ANGLE_T GetOpenAngle(coOrd pos[2],ANGLE_T angle[2],int moved) { + ANGLE_T a = FindAngle(pos[1-moved],pos[moved]); + ANGLE_T diff = (180+a)-angle[1-moved]; //Difference between input and line + return a+diff; //Change to line plus this at the other end +} + +static struct { + ANGLE_T angle; + DIST_T radius; + +} cornuModCmdContext; + +static BOOL_T infoSubst = FALSE; + +static paramFloatRange_t r10000_10000 = {-10000, 10000}; +static paramFloatRange_t r0_360 = { 0, 360, 80 }; + +static paramData_t cornuModPLs[] = { + +#define cornuModEndAnglePD (cornuModPLs[0]) +#define cornuModEndAngle 0 + { PD_FLOAT, &cornuModCmdContext.angle, "End Angle", PDO_NORECORD|BO_ENTER, &r0_360, N_("End Angle") }, +#define cornuModEndRadiusPD (cornuModPLs[1]) +#define cornuModEndRadius 1 + { PD_FLOAT, &cornuModCmdContext.radius, "End Radius", PDO_DIM|PDO_NORECORD|BO_ENTER, &r10000_10000, N_("End Radius") }, +}; +static paramGroup_t cornuModPG = { "cornuMod", 0, cornuModPLs, sizeof cornuModPLs/sizeof cornuModPLs[0] }; /* * AdjustCornuCurve @@ -509,221 +1044,535 @@ EXPORT STATUS_T AdjustCornuCurve( track_p t; DIST_T d; ANGLE_T a, a2; - DIST_T dd; EPINX_T ep; cornuParm_t cp; + wControl_p controls[5]; //Always needs a NULL last entry + char * labels[4]; + + Da.cmdType = (long)commandContext; + if (Da.state != PICK_POINT && Da.state != POINT_PICKED && Da.state != TRACK_SELECTED) return C_CONTINUE; switch ( action & 0xFF) { case C_START: - Da.selectPoint = -1; - Da.extend[0] = FALSE; - Da.extend[1] = FALSE; - CreateBothEnds(Da.selectPoint); - Da.crvSegs_da.cnt = 0; - SetUpCornuParms(&cp); - if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; - else Da.crvSegs_da_cnt = 0; - Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); - InfoMessage( _("Select End-Point") ); - DrawTempCornu(); - return C_CONTINUE; + DYNARR_RESET(trkSeg_t,anchors_da); + infoSubst = FALSE; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + Da.selectEndHandle = -1; + Da.prevSelected = -1; + Da.prevEndPoint = -1; + Da.extend[0] = FALSE; + Da.extend[1] = FALSE; + CreateBothEnds(Da.selectEndPoint, Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + Da.crvSegs_da.cnt = 0; + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); + InfoMessage( _("Select Point, or Add Point") ); + TempRedraw(); // AdjustCornuCurve C_START + return C_CONTINUE; + + case C_UPDATE: + if (Da.state != PICK_POINT && Da.prevSelected>-1) return C_CONTINUE; + int sel = Da.prevSelected; + if (Da.trk[sel]) return C_CONTINUE; //Track Here - should never happen + Da.radius[sel] = fabs(cornuModCmdContext.radius); + Da.angle[sel] = cornuModCmdContext.angle; + if (cornuModCmdContext.radius!=0) + Translate(&Da.center[sel],Da.pos[sel],Da.angle[sel]+90,cornuModCmdContext.radius); + CreateBothEnds(Da.prevSelected,-1,-1,Da.prevSelected); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); + return C_CONTINUE; + break; + + case wActionMove: + if (Da.state == NONE || Da.state == PICK_POINT) { + DYNARR_RESET(trkSeg_t,anchors_da); + for(int i=0;i<2;i++) { + if (IsClose(FindDistance(pos,Da.pos[i]))) { + if (((MyGetKeyState() & WKEY_SHIFT) != 0) && Da.selectTrack) { + CreateCornuExtendAnchor(Da.pos[i], Da.angle[i], FALSE); + return C_CONTINUE; + } else { + CreateCornuAnchor(Da.pos[i], FALSE); + return C_CONTINUE; + } + } + } + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + Da.selectEndPoint = -1; + for (int i=0;i Extend + Da.extend[Da.selectEndPoint] = TRUE; //Adding to end Point + DYNARR_RESET(trkSeg_t,anchors_da); + CreateCornuExtendAnchor(Da.pos[Da.selectEndPoint], Da.angle[Da.selectEndPoint], FALSE); + } + } + if (Da.selectMidPoint ==-1 && Da.selectEndPoint ==-1 && Da.selectEndHandle ==-1) { + coOrd temp_pos = pos; + wIndex_t index; + if (IsClose(DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&index))) { + //Add Point between two other points + //Find closest two points along Track + int closest = -1; + wIndex_t pIndex, nIndex; + temp_pos = Da.pos[0]; + DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&pIndex); + if (Da.mid_points.cnt>0) { + for (int i=0;i=index))) { + closest = i; + break; + } + pIndex = nIndex; + } + temp_pos = Da.pos[1]; + DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&nIndex); + if (index == nIndex) closest = Da.mid_points.cnt; + if (closest == -1) + closest = Da.mid_points.cnt; + } else closest = 0; + DYNARR_APPEND(coOrd,Da.mid_points,1); + for (int i=Da.mid_points.cnt-1;i>closest;i--) { + DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd ,Da.mid_points,i-1); + } + DYNARR_N(coOrd,Da.mid_points,closest) = pos; + Da.selectMidPoint = closest; + Da.number_of_points++; + CreateCornuAnchor(pos,FALSE); + InfoMessage("Pin Point Added"); + } else { + wBeep(); + InfoMessage("Add Point Is Not on Track"); + return C_CONTINUE; + } + } + if (Da.selectEndPoint == -1 && Da.selectMidPoint == -1 && Da.selectEndHandle ==-1) { wBeep(); - InfoMessage( _("Not close enough to end point, reselect") ); + InfoMessage( _("Not close enough to track or point, reselect") ); return C_CONTINUE; } else { - pos = Da.pos[Da.selectPoint]; + if (Da.selectEndPoint >=0 ) { + pos = Da.pos[Da.selectEndPoint]; + if (Da.extend[Da.selectEndPoint]) + InfoMessage( _("Drag out end of Cornu")); + else if (Da.trk[Da.selectEndPoint]) { + InfoMessage( _("Drag along end of track")); + } else + InfoMessage( _("Drag to move")); + } else if (Da.selectMidPoint >=0 ) { + pos = DYNARR_N(coOrd,Da.mid_points,Da.selectMidPoint); + InfoMessage( _("Drag point to new location, Delete to remove")); + } else { + if (Da.selectEndHandle%2 == 0) { + pos = Da.endHandle[Da.selectEndHandle/2].end_center; + InfoMessage( _("Drag to change end radius")); + } else { + pos = Da.endHandle[Da.selectEndHandle/2].end_curve; + InfoMessage( _("Drag to change end angle")); + } + } Da.state = POINT_PICKED; - InfoMessage( _("Drag point %d to new location and release it"),Da.selectPoint+1 ); } - DrawTempCornu(); //wipe out - CreateBothEnds(Da.selectPoint); + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); SetUpCornuParms(&cp); - if (CallCornu(Da.pos, Da.trk,Da.ep, &Da.crvSegs_da, &cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; else Da.crvSegs_da_cnt = 0; Da.minRadius = CornuMinRadius(Da.pos, Da.crvSegs_da); - DrawTempCornu(); return C_CONTINUE; case C_MOVE: + DYNARR_RESET(trkSeg_t,anchors_da); if (Da.state != POINT_PICKED) { - InfoMessage(_("Pick any circle to adjust it by dragging - Enter to accept, Esc to cancel")); + InfoMessage(_("Pick any circle to adjust or add - Enter to accept, Esc to cancel")); return C_CONTINUE; } - //If locked, reset pos to be on line from other track - int sel = Da.selectPoint; - coOrd pos2 = pos; - BOOL_T inside = FALSE; - if (Da.trk[sel]) { //There is a track - if (OnTrack(&pos,FALSE,TRUE) == Da.trk[sel]) { //And the pos is on it - inside = TRUE; - if (!QueryTrack(Da.trk[Da.selectPoint],Q_CORNU_CAN_MODIFY)) { //Turnouts - InfoMessage(_("Track can't be split")); - if (Da.ep[sel]>=0) //Ignore if turntable - pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + if (Da.selectEndPoint >= 0) { + //If locked, reset pos to be on line from other track + int sel = Da.selectEndPoint; + coOrd pos2 = pos; + BOOL_T inside = FALSE; + if (Da.trk[sel]) { //Track + if (OnTrack(&pos,FALSE,TRUE) == Da.trk[sel]) { //And the pos is on it + inside = TRUE; + if (!QueryTrack(Da.trk[Da.selectEndPoint],Q_CORNU_CAN_MODIFY)) { //Turnouts + InfoMessage(_("Track can't be split")); + inside = FALSE; + if (Da.ep[sel]>=0) { //If not turntable + Da.pos[sel] = pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + } else { + if (QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)){ //Turntable + trackParams_t tp; + if (!GetTrackParams(PARAMS_CORNU, Da.trk[sel], pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + Translate(&pos,tp.ttcenter,a,tp.ttradius); + Da.angle[sel] = NormalizeAngle(a+180); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + } else return C_CONTINUE; + } + } + } else { + pos = pos2; //Put Back to original position as outside track } - } else { - pos = pos2; //Put Back to original position as outside track - } - // Stop the user extending right through the other track - if (Da.ep[sel]>=0 && QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY)) { //For non-turnouts - if ((!QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)) // But Not Helix or Circle - && (!QueryTrack(Da.trk[sel],Q_HAS_VARIABLE_ENDPOINTS))) { // Not a Turntable - DIST_T ab = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),GetTrkEndPos(Da.trk[sel],1-Da.ep[sel])); - DIST_T ac = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),pos); - DIST_T cb = FindDistance(GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]), pos); - if (cb=0) { //Track defined end point + ANGLE_T diff = NormalizeAngle(GetTrkEndAngle(Da.trk[sel],Da.ep[sel])-FindAngle(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),pos)); + if (diff>90.0 && diff<270.0) { //The point is not on track but outside cone of end angle+/-90 + Da.pos[sel] = pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + return C_CONTINUE; + } + } else { //Not an end point + if (QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)){ //Turntable + trackParams_t tp; + if (!GetTrackParams(PARAMS_CORNU, Da.trk[sel], pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + coOrd edge; + Translate(&edge,tp.ttcenter,a,tp.ttradius); + ANGLE_T da = DifferenceBetweenAngles(FindAngle(edge,pos),a); + DIST_T d = fabs(FindDistance(edge,pos)*cos(R2D(da))); + Translate(&pos,edge,a,d); + Da.angle[sel] = NormalizeAngle(a+180); + Da.pos[sel] = pos; + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + Da.extendSeg[sel].type = SEG_STRTRK; + Da.extendSeg[sel].width = 0; + Da.extendSeg[sel].color = wDrawColorBlack; + Da.extendSeg[sel].u.l.pos[1-sel] = pos; + Da.extendSeg[sel].u.l.pos[sel] = edge; + Da.extend[sel] = TRUE; + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + return C_CONTINUE; //Stop moving end point + } else return C_CONTINUE; + } } - if ((ac>=cb) && (ac>=ab)) { //Closer to far end and as long as the track - pos = GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]); //Make other end of track + // Stop the user extending right through the other track + if (Da.ep[sel]>=0 && QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY)) { //For non-turnouts + if ((!QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)) // Not Turntable - may not be needed + && (!QueryTrack(Da.trk[sel],Q_HAS_VARIABLE_ENDPOINTS))) { // Not Helix or a Circle + DIST_T ab = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),GetTrkEndPos(Da.trk[sel],1-Da.ep[sel])); + DIST_T ac = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),pos); + DIST_T cb = FindDistance(GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]),pos); + if (cb=cb) && (ac>=ab)) { //Closer to far end and as long as the track + pos = GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]); //Make other end of track + } + } + } else if (Da.ep[sel]>=0 && inside) { //Has a point and inside track + InfoMessage(_("Can't move end inside a turnout")); //Turnouts are stuck to end-point + Da.pos[sel] = pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); + return C_CONTINUE; } } - } - } - DrawTempCornu(); //wipe out old - Da.extend[sel] = FALSE; - if(!Da.trk[sel]) { //Cornu with no ends - struct extraData *xx = GetTrkExtraData(Da.selectTrack); - Da.pos[sel] = xx->cornuData.pos[sel]; //Re-Copy parms from old trk - Da.radius[sel] = xx->cornuData.r[sel]; - Da.angle[sel] = xx->cornuData.a[sel]; - Da.center[sel] = xx->cornuData.c[sel]; - if (Da.radius[sel] == 0) { //Straight - Da.extendSeg[sel].type = SEG_STRTRK; - Da.extendSeg[sel].width = 0; - Da.extendSeg[sel].color = wDrawColorBlack; - Da.extendSeg[sel].u.l.pos[1-sel] = Da.pos[sel]; - d = FindDistance( Da.extendSeg[sel].u.l.pos[1-sel], pos ); - a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel])); - if (cos(D2R(a))<=0) { - Translate( &Da.extendSeg[sel].u.l.pos[sel], - Da.extendSeg[sel].u.l.pos[1-sel], - Da.angle[sel], - d * cos(D2R(a))); - pos = Da.extendSeg[sel].u.l.pos[1-sel]; - Da.extend[sel] = TRUE; - } - } else { //Curve - Da.extendSeg[sel].type = SEG_CRVTRK; - Da.extendSeg[sel].width = 0; - Da.extendSeg[sel].color = wDrawColorBlack; - Da.extendSeg[sel].u.c.center = Da.center[sel]; - Da.extendSeg[sel].u.c.radius = Da.radius[sel]; - a = FindAngle( Da.center[sel], pos ); - PointOnCircle( &pos, Da.center[sel], Da.radius[sel], a ); - a2 = FindAngle(Da.center[sel],Da.pos[sel]); - if (((Da.angle[sel] < 180) && (a2>90 && a2<270)) || - ((Da.angle[sel] > 180) && (a2<90 || a2>270))) { - Da.extendSeg[sel].u.c.a0 = a; - Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a); + if(!Da.trk[sel]) { //Cornu with no end + if (((MyGetKeyState() & WKEY_SHIFT) != 0) && Da.selectTrack) { //Extend end locked + SetUpCornuParms(&cp); + CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,FALSE); + struct extraData *xx = GetTrkExtraData(Da.selectTrack); + if (Da.radius[sel] == 0) { //Straight + Da.extendSeg[sel].type = SEG_STRTRK; + Da.extendSeg[sel].width = 0; + Da.extendSeg[sel].color = wDrawColorBlack; + Da.extendSeg[sel].u.l.pos[1-sel] = Da.pos[sel]; + d = FindDistance( Da.extendSeg[sel].u.l.pos[1-sel], pos ); + a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel])); + if (cos(D2R(a))<=0) { + Translate( &Da.extendSeg[sel].u.l.pos[sel], + Da.extendSeg[sel].u.l.pos[1-sel], + Da.angle[sel], - d * cos(D2R(a))); + pos = Da.extendSeg[sel].u.l.pos[sel]; + Da.extend[sel] = TRUE; + } else Da.extend[sel] = FALSE; + } else { //Curve + Da.extendSeg[sel].type = SEG_CRVTRK; + Da.extendSeg[sel].width = 0; + Da.extendSeg[sel].color = wDrawColorBlack; + Da.extendSeg[sel].u.c.center = Da.center[sel]; + Da.extendSeg[sel].u.c.radius = Da.radius[sel]; + a = FindAngle( Da.center[sel], pos ); + PointOnCircle( &pos, Da.extendSeg[sel].u.c.center, Da.radius[sel], a ); + a2 = FindAngle(Da.extendSeg[sel].u.c.center,Da.pos[sel]); + if (((Da.angle[sel] < 180) && (a2>90 && a2<270)) || + ((Da.angle[sel] > 180) && (a2<90 || a2>270))) { + Da.extendSeg[sel].u.c.a0 = a; + Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a); + } else { + Da.extendSeg[sel].u.c.a0 = a2; + Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2); + } + if (Da.extendSeg[sel].u.c.a1 == 0 || Da.extendSeg[sel].u.c.a1 >180 ) + Da.extend[sel] = FALSE; + else + Da.extend[sel] = TRUE; + } } else { - Da.extendSeg[sel].u.c.a0 = a2; - Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2); - } - if (Da.extendSeg[sel].u.c.a1 == 0 || Da.extendSeg[sel].u.c.a1 >180 ) Da.extend[sel] = FALSE; - else - Da.extend[sel] = TRUE; - } - if (Da.extend[sel] == FALSE) { // Not extending - so trim along our own Cornu - GetCornuParmsNear(Da.selectTrack, sel, &pos, &Da.center[sel], &Da.angle[sel], &Da.radius[sel] ); - Da.pos[sel] = pos; - } - } else { //Cornu with ends - if (inside) Da.pos[sel] = pos; - if (!GetConnectedTrackParms(Da.trk[sel],pos,sel,Da.ep[sel])) { - DrawTempCornu(); - wBeep(); - return C_CONTINUE; //Stop drawing - } - CorrectHelixAngles(); - if (!inside) { //Extend the track - if (Da.trackType[sel] == curveTypeStraight) { //Extend with a straight - Da.extendSeg[sel].type = SEG_STRTRK; - Da.extendSeg[sel].width = 0; - Da.extendSeg[sel].color = wDrawColorBlack; - if (Da.ep[sel]>=0) { - Da.extendSeg[sel].u.l.pos[0] = GetTrkEndPos( Da.trk[sel], Da.ep[sel] ); - a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,GetTrkEndPos(Da.trk[sel],Da.ep[sel]))); - } else { //Turntable when unconnected - Da.extendSeg[sel].u.l.pos[0] = Da.pos[sel]; - a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel])); + coOrd offset; //Just move end (no shift) + offset.x = pos.x-Da.pos[sel].x; + offset.y = pos.y-Da.pos[sel].y; + Da.pos[sel] = pos; + if (Da.radius[sel] >0.0) { + Da.center[sel].x += offset.x; + Da.center[sel].y += offset.y; } - // Remove any extend in opposite direction for Turntable/Turnouts - if ((QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS) && Da.ep[sel]>=0) - && (!QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY)) - && (a>90 && a<270)) { - Da.extend[sel] = FALSE; //Turntable with point and extension is other side of well - Da.pos[sel] = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); - } else { - Da.extend[sel] = TRUE; - d = FindDistance( Da.extendSeg[sel].u.l.pos[0], pos ); - Translate( &Da.extendSeg[sel].u.l.pos[1], - Da.extendSeg[sel].u.l.pos[0], - Da.angle[sel], -d * cos(D2R(a))); - Da.pos[sel] = pos = Da.extendSeg[sel].u.l.pos[1]; + if (Da.selectTrack) { //We have track + if (!Da.trk[sel] && ((t = OnTrackIgnore(&pos,FALSE,TRUE,Da.selectTrack))!= NULL) ) { + if ((ep = PickUnconnectedEndPointSilent(pos,t))>=0) { + pos = GetTrkEndPos(t,ep); + if (IsClose(FindDistance(pos,pos)/2)) { + CreateCornuEndAnchor(pos,FALSE); + } + } + } + } else { //Not yet a track + coOrd p = pos; + Da.angle[sel] = GetOpenAngle(Da.pos,Da.angle,sel); + if ((t = OnTrack(&p,FALSE,TRUE)) !=NULL ) { + if ((ep = PickUnconnectedEndPointSilent(pos,t))>=0) { + p = GetTrkEndPos(t,ep); + if (IsClose(FindDistance(p,pos)/2)) { + CreateCornuEndAnchor(p,FALSE); + } + } + } } - } else if (Da.trackType[sel] == curveTypeCurve) { //Extend with temp curve - Da.extendSeg[sel].type = SEG_CRVTRK; - Da.extendSeg[sel].width = 0; - Da.extendSeg[sel].color = wDrawColorBlack; - Da.extendSeg[sel].u.c.center = Da.center[sel]; - Da.extendSeg[sel].u.c.radius = Da.radius[sel]; - a = FindAngle( Da.center[sel], pos ); - PointOnCircle( &pos, Da.center[sel], Da.radius[sel], a ); - a2 = FindAngle(Da.center[sel],GetTrkEndPos(Da.trk[sel],Da.ep[sel])); - if ((Da.angle[sel] < 180 && (a2>90 && a2 <270)) || - (Da.angle[sel] > 180 && (a2<90 || a2 >270))) { - Da.extendSeg[sel].u.c.a0 = a2; - Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2); - } else { - Da.extendSeg[sel].u.c.a0 = a; - Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a); + } + } else { //Cornu with ends + if (inside) Da.pos[sel] = pos; + if (!GetConnectedTrackParms(Da.trk[sel],pos,sel,Da.ep[sel],inside?FALSE:TRUE)) { + wBeep(); + return C_CONTINUE; //Stop drawing + } + CorrectHelixAngles(); + if (!inside) { //Extend the track + if (Da.trackType[sel] == curveTypeStraight) { //Extend with a straight + Da.extendSeg[sel].type = SEG_STRTRK; + Da.extendSeg[sel].width = 0; + Da.extendSeg[sel].color = wDrawColorBlack; + if (Da.ep[sel]>=0) { + Da.extendSeg[sel].u.l.pos[0] = GetTrkEndPos( Da.trk[sel], Da.ep[sel] ); + a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,GetTrkEndPos(Da.trk[sel],Da.ep[sel]))); + } else { //Turntable when unconnected + Da.extendSeg[sel].u.l.pos[0] = Da.pos[sel]; + a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel])); + } + // Remove any extend in opposite direction for Turntable/Turnouts + if ((QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS) && Da.ep[sel]>=0) + && (!QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY)) + && (a>90 && a<270)) { + Da.extend[sel] = FALSE; //Turntable with point and extension is other side of well + Da.pos[sel] = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + } else { + Da.extend[sel] = TRUE; + d = FindDistance( Da.extendSeg[sel].u.l.pos[0], pos ); + Translate( &Da.extendSeg[sel].u.l.pos[1], + Da.extendSeg[sel].u.l.pos[0], + Da.angle[sel], -d * cos(D2R(a))); + Da.pos[sel] = pos = Da.extendSeg[sel].u.l.pos[1]; + } + } else if (Da.trackType[sel] == curveTypeCurve) { //Extend with temp curve + Da.extendSeg[sel].type = SEG_CRVTRK; + Da.extendSeg[sel].width = 0; + Da.extendSeg[sel].color = wDrawColorBlack; + Da.extendSeg[sel].u.c.center = Da.center[sel]; + Da.extendSeg[sel].u.c.radius = Da.radius[sel]; + a = FindAngle( Da.center[sel], pos ); + PointOnCircle( &pos, Da.center[sel], Da.radius[sel], a ); + a2 = FindAngle(Da.center[sel],GetTrkEndPos(Da.trk[sel],Da.ep[sel])); + if ((Da.angle[sel] < 180 && (a2>90 && a2 <270)) || + (Da.angle[sel] > 180 && (a2<90 || a2 >270))) { + Da.extendSeg[sel].u.c.a0 = a2; + Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2); + } else { + Da.extendSeg[sel].u.c.a0 = a; + Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a); + } + if (Da.extendSeg[sel].u.c.a1 == 0.0 || Da.extendSeg[sel].u.c.a1 >180 + || (Da.extendSeg[sel].u.c.a0 >= Da.arcA0[sel] && Da.extendSeg[sel].u.c.a0 < Da.arcA0[sel]+Da.arcA1[sel] + && Da.extendSeg[sel].u.c.a0 + Da.extendSeg[sel].u.c.a1 <= Da.arcA0[sel] + Da.arcA1[sel]) + ) { + Da.extend[sel] = FALSE; + Da.pos[sel] = pos; + } else { + Da.extend[sel] = TRUE; + Da.pos[sel] = pos; + } + + } else { //Bezier and Cornu that we are joining TO can't extend + wBeep(); + InfoMessage(_("Can't extend connected Bezier or Cornu")); + pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); + return C_CONTINUE; } - if (Da.extendSeg[sel].u.c.a1 == 0.0 || Da.extendSeg[sel].u.c.a1 >180 - || (Da.extendSeg[sel].u.c.a0 >= Da.arcA0[sel] && Da.extendSeg[sel].u.c.a0 < Da.arcA0[sel]+Da.arcA1[sel] - && Da.extendSeg[sel].u.c.a0 + Da.extendSeg[sel].u.c.a1 <= Da.arcA0[sel] + Da.arcA1[sel]) - ) { - Da.extend[sel] = FALSE; - Da.pos[sel] = pos; - } else { - Da.extend[sel] = TRUE; - Da.pos[sel] = pos; + } else Da.pos[sel] = pos; + } + } else if (Da.selectMidPoint >=0){ + DYNARR_N(coOrd,Da.mid_points,Da.selectMidPoint) = pos; + } else if (Da.selectEndHandle >=0) { //Cornu has no end, so has handles + int end = Da.selectEndHandle/2; + if (Da.selectEndHandle%2 == 0) { //Radius + coOrd p0 = Da.pos[end]; //Start + coOrd p1 = Da.endHandle[end].end_curve; //End + ANGLE_T a0 = FindAngle( p1, p0 ); + DIST_T d0 = FindDistance( p0, p1 )/2.0; //Distance to Middle of Chord + coOrd pos2 = pos; //New pos + Rotate( &pos2, p1, -a0 ); + pos2.x -= p1.x; //Deflection at right angles to Chord + DIST_T r = 1000.0; + if ( fabs(pos2.x) >= 0.01 ) { //Not zero + double d2 = sqrt( d0*d0 + pos2.x*pos2.x )/2.0; + r = d2*d2*2.0/pos2.x; + if ( fabs(r) > 1000.0 ) { //Limit Radius + r = 0.0; + //r = ((r > 0) ? 1 : -1 ) *1000.0; } - - } else { //Bezier and Cornu that we are joining TO can't extend - DrawTempCornu(); //put back - wBeep(); - InfoMessage(_("Can't extend connected Bezier or Cornu")); - pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]); - return C_CONTINUE; + } else { + r = 0.0; + //r = ((r > 0) ? 1 : -1 ) *1000.0; } + coOrd posx; //Middle of chord + posx.x = (p1.x-p0.x)/2.0 + p0.x; + posx.y = (p1.y-p0.y)/2.0 + p0.y; + a0 -= 90.0; + if (r<0) { //Negative radius means other side + coOrd pt = p0; + p0 = p1; + p1 = pt; + a0 += 180.0; + } + coOrd pc; + if (r == 0.0) { + Da.center[end] = zero; + Da.radius[end] = 0.0; + Da.angle[end] = FindAngle(Da.pos[end],Da.endHandle[end].end_curve); + } else { + Translate( &pc, posx, a0, fabs(r) - fabs(pos2.x) ); //Move Radius less Deflection to get to center + Da.center[end] = pc; + if (DifferenceBetweenAngles(FindAngle(Da.center[end],Da.pos[end]),FindAngle(Da.center[end],Da.endHandle[end].end_curve))>0.0) + Da.angle[end] = NormalizeAngle(FindAngle(Da.center[end],Da.pos[end])+90.0); + else + Da.angle[end] = NormalizeAngle(FindAngle(Da.center[end],Da.pos[end])-90.0); + Da.radius[end] = fabs(r); + } + } else { + Da.angle[end] = FindAngle(Da.pos[end],pos); + Da.radius[end] = 0.0; + Translate(&Da.center[end],Da.pos[end],NormalizeAngle(Da.angle[end]+90.0),Da.radius[end]); } } - - CreateBothEnds(Da.selectPoint); + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); SetUpCornuParms(&cp); //In case we want to use these because the ends are not on the track - - if (CallCornu(Da.pos, Da.trk, Da.ep, &Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; else Da.crvSegs_da_cnt = 0; + for (int i=0;i<2;i++) { + if (Da.trk[i] || Da.ends[i]) continue; + coOrd p = Da.pos[i]; + Da.angle[i] = NormalizeAngle((i?0:180)+GetAngleSegs( Da.crvSegs_da_cnt, Da.crvSegs_da.ptr, &p, NULL, NULL, NULL, NULL, NULL)); + Da.radius[i] = 0.0; + } Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); DIST_T rin = Da.radius[0]; InfoMessage( _("Cornu : Min Radius=%s MaxRateofCurveChange/Scale=%s Length=%s Winding Arc=%s"), @@ -731,25 +1580,121 @@ EXPORT STATUS_T AdjustCornuCurve( FormatFloat(CornuMaxRateofChangeofCurvature(Da.pos,Da.crvSegs_da,&rin)*GetScaleRatio(GetLayoutCurScale())), FormatDistance(CornuLength(Da.pos,Da.crvSegs_da)), FormatDistance(CornuTotalWindingArc(Da.pos,Da.crvSegs_da))); - DrawTempCornu(); return C_CONTINUE; case C_UP: - if (Da.state != POINT_PICKED) return C_CONTINUE; + DYNARR_RESET(trkSeg_t,anchors_da); + if (Da.state != POINT_PICKED) { + Da.state = PICK_POINT; + return C_CONTINUE; + } ep = 0; - DrawTempCornu(); //wipe out - Da.selectPoint = -1; - CreateBothEnds(Da.selectPoint); + if (Da.selectMidPoint!=-1) Da.prevSelected = Da.selectMidPoint; + else if (Da.selectEndPoint!=-1) { + if (!Da.trk[Da.selectEndPoint] && + (t=OnTrack(&pos,FALSE,TRUE)) != NULL && t != Da.selectTrack ) { + EPINX_T ep = PickUnconnectedEndPoint(pos,t); + if (ep>=0) { + if (QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS)) { //Circle/Helix find if there is an open slot and where + if ((GetTrkEndTrk(t,0) != NULL) && (GetTrkEndTrk(t,1) != NULL)) { + InfoMessage(_("Helix Already Connected")); + return C_CONTINUE; + } + ep = -1; //Not a real ep yet + } else ep = PickUnconnectedEndPointSilent(pos, t); //EP + if (ep>=0 && QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) { + ep=-1; //Don't attach to Turntable + trackParams_t tp; + if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + Translate(&pos,tp.ttcenter,a,tp.ttradius); + } + if ( ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle + wBeep(); + InfoMessage(_("No Valid end point on that track")); + return C_CONTINUE; + } + if (GetTrkScale(t) != (char)GetLayoutCurScale()) { + wBeep(); + InfoMessage(_("Track is different scale")); + return C_CONTINUE; + } + } + if (ep>=0 && t) { //Real end point, real track + Da.trk[Da.selectEndPoint] = t; + Da.ep[Da.selectEndPoint] = ep; // Note: -1 for Turntable or Circle + pos = GetTrkEndPos(t,ep); + Da.pos[Da.selectEndPoint] = pos; + if (!GetConnectedTrackParms(t,pos,Da.selectEndPoint,ep,FALSE)) return C_CONTINUE; + } + } else { + cornuModCmdContext.angle = NormalizeAngle(Da.angle[Da.selectEndPoint]); + cornuModCmdContext.radius = Da.radius[Da.selectEndPoint]; + if (DifferenceBetweenAngles(FindAngle(Da.center[Da.selectEndPoint],Da.pos[Da.selectEndPoint]),Da.angle[Da.selectEndPoint])<0.0) + cornuModCmdContext.radius = -cornuModCmdContext.radius; + controls[0] = cornuModEndRadiusPD.control; + controls[1] = cornuModEndAnglePD.control; + controls[2] = NULL; + labels[0] = N_("End Radius"); + labels[1] = N_("End Angle"); + ParamLoadControls( &cornuModPG ); + InfoSubstituteControls( controls, labels ); + cornuModEndRadiusPD.option &= ~PDO_NORECORD; + cornuModEndAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + Da.prevSelected = Da.selectEndPoint; + Da.selectEndHandle = -1; + } + } else if (Da.selectEndHandle!=-1) { + Da.prevSelected = Da.selectEndHandle>2?1:0; + cornuModCmdContext.angle = NormalizeAngle(Da.angle[Da.prevSelected]); + cornuModCmdContext.radius = Da.radius[Da.prevSelected]; + if (DifferenceBetweenAngles(FindAngle(Da.center[Da.prevSelected],Da.pos[Da.prevSelected]),Da.angle[Da.prevSelected])<0.0) + cornuModCmdContext.radius = -cornuModCmdContext.radius; + controls[0] = cornuModEndRadiusPD.control; + controls[1] = cornuModEndAnglePD.control; + controls[2] = NULL; + labels[0] = N_("End Radius"); + labels[1] = N_("End Angle"); + ParamLoadControls( &cornuModPG ); + InfoSubstituteControls( controls, labels ); + cornuModEndRadiusPD.option &= ~PDO_NORECORD; + cornuModEndAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + Da.selectEndHandle = -1; + } + Da.selectEndPoint = -1; Da.selectMidPoint = -1; + CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected); SetUpCornuParms(&cp); - if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; else Da.crvSegs_da_cnt = 0; Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); - InfoMessage(_("Pick on point to adjust it along track - Enter to confirm, ESC to abort")); - DrawTempCornu(); + InfoMessage(_("Pick on point to adjust it along track - Delete to remove, Enter to confirm, ESC to abort")); Da.state = PICK_POINT; return C_CONTINUE; + case C_TEXT: + DYNARR_RESET(trkSeg_t,anchors_da); + //Delete or backspace deletes last selected index + if (action>>8 == 127 || action>>8 == 8) { + if ((Da.state == PICK_POINT) && Da.prevSelected !=-1) { + for (int i=Da.prevSelected;i4*360) { @@ -762,63 +1707,109 @@ EXPORT STATUS_T AdjustCornuCurve( return C_CONTINUE; } for (int i=0;i<2;i++) { - if (!(QueryTrack(Da.trk[i],Q_CAN_ADD_ENDPOINTS))) { // Not Turntable + if (Da.trk[i] && !(QueryTrack(Da.trk[i],Q_CAN_ADD_ENDPOINTS))) { // Not Turntable if (FindDistance(Da.pos[i],GetTrkEndPos(Da.trk[i],1-Da.ep[i])) < minLength) { wBeep(); - InfoMessage(_("Cornu end %d too close to other end of connect track - reposition it"),i+1); + InfoMessage(_("Cornu point %d too close to other end of connect track - reposition it"),i+1); return C_CONTINUE; } } } - - DrawTempCornu(); - UndoStart( _("Create Cornu"),"newCornu curve"); - t = NewCornuTrack( Da.pos, Da.center, Da.angle, Da.radius,(trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt); - if (t==NULL) { - wBeep(); - InfoMessage(_("Cornu Create Failed for p1[%0.3f,%0.3f] p2[%0.3f,%0.3f], c1[%0.3f,%0.3f] c2[%0.3f,%0.3f], a1=%0.3f a2=%0.3f, r1=%s r2=%s"), - Da.pos[0].x,Da.pos[0].y, - Da.pos[1].x,Da.pos[1].y, - Da.center[0].x,Da.center[0].y, - Da.center[1].x,Da.center[1].y, - Da.angle[0],Da.angle[1], - FormatDistance(Da.radius[0]),FormatDistance(Da.radius[1])); - return C_TERMINATE; + UndoStart( _("Create Cornu"),"newCornu curves"); + BOOL_T end_point[2]; + end_point[0] = TRUE; + end_point[1] = FALSE; + coOrd sub_pos[2]; + sub_pos[0] = Da.pos[0]; + if (Da.radius[0] == -1) end_point[0] = FALSE; + track_p first_trk= NULL,trk1=NULL,trk2 = NULL; + + for (int i=0;i=0) + ConnectTracks(Da.trk[i],Da.ep[i],i==0?first_trk:trk1,i); } - if (Da.ep[i]>=0) - ConnectTracks(Da.trk[i],Da.ep[i],t,i); } UndoEnd(); - DrawNewTrack(t); + if (infoSubst) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } Da.state = NONE; - MainRedraw(); - MapRedraw(); return C_TERMINATE; } return C_CONTINUE; case C_REDRAW: + if (Da.state == NONE) return C_CONTINUE; DrawTempCornu(); + if (anchors_da.cnt) { + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + } return C_CONTINUE; + case C_CANCEL: + case C_FINISH: + break; default: return C_CONTINUE; } + return C_CONTINUE; } +static void cornuModDlgUpdate( + paramGroup_p pg, + int inx, + void * valueP ) +{ + AdjustCornuCurve(C_UPDATE, zero, InfoMessage); + ParamLoadControl(&cornuModPG,cornuModEndRadius); // Make sure Radius updated + ParamLoadControl(&cornuModPG,cornuModEndAngle); //Relative Angle as well + TempRedraw(); + +} /** * CmdCornuModify @@ -835,11 +1826,12 @@ EXPORT STATUS_T AdjustCornuCurve( * */ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG ) { - track_p t; struct extraData *xx = GetTrkExtraData(trk); Da.trackGauge = trackG; + Da.commandType = CORNU_MODIFY; + switch (action&0xFF) { case C_START: Da.state = NONE; @@ -847,42 +1839,90 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG Da.ep1Segs_da_cnt = 0; Da.ep2Segs_da_cnt = 0; Da.crvSegs_da_cnt = 0; + Da.midSegs.cnt = 0; Da.extend[0] = FALSE; Da.extend[1] = FALSE; - Da.selectPoint = -1; + Da.selectEndPoint = -1; Da.selectTrack = NULL; + DYNARR_RESET(coOrd,Da.mid_points); + DYNARR_RESET(track_p,Da.tracks); Da.selectTrack = trk; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = trk; Da.trk[0] = GetTrkEndTrk( trk, 0 ); + track_p prior = trk; if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],trk); - Da.trk[1] = GetTrkEndTrk( trk, 1 ); - if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk); + EPINX_T ep0 = 0; + //Move down the LHS adding tracks until no more Cornu + while (Da.trk[0] && QueryTrack(Da.trk[0],Q_IS_CORNU)) { + prior = Da.trk[0]; + ep0 = 1-Da.ep[0]; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = prior; + DYNARR_APPEND(coOrd,Da.mid_points,1); + for (int i=Da.mid_points.cnt-1;i>0;i--) { + DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd,Da.mid_points,i-1); + } + DYNARR_N(coOrd,Da.mid_points,0) = GetTrkEndPos(prior,1-ep0); + Da.trk[0] = GetTrkEndTrk( prior, ep0 ); + if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],prior); + else Da.ep[0] = -1; + } + if (prior) { + struct extraData *xx0 = GetTrkExtraData(prior); + Da.pos[0] = xx0->cornuData.pos[ep0]; //Copy parms from FIRST CORNU trk + Da.radius[0] = xx0->cornuData.r[ep0]; + Da.angle[0] = xx0->cornuData.a[ep0]; + Da.center[0] = xx0->cornuData.c[ep0]; + } - for (int i=0;i<2;i++) { - Da.pos[i] = xx->cornuData.pos[i]; //Copy parms from old trk - Da.radius[i] = xx->cornuData.r[i]; - Da.angle[i] = xx->cornuData.a[i]; - Da.center[i] = xx->cornuData.c[i]; - } + //Move to RHS + Da.trk[1] = GetTrkEndTrk( trk, 1 ); + track_p next = trk; + EPINX_T ep1 = 1; + if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk); + //Move down RHS adding tracks until no more Cornu + while (Da.trk[1] && QueryTrack(Da.trk[1],Q_IS_CORNU)) { + next = Da.trk[1]; + ep1 = 1-Da.ep[1]; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = next; + DYNARR_APPEND(coOrd,Da.mid_points,1); + DYNARR_LAST(coOrd,Da.mid_points) = GetTrkEndPos(next,1-ep1); + Da.trk[1] = GetTrkEndTrk( next, ep1 ); + if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],next); + } - if ((Da.trk[0] && (!QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY) && !QueryTrack(Da.trk[0],Q_CAN_EXTEND))) && - (Da.trk[1] && (!QueryTrack(Da.trk[1],Q_CORNU_CAN_MODIFY) && !QueryTrack(Da.trk[1],Q_CAN_EXTEND)))) { - wBeep(); - ErrorMessage("Both Ends of this Cornu are UnAdjustable"); - return C_TERMINATE; - } + if (next) { + struct extraData *xx1 = GetTrkExtraData(next); + Da.pos[1] = xx1->cornuData.pos[ep1]; //Copy parms from LAST CORNU trk + Da.radius[1] = xx1->cornuData.r[ep1]; + Da.angle[1] = xx1->cornuData.a[ep1]; + Da.center[1] = xx1->cornuData.c[ep1]; + } - InfoMessage(_("Track picked - now select a Point")); + InfoMessage(_("Now Select or Add (+Shift) a Point")); Da.state = TRACK_SELECTED; - DrawTrack(Da.selectTrack,&mainD,wDrawColorWhite); //Wipe out real track, draw replacement + for (int i=0;i>8) != 32) + //Delete or backspace deletes last selected index + if (action>>8 == 127 || action>>8 == 8) { + return AdjustCornuCurve(action, pos, InfoMessage); + } + //Space bar or enter means done + if ( (action>>8 != ' ') && (action>>8 != 13) ) return C_CONTINUE; /* no break */ case C_OK: + if (infoSubst) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } if (Da.state != PICK_POINT) { //Too early - abandon InfoMessage(_("No changes made")); Da.state = NONE; @@ -928,23 +1977,59 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG } else { Da.trk[i] = NewCurvedTrack(Da.extendSeg[i].u.c.center,fabs(Da.extendSeg[i].u.c.radius), Da.extendSeg[i].u.c.a0,Da.extendSeg[i].u.c.a1,FALSE); - - if (Da.angle[i]>180) - Da.ep[i] = (Da.extendSeg[i].u.c.a0>90 && Da.extendSeg[i].u.c.a0<270)?0:1; - else - Da.ep[i] = (Da.extendSeg[i].u.c.a0>90 && Da.extendSeg[i].u.c.a0<270)?1:0; + if (FindDistance(GetTrkEndPos(Da.trk[i],0),Da.pos[i])<=connectDistance) { + Da.ep[i] = 0; + } else Da.ep[i] = 1; } if (!Da.trk[i]) { wBeep(); InfoMessage(_("Cornu Extension Create Failed for end %d"),i); + Da.state = NONE; return C_TERMINATE; } } } - - t = NewCornuTrack( Da.pos, Da.center, Da.angle, Da.radius, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt); - if (t==NULL) { + BOOL_T end_point[2]; + end_point[0] = TRUE; + end_point[1] = FALSE; + coOrd sub_pos[2]; + sub_pos[0] = Da.pos[0]; + + track_p first_trk= NULL,trk1=NULL,trk2 = NULL; + for (int i=0;i= 0) - ConnectTracks(t,i,Da.trk[i],Da.ep[i]); + ConnectTracks(i==0?first_trk:trk1,i,Da.trk[i],Da.ep[i]); } else { UndoUndo(); wBeep(); @@ -986,18 +2081,18 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG } } UndoEnd(); - MainRedraw(); - MapRedraw(); Da.state = NONE; - //DYNARR_FREE(trkSeg_t,Da.crvSegs_da); + //DYNARR_FREE(trkSeg_t,Da.crvSegs_da) return C_TERMINATE; case C_CANCEL: InfoMessage(_("Modify Cornu Cancelled")); Da.state = NONE; + if (infoSubst) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } //DYNARR_FREE(trkSeg_t,Da.crvSegs_da); - MainRedraw(); - MapRedraw(); return C_TERMINATE; case C_REDRAW: @@ -1028,6 +2123,22 @@ DIST_T CornuLength(coOrd pos[4],dynArr_t segs) { return dd; } +DIST_T CornuOffsetLength(dynArr_t segs, double offset) { + DIST_T dd = 0.0; + if (segs.cnt == 0 ) return dd; + for (int i = 0;i0?offset:-offset))*D2R(t.u.c.a1)); + } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) { + dd +=CornuOffsetLength(t.bezSegs,offset); + } else if (t.type == SEG_STRLIN || t.type == SEG_STRTRK ) { + dd += FindDistance(t.u.l.pos[0],t.u.l.pos[1]); + } + } + return dd; +} + DIST_T CornuMinRadius(coOrd pos[4],dynArr_t segs) { DIST_T r = 100000.0, rr; if (segs.cnt == 0 ) return r; @@ -1081,6 +2192,9 @@ DIST_T CornuMaxRateofChangeofCurvature(coOrd pos[4], dynArr_t segs, DIST_T * las return r_max; } + + + /* * Create a Cornu Curve Track * Sequence is @@ -1091,167 +2205,359 @@ DIST_T CornuMaxRateofChangeofCurvature(coOrd pos[4], dynArr_t segs, DIST_T * las */ STATUS_T CmdCornu( wAction_t action, coOrd pos ) { - track_p t; + track_p t = NULL; cornuParm_t cp; - Da.color = lineColor; + Da.commandType = CORNU_CREATE; + Da.width = (double)lineWidth/mainD.dpi; Da.trackGauge = trackGauge; + Da.selectTrack = NULL; switch (action&0xFF) { case C_START: + Da.cmdType = (long)commandContext; Da.state = NONE; - Da. selectPoint = -1; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + Da.endHandle[0].end_valid = FALSE; + Da.endHandle[1].end_valid = FALSE; for (int i=0;i<2;i++) { + Da.ends[i] = FALSE; Da.pos[i] = zero; + Da.angle[i] = 0.0; + Da.radius[i] = -1.0; } Da.trk[0] = Da.trk[1] = NULL; //tempD.orig = mainD.orig; - DYNARR_RESET(trkSeg_t,Da.crvSegs_da); Da.ep1Segs_da_cnt = 0; Da.ep2Segs_da_cnt = 0; + Da.crvSegs_da_cnt = 0; + Da.midSegs.cnt = 0; + DYNARR_RESET(coOrd,Da.mid_points); + DYNARR_RESET(track_p,Da.tracks); + DYNARR_RESET(trkSeg_t,anchors_da); Da.extend[0] = FALSE; Da.extend[1] = FALSE; - if (selectedTrackCount==0) - InfoMessage( _("Left click - join with Cornu track") ); - else - InfoMessage( _("Left click - join with Cornu track, Shift Left click - move to join") ); + if (Da.cmdType == cornuCmdCreateTrack) + InfoMessage( _("Left click - Start Cornu track") ); + else if (Da.cmdType == cornuCmdHotBar) { + InfoMessage( _("Left click - Place Flextrack") ); + } else { + if (selectedTrackCount==0) + InfoMessage( _("Left click - join with Cornu track") ); + else + InfoMessage( _("Left click - join with Cornu track, Shift Left click - move to join") ); + } return C_CONTINUE; case C_DOWN: + DYNARR_RESET(trkSeg_t,anchors_da); if ( Da.state == NONE || Da.state == LOC_2) { //Set the first or second point coOrd p = pos; - int end = Da.state==NONE?0:1; - EPINX_T ep; - if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) { - if (QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS)) { //Circle/Helix find if there is an open slot and where - if ((GetTrkEndTrk(t,0) != NULL) && (GetTrkEndTrk(t,1) != NULL)) { + t = NULL; + int end = 0; + if (Da.state != NONE) end=1; + EPINX_T ep = -1; + //Lock to endpoint if one is available and under pointer + if ((t = OnTrack(&p, FALSE, TRUE)) != NULL && t != Da.selectTrack) { + if (QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS)) { //Circle/Helix find if there is an open slot and where + if ((GetTrkEndTrk(t,0) != NULL) && (GetTrkEndTrk(t,1) != NULL)) { + wBeep(); InfoMessage(_("Helix Already Connected")); - return C_CONTINUE; + t= NULL; } ep = -1; //Not a real ep yet - } else ep = PickUnconnectedEndPointSilent(p, t); - if (ep>=0 && QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) ep=-1; //Ignore Turntable Unconnected - else if (ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle - wBeep(); - InfoMessage(_("No Unconnected end point on that track")); - return C_CONTINUE; + } else if (QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) { + ep=-1; //Don't attach to existing Turntable ep + trackParams_t tp; + if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + Translate(&pos,tp.ttcenter,a,tp.ttradius); + p = pos; //Fix to wall of turntable initially + } else ep = PickUnconnectedEndPointSilent(p, t); //EP + if ( t && ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle + wBeep(); + InfoMessage(_("No valid open endpoint on that track")); + t = NULL; + } + if (t && GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) { + wBeep(); + InfoMessage(_("Track is different gauge")); + t = NULL; } + } + if (ep>=0 && t) { //Real end point, real track Da.trk[end] = t; Da.ep[end] = ep; // Note: -1 for Turntable or Circle - if (ep ==-1) pos = p; - else pos = GetTrkEndPos(t,ep); + pos = GetTrkEndPos(t,ep); Da.pos[end] = pos; - InfoMessage( _("Place 2nd end point of Cornu track on track with an unconnected end-point") ); - } else { + Da.angle[end] = GetTrkEndAngle(t,ep); + } else if (t == NULL) { //end not on Track, OK for CreateCornu -> empty end point + pos = p; //Reset to initial + SnapPos( &pos ); + if (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) { + Da.trk[end] = NULL; + Da.pos[end] = pos; + Da.radius[end] = -1.0; //No End Rad for open + if (Da.state == NONE ) { + Da.state = POS_1; + Da.angle[0] = 270.0; + Da.radius[0] = 0.0; + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,TRUE,TRUE,FALSE,Da.angle[0],Da.radius[0],zero,&Da.endHandle[0]); + Da.ep2Segs_da_cnt = 0; + InfoMessage( _("Drag arm in the direction of track") ); + return C_CONTINUE; + } + Da.state = POS_2; //Now this is second end and it is open + Da.selectEndPoint = 1; + Da.mid_points.cnt=0; + Da.angle[1] = GetOpenAngle(Da.pos,Da.angle,1); + Da.radius[1] = 0.0; + CreateBothEnds(1,-1,-1,-1); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) + Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + InfoMessage( _("Drag arm in the direction of track") ); + return C_CONTINUE; + } wBeep(); - InfoMessage(_("No Unconnected Track End there")); + InfoMessage(_("No Unconnected Track End there")); //Not creating a Cornu - Join can't be open return C_CONTINUE; + } else { + Da.pos[end] = p; + //Either a real end or a track but no end } if (Da.state == NONE) { - if (!GetConnectedTrackParms(t, pos, 0, Da.ep[0])) { + if (!GetConnectedTrackParms(t, pos, 0, Da.ep[0],FALSE)) { //Must get parms Da.trk[0] = NULL; + Da.ep[0] = -1; + wBeep(); + InfoMessage(_("No Valid Track End there")); return C_CONTINUE; } + if (ep<0) { + Da.trk[0] = t; + Da.pos[0] = p; + Da.ep[0] = ep; + } Da.state = POS_1; - Da.selectPoint = 0; - Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE, !QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY)); - DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack); - InfoMessage( _("Move 1st end point of Cornu track along track 1") ); - } else { - if ( Da.trk[0] == t) { + Da.selectEndPoint = 0; //Select first end point + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE, !QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY), + Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],NULL); + InfoMessage( _("Locked - Move 1st end point of Cornu track along track 1") ); + return C_CONTINUE; + } else { //Second Point + if (Da.trk[0] == t) { ErrorMessage( MSG_JOIN_CORNU_SAME ); Da.trk[1] = NULL; + Da.ep[1] = -1; return C_CONTINUE; } - if (!GetConnectedTrackParms(t, pos, 1, Da.ep[1])) { + if (!GetConnectedTrackParms(t, pos, 1, Da.ep[1],FALSE)) { Da.trk[1] = NULL; //Turntable Fail + wBeep(); + InfoMessage(_("No Valid Track End there")); return C_CONTINUE; } + if (ep<0) { + Da.trk[1] = t; + Da.pos[1] = p; + Da.ep[1] = -1; + Da.radius[1] = 0.0; + } CorrectHelixAngles(); - Da.selectPoint = 1; + Da.selectEndPoint = 1; //Select second end point Da.state = POINT_PICKED; - DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack); //Wipe out initial Arm - CreateBothEnds(1); - if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da, &cp)) - Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; - DrawTempCornu(); - InfoMessage( _("Move 2nd end point of Cornu track along track 2") ); + InfoMessage( _("Locked - Move 2nd end point of Cornu track along track 2") ); } + CreateBothEnds(1,-1,-1,-1); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) + Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; return C_CONTINUE; - } else { + } else { //This is after both ends exist return AdjustCornuCurve( action&0xFF, pos, InfoMessage ); } return C_CONTINUE; + + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if (Da.state != NONE && Da.state != LOC_2) return C_CONTINUE; + if (Da.trk[0] && Da.trk[1]) return C_CONTINUE; + EPINX_T ep = -1; + t = NULL; + if (((MyGetKeyState() & WKEY_ALT) == 0) == magneticSnap) { + //Lock to endpoint if one is available and under pointer + if ((t = OnTrack(&pos, FALSE, TRUE)) != NULL && t != Da.selectTrack) { + if (QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS)) { //Circle/Helix find if there is an open slot and where + if ((GetTrkEndTrk(t,0) != NULL) && (GetTrkEndTrk(t,1) != NULL)) { + return C_CONTINUE; + } + ep = -1; //Not a real ep yet + } else ep = PickUnconnectedEndPointSilent(pos, t); //EP + if (ep>=0 && QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) ep=-1; //Don't attach to Turntable + if ( ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle + return C_CONTINUE; + } + if (GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) { + return C_CONTINUE; + } + if (Da.state != NONE && t==Da.trk[0]) return C_CONTINUE; + } + } + if (ep>=0 && t) { + pos = GetTrkEndPos(t,ep); + CreateCornuEndAnchor(pos,TRUE); + } else if (t) { + trackParams_t tp; //Turntable or extendable track + if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE; + if (QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) { + if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + Translate(&pos,tp.ttcenter,a,tp.ttradius); + CreateCornuEndAnchor(pos,TRUE); + } else CreateCornuEndAnchor(pos,TRUE); + } + + return C_CONTINUE; case C_MOVE: - if (Da.state == NONE) { - InfoMessage("Place 1st end point of Cornu track on unconnected end-point"); + if (Da.state == NONE) { //First point not created + if (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) { + InfoMessage("Place 1st end point of Cornu track"); + } else + InfoMessage("Place 1st end point of Cornu track on unconnected end-point"); return C_CONTINUE; } - if (Da.state == POS_1) { + if (Da.state == POS_1) { //First point has been created + if ((Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) && !Da.trk[0]) { //OK for CreateCornu -> No track selected + if (IsClose(FindDistance(pos,Da.pos[0]))) return C_CONTINUE; + Da.selectEndPoint = 0; + Da.angle[0] = NormalizeAngle(FindAngle(Da.pos[0],pos)+180); + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],TRUE,TRUE,TRUE,FALSE,Da.angle[0],0.0,zero,&Da.endHandle[0]); + Da.radius[1] = -1.0; /*No end*/ + return C_CONTINUE; + } EPINX_T ep = 0; BOOL_T found = FALSE; int end = Da.state==POS_1?0:1; if(!QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY) && !QueryTrack(Da.trk[0],Q_CAN_ADD_ENDPOINTS)) { - InfoMessage(_("Can't Split - Locked to End Point")); + InfoMessage(_("Track can't be split - so locked to endpoint")); return C_CONTINUE; } if (Da.trk[0] != OnTrack(&pos, FALSE, TRUE)) { wBeep(); InfoMessage(_("Point not on track 1")); Da.state = POS_1; - Da.selectPoint = 1; + Da.selectEndPoint = 0; return C_CONTINUE; } t = Da.trk[0]; - DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack); - if (!GetConnectedTrackParms(t, pos, ep, Da.ep[ep])) { + if (!GetConnectedTrackParms(t, pos, ep, Da.ep[ep],FALSE)) { Da.state = POS_1; - Da.selectPoint = 1; + Da.selectEndPoint = 0; return C_CONTINUE; } Da.pos[ep] = pos; - Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],TRUE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY)); - DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack); - } else { + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs,Da.pos[0],TRUE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY), + Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],NULL); + } else if (Da.state == POS_2 && + (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) && !Da.trk[1]) { //OK for CreateCornu -> No track selected + if (IsClose(FindDistance(pos,Da.pos[1]))) return C_CONTINUE; + Da.selectEndPoint = 1; + Da.angle[1] = NormalizeAngle(FindAngle(Da.pos[1],pos)+180); + Da.radius[1] = 0.0; /*No end*/ + Da.ep1Segs_da_cnt = createEndPoint(Da.ep2Segs,Da.pos[1],TRUE,TRUE,TRUE,FALSE,Da.angle[1],0.0,zero,&Da.endHandle[1]); + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + CreateBothEnds(-1,-1,-1,-1); + Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); + return C_CONTINUE; + } else { //Second Point Has Been Created and aligned return AdjustCornuCurve( action&0xFF, pos, InfoMessage ); } return C_CONTINUE; case C_UP: - if (Da.state == POS_1 && Da.trk[0]) { - DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack); + if (Da.state == POS_1 && (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar || Da.trk[0])) { Da.state = LOC_2; + Da.selectEndPoint = -1; + if (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) { + if (Da.cmdType == cornuCmdCreateTrack) + InfoMessage( _("Pick other end of Cornu") ); + else + InfoMessage( _("Select flextrack ends or anchors and drag, Enter to approve, Esc to Cancel") ); + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,TRUE,TRUE,FALSE,0.0,0.0,zero,NULL); + return C_CONTINUE; + } InfoMessage( _("Put other end of Cornu on a track with an unconnected end point") ); - Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY)); - DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack); + if (Da.trk[0]) + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY), + Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],NULL); + else + Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,TRUE,TRUE,FALSE, Da.angle[0],Da.radius[0],Da.center[0],&Da.endHandle[0]); + return C_CONTINUE; + } else if (Da.state == POS_2 && (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar || Da.trk[1] )){ + Da.state = PICK_POINT; + Da.selectEndPoint = -1; + Da.prevEndPoint = 1; + Da.prevSelected = -1; + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else Da.crvSegs_da_cnt = 0; + CreateBothEnds(-1,-1,-1,-1); + Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da); return C_CONTINUE; } else { return AdjustCornuCurve( action&0xFF, pos, InfoMessage ); } + return C_CONTINUE; + break; case C_TEXT: - if (Da.state != PICK_POINT || (action>>8) != 32) //Space is same as Enter. + if (Da.state != PICK_POINT) return C_CONTINUE; + if ((action>>8 == 127) || (action>>8 == 8)) // + return AdjustCornuCurve(action, pos, InfoMessage); + if (!(action>>8 == 32 )) //Space is same as Enter. return C_CONTINUE; /* no break */ case C_OK: if (Da.state != PICK_POINT) return C_CONTINUE; - return AdjustCornuCurve( C_OK, pos, InfoMessage); + STATUS_T rc = AdjustCornuCurve( C_OK, pos, InfoMessage); + if (rc == C_TERMINATE) { + Da.state = NONE; + Da.ep1Segs_da_cnt = 0; + Da.ep2Segs_da_cnt = 0; + Da.crvSegs_da_cnt = 0; + for (int i=0;i<2;i++) { + Da.radius[i] = 0.0; + Da.angle[i] = 0.0; + Da.center[i] = zero; + Da.trk[i] = NULL; + Da.ep[i] = -1; + Da.pos[i] = zero; + Da.endHandle[i].end_valid = FALSE; + } + } + return rc; case C_REDRAW: if ( Da.state != NONE ) { - DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,Da.ep2Segs,Da.ep2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, NULL, - Da.extend[0]?&Da.extendSeg[0]:NULL,Da.extend[1]?&Da.extendSeg[1]:NULL,Da.color); + DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,Da.ep2Segs,Da.ep2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da_cnt, NULL, + Da.extend[0]?&Da.extendSeg[0]:NULL,Da.extend[1]?&Da.extendSeg[1]:NULL,(trkSeg_t *)Da.midSegs.ptr,Da.midSegs.cnt,wDrawColorBlack); } + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + if (MyGetKeyState()&WKEY_SHIFT) DrawHighlightBoxes(FALSE,FALSE,NULL); + return C_CONTINUE; case C_CANCEL: if (Da.state != NONE) { - DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,Da.ep2Segs,Da.ep2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, NULL, - Da.extend[0]?&Da.extendSeg[0]:NULL,Da.extend[1]?&Da.extendSeg[1]:NULL,Da.color); Da.ep1Segs_da_cnt = 0; Da.ep2Segs_da_cnt = 0; Da.crvSegs_da_cnt = 0; @@ -1262,21 +2568,486 @@ STATUS_T CmdCornu( wAction_t action, coOrd pos ) Da.trk[i] = NULL; Da.ep[i] = -1; Da.pos[i] = zero; + Da.endHandle[i].end_valid = FALSE; } //DYNARR_FREE(trkSeg_t,Da.crvSegs_da); } Da.state = NONE; + if (infoSubst) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } return C_CONTINUE; default: return C_CONTINUE; } + return C_CONTINUE; +} +BOOL_T GetTracksFromCornuTrack(track_p trk, track_p newTracks[2]) { + track_p trk_old = NULL; + newTracks[0] = NULL, newTracks[1] = NULL; + struct extraData * xx = GetTrkExtraData(trk); + if (!IsTrack(trk)) return FALSE; + for (int i=0; icornuData.arcSegs.cnt;i++) { + track_p bezTrack[2]; + bezTrack[0] = NULL, bezTrack[1] = NULL; + trkSeg_p seg = &DYNARR_N(trkSeg_t,xx->cornuData.arcSegs,i); + if (seg->type == SEG_BEZTRK) { + DYNARR_RESET(trkSeg_t,seg->bezSegs); + FixUpBezierSeg(seg->u.b.pos,seg,TRUE); + GetTracksFromBezierSegment(seg, bezTrack, trk); + if (newTracks[0] == NULL) newTracks[0] = bezTrack[0]; + newTracks[1] = bezTrack[1]; + if (trk_old) { + for (int i=0;i<2;i++) { + if (GetTrkEndTrk(trk_old,i)==NULL) { + coOrd pos = GetTrkEndPos(trk_old,i); + EPINX_T ep_n = PickUnconnectedEndPoint(pos,bezTrack[0]); + if ((connectDistance >= FindDistance(GetTrkEndPos(trk_old,i),GetTrkEndPos(bezTrack[0],ep_n))) && + (connectAngle >= fabs(DifferenceBetweenAngles(GetTrkEndAngle(trk_old,i),GetTrkEndAngle(bezTrack[0],ep_n)+180))) ) { + ConnectTracks(trk_old,i,bezTrack[0],ep_n); + break; + } + } + } + } + trk_old = newTracks[1]; + } else { + track_p new_trk; + if (seg->type == SEG_CRVTRK) + new_trk = NewCurvedTrack(seg->u.c.center,seg->u.c.radius,seg->u.c.a0,seg->u.c.a1,0); + else if (seg->type == SEG_STRTRK) + new_trk = NewStraightTrack(seg->u.l.pos[0],seg->u.l.pos[1]); + if (newTracks[0] == NULL) newTracks[0] = new_trk; + CopyAttributes( trk, new_trk ); + newTracks[1] = new_trk; + if (trk_old) { + for (int i=0;i<2;i++) { + if (GetTrkEndTrk(trk_old,i)==NULL) { + coOrd pos = GetTrkEndPos(trk_old,i); + EPINX_T ep_n = PickUnconnectedEndPoint(pos,new_trk); + if ((connectDistance >= FindDistance(GetTrkEndPos(trk_old,i),GetTrkEndPos(new_trk,ep_n))) && + (connectAngle >= fabs(DifferenceBetweenAngles(GetTrkEndAngle(trk_old,i),GetTrkEndAngle(new_trk,ep_n)+180)))) { + ConnectTracks(trk_old,i,new_trk,ep_n); + break; + } + } + } + } + trk_old = new_trk; + } + } + return TRUE; + +} + +static STATUS_T cmdCornuCreate( + wAction_t action, + coOrd pos ) { + static int createState = 0; + int rc = 0; + + switch(action&0xFF) { + + case C_DOWN: + return CmdCornu(C_DOWN,pos); + case C_UP: + rc = CmdCornu(C_UP,pos); + return rc; + case C_FINISH: + if (createState != 0 ) { + createState = 0; + CmdCornu( C_OK, pos ); + } else + CmdCornu( C_CANCEL, pos ); + Da.prevSelected = -1; + Da.selectEndHandle = -1; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + Da.selectTrack = NULL; + Da.trk[0] = NULL; Da.trk[1] = NULL; + Da.radius[0] = Da.radius[1] = -1.0; + Da.angle[0] = Da.angle[1] = 0.0; + Da.ends[0] = Da.ends[1] = FALSE; + Da.endHandle[0].end_valid = Da.endHandle[1].end_valid = FALSE; + return C_TERMINATE; + case C_TEXT: + if ((action>>8) != ' ' && (action>>8) != 32) + return CmdCornu(action,pos); + /*no break*/ + case C_OK: + CmdCornu(C_OK,pos); + MainRedraw(); + return C_CONTINUE; + case C_CANCEL: + HotBarCancel(); + CmdCornu(C_CANCEL, pos); + createState = 0; + rc = C_TERMINATE; + /* no break */ + case C_START: + createState = 0; + commandContext = (void *)cornuCmdHotBar; + rc = CmdCornu(C_START, pos); + Da.prevSelected = -1; + Da.selectEndHandle = -1; + Da.selectEndPoint = -1; + Da.selectMidPoint = -1; + Da.selectTrack = NULL; + Da.trk[0] = NULL; Da.trk[1] = NULL; + Da.radius[0] = Da.radius[1] = -1.0; + Da.angle[0] = Da.angle[1] = 0.0; + Da.ends[0] = Da.ends[1] = FALSE; + Da.endHandle[0].end_valid = Da.endHandle[1].end_valid = FALSE; + return rc; + default: + return CmdCornu(action,pos); + } + return C_CONTINUE; } +static STATUS_T CmdConvertTo( + wAction_t action, + coOrd pos ) +{ + static track_p trk; + cornuParm_t cp; + switch (action) { + + case wActionMove: + if ((trk = OnTrack(&pos,FALSE,TRUE)) == NULL) return C_CONTINUE; + if (!QueryTrack(trk, Q_CORNU_CAN_MODIFY) && //Not Fixed Track/Turnout/Turntable + !QueryTrack(trk, Q_IGNORE_EASEMENT_ON_EXTEND )) + trk = NULL; + return C_CONTINUE; + + case C_LCLICK: + if ((trk = OnTrack(&pos,FALSE,TRUE))!=NULL) { + SetTrkBits(trk,TB_SELECTED); + selectedTrackCount = 1; + } else { + wBeep(); + InfoMessage( _("Not on a Track") ); + return C_CONTINUE; + } + trk = NULL; + + /* no break */ + case C_START: + if (selectedTrackCount==0) { + InfoMessage( _("Select a Track To Convert") ); + return C_CONTINUE; + } + else if (selectedTrackCount>1) { + if (NoticeMessage(_("Convert all Selected Tracks to Cornu Tracks?"), _("Yes"), _("No"))<=0) { + SetAllTrackSelect(FALSE); + return C_TERMINATE; + } + } + UndoStart( _("Convert Cornu"),"newCornu curves"); + trk = NULL; + int converted=0, not_convertable = 0, created=0, deleted=0; + DYNARR_RESET(track_p,Da.tracks); + while ( TrackIterate( &trk ) ) { + if (!GetTrkSelected( trk )) continue; //Only selected + if (!QueryTrack(trk, Q_CORNU_CAN_MODIFY) && //Not Fixed Track/Turnout/Turntable + !QueryTrack( trk, Q_IGNORE_EASEMENT_ON_EXTEND )) { //But Yes to Easement + not_convertable++; + continue; + } + converted++; + DYNARR_RESET(trkSeg_t,Da.crvSegs_da); + Da.ep1Segs_da_cnt = 0; + Da.ep2Segs_da_cnt = 0; + Da.midSegs.cnt = 0; + Da.extend[0] = FALSE; + Da.extend[1] = FALSE; + Da.selectEndPoint = -1; + Da.selectTrack = NULL; + DYNARR_RESET(coOrd,Da.mid_points); + ClrTrkBits( trk, TB_SELECTED ); //Done with this one + Da.selectTrack = trk; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = trk; + Da.trk[0] = GetTrkEndTrk( trk, 0 ); + track_p prior = trk; + if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],trk); + else Da.ep[0] = -1; + EPINX_T ep0 = 0; + //Move down the LHS adding tracks until no more Selected or not modifyable + while (Da.trk[0] && GetTrkSelected( Da.trk[0]) && IsTrack(Da.trk[0]) && (QueryTrack(Da.trk[0], Q_CORNU_CAN_MODIFY) || QueryTrack(Da.trk[0], Q_IS_CORNU)) ) { + prior = Da.trk[0]; + ep0 = 1-Da.ep[0]; + ClrTrkBits( Da.trk[0], TB_SELECTED ); //Done with this one + if (selectedTrackCount>0) selectedTrackCount--; + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = prior; + DYNARR_APPEND(coOrd,Da.mid_points,1); + for (int i=Da.mid_points.cnt-1;i>1;i--) { + DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd,Da.mid_points,i-1); + } + DYNARR_N(coOrd,Da.mid_points,0) = GetTrkEndPos(prior,1-ep0); + Da.trk[0] = GetTrkEndTrk( prior, ep0 ); + if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],prior); + else Da.ep[0] = -1; + converted++; + } + Da.radius[0] = -1.0; //Initialize with no end + Da.ends[0] = FALSE; + Da.center[0] = zero; + Da.pos[0] = GetTrkEndPos(prior,ep0); + if (Da.trk[0] && Da.ep[0]>=0) { + GetConnectedTrackParms(Da.trk[0],GetTrkEndPos(Da.trk[0],Da.ep[0]),0,Da.ep[0],FALSE); + } + + //Move to RHS + + Da.trk[1] = GetTrkEndTrk( trk, 1 ); + track_p next = trk; + EPINX_T ep1 = 1; + if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk); + else Da.ep[1] = -1; + //Move down RHS adding tracks until no more Selected or not modifyable + while (Da.trk[1] && GetTrkSelected( Da.trk[1]) && (QueryTrack(Da.trk[1], Q_CORNU_CAN_MODIFY) || QueryTrack(Da.trk[1], Q_IS_CORNU))) { + next = Da.trk[1]; + ep1 = 1-Da.ep[1]; + if (selectedTrackCount>0) selectedTrackCount--; + ClrTrkBits( Da.trk[1], TB_SELECTED ); //Done with this one + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = next; + DYNARR_APPEND(coOrd,Da.mid_points,1); + DYNARR_LAST(coOrd,Da.mid_points) = GetTrkEndPos(next,1-ep1); + Da.trk[1] = GetTrkEndTrk( next, ep1 ); + if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],next); + converted++; + } + Da.radius[1] = -1.0; //Initialize with no end + Da.ends[1] = FALSE; + Da.center[1] = zero; + Da.pos[1] = GetTrkEndPos(next,ep1); + if (Da.trk[1] && Da.ep[1]>=0) { + GetConnectedTrackParms(Da.trk[1],GetTrkEndPos(Da.trk[1],Da.ep[1]),1,Da.ep[1],FALSE); + } + SetUpCornuParms(&cp); + if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt; + else continue; //Checks that a solution can be found + + // Do the deed - Create a replacement Cornu + + BOOL_T end_point[2]; + end_point[0] = TRUE; + end_point[1] = FALSE; + coOrd sub_pos[2]; + sub_pos[0] = Da.pos[0]; + if (Da.radius[0] == -1) end_point[0] = FALSE; + track_p first_trk= NULL,trk1=NULL,trk2 = NULL; + + for (int i=0;i=0 && Da.trk[i]) { + track_p trk_old = GetTrkEndTrk(Da.trk[i],Da.ep[i]); + EPINX_T old_ep = GetEndPtConnectedToMe(trk_old,Da.trk[i]); + DisconnectTracks(Da.trk[i],Da.ep[i],trk_old,old_ep); + if (Da.ep[i]>=0 && Da.trk[i]) + ConnectTracks(Da.trk[i],Da.ep[i],i==0?first_trk:trk1,i); + } + } + + } //Find next track + SetAllTrackSelect(FALSE); + //Get rid of old tracks + for (int i = 0; i1) { + if (NoticeMessage(_("Convert all Selected Tracks to Fixed Tracks?"), _("Yes"), _("No"))<=0) { + SetAllTrackSelect(FALSE); + return C_TERMINATE; + } + } + dynArr_t trackSegs_da; + DYNARR_RESET(trkSeg_t,trackSegs_da); + trk1 = NULL; + trk2 = NULL; + trk = NULL; + UndoStart( _("Convert Bezier and Cornu"),"Try to convert all selected tracks"); + track_p tracks[2]; + DYNARR_RESET(track_p,Da.tracks); + int converted=0, not_convertable = 0, created=0, deleted=0; + while ( TrackIterate( &trk1 ) ) { + if ( GetTrkSelected( trk1 ) && IsTrack( trk1 ) ) { + //Only Cornu or Bezier + tracks[0] = NULL, tracks[1] = NULL; + if (selectedTrackCount>0) selectedTrackCount--; + ClrTrkBits( trk1, TB_SELECTED ); //Done with this one + if (GetTrkType(trk1) == T_CORNU) { + GetTracksFromCornuTrack(trk1,tracks); + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = trk1; + converted++; + } else if (GetTrkType(trk1) == T_BEZIER) { + GetTracksFromBezierTrack(trk1,tracks); + DYNARR_APPEND(track_p,Da.tracks,1); + DYNARR_LAST(track_p,Da.tracks) = trk1; + converted++; + } else { + not_convertable++; + continue; + } + for (int i=0;i<2;i++) { + track_p trk2 = GetTrkEndTrk(trk1,i); + if (trk2) { + EPINX_T ep1 = GetEndPtConnectedToMe( trk2, trk1 ); + DisconnectTracks(trk2,ep1,trk1,i); + pos = GetTrkEndPos(trk2,ep1); + for (int j=0;j<2;j++) { + EPINX_T ep2 = PickUnconnectedEndPointSilent( pos, tracks[j] ); + coOrd ep_pos; + if (ep2<0) continue; + ep_pos = GetTrkEndPos(tracks[j],ep2); + if (connectDistance>=FindDistance(pos,ep_pos) && + connectAngle >= fabs(DifferenceBetweenAngles(GetTrkEndAngle(tracks[j],ep2),GetTrkEndAngle(trk2,ep1)+180))) { + ConnectTracks(trk2,ep1,tracks[j],ep2); + break; + } + } + } + } + } + } + SetAllTrackSelect(FALSE); + for (int i = 0; i 90.0 && angle2 < 270.0) - Translate( &pos, pos0, angle1, -FindDistance( pos0, pos )*cos(D2R(angle2)) ); - else pos = pos0; - } else { - DIST_T dp = -FindDistance(pos0, pos)*sin(D2R(angle2)); - if (angle2 > 180.0) - Translate( &pos, pos0, angle1+90.0, dp ); + Translate( &pos, Da.pos0, angle1, -FindDistance( Da.pos0, pos )*cos(D2R(angle2)) ); + else pos = Da.pos0; + } else if ( mode == crvCmdFromChord ) { + DIST_T dp = -FindDistance(Da.pos0, pos)*sin(D2R(angle2)); + if (DifferenceBetweenAngles(FindAngle(Da.pos0,pos),angle1)>0) + Translate( &pos, Da.pos0, angle1+90, dp ); + else + Translate( &pos, Da.pos0, angle1-90, -dp ); + } else if (mode == crvCmdFromCenter) { + DIST_T dp = -FindDistance(Da.pos0, pos)*sin(D2R(angle2)); + if (angle2 > 90 && angle2 < 270.0) + Translate( &pos, Da.pos0, angle1+90.0, dp ); else - Translate( &pos, pos0, angle1-90.0, dp ); + Translate( &pos, Da.pos0, angle1-90.0, dp ); + } else if (mode == crvCmdFromTangent) { + DIST_T dp = FindDistance(Da.pos0, pos)*sin(D2R(angle2)); + Translate( &pos, Da.pos0, angle1-90.0, dp ); } } else SnapPos(&pos); - tempSegs(0).u.l.pos[1] = pos; - d = FindDistance( pos0, pos ); - a = FindAngle( pos0, pos ); + tempSegs_da.cnt =1; + if (Da.trk && mode == crvCmdFromChord) { + tempSegs(0).type = SEG_CRVTRK; + tempSegs(0).u.c.center.x = (pos.x+Da.pos0.x)/2.0; + tempSegs(0).u.c.center.y = (pos.y+Da.pos0.y)/2.0; + tempSegs(0).u.c.radius = FindDistance(pos,Da.pos0)/2; + ANGLE_T a0 = FindAngle(tempSegs(0).u.c.center,Da.pos0); + ANGLE_T a1 = FindAngle(tempSegs(0).u.c.center,pos); + if (NormalizeAngle(a0+90-GetTrkEndAngle(Da.trk,Da.ep))<90) { + tempSegs(0).u.c.a0 = a0; + } else { + tempSegs(0).u.c.a0 = a1; + } + tempSegs(0).u.c.a1 = 180.0; + } else tempSegs(0).u.l.pos[1] = pos; + Da.pos1 = pos; + + d = FindDistance( Da.pos0, Da.pos1 ); + a = FindAngle( Da.pos0, Da.pos1 ); switch ( mode ) { case crvCmdFromEP1: if (Da.trk) message( _("Start Locked: Drag out curve start - Angle=%0.3f"), PutAngle(a)); else message( _("Drag out curve start - Angle=%0.3f"), PutAngle(a) ); + CreateEndAnchor(Da.pos0,anchor_array,Da.lock0); + DrawArrowHeadsArray( anchor_array, pos, FindAngle(Da.pos0,Da.pos1)+90, TRUE, wDrawColorBlue ); tempSegs_da.cnt = 1; break; case crvCmdFromTangent: - if (Da.trk) message( _("Tangent Locked: Drag out center - Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); + if (Da.trk) message( _("Tangent locked: Drag out center - Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); else message( _("Drag out center - Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); - tempSegs(1).u.c.center = pos; - DrawArrowHeads( &tempSegs(2), pos0, FindAngle(pos0,pos)+90, TRUE, wDrawColorBlack ); - tempSegs_da.cnt = 7; + CreateEndAnchor(Da.pos1,anchor_array,TRUE); + DrawArrowHeadsArray( anchor_array, Da.pos0, FindAngle(Da.pos0,Da.pos1)+90, TRUE, wDrawColorBlue ); + tempSegs_da.cnt = 1; break; case crvCmdFromCenter: - message( _("Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); - tempSegs(1).u.c.center = pos0; - DrawArrowHeads( &tempSegs(2), pos, FindAngle(pos,pos0)+90, TRUE, wDrawColorBlack ); - tempSegs_da.cnt = 7; + message( _("Drag to Edge: Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); + CreateEndAnchor(Da.pos0,anchor_array,Da.lock0); + DrawArrowHeadsArray( anchor_array, Da.pos1, FindAngle(Da.pos1,Da.pos0)+90, TRUE, wDrawColorBlue ); + tempSegs_da.cnt = 1; break; case crvCmdFromChord: - message( _("Length=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); - if ( d > mainD.scale*0.25 ) { - pos.x = (pos.x+pos0.x)/2.0; - pos.y = (pos.y+pos0.y)/2.0; - DrawArrowHeads( &tempSegs(1), pos, FindAngle(pos,pos0)+90, TRUE, wDrawColorBlack ); - tempSegs_da.cnt = 6; - } else { - tempSegs_da.cnt = 1; + if (Da.trk) message( _("Start locked: Drag out chord length=%s angle=%0.3f"), FormatDistance(d), PutAngle(a) ); + else message( _("Drag out chord length=%s angle=%0.3f"), FormatDistance(d), PutAngle(a) ); + Da.middle.x = (Da.pos1.x+Da.pos0.x)/2.0; + Da.middle.y = (Da.pos1.y+Da.pos0.y)/2.0; + if (track && Da.trk) { + ANGLE_T ea = GetTrkEndAngle(Da.trk,Da.ep); + Translate(&Da.middle,Da.middle,ea,FindDistance(Da.middle,Da.pos0)); } + CreateEndAnchor(Da.pos0,anchor_array,TRUE); + CreateEndAnchor(Da.pos1,anchor_array,FALSE); + if (!track || !Da.trk) + DrawArrowHeadsArray( anchor_array, Da.middle, FindAngle(Da.pos0,Da.pos1)+90, TRUE, wDrawColorBlue ); break; } return C_CONTINUE; case C_UP: + /* Note - no anchor reset - assumes run after Down/Move */ if (!Da.down) return C_CONTINUE; if (Da.trk) { angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk, Da.ep)); - angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1); + angle2 = NormalizeAngle(FindAngle(pos, Da.pos0)-angle1); if (mode == crvCmdFromEP1) { if (angle2 > 90.0 && angle2 < 270.0) { - Translate( &pos, pos0, angle1, -FindDistance( pos0, pos )*cos(D2R(angle2)) ); + Translate( &pos, Da.pos0, angle1, -FindDistance( Da.pos0, pos )*cos(D2R(angle2)) ); Da.pos1 = pos; } else { ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(0.0) ); return C_TERMINATE; } + } else if (mode == crvCmdFromTangent) { + DIST_T dp = FindDistance(Da.pos0, pos)*sin(D2R(angle2)); + Translate( &pos, Da.pos0, angle1-90.0, dp ); + Da.pos1 = pos; } else { - DIST_T dp = -FindDistance(pos0, pos)*sin(D2R(angle2)); + DIST_T dp = -FindDistance(Da.pos0, pos)*sin(D2R(angle2)); if (angle2 > 180.0) - Translate( &pos, pos0, angle1+90.0, dp ); + Translate( &pos, Da.pos0, angle1+90.0, dp ); else - Translate( &pos, pos0, angle1-90.0, dp ); + Translate( &pos, Da.pos0, angle1-90.0, dp ); Da.pos1 = pos; } + if (FindDistance(Da.pos0,Da.pos1)options = wDrawOptTemp; - DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); if ( Da.state == 0 ) { Da.pos1 = pos; - rc = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); + rc = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage ); + segCnt = tempSegs_da.cnt ; } else { + DYNARR_RESET(trkSeg_t,anchors_da); // SnapPos( &pos ); + tempSegs_da.cnt = segCnt; if (Da.trk) PlotCurve( curveMode, Da.pos0, Da.pos1, pos, &Da.curveData, FALSE ); else PlotCurve( curveMode, Da.pos0, Da.pos1, pos, &Da.curveData, TRUE ); if (Da.curveData.type == curveTypeStraight) { @@ -349,11 +497,14 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) tempSegs(0).u.l.pos[0] = Da.pos0; tempSegs(0).u.l.pos[1] = Da.curveData.pos1; tempSegs_da.cnt = 1; + segCnt = 1; InfoMessage( _("Straight Track: Length=%s Angle=%0.3f"), FormatDistance(FindDistance( Da.pos0, Da.curveData.pos1 )), PutAngle(FindAngle( Da.pos0, Da.curveData.pos1 )) ); + DrawArrowHeadsArray(&anchors_da,Da.curveData.pos1,FindAngle(Da.pos0, Da.curveData.pos1)+90,TRUE,wDrawColorRed); } else if (Da.curveData.type == curveTypeNone) { tempSegs_da.cnt = 0; + segCnt = 0; InfoMessage( _("Back") ); } else if (Da.curveData.type == curveTypeCurve) { tempSegs(0).type = SEG_CRVTRK; @@ -362,6 +513,7 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) tempSegs(0).u.c.a0 = Da.curveData.a0; tempSegs(0).u.c.a1 = Da.curveData.a1; tempSegs_da.cnt = 1; + segCnt = 1; d = D2R(Da.curveData.a1); if (d < 0.0) d = 2*M_PI+d; @@ -375,80 +527,101 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) InfoMessage( _("Curved Track: Radius=%s Angle=%0.3f Length=%s"), FormatDistance(Da.curveData.curveRadius), Da.curveData.a1, FormatDistance(Da.curveData.curveRadius*d) ); + coOrd pos1; + Translate(&pos1,Da.curveData.curvePos,Da.curveData.a0+Da.curveData.a1,Da.curveData.curveRadius); + if (curveMode == crvCmdFromEP1 || curveMode == crvCmdFromChord) + DrawArrowHeadsArray(&anchors_da,pos,FindAngle(Da.curveData.curvePos,pos),TRUE,wDrawColorRed); + else if (curveMode == crvCmdFromTangent || curveMode == crvCmdFromCenter) { + CreateEndAnchor(Da.curveData.pos2,&anchors_da,FALSE); + DrawArrowHeadsArray(&anchors_da,Da.curveData.pos2,FindAngle(Da.curveData.curvePos,Da.curveData.pos2)+90,TRUE,wDrawColorRed); + } + CreateEndAnchor(Da.curveData.curvePos,&anchors_da,TRUE); } } - DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); mainD.funcs->options = 0; return rc; - - + case C_TEXT: + if ( Da.state == 0 ) + return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage ); + /*no break*/ case C_UP: if (Da.state<0) return C_CONTINUE; - mainD.funcs->options = wDrawOptTemp; - DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - if (Da.state == 0) { + if (Da.state == 0 && ((curveMode != crvCmdFromChord) || (curveMode == crvCmdFromChord && !Da.trk))) { SnapPos( &pos ); Da.pos1 = pos; + if ((d = FindDistance(Da.pos0,Da.pos1))options = 0; segCnt = tempSegs_da.cnt; InfoMessage( _("Drag on Red arrows to adjust curve") ); return C_CONTINUE; - } else { - mainD.funcs->options = 0; - tempSegs_da.cnt = 0; - Da.state = -1; - if (Da.curveData.type == curveTypeStraight) { - if ((d=FindDistance( Da.pos0, Da.curveData.pos1 )) <= minLength) { - ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); - return C_TERMINATE; - } - UndoStart( _("Create Straight Track"), "newCurve - straight" ); - t = NewStraightTrack( Da.pos0, Da.curveData.pos1 ); - if (Da.trk) { - EPINX_T ep = PickUnconnectedEndPoint(Da.pos0, t); - if (ep != -1) ConnectTracks(Da.trk, Da.ep, t, ep); - } - UndoEnd(); - } else if (Da.curveData.type == curveTypeCurve) { - if ((d= Da.curveData.curveRadius * Da.curveData.a1 *2.0*M_PI/360.0) <= minLength) { - ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); - return C_TERMINATE; - } - UndoStart( _("Create Curved Track"), "newCurve - curve" ); - t = NewCurvedTrack( Da.curveData.curvePos, Da.curveData.curveRadius, - Da.curveData.a0, Da.curveData.a1, 0 ); - if (Da.trk) { - EPINX_T ep = PickUnconnectedEndPoint(Da.pos0, t); - if (ep != -1) ConnectTracks(Da.trk, Da.ep, t, ep); - } - UndoEnd(); - } else { - return C_ERROR; + } else if ((curveMode == crvCmdFromChord && Da.state == 0 && Da.trk)) { + pos = Da.middle; + if ((d = FindDistance(Da.pos0,Da.pos1))options = 0; + tempSegs_da.cnt = 0; + segCnt = 0; + Da.state = -1; + DYNARR_RESET(trkSeg_t,anchors_da); // No More anchors for this one + if (Da.curveData.type == curveTypeStraight) { + if ((d = FindDistance( Da.pos0, Da.curveData.pos1 )) < minLength) { + ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); + return C_TERMINATE; + } + UndoStart( _("Create Straight Track"), "newCurve - straight" ); + t = NewStraightTrack( Da.pos0, Da.curveData.pos1 ); + if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) { + EPINX_T ep = PickUnconnectedEndPoint(Da.pos0, t); + if (ep != -1) ConnectTracks(Da.trk, Da.ep, t, ep); + } + UndoEnd(); + } else if (Da.curveData.type == curveTypeCurve) { + if ((d = Da.curveData.curveRadius * Da.curveData.a1 *2.0*M_PI/360.0) < minLength) { + ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) ); + return C_TERMINATE; + } + UndoStart( _("Create Curved Track"), "newCurve - curve" ); + t = NewCurvedTrack( Da.curveData.curvePos, Da.curveData.curveRadius, + Da.curveData.a0, Da.curveData.a1, 0 ); + if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) { + EPINX_T ep = PickUnconnectedEndPoint(Da.pos0, t); + if (ep != -1) ConnectTracks(Da.trk, Da.ep, t, ep); } - DrawNewTrack( t ); - return C_TERMINATE; + UndoEnd(); + } else { + return C_ERROR; } + DrawNewTrack( t ); + return C_TERMINATE; case C_REDRAW: if ( Da.state >= 0 ) { - mainD.funcs->options = wDrawOptTemp; - DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); + DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); mainD.funcs->options = 0; } + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); return C_CONTINUE; case C_CANCEL: if (Da.state == 1) { - mainD.funcs->options = wDrawOptTemp; - DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - mainD.funcs->options = 0; tempSegs_da.cnt = 0; Da.trk = NULL; } + DYNARR_RESET(trkSeg_t,anchors_da); + DYNARR_RESET(trkSeg_t,tempSegs_da); Da.state = -1; + segCnt = 0; return C_CONTINUE; } @@ -581,7 +754,6 @@ static void ComputeHelix( static void HelixCancel( wWin_p win ) { wHide( helixW ); - Reset(); } @@ -610,30 +782,30 @@ static STATUS_T CmdCircleCommon( wAction_t action, coOrd pos, BOOL_T helix ) case C_START: if (helix) { if (helixW == NULL) - helixW = ParamCreateDialog( &helixPG, MakeWindowTitle(_("Helix")), NULL, NULL, HelixCancel, TRUE, NULL, 0, ComputeHelix ); - ParamLoadControls( &helixPG ); - ParamGroupRecord( &helixPG ); - ComputeHelix( NULL, 6, NULL ); - wShow( helixW ); - memset( h_orders, 0, sizeof h_orders ); + helixW = ParamCreateDialog(&helixPG, MakeWindowTitle(_("Helix")), NULL, NULL, HelixCancel, TRUE, NULL, 0, ComputeHelix); + ParamLoadControls(&helixPG); + ParamGroupRecord(&helixPG); + ComputeHelix(NULL, 6, NULL); + wShow(helixW); + memset(h_orders, 0, sizeof h_orders); h_clock = 0; } else { - ParamLoadControls( &circleRadiusPG ); - ParamGroupRecord( &circleRadiusPG ); - switch ( circleMode ) { + ParamLoadControls(&circleRadiusPG); + ParamGroupRecord(&circleRadiusPG); + switch (circleMode) { case circleCmdFixedRadius: controls[0] = circleRadiusPLs[0].control; controls[1] = NULL; labels[0] = N_("Circle Radius"); - InfoSubstituteControls( controls, labels ); + InfoSubstituteControls(controls, labels); break; case circleCmdFromTangent: - InfoSubstituteControls( NULL, NULL ); - InfoMessage( _("Click on Circle Edge") ); + InfoSubstituteControls(NULL, NULL); + InfoMessage(_("Click on Circle Edge")); break; case circleCmdFromCenter: - InfoSubstituteControls( NULL, NULL ); - InfoMessage( _("Click on Circle Center") ); + InfoSubstituteControls(NULL, NULL); + InfoMessage(_("Click on Circle Center")); break; } } @@ -641,98 +813,95 @@ static STATUS_T CmdCircleCommon( wAction_t action, coOrd pos, BOOL_T helix ) return C_CONTINUE; case C_DOWN: - DYNARR_SET( trkSeg_t, tempSegs_da, 1 ); + DYNARR_SET(trkSeg_t, tempSegs_da, 1); tempSegs_da.cnt = 0; if (helix) { if (helixRadius <= 0.0) { - ErrorMessage( MSG_RADIUS_GTR_0 ); + ErrorMessage(MSG_RADIUS_GTR_0); return C_ERROR; } if (helixTurns <= 0) { - ErrorMessage( MSG_HELIX_TURNS_GTR_0 ); + ErrorMessage(MSG_HELIX_TURNS_GTR_0); return C_ERROR; } - ParamLoadData( &helixPG ); + ParamLoadData(&helixPG); } else { - ParamLoadData( &circleRadiusPG ); - switch( circleMode ) { + ParamLoadData(&circleRadiusPG); + switch (circleMode) { case circleCmdFixedRadius: if (circleRadius <= 0.0) { - ErrorMessage( MSG_RADIUS_GTR_0 ); + ErrorMessage(MSG_RADIUS_GTR_0); return C_ERROR; } break; case circleCmdFromTangent: - InfoSubstituteControls( NULL, NULL ); - InfoMessage( _("Drag to Center") ); + InfoSubstituteControls(NULL, NULL); + InfoMessage(_("Drag to Center")); break; case circleCmdFromCenter: - InfoSubstituteControls( NULL, NULL ); - InfoMessage( _("Drag to Edge") ); + InfoSubstituteControls(NULL, NULL); + InfoMessage(_("Drag to Edge")); break; } } - SnapPos( &pos ); + SnapPos(&pos); tempSegs(0).u.c.center = pos0 = pos; tempSegs(0).color = wDrawColorBlack; tempSegs(0).width = 0; return C_CONTINUE; case C_MOVE: - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - SnapPos( &pos ); + SnapPos(&pos); tempSegs(0).u.c.center = pos; - if ( !helix ) { - switch ( circleMode ) { + if (!helix) { + switch (circleMode) { case circleCmdFixedRadius: break; case circleCmdFromCenter: tempSegs(0).u.c.center = pos0; - circleRadius = FindDistance( tempSegs(0).u.c.center, pos ); - InfoMessage( _("Radius=%s"), FormatDistance(circleRadius) ); + circleRadius = FindDistance(tempSegs(0).u.c.center, pos); + InfoMessage(_("Radius=%s"), FormatDistance(circleRadius)); break; case circleCmdFromTangent: - circleRadius = FindDistance( tempSegs(0).u.c.center, pos0 ); - InfoMessage( _("Radius=%s"), FormatDistance(circleRadius) ); + circleRadius = FindDistance(tempSegs(0).u.c.center, pos0); + InfoMessage(_("Radius=%s"), FormatDistance(circleRadius)); break; } } tempSegs(0).type = SEG_CRVTRK; - tempSegs(0).u.c.radius = helix?helixRadius:circleRadius; + tempSegs(0).u.c.radius = helix ? helixRadius : circleRadius; tempSegs(0).u.c.a0 = 0.0; tempSegs(0).u.c.a1 = 360.0; tempSegs_da.cnt = 1; - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); return C_CONTINUE; case C_UP: - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - if (helixRadius > mapD.size.x && helixRadius > mapD.size.y) { - ErrorMessage( MSG_RADIUS_TOO_BIG ); - return C_ERROR; - } - if (circleRadius > mapD.size.x && circleRadius > mapD.size.y) { - ErrorMessage( MSG_RADIUS_TOO_BIG ); - return C_ERROR; - } - if ( helix ) { + if (helix) { + if (helixRadius > mapD.size.x || helixRadius > mapD.size.y) { + ErrorMessage(MSG_RADIUS_TOO_BIG); + return C_ERROR; + } if (helixRadius > 10000) { - ErrorMessage( MSG_RADIUS_GTR_10000 ); + ErrorMessage(MSG_RADIUS_GTR_10000); return C_ERROR; } - UndoStart( _("Create Helix Track"), "newHelix" ); - t = NewCurvedTrack( tempSegs(0).u.c.center, helixRadius, 0.0, 0.0, helixTurns ); + UndoStart(_("Create Helix Track"), "newHelix"); + t = NewCurvedTrack(tempSegs(0).u.c.center, helixRadius, 0.0, 0.0, helixTurns); } else { - if ( circleRadius <= 0 ) { - ErrorMessage( MSG_RADIUS_GTR_0 ); + if (circleRadius > mapD.size.x || circleRadius > mapD.size.y) { + ErrorMessage(MSG_RADIUS_TOO_BIG); + return C_ERROR; + } + if (circleRadius <= 0) { + ErrorMessage(MSG_RADIUS_GTR_0); return C_ERROR; } if ((circleRadius > 100000) || (helixRadius > 10000)) { - ErrorMessage( MSG_RADIUS_GTR_10000 ); + ErrorMessage(MSG_RADIUS_GTR_10000); return C_ERROR; } - UndoStart( _("Create Circle Track"), "newCircle" ); - t = NewCurvedTrack( tempSegs(0).u.c.center, circleRadius, 0.0, 0.0, 0 ); + UndoStart(_("Create Circle Track"), "newCircle"); + t = NewCurvedTrack(tempSegs(0).u.c.center, circleRadius, 0.0, 0.0, 0); } UndoEnd(); DrawNewTrack(t); @@ -779,19 +948,21 @@ static STATUS_T CmdHelix( wAction_t action, coOrd pos ) #include "bitmaps/curve3.xpm" #include "bitmaps/curve4.xpm" #include "bitmaps/bezier.xpm" +#include "bitmaps/cornu.xpm" #include "bitmaps/circle1.xpm" #include "bitmaps/circle2.xpm" #include "bitmaps/circle3.xpm" EXPORT void InitCmdCurve( wMenu_p menu ) { + AddMenuButton( menu, CmdCornu, "cmdCornu", _("Cornu Curve"), wIconCreatePixMap(cornu_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CORNU, (void*)cornuCmdCreateTrack); ButtonGroupBegin( _("Curve Track"), "cmdCircleSetCmd", _("Curve Tracks") ); - AddMenuButton( menu, CmdCurve, "cmdCurveEndPt", _("Curve from End-Pt"), wIconCreatePixMap( curve1_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE1, (void*)0 ); - AddMenuButton( menu, CmdCurve, "cmdCurveTangent", _("Curve from Tangent"), wIconCreatePixMap( curve2_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE2, (void*)1 ); - AddMenuButton( menu, CmdCurve, "cmdCurveCenter", _("Curve from Center"), wIconCreatePixMap( curve3_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE3, (void*)2 ); - AddMenuButton( menu, CmdCurve, "cmdCurveChord", _("Curve from Chord"), wIconCreatePixMap( curve4_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE4, (void*)3 ); - AddMenuButton( menu, CmdBezCurve, "cmdBezier", _("Bezier Curve"), wIconCreatePixMap(bezier_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_BEZIER, (void*)bezCmdCreateTrack ); + AddMenuButton( menu, CmdCurve, "cmdCurveEndPt", _("Curve from End-Pt"), wIconCreatePixMap( curve1_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CURVE1, (void*)0 ); + AddMenuButton( menu, CmdCurve, "cmdCurveTangent", _("Curve from Tangent"), wIconCreatePixMap( curve2_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CURVE2, (void*)1 ); + AddMenuButton( menu, CmdCurve, "cmdCurveCenter", _("Curve from Center"), wIconCreatePixMap( curve3_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CURVE3, (void*)2 ); + AddMenuButton( menu, CmdCurve, "cmdCurveChord", _("Curve from Chord"), wIconCreatePixMap( curve4_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_CURVE4, (void*)3 ); + AddMenuButton( menu, CmdBezCurve, "cmdBezier", _("Bezier Curve"), wIconCreatePixMap(bezier_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_BEZIER, (void*)bezCmdCreateTrack ); ButtonGroupEnd(); ButtonGroupBegin( _("Circle Track"), "cmdCurveSetCmd", _("Circle Tracks") ); @@ -816,7 +987,7 @@ EXPORT void InitCmdCurve( wMenu_p menu ) void InitCmdHelix(wMenu_p menu) { AddMenuButton(menu, CmdHelix, "cmdHelix", _("Helix"), NULL, LEVEL0_50, - IC_STICKY|IC_POPUP2, ACCL_HELIX, NULL); + IC_STICKY|IC_INITNOTSTICKY|IC_POPUP2, ACCL_HELIX, NULL); ParamRegister(&helixPG); RegisterChangeNotification(ChangeHelixW); } diff --git a/app/bin/ccurve.h b/app/bin/ccurve.h index c9d1c8c..0c00c46 100644 --- a/app/bin/ccurve.h +++ b/app/bin/ccurve.h @@ -32,6 +32,7 @@ typedef struct { curveType_e type; coOrd curvePos; coOrd pos1; + coOrd pos2; DIST_T curveRadius; ANGLE_T a0, a1; BOOL_T negative; @@ -48,13 +49,14 @@ typedef struct { #define circleCmdFromCenter (2) typedef void (*curveMessageProc)( char *, ... ); -STATUS_T CreateCurve( wAction_t, coOrd, BOOL_T, wDrawColor, DIST_T, long, curveMessageProc ); +STATUS_T CreateCurve( wAction_t, coOrd, BOOL_T, wDrawColor, DIST_T, long, dynArr_t *,curveMessageProc ); int IsCurveCircle( track_p ); void PlotCurve( long, coOrd, coOrd, coOrd, curveData_t *, BOOL_T ); track_p NewCurvedTrack( coOrd, DIST_T, ANGLE_T, ANGLE_T, long ); -DIST_T CurveDescriptionDistance( coOrd, track_p ); +DIST_T CurveDescriptionDistance( coOrd, track_p, coOrd *, BOOL_T, BOOL_T * ); STATUS_T CurveDescriptionMove( track_p, wAction_t, coOrd ); BOOL_T GetCurveMiddle( track_p , coOrd * ); -void DrawArrowHeads(trkSeg_p sp, coOrd pos, ANGLE_T angle, BOOL_T bidirectional, wDrawColor color ); +int DrawArrowHeads(trkSeg_p sp, coOrd pos, ANGLE_T angle, BOOL_T bidirectional, wDrawColor color ); +int DrawArrowHeadsArray(dynArr_t *anchor_array,coOrd pos,ANGLE_T angle,BOOL_T bidirectional,wDrawColor color ); #endif // !HAVE_CCURVE_H diff --git a/app/bin/cdraw.c b/app/bin/cdraw.c index 9bddcaf..6bb4c4a 100644 --- a/app/bin/cdraw.c +++ b/app/bin/cdraw.c @@ -23,6 +23,7 @@ #include #include #include +#include "wlib.h" #include "ccurve.h" #include "cbezier.h" @@ -37,7 +38,31 @@ extern TRKTYP_T T_BZRLIN; -extern void wSetSelectedFontSize(int size); +static wMenu_p drawModDelMI; +static wMenu_p drawModLinMI; +static wMenuPush_p drawModDel; +static wMenuPush_p drawModSmooth; +static wMenuPush_p drawModVertex; +static wMenuPush_p drawModRound; +static wMenuPush_p drawModriginMode; +static wMenuPush_p drawModPointsMode; +static wMenuPush_p drawModOrigin; +static wMenuPush_p drawModLast; +static wMenuPush_p drawModCenter; +static wMenuPush_p drawModClose; +static wMenuPush_p drawModOpen; +static wMenuPush_p drawModFill; +static wMenuPush_p drawModEmpty; +static wMenuPush_p drawModSolid; +static wMenuPush_p drawModDot; +static wMenuPush_p drawModDash; +static wMenuPush_p drawModDashDot; +static wMenuPush_p drawModDashDotDot; +static wMenuPush_p drawModCenterDot; +static wMenuPush_p drawModPhantom; + + +extern void wSetSelectedFontSize(wFontSize_t size); static long fontSizeList[] = { 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, @@ -111,7 +136,7 @@ EXPORT void UpdateFontSizeList( *fontSizeR = fontSize; /* inform gtkfont dialog from change */ - wSetSelectedFontSize((int)fontSize); + wSetSelectedFontSize((wFontSize_t)fontSize); /*LoadFontSizeList( list, *fontSizeR );*/ } else { sprintf( message, "%ld", *fontSizeR ); @@ -128,9 +153,11 @@ EXPORT void UpdateFontSizeList( * */ + struct extraData { coOrd orig; ANGLE_T angle; + drawLineType_e lineType; wIndex_t segCnt; trkSeg_t segs[1]; }; @@ -167,12 +194,13 @@ static track_p MakeDrawFromSeg1( xx->orig = pos; xx->angle = angle; xx->segCnt = 1; + xx->lineType = DRAWLINESOLID; memcpy( xx->segs, sp, sizeof *(trkSeg_p)0 ); if (xx->segs[0].type == SEG_POLY || - xx->segs[0].type == SEG_FILPOLY) { - xx->segs[0].u.p.pts = (coOrd*)MyMalloc( (sp->u.p.cnt) * sizeof (coOrd) ); - memcpy(xx->segs[0].u.p.pts, sp->u.p.pts, sp->u.p.cnt * sizeof (coOrd) ); + xx->segs[0].type == SEG_FILPOLY ) { + xx->segs[0].u.p.pts = (pts_t*)MyMalloc( (sp->u.p.cnt) * sizeof (pts_t) ); + memcpy(xx->segs[0].u.p.pts, sp->u.p.pts, sp->u.p.cnt * sizeof (pts_t) ); } if (xx->segs[0].type == SEG_TEXT) { xx->segs[0].u.t.string = MyStrdup(sp->u.t.string); @@ -189,6 +217,254 @@ EXPORT track_p MakeDrawFromSeg( return MakeDrawFromSeg1( 0, pos, angle, sp ); } +int SliceCuts(ANGLE_T a, DIST_T radius) { + double Error = 0.05; + double Error_angle = acos(1-(Error/fabs(radius))); + if (Error_angle <0.0001) return 0; + return (int)(floor(D2R(a)/(2*Error_angle))); +} + +/* Only straight, curved and PolyLine */ +EXPORT track_p MakePolyLineFromSegs( + coOrd pos, + ANGLE_T angle, + dynArr_t * segsArr) +{ + struct extraData * xx; + track_p trk; + trk = NewTrack( 0, T_DRAW, 0, sizeof *xx ); + xx = GetTrkExtraData( trk ); + xx->orig = pos; + xx->angle = angle; + xx->lineType = DRAWLINESOLID; + xx->segCnt = 1; + xx->segs[0].type = SEG_POLY; + xx->segs[0].width = 0; + xx->segs[0].u.p.polyType = POLYLINE; + xx->segs[0].color = wDrawColorBlack; + coOrd last; + BOOL_T first = TRUE; + int cnt = 0; + for (int i=0;icnt;i++) { + trkSeg_p sp = &DYNARR_N(trkSeg_t,*segsArr,i); + if (sp->type == SEG_BEZLIN || sp->type == SEG_BEZTRK ) { + for (int j=0;jbezSegs.cnt;j++) { + trkSeg_p spb = &DYNARR_N(trkSeg_t,sp->bezSegs,j); + if (spb->type == SEG_STRLIN || spb->type == SEG_STRTRK) { + if (!first && IsClose(FindDistance(spb->u.l.pos[0], last))) + cnt++; + else + cnt=cnt+2; + last = spb->u.l.pos[1]; + first = FALSE; + } + else if (spb->type == SEG_CRVLIN || spb->type == SEG_CRVTRK) { + coOrd this; + if (spb->u.c.radius >= 0.0) + Translate(&this, spb->u.c.center, spb->u.c.a0, fabs(spb->u.c.radius)); + else + Translate(&this, spb->u.c.center, spb->u.c.a0+spb->u.c.a1, fabs(spb->u.c.radius)); + if (first || !IsClose(FindDistance(this, last))) { + cnt++; //Add first point + } + cnt += 1 + SliceCuts(spb->u.c.a1,spb->u.c.radius); + if (spb->u.c.radius >= 0.0) + Translate(&last, spb->u.c.center, spb->u.c.a0+spb->u.c.a1, fabs(spb->u.c.radius)); + else + Translate(&last, spb->u.c.center, spb->u.c.a0, fabs(spb->u.c.radius)); + first = FALSE; + } + } + } + else if (sp->type == SEG_STRLIN || sp->type == SEG_STRTRK) { + if (!first && IsClose(FindDistance(sp->u.l.pos[0], last))) + cnt++; + else + cnt=cnt+2; + last = sp->u.l.pos[1]; + first = FALSE; + } + else if (sp->type == SEG_CRVLIN || sp->type == SEG_CRVTRK) { + coOrd this; + if (sp->u.c.radius >= 0.0) + Translate(&this, sp->u.c.center, sp->u.c.a0, fabs(sp->u.c.radius)); + else + Translate(&this, sp->u.c.center, sp->u.c.a0+sp->u.c.a1, fabs(sp->u.c.radius)); + if (first || !IsClose(FindDistance(this, last))) { + cnt++; //Add first point + } + cnt += 1+ SliceCuts(sp->u.c.a1,sp->u.c.radius); + if (sp->u.c.radius >= 0.0) + Translate(&last, sp->u.c.center, sp->u.c.a0+sp->u.c.a1, fabs(sp->u.c.radius)); + else + Translate(&last, sp->u.c.center, sp->u.c.a0, fabs(sp->u.c.radius)); + first = FALSE; + } + else if (sp->type == SEG_POLY) { + if (!first && IsClose(FindDistance(sp->u.p.pts[0].pt, last))) + cnt = cnt + sp->u.p.cnt-1; + else + cnt = cnt + sp->u.p.cnt; + last = sp->u.p.pts[sp->u.p.cnt-1].pt; + first = FALSE; + } + } + xx->segs[0].u.p.cnt = cnt; + xx->segs[0].u.p.pts = (pts_t*)MyMalloc( (cnt) * sizeof (pts_t) ); + first = TRUE; + int j =0; + for (int i=0;icnt;i++) { + trkSeg_p sp = &DYNARR_N(trkSeg_t,*segsArr,i); + if (sp->type == SEG_BEZLIN || sp->type == SEG_BEZTRK ) { + for (int l=0;lbezSegs.cnt;l++) { + trkSeg_p spb = &DYNARR_N(trkSeg_t,sp->bezSegs,l); + if (spb->type == SEG_STRLIN || spb->type == SEG_STRTRK) { + if (first || !IsClose(FindDistance(spb->u.l.pos[0], last))) { + xx->segs[0].u.p.pts[j].pt = spb->u.l.pos[0]; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + j++; + } + xx->segs[0].u.p.pts[j].pt = spb->u.l.pos[1]; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + last = xx->segs[0].u.p.pts[j].pt; + j ++; + first = FALSE; + } + if (spb->type == SEG_CRVLIN || spb->type == SEG_CRVTRK) { + coOrd this; + if (spb->u.c.radius>=0.0) + Translate(&this, spb->u.c.center, spb->u.c.a0, fabs(spb->u.c.radius)); + else + Translate(&this, spb->u.c.center, spb->u.c.a0+spb->u.c.a1, fabs(spb->u.c.radius)); + if (first || !IsClose(FindDistance(this, last))) { + xx->segs[0].u.p.pts[j].pt= this; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + j++; + } + int slices = SliceCuts(spb->u.c.a1,spb->u.c.radius); + for (int k=1; ku.c.radius>=0.0) + Translate(&xx->segs[0].u.p.pts[j].pt, spb->u.c.center, spb->u.c.a0+(k*(spb->u.c.a1/(slices))), fabs(spb->u.c.radius)); + else + Translate(&xx->segs[0].u.p.pts[j].pt, spb->u.c.center, spb->u.c.a0+((slices-k)*(spb->u.c.a1/(slices))), fabs(spb->u.c.radius)); + xx->segs[0].u.p.pts[j].pt_type = wPolyLineSmooth; + j++; + } + if (spb->u.c.radius>=0.0) + Translate(&xx->segs[0].u.p.pts[j].pt, spb->u.c.center, spb->u.c.a0+spb->u.c.a1, fabs(spb->u.c.radius)); + else + Translate(&xx->segs[0].u.p.pts[j].pt, spb->u.c.center, spb->u.c.a0, fabs(spb->u.c.radius)); + + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + last = xx->segs[0].u.p.pts[j].pt; + j++; + first = FALSE; + } + } + } + if (sp->type == SEG_STRLIN || sp->type == SEG_STRTRK) { + if (first || !IsClose(FindDistance(sp->u.l.pos[0], last))) { + xx->segs[0].u.p.pts[j].pt = sp->u.l.pos[0]; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + j++; + } + xx->segs[0].u.p.pts[j].pt = last = sp->u.l.pos[1]; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + last = xx->segs[0].u.p.pts[j].pt; + j++; + first = FALSE; + } + if (sp->type == SEG_CRVLIN || sp->type == SEG_CRVTRK) { + coOrd this; + if (sp->u.c.radius>0) + Translate(&this, sp->u.c.center, sp->u.c.a0, fabs(sp->u.c.radius)); + else + Translate(&this, sp->u.c.center, sp->u.c.a0+sp->u.c.a1, fabs(sp->u.c.radius)); + if (first || !IsClose(FindDistance(this, last))) { + xx->segs[0].u.p.pts[j].pt= this; + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + j++; + } + int slices = SliceCuts(sp->u.c.a1,sp->u.c.radius); + + for (int k=1; ku.c.radius>0) + Translate(&xx->segs[0].u.p.pts[j].pt, sp->u.c.center, sp->u.c.a0+(k*(sp->u.c.a1/(slices))), fabs(sp->u.c.radius)); + else + Translate(&xx->segs[0].u.p.pts[j].pt, sp->u.c.center, sp->u.c.a0+((slices-k)*(sp->u.c.a1/(slices))), fabs(sp->u.c.radius)); + xx->segs[0].u.p.pts[j].pt_type = wPolyLineSmooth; + j++; + } + if (sp->u.c.radius>0) + Translate(&xx->segs[0].u.p.pts[j].pt, sp->u.c.center, sp->u.c.a0+sp->u.c.a1, fabs(sp->u.c.radius)); + else + Translate(&xx->segs[0].u.p.pts[j].pt, sp->u.c.center, sp->u.c.a0, fabs(sp->u.c.radius)); + + xx->segs[0].u.p.pts[j].pt_type = wPolyLineStraight; + last = xx->segs[0].u.p.pts[j].pt; + j++; + first = FALSE; + } + if (sp->type == SEG_POLY) { + if (first || !IsClose(FindDistance(sp->u.p.pts[0].pt, last))) { + xx->segs[0].u.p.pts[j] = sp->u.p.pts[0]; + j++; + } + memcpy(&xx->segs[0].u.p.pts[j],&sp->u.p.pts[1], (sp->u.p.cnt-1) * sizeof (pts_t)); + last = xx->segs[0].u.p.pts[sp->u.p.cnt-1].pt; + j +=sp->u.p.cnt-1; + first = FALSE; + } + ASSERT(j<=cnt); + + } + xx->segs[0].u.p.cnt = j; + + if (IsClose(FindDistance(xx->segs[0].u.p.pts[0].pt,xx->segs[0].u.p.pts[xx->segs[0].u.p.cnt-1].pt))) { + xx->segs[0].u.p.polyType = FREEFORM; + xx->segs[0].u.p.cnt = xx->segs[0].u.p.cnt-1; + } + + ComputeDrawBoundingBox( trk ); + return trk; +} + + +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) + +void static CreateOriginAnchor(coOrd origin, wBool_t trans_selected) { + double d = tempD.scale*0.15; + DYNARR_APPEND(trkSeg_t,anchors_da,2); + int i = anchors_da.cnt-1; + coOrd p0,p1; + Translate(&p0,origin,0,d*4); + Translate(&p1,origin,0,-d*4); + anchors(i).type = SEG_STRLIN; + anchors(i).u.l.pos[0] = p0; + anchors(i).u.l.pos[1] = p1; + anchors(i).color = wDrawColorBlue; + anchors(i).width = 0; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + Translate(&p0,origin,90,d*4); + Translate(&p1,origin,90,-d*4); + i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).u.l.pos[0] = p0; + anchors(i).u.l.pos[1] = p1; + anchors(i).color = wDrawColorBlue; + anchors(i).width = 0; +} + +EXPORT void DrawOriginAnchor(track_p trk) { + if (!trk || GetTrkType(trk) != T_DRAW) return; + struct extraData * xx = GetTrkExtraData(trk); + if ((xx->orig.x != 0.0) || (xx->orig.y !=0.0) ) { + DYNARR_RESET(trkSeg_t,anchors_da); + CreateOriginAnchor(xx->orig,FALSE); + DrawSegs(&tempD, zero, 0.0, anchors_da.ptr, anchors_da.cnt, trackGauge, wDrawColorBlue); + } +} @@ -204,15 +480,27 @@ static DIST_T DistanceDraw( track_p t, coOrd * p ) static struct { - coOrd endPt[2]; + coOrd endPt[4]; + coOrd origin; + coOrd oldOrigin; + coOrd oldE0; + coOrd oldE1; FLOAT_T length; + FLOAT_T height; + FLOAT_T width; coOrd center; DIST_T radius; ANGLE_T angle0; ANGLE_T angle1; ANGLE_T angle; + ANGLE_T rotate_angle; + ANGLE_T oldAngle; long pointCount; long lineWidth; + BOOL_T boxed; + BOOL_T filled; + BOOL_T open; + BOOL_T lock_origin; wDrawColor color; wIndex_t benchChoice; wIndex_t benchOrient; @@ -221,21 +509,31 @@ static struct { wIndex_t fontSizeInx; char text[STR_LONG_SIZE]; unsigned int layer; - char polyType[STR_SIZE]; + wIndex_t lineType; } drawData; -typedef enum { E0, E1, CE, RA, LN, AL, A1, A2, VC, LW, CO, BE, OR, DS, TP, TA, TS, TX, PV, LY, PT } drawDesc_e; +typedef enum { E0, E1, PP, CE, AL, A1, A2, RD, LN, HT, WT, LK, OI, RA, VC, LW, LT, CO, FL, OP, BX, BE, OR, DS, TP, TA, TS, TX, PV, LY } drawDesc_e; static descData_t drawDesc[] = { /*E0*/ { DESC_POS, N_("End Pt 1: X,Y"), &drawData.endPt[0] }, /*E1*/ { DESC_POS, N_("End Pt 2: X,Y"), &drawData.endPt[1] }, +/*PP*/ { DESC_POS, N_("First Point: X,Y"), &drawData.endPt[0] }, /*CE*/ { DESC_POS, N_("Center: X,Y"), &drawData.center }, -/*RA*/ { DESC_DIM, N_("Radius"), &drawData.radius }, -/*LN*/ { DESC_DIM, N_("Length"), &drawData.length }, /*AL*/ { DESC_FLOAT, N_("Angle"), &drawData.angle }, /*A1*/ { DESC_ANGLE, N_("CCW Angle"), &drawData.angle0 }, /*A2*/ { DESC_ANGLE, N_("CW Angle"), &drawData.angle1 }, +/*RD*/ { DESC_DIM, N_("Radius"), &drawData.radius }, +/*LN*/ { DESC_DIM, N_("Length"), &drawData.length }, +/*HT*/ { DESC_DIM, N_("Height"), &drawData.height }, +/*WT*/ { DESC_DIM, N_("Width"), &drawData.width }, +/*LK*/ { DESC_BOXED, N_("Keep Origin Relative"), &drawData.lock_origin}, +/*OI*/ { DESC_POS, N_("Rot Origin: X,Y"), &drawData.origin }, +/*RA*/ { DESC_FLOAT, N_("Rotate Angle"), &drawData.angle }, /*VC*/ { DESC_LONG, N_("Point Count"), &drawData.pointCount }, /*LW*/ { DESC_LONG, N_("Line Width"), &drawData.lineWidth }, +/*LT*/ { DESC_LIST, N_("Line Type"), &drawData.lineType }, /*CO*/ { DESC_COLOR, N_("Color"), &drawData.color }, +/*FL*/ { DESC_BOXED, N_("Filled"), &drawData.filled }, +/*OP*/ { DESC_BOXED, N_("Open End"), &drawData.open }, +/*BX*/ { DESC_BOXED, N_("Boxed"), &drawData.boxed }, /*BE*/ { DESC_LIST, N_("Lumber"), &drawData.benchChoice }, /*OR*/ { DESC_LIST, N_("Orientation"), &drawData.benchOrient }, /*DS*/ { DESC_LIST, N_("Size"), &drawData.dimenSize }, @@ -245,9 +543,8 @@ static descData_t drawDesc[] = { /*TX*/ { DESC_TEXT, N_("Text"), &drawData.text }, /*PV*/ { DESC_PIVOT, N_("Pivot"), &drawData.pivot }, /*LY*/ { DESC_LAYER, N_("Layer"), &drawData.layer }, -/*PT*/ { DESC_STRING, N_("Type"), &drawData.polyType }, { DESC_NULL } }; -int drawSegInx; +static int drawSegInx; #define UNREORIGIN( Q, P, A, O ) { \ (Q) = (P); \ @@ -257,6 +554,23 @@ int drawSegInx; Rotate( &(Q), zero, -(A) ); \ } +/* + * Notes - + * + * In V5.1, Origin was always {0,0} and Angle 0.0 after editing a Draw object. + * This did not allow for the use of the objects in other contexts (such as Signal Arms). + * + * In V5.2 - + * + * OI - Origin will be adjusted if it is locked to remain relative to the end point - this equally applies when moving the object points. + * If not locked, the object points will be set relative to the new origin value, + * so that the object remains at the same place as the user specifies. + * If the edit starts with origin {0,0}, it will be set unlocked, otherwise set locked. + * + * AL- Angle will be set to 0.0 when the object is modified. The points of the objects will be rotated so that + * rotated and adjusted so they don't need rotation to lie where the user left them. + * + */ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) { struct extraData *xx = GetTrkExtraData(trk); @@ -271,9 +585,9 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) if (segPtr->type != SEG_TEXT) return; else inx = TX; //Always look at TextField for SEG_TEXT on "Done" } - MainRedraw(); - MapRedraw(); UndrawNewTrack( trk ); + coOrd pt; + coOrd off; switch ( inx ) { case LW: segPtr->width = drawData.lineWidth/mainD.dpi; @@ -284,37 +598,251 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) case E0: case E1: if ( inx == E0 ) { - UNREORIGIN( segPtr->u.l.pos[0], drawData.endPt[0], xx->angle, xx->orig ); - } else { - UNREORIGIN( segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + coOrd off; + off.x = drawData.endPt[0].x - drawData.oldE0.x; + off.y = drawData.endPt[0].y - drawData.oldE0.y; + if (drawData.lock_origin) { + xx->orig.x +=off.x; + xx->orig.y +=off.y; + drawDesc[OI].mode |= DESC_CHANGE; + } else { + switch(segPtr->type) { //E0 does not alter length - translates + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + UNREORIGIN( segPtr->u.l.pos[0], drawData.endPt[0], xx->angle, xx->orig ); + drawData.endPt[1].x = off.x+drawData.endPt[1].x; + drawData.endPt[1].y = off.y+drawData.endPt[1].y; + UNREORIGIN( segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + drawDesc[E1].mode |= DESC_CHANGE; + break; + case SEG_CRVLIN: + case SEG_FILCRCL: + UNREORIGIN( segPtr->u.c.center, drawData.endPt[0], xx->angle, xx->orig ); + break; + case SEG_TEXT: + UNREORIGIN( segPtr->u.t.pos, drawData.endPt[0], xx->angle, xx->orig ); + break; + case SEG_POLY: + case SEG_FILPOLY: + break; //Note not used by POLYGONS + default:; + } + } + } else { //E1 - alters length + off.x = drawData.endPt[1].x - drawData.oldE1.x; + off.y = drawData.endPt[1].y - drawData.oldE1.y; + drawDesc[E1].mode |= DESC_CHANGE; + if (drawData.lock_origin) { + xx->orig.x +=off.x; + xx->orig.y +=off.y; + drawDesc[OI].mode |= DESC_CHANGE; + } else { + UNREORIGIN( segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + } } drawData.length = FindDistance( drawData.endPt[0], drawData.endPt[1] ); - drawData.angle = FindAngle( drawData.endPt[0], drawData.endPt[1] ); drawDesc[LN].mode |= DESC_CHANGE; - drawDesc[AL].mode |= DESC_CHANGE; break; - case LN: - case AL: - if ( segPtr->type == SEG_CRVLIN && inx == AL ) { - if ( drawData.angle <= 0.0 || drawData.angle >= 360.0 ) { - ErrorMessage( MSG_CURVE_OUT_OF_RANGE ); - drawData.angle = segPtr->u.c.a1; - drawDesc[AL].mode |= DESC_CHANGE; + case OI: + off.x = drawData.origin.x - drawData.oldOrigin.x; + off.y = drawData.origin.y - drawData.oldOrigin.y; + xx->orig = drawData.origin; + if (!drawData.lock_origin) { + switch(segPtr->type) { + case SEG_POLY: + case SEG_FILPOLY: + for (int i=0;iu.p.cnt;i++) { + REORIGIN( pt, segPtr->u.p.pts[i].pt, xx->angle, drawData.oldOrigin); + UNREORIGIN( segPtr->u.p.pts[i].pt, pt, xx->angle, xx->orig ); + } break; + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + for (int i=0;i<2;i++) { + UNREORIGIN( segPtr->u.l.pos[i], drawData.endPt[i], xx->angle, xx->orig ); + } + break; + case SEG_CRVLIN: + case SEG_FILCRCL: + UNREORIGIN( segPtr->u.c.center, drawData.center, xx->angle, xx->orig ); + break; + case SEG_TEXT: + UNREORIGIN( segPtr->u.t.pos, drawData.endPt[0], xx->angle, xx->orig ); + break; + default:; } } else { - if ( drawData.length <= minLength ) { - ErrorMessage( MSG_OBJECT_TOO_SHORT ); - if ( segPtr->type != SEG_CRVLIN ) { - drawData.length = FindDistance( drawData.endPt[0], drawData.endPt[1] ); + drawData.endPt[0].x += off.x; + drawData.endPt[0].y += off.y; + switch(segPtr->type) { + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + drawDesc[E0].mode |= DESC_CHANGE; + UNREORIGIN( segPtr->u.l.pos[0], drawData.endPt[0], xx->angle, xx->orig ); + drawData.endPt[1].x = off.x+drawData.endPt[1].x; + drawData.endPt[1].y = off.y+drawData.endPt[1].y; + UNREORIGIN( segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + drawDesc[E1].mode |= DESC_CHANGE; + break; + case SEG_CRVLIN: + case SEG_FILCRCL: + UNREORIGIN( segPtr->u.c.center, drawData.endPt[0], xx->angle, xx->orig ); + drawDesc[E0].mode |= DESC_CHANGE; + break; + case SEG_TEXT: + UNREORIGIN( segPtr->u.t.pos, drawData.endPt[0], xx->angle, xx->orig ); + drawDesc[E0].mode |= DESC_CHANGE; + break; + case SEG_POLY: + case SEG_FILPOLY: + for (int i=0;iu.p.cnt;i++) { + REORIGIN( pt, segPtr->u.p.pts[i].pt, xx->angle, drawData.oldOrigin); + pt.x += off.x; + pt.y += off.y; + UNREORIGIN( segPtr->u.p.pts[i].pt, pt, xx->angle, xx->orig ); + } + drawDesc[PP].mode |= DESC_CHANGE; + break; + default:; + } + } + break; + case HT: + case WT: + if ((segPtr->type == SEG_POLY) || (segPtr->type == SEG_FILPOLY)) { + if (segPtr->u.p.polyType == RECTANGLE) { + if (inx == HT) { + ANGLE_T angle = NormalizeAngle(FindAngle(drawData.endPt[0],drawData.endPt[3])); + Translate( &drawData.endPt[3], drawData.endPt[0], angle, drawData.height); + UNREORIGIN( segPtr->u.p.pts[3].pt, drawData.endPt[3], xx->angle, xx->orig ); + Translate( &drawData.endPt[2], drawData.endPt[1], angle, drawData.height); + UNREORIGIN( segPtr->u.p.pts[2].pt, drawData.endPt[2], xx->angle, xx->orig ); } else { - drawData.length = fabs(segPtr->u.c.radius)*2*M_PI*segPtr->u.c.a1/360.0; + ANGLE_T angle = NormalizeAngle(FindAngle(drawData.endPt[0],drawData.endPt[1]));; + Translate( &drawData.endPt[1], drawData.endPt[0], angle, drawData.width); + UNREORIGIN( segPtr->u.p.pts[1].pt, drawData.endPt[1], xx->angle, xx->orig ); + Translate( &drawData.endPt[2], drawData.endPt[3], angle, drawData.width); + UNREORIGIN( segPtr->u.p.pts[2].pt, drawData.endPt[2], xx->angle, xx->orig ); } - drawDesc[LN].mode |= DESC_CHANGE; + drawDesc[E0].mode |= DESC_CHANGE; + } + } + break; + case RA:; + ANGLE_T angle = NormalizeAngle(drawData.rotate_angle); + switch(segPtr->type) { + case SEG_POLY: + case SEG_FILPOLY: + for (int i=0;iu.p.cnt;i++) { + REORIGIN(pt,segPtr->u.p.pts[i].pt, angle, xx->orig); + if (i == 0) drawData.endPt[0] = pt; + UNREORIGIN(segPtr->u.p.pts[i].pt, pt, 0.0, xx->orig); + } + drawDesc[PP].mode |= DESC_CHANGE; break; + case SEG_CRVLIN:; + coOrd end0, end1; + Translate(&end0,segPtr->u.c.center,segPtr->u.c.a0,segPtr->u.c.radius); + Translate(&end1,segPtr->u.c.center,segPtr->u.c.a0+segPtr->u.c.a1,segPtr->u.c.radius); + REORIGIN(end0, end0, angle, xx->orig ); + REORIGIN(end1, end1, angle, xx->orig ); + REORIGIN( drawData.center,segPtr->u.c.center, angle, xx->orig ); + drawData.angle0 = FindAngle( drawData.center, end0); + drawData.angle1 = FindAngle( drawData.center, end1); + drawDesc[CE].mode |= DESC_CHANGE; + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + /*no break*/ + case SEG_FILCRCL: + REORIGIN( drawData.center,segPtr->u.c.center, angle, xx->orig ); + UNREORIGIN( segPtr->u.c.center, drawData.center, 0.0, xx->orig); //Remove angle + drawDesc[CE].mode |= DESC_CHANGE; + break; + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + for (int i=0;i<2;i++) { + REORIGIN( drawData.endPt[i], segPtr->u.l.pos[i], angle, xx->orig ); + UNREORIGIN(segPtr->u.l.pos[i], drawData.endPt[i], 0.0, xx->orig ); + } + drawDesc[E0].mode |= DESC_CHANGE; + drawDesc[E1].mode |= DESC_CHANGE; + break; + case SEG_TEXT: + + break; + default:; + } + xx->angle = drawData.rotate_angle = 0.0; + drawDesc[RA].mode |= DESC_CHANGE; + break; + case AL:; + angle = NormalizeAngle(drawData.angle); + switch(segPtr->type) { + case SEG_POLY: + case SEG_FILPOLY: + break; //Doesn't Use + case SEG_CRVLIN: + switch ( drawData.pivot ) { + case DESC_PIVOT_FIRST: + segPtr->u.c.a1 = drawData.angle; + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A2].mode |= DESC_CHANGE; + break; + case DESC_PIVOT_SECOND: + segPtr->u.c.a0 = NormalizeAngle( segPtr->u.c.a1+segPtr->u.c.a0-drawData.angle); + segPtr->u.c.a1 = drawData.angle; + drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + break; + case DESC_PIVOT_MID: + segPtr->u.c.a0 = NormalizeAngle( segPtr->u.c.a0+segPtr->u.c.a1/2.0-drawData.angle/2.0); + segPtr->u.c.a1 = drawData.angle; + drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + break; + default: + break; + } + break; + case SEG_FILCRCL: + break; //Doesn't Use + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + Translate(&drawData.endPt[1],drawData.endPt[0],angle,drawData.length); + UNREORIGIN(segPtr->u.l.pos[1], drawData.endPt[1], xx->angle, xx->orig ); + drawDesc[E1].mode |= DESC_CHANGE; + break; + case SEG_TEXT: + break; //Doesnt Use + default:; + } + break; + case LN: + if ( drawData.length <= minLength ) { + ErrorMessage( MSG_OBJECT_TOO_SHORT ); + if ( segPtr->type != SEG_CRVLIN ) { + drawData.length = FindDistance( drawData.endPt[0], drawData.endPt[1] ); + } else { + drawData.length = fabs(segPtr->u.c.radius)*2*M_PI*segPtr->u.c.a1/360.0; } + drawDesc[LN].mode |= DESC_CHANGE; + break; } - if ( segPtr->type != SEG_CRVLIN ) { + if ( segPtr->type != SEG_CRVLIN ) { switch ( drawData.pivot ) { case DESC_PIVOT_FIRST: Translate( &drawData.endPt[1], drawData.endPt[0], drawData.angle, drawData.length ); @@ -340,6 +868,7 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) break; } } else { + if ( drawData.angle < 0.0 || drawData.angle >= 360.0 ) { ErrorMessage( MSG_CURVE_OUT_OF_RANGE ); drawData.angle = segPtr->u.c.a1; @@ -357,13 +886,44 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) case CE: UNREORIGIN( segPtr->u.c.center, drawData.center, xx->angle, xx->orig ); break; - case RA: + case RD: + if ( drawData.pivot == DESC_PIVOT_FIRST ) { + Translate( &segPtr->u.c.center, segPtr->u.c.center, segPtr->u.c.a0, segPtr->u.c.radius-drawData.radius ); + } else if ( drawData.pivot == DESC_PIVOT_SECOND ) { + Translate( &segPtr->u.c.center, segPtr->u.c.center, segPtr->u.c.a0+segPtr->u.c.a1, segPtr->u.c.radius-drawData.radius ); + } else { + Translate( &segPtr->u.c.center, segPtr->u.c.center, (segPtr->u.c.a0+segPtr->u.c.a1)/2.0, segPtr->u.c.radius-drawData.radius ); + } + drawDesc[CE].mode |= DESC_CHANGE; segPtr->u.c.radius = drawData.radius; + drawDesc[LN].mode |= DESC_CHANGE; break; case A1: - segPtr->u.c.a0 = NormalizeAngle( drawData.angle0-xx->angle ); - drawData.angle1 = NormalizeAngle( drawData.angle0+drawData.angle ); - drawDesc[A2].mode |= DESC_CHANGE; + switch ( drawData.pivot ) { + case DESC_PIVOT_FIRST: + segPtr->u.c.a1 = drawData.angle; + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A2].mode |= DESC_CHANGE; + break; + case DESC_PIVOT_SECOND: + segPtr->u.c.a0 = NormalizeAngle( segPtr->u.c.a1+segPtr->u.c.a0-drawData.angle); + segPtr->u.c.a1 = drawData.angle; + drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + break; + case DESC_PIVOT_MID: + segPtr->u.c.a0 = NormalizeAngle( segPtr->u.c.a0+segPtr->u.c.a1/2.0-drawData.angle/2.0); + segPtr->u.c.a1 = drawData.angle; + drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); + drawData.angle1 = NormalizeAngle( drawData.angle0+segPtr->u.c.a1 ); + drawDesc[A1].mode |= DESC_CHANGE; + drawDesc[A2].mode |= DESC_CHANGE; + break; + default: + break; + } break; case A2: segPtr->u.c.a0 = NormalizeAngle( drawData.angle1-segPtr->u.c.a1-xx->angle ); @@ -387,6 +947,28 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) case TP: UNREORIGIN( segPtr->u.t.pos, drawData.endPt[0], xx->angle, xx->orig ); break; + case PP: + off.x = drawData.endPt[0].x - drawData.oldE0.x; + off.y = drawData.endPt[0].y - drawData.oldE0.y; + if (drawData.lock_origin) { + xx->orig.x +=off.x; + xx->orig.y +=off.y; + drawData.origin = xx->orig; + drawDesc[OI].mode |= DESC_CHANGE; + drawDesc[E0].mode |= DESC_CHANGE; + break; + } else { + for (int i=0;iu.p.cnt;i++) { + REORIGIN( pt, segPtr->u.p.pts[i].pt, xx->angle, xx->orig ); + pt.x += off.x; + pt.y += off.y; + if (i<5) drawData.endPt[i] = pt; + UNREORIGIN( segPtr->u.p.pts[i].pt, pt, 0.0, xx->orig ); + } + xx->angle = 0.0; + drawDesc[AL].mode |= DESC_CHANGE; + } + break; case TA: //segPtr->u.t.angle = NormalizeAngle( drawData.angle ); xx->angle = NormalizeAngle( drawData.angle ); @@ -396,6 +978,39 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) UpdateFontSizeList( &fontSize, (wList_p)drawDesc[TS].control0, drawData.fontSizeInx ); segPtr->u.t.fontSize = fontSize; break; + case FL: + if (segPtr->type == SEG_POLY && drawData.open) { + drawData.filled = FALSE; + drawDesc[FL].mode |= DESC_CHANGE; + break; + } + if(drawData.filled) { + if (segPtr->type == SEG_POLY) segPtr->type = SEG_FILPOLY; + if (segPtr->type == SEG_CRVLIN) segPtr->type = SEG_FILCRCL; + } else { + if (segPtr->type == SEG_FILPOLY) segPtr->type = SEG_POLY; + if (segPtr->type == SEG_FILCRCL) { + segPtr->type = SEG_CRVLIN; + segPtr->u.c.a0 = 0.0; + segPtr->u.c.a1 = 360.0; + } + } + break; + case OP: + if (drawData.filled || (segPtr->type != SEG_POLY)) { + drawData.open = FALSE; + drawDesc[OP].mode |= DESC_CHANGE; + break; + } + if (drawData.open) { + if (segPtr->type == SEG_POLY && segPtr->u.p.polyType == FREEFORM) segPtr->u.p.polyType = POLYLINE; + } else { + if (segPtr->type == SEG_POLY && segPtr->u.p.polyType == POLYLINE) segPtr->u.p.polyType = FREEFORM; + } + break; + case BX: + segPtr->u.t.boxed = drawData.boxed; + break; case TX: if ( wTextGetModified((wText_p)drawDesc[TX].control0 )) { int len = wTextGetSize((wText_p)drawDesc[TX].control0); @@ -409,14 +1024,25 @@ static void UpdateDraw( track_p trk, int inx, descData_p descUpd, BOOL_T final ) case LY: SetTrkLayer( trk, drawData.layer); break; + case LK: + break; + case LT: + xx->lineType = drawData.lineType; + break; default: AbortProg( "bad op" ); } + drawData.oldE0 = drawData.endPt[0]; + drawData.oldE1 = drawData.endPt[1]; + drawData.oldAngle = drawData.angle; + drawData.oldOrigin = drawData.origin; ComputeDrawBoundingBox( trk ); DrawNewTrack( trk ); - DoCurCommand( C_REDRAW, zero ); + TempRedraw(); // UpdateDraw } +extern BOOL_T inDescribeCmd; + static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) { struct extraData *xx = GetTrkExtraData(trk); @@ -443,8 +1069,17 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) drawDesc[LY].mode = DESC_NOREDRAW; drawDesc[BE].mode = drawDesc[OR].mode = + drawDesc[LT].mode = drawDesc[DS].mode = DESC_IGNORE; drawData.pivot = DESC_PIVOT_MID; + + if ((xx->orig.x == 0.0) && (xx->orig.y == 0.0)) drawData.lock_origin = FALSE; + else drawData.lock_origin = TRUE; + + drawData.rotate_angle = xx->angle; + + drawDesc[LK].mode = 0; + switch ( segPtr->type ) { case SEG_STRLIN: case SEG_DIMLIN: @@ -454,24 +1089,35 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) REORIGIN( drawData.endPt[1], segPtr->u.l.pos[1], xx->angle, xx->orig ); drawData.length = FindDistance( drawData.endPt[0], drawData.endPt[1] ); drawData.angle = FindAngle( drawData.endPt[0], drawData.endPt[1] ); + drawData.origin = xx->orig; drawDesc[LN].mode = drawDesc[AL].mode = drawDesc[PV].mode = 0; drawDesc[E0].mode = + drawDesc[OI].mode = 0; drawDesc[E1].mode = 0; + drawDesc[RA].mode = 0; switch (segPtr->type) { case SEG_STRLIN: title = _("Straight Line"); + drawDesc[LT].mode = 0; + drawData.lineType = (wIndex_t)xx->lineType; break; case SEG_DIMLIN: title = _("Dimension Line"); - drawDesc[CO].mode = DESC_IGNORE; - drawDesc[LW].mode = DESC_IGNORE; + drawDesc[CO].mode = + drawDesc[LW].mode = + drawDesc[LK].mode = + drawDesc[OI].mode = + drawDesc[RA].mode = DESC_IGNORE; drawData.dimenSize = (wIndex_t)segPtr->u.l.option; drawDesc[DS].mode = 0; break; case SEG_BENCH: title = _("Lumber"); + drawDesc[LK].mode = + drawDesc[OI].mode = + drawDesc[RA].mode = drawDesc[LW].mode = DESC_IGNORE; drawDesc[BE].mode = drawDesc[OR].mode = 0; @@ -480,6 +1126,9 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) break; case SEG_TBLEDGE: title = _("Table Edge"); + drawDesc[LK].mode = + drawDesc[OI].mode = + drawDesc[RA].mode = DESC_IGNORE; drawDesc[CO].mode = DESC_IGNORE; drawDesc[LW].mode = DESC_IGNORE; break; @@ -488,10 +1137,17 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) case SEG_CRVLIN: REORIGIN( drawData.center, segPtr->u.c.center, xx->angle, xx->orig ); drawData.radius = fabs(segPtr->u.c.radius); + drawData.origin = xx->orig; + drawDesc[OI].mode = 0; + drawDesc[RA].mode = drawDesc[CE].mode = - drawDesc[RA].mode = 0; + drawDesc[RD].mode = 0; + drawDesc[LT].mode = 0; + drawData.lineType = (wIndex_t)xx->lineType; if ( segPtr->u.c.a1 >= 360.0 ) { title = _("Circle"); + drawDesc[FL].mode = 0; + drawData.filled = FALSE; } else { drawData.angle = segPtr->u.c.a1; drawData.angle0 = NormalizeAngle( segPtr->u.c.a0+xx->angle ); @@ -499,64 +1155,127 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) drawDesc[AL].mode = drawDesc[A1].mode = drawDesc[A2].mode = 0; + drawDesc[PV].mode = 0; title = _("Curved Line"); } break; case SEG_FILCRCL: REORIGIN( drawData.center, segPtr->u.c.center, xx->angle, xx->orig ); drawData.radius = fabs(segPtr->u.c.radius); + drawData.origin = xx->orig; + drawDesc[OI].mode = + drawDesc[RA].mode = + drawDesc[FL].mode = 0; + drawData.filled = TRUE; drawDesc[CE].mode = - drawDesc[RA].mode = 0; + drawDesc[RD].mode = 0; + drawDesc[PV].mode = 0; + drawDesc[OI].mode = 0; drawDesc[LW].mode = DESC_IGNORE; title = _("Filled Circle"); break; case SEG_POLY: + REORIGIN(drawData.endPt[0],segPtr->u.p.pts[0].pt, xx->angle, xx->orig); + drawDesc[PP].mode = 0; drawData.pointCount = segPtr->u.p.cnt; drawDesc[VC].mode = DESC_RO; - drawDesc[PT].mode = DESC_RO; + drawData.filled = FALSE; + drawDesc[FL].mode = 0; + drawData.angle = 0.0; + drawDesc[RA].mode = 0; + drawData.origin = xx->orig; + drawDesc[OI].mode = 0; + drawData.open=FALSE; + drawDesc[OP].mode = 0; + drawDesc[LT].mode = 0; + drawData.lineType = (wIndex_t)xx->lineType; switch (segPtr->u.p.polyType) { case RECTANGLE: - polyType = _("Rectangle"); + title = _("Rectangle"); + drawDesc[OP].mode = DESC_IGNORE; + drawDesc[VC].mode = DESC_IGNORE; + drawData.width = FindDistance(segPtr->u.p.pts[0].pt, segPtr->u.p.pts[1].pt); + drawDesc[WT].mode = 0; + drawData.height = FindDistance(segPtr->u.p.pts[0].pt, segPtr->u.p.pts[3].pt); + drawDesc[HT].mode = 0; + for(int i=0;i<4;i++) { + REORIGIN( drawData.endPt[i], segPtr->u.p.pts[i].pt, xx->angle, xx->orig ); + } + drawDesc[E0].mode = DESC_IGNORE; + drawData.origin = xx->orig; + break; + case POLYLINE: + title = _("Polyline"); + drawData.open=TRUE; break; default: - polyType = _("Freeform"); + title = _("Polygon"); } - strncpy( drawData.polyType, polyType, sizeof drawData.polyType ); - title = _("Polygonal Line"); break; case SEG_FILPOLY: + REORIGIN(drawData.endPt[0],segPtr->u.p.pts[0].pt, xx->angle, xx->orig); + drawDesc[PP].mode = 0; drawData.pointCount = segPtr->u.p.cnt; drawDesc[VC].mode = DESC_RO; + drawData.filled = TRUE; + drawDesc[FL].mode = 0; drawDesc[LW].mode = DESC_IGNORE; - drawDesc[PT].mode = DESC_RO; + drawData.angle = xx->angle; + drawDesc[RA].mode = 0; + drawData.origin = xx->orig; + drawDesc[OI].mode = DESC_RO; + drawData.open = FALSE; switch (segPtr->u.p.polyType) { case RECTANGLE: - polyType =_("Rectangle"); + title =_("Filled Rectangle"); + drawDesc[VC].mode = DESC_IGNORE; + drawData.width = FindDistance(segPtr->u.p.pts[0].pt, segPtr->u.p.pts[1].pt); + drawDesc[WT].mode = 0; + drawData.height = FindDistance(segPtr->u.p.pts[0].pt, segPtr->u.p.pts[3].pt); + drawDesc[HT].mode = 0; + for(int i=0;i<4;i++) { + REORIGIN( drawData.endPt[i], segPtr->u.p.pts[i].pt, xx->angle, xx->orig ); + } + drawDesc[E0].mode = DESC_IGNORE; + drawData.origin = xx->orig; break; default: - polyType = _("Freeform"); + title = _("Filled Polygon"); } - strncpy( drawData.polyType, polyType, sizeof drawData.polyType ); - title = _("Polygon"); break; case SEG_TEXT: REORIGIN( drawData.endPt[0], segPtr->u.t.pos, xx->angle, xx->orig ); drawData.angle = NormalizeAngle( xx->angle ); strncpy( drawData.text, segPtr->u.t.string, sizeof drawData.text ); drawData.text[sizeof drawData.text-1] ='\0'; + drawData.boxed = segPtr->u.t.boxed; + drawData.origin = xx->orig; + drawDesc[E0].mode = drawDesc[TP].mode = drawDesc[TS].mode = drawDesc[TX].mode = - drawDesc[TA].mode = + drawDesc[TA].mode = + drawDesc[BX].mode = + drawDesc[RA].mode = + drawDesc[OI].mode = 0; drawDesc[CO].mode = 0; /*Allow Text color setting*/ drawDesc[LW].mode = DESC_IGNORE; title = _("Text"); break; default: - AbortProg( "bad seg type" ); + ; } - sprintf( str, _("%s: Layer=%d"), title, GetTrkLayer(trk)+1 ); + snprintf( str, len, _("%s(%d) Layer=%d"), title, GetTrkIndex(trk), GetTrkLayer(trk)+1 ); + + if (!inDescribeCmd) return; + + drawData.oldE0 = drawData.endPt[0]; + drawData.oldE1 = drawData.endPt[1]; + drawData.oldAngle = drawData.angle; + drawData.oldOrigin = drawData.origin; + + DoDescribe( title, trk, drawDesc, UpdateDraw ); if ( segPtr->type==SEG_BENCH && drawDesc[BE].control0!=NULL && drawDesc[OR].control0!=NULL) { @@ -565,6 +1284,17 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) BenchUpdateOrientationList( (long)wListGetItemContext((wList_p)drawDesc[BE].control0, drawData.benchChoice ), (wList_p)drawDesc[OR].control0 ); wListSetIndex( (wList_p)drawDesc[OR].control0, drawData.benchOrient ); } + if ( (segPtr->type==SEG_STRLIN || segPtr->type==SEG_CRVLIN || segPtr->type==SEG_POLY) && drawDesc[LT].control0!=NULL) { + wListClear( (wList_p)drawDesc[LT].control0 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("Solid"), NULL, (void*)0 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("Dash"), NULL, (void*)1 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("Dot"), NULL, (void*)2 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("DashDot"), NULL, (void*)3 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("DashDotDot"), NULL, (void*)4 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("CenterDot"), NULL, (void*)5 ); + wListAddValue( (wList_p)drawDesc[LT].control0, _("PhantomDot"), NULL, (void*)6 ); + wListSetIndex( (wList_p)drawDesc[LT].control0, drawData.lineType ); + } if ( segPtr->type==SEG_DIMLIN && drawDesc[DS].control0!=NULL ) { wListClear( (wList_p)drawDesc[DS].control0 ); wListAddValue( (wList_p)drawDesc[DS].control0, _("Tiny"), NULL, (void*)0 ); @@ -582,8 +1312,17 @@ static void DescribeDraw( track_p trk, char * str, CSIZE_T len ) static void DrawDraw( track_p t, drawCmd_p d, wDrawColor color ) { struct extraData * xx = GetTrkExtraData(t); - if ( (d->funcs->options&DC_QUICK) == 0 ) - DrawSegs( d, xx->orig, xx->angle, xx->segs, xx->segCnt, 0.0, color ); + unsigned long NotSolid = ~(DC_NOTSOLIDLINE); + d->options &= NotSolid; + if (xx->lineType == DRAWLINESOLID) {} + else if (xx->lineType == DRAWLINEDASH) d->options |= DC_DASH; + else if (xx->lineType == DRAWLINEDOT) d->options |= DC_DOT; + else if (xx->lineType == DRAWLINEDASHDOT) d->options |= DC_DASHDOT; + else if (xx->lineType == DRAWLINEDASHDOTDOT) d->options |= DC_DASHDOTDOT; + else if (xx->lineType == DRAWLINECENTER) d->options |= DC_CENTER; + else if (xx->lineType == DRAWLINEPHANTOM) d->options |= DC_PHANTOM; + DrawSegs( d, xx->orig, xx->angle, xx->segs, xx->segCnt, 0.0, color ); + d->options = d->options&~(DC_NOTSOLIDLINE); } @@ -594,6 +1333,7 @@ static void DeleteDraw( track_p t ) if (xx->segs[0].type == SEG_POLY || xx->segs[0].type == SEG_FILPOLY) { MyFree(xx->segs[0].u.p.pts); + xx->segs[0].u.p.pts = NULL; } } @@ -602,14 +1342,15 @@ static BOOL_T WriteDraw( track_p t, FILE * f ) { struct extraData * xx = GetTrkExtraData(t); BOOL_T rc = TRUE; - rc &= fprintf(f, "DRAW %d %d 0 0 0 %0.6f %0.6f 0 %0.6f\n", GetTrkIndex(t), GetTrkLayer(t), + rc &= fprintf(f, "DRAW %d %d %d 0 0 %0.6f %0.6f 0 %0.6f\n", GetTrkIndex(t), GetTrkLayer(t), + xx->lineType, xx->orig.x, xx->orig.y, xx->angle )>0; rc &= WriteSegs( f, xx->segCnt, xx->segs ); return rc; } -static void ReadDraw( char * header ) +static BOOL_T ReadDraw( char * header ) { track_p trk; wIndex_t index; @@ -617,12 +1358,14 @@ static void ReadDraw( char * header ) DIST_T elev; ANGLE_T angle; wIndex_t layer; + int lineType; struct extraData * xx; - if ( !GetArgs( header+5, paramVersion<3?"dXpYf":paramVersion<9?"dL000pYf":"dL000pff", - &index, &layer, &orig, &elev, &angle ) ) - return; - ReadSegs(); + if ( !GetArgs( header+5, paramVersion<3?"dXXpYf":paramVersion<9?"dLX00pYf":"dLd00pff", + &index, &layer, &lineType, &orig, &elev, &angle ) ) + return FALSE; + if ( !ReadSegs() ) + return FALSE; if (tempSegs_da.cnt == 1) { trk = MakeDrawFromSeg1( index, orig, angle, &tempSegs(0) ); SetTrkLayer( trk, layer ); @@ -633,9 +1376,11 @@ static void ReadDraw( char * header ) xx->orig = orig; xx->angle = angle; xx->segCnt = tempSegs_da.cnt; + xx->lineType = lineType; memcpy( xx->segs, tempSegs_da.ptr, tempSegs_da.cnt * sizeof *(trkSeg_p)0 ); ComputeDrawBoundingBox( trk ); } + return TRUE; } @@ -665,22 +1410,283 @@ static void RescaleDraw( track_p trk, FLOAT_T ratio ) RescaleSegs( xx->segCnt, xx->segs, ratio, ratio, ratio ); } +static void DoConvertFill(void) { + +} + +static drawModContext_t drawModCmdContext = { + InfoMessage, + DoRedraw, + &mainD}; + + +static BOOL_T infoSubst = FALSE; + +static paramIntegerRange_t i0_100 = { 0, 100, 25 }; +static paramFloatRange_t r1_10000 = { 1, 10000 }; +static paramFloatRange_t r0_10000 = { 0, 10000 }; +static paramFloatRange_t r10000_10000 = {-10000, 10000}; +static paramFloatRange_t r360_360 = { -360, 360, 80 }; +static paramFloatRange_t r0_360 = { 0, 360, 80 }; +static paramData_t drawModPLs[] = { + +#define drawModLengthPD (drawModPLs[0]) + { PD_FLOAT, &drawModCmdContext.length, "Length", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Length") }, +#define drawModAnglePD (drawModPLs[1]) + { PD_FLOAT, &drawModCmdContext.abs_angle, "Angle", PDO_NORECORD|BO_ENTER, &r360_360, N_("Angle") }, +#define drawModRelAnglePD (drawModPLs[2]) +#define drawModRelAngle 2 + { PD_FLOAT, &drawModCmdContext.rel_angle, "Rel Angle", PDO_NORECORD|BO_ENTER, &r360_360, N_("Relative Angle") }, +#define drawModWidthPD (drawModPLs[3]) + { PD_FLOAT, &drawModCmdContext.width, "Width", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Width") }, +#define drawModHeightPD (drawModPLs[4]) + { PD_FLOAT, &drawModCmdContext.height, "Height", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Height") }, +#define drawModRadiusPD (drawModPLs[5]) +#define drawModRadius 5 + { PD_FLOAT, &drawModCmdContext.radius, "Radius", PDO_DIM|PDO_NORECORD|BO_ENTER, &r10000_10000, N_("Radius") }, +#define drawModArcAnglePD (drawModPLs[6]) + { PD_FLOAT, &drawModCmdContext.arc_angle, "ArcAngle", PDO_NORECORD|BO_ENTER, &r360_360, N_("Arc Angle") }, +#define drawModRotAnglePD (drawModPLs[7) + { PD_FLOAT, &drawModCmdContext.rot_angle, "Rot Angle", PDO_NORECORD|BO_ENTER, &r0_360, N_("Rotate Angle") }, +#define drawModRotCenterXPD (drawModPLs[8]) +#define drawModRotCenterInx 8 + { PD_FLOAT, &drawModCmdContext.rot_center.x, "Rot Center X,Y", PDO_NORECORD|BO_ENTER, &r0_10000, N_("Rot Center X") }, +#define drawModRotCenterYPD (drawModPLs[9]) + { PD_FLOAT, &drawModCmdContext.rot_center.y, " ", PDO_NORECORD|BO_ENTER, &r0_10000, N_("Rot Center Y") }, + +}; +static paramGroup_t drawModPG = { "drawMod", 0, drawModPLs, sizeof drawModPLs/sizeof drawModPLs[0] }; + +static void DrawModDlgUpdate( + paramGroup_p pg, + int inx, + void * valueP ) +{ + DrawGeomModify(C_UPDATE,zero,&drawModCmdContext); + ParamLoadControl(&drawModPG,drawModRotCenterInx-1); //Make sure the angle is updated in case center moved + ParamLoadControl(&drawModPG,drawModRadius); // Make sure Radius updated + ParamLoadControl(&drawModPG,drawModRelAngle); //Relative Angle as well + MainRedraw(); + +} static STATUS_T ModifyDraw( track_p trk, wAction_t action, coOrd pos ) { struct extraData * xx = GetTrkExtraData(trk); - STATUS_T rc; + STATUS_T rc = C_CONTINUE; - if (action == C_DOWN) { - //UndrawNewTrack( trk ); - } - if ( action == C_MOVE ) + wControl_p controls[5]; //Always needs a NULL last entry + char * labels[4]; + + drawModCmdContext.trk = trk; + drawModCmdContext.orig = xx->orig; + drawModCmdContext.angle = xx->angle; + drawModCmdContext.segCnt = xx->segCnt; + drawModCmdContext.segPtr = xx->segs; + drawModCmdContext.selected = GetTrkSelected(trk); + + + switch(action&0xFF) { //Remove Text value + case C_START: + drawModCmdContext.type = xx->segs[0].type; + switch(drawModCmdContext.type) { + case SEG_POLY: + case SEG_FILPOLY: + drawModCmdContext.filled = (drawModCmdContext.type==SEG_FILPOLY)?TRUE:FALSE; + drawModCmdContext.subtype = xx->segs[0].u.p.polyType; + drawModCmdContext.open = (drawModCmdContext.subtype==POLYLINE)?TRUE:FALSE; + break; + case SEG_TEXT: + InfoMessage("Text can only be modified in Describe Mode"); + wBeep(); + return C_ERROR; + default: + break; + + } + drawModCmdContext.rot_moved = FALSE; + drawModCmdContext.rotate_state = FALSE; + + infoSubst = FALSE; + rc = DrawGeomModify( C_START, pos, &drawModCmdContext ); + break; + case C_DOWN: + rc = DrawGeomModify( C_DOWN, pos, &drawModCmdContext ); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + case C_LDOUBLE: + rc = DrawGeomModify( C_LDOUBLE, pos, &drawModCmdContext ); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + case wActionMove: + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + break; + case C_REDRAW: + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + break; + case C_MOVE: + ignoredDraw = trk; + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + ignoredDraw = NULL; + break; + case C_UP: + ignoredDraw = trk; + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + ignoredDraw = NULL; + ComputeDrawBoundingBox( trk ); + if (drawModCmdContext.state == MOD_AFTER_PT) { + switch(drawModCmdContext.type) { + case SEG_POLY: + case SEG_FILPOLY: + if (xx->segs[0].u.p.polyType != RECTANGLE) { + if (drawModCmdContext.prev_inx >= 0) { + controls[0] = drawModLengthPD.control; + controls[1] = drawModRelAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Seg Lth"); + labels[1] = N_("Rel Ang"); + ParamLoadControls( &drawModPG ); + InfoSubstituteControls( controls, labels ); + drawModLengthPD.option &= ~PDO_NORECORD; + drawModRelAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + } + } else { + controls[0] = drawModWidthPD.control; + controls[1] = drawModHeightPD.control; + controls[2] = NULL; + labels[0] = N_("Width"); + labels[1] = N_("Height"); + ParamLoadControls( &drawModPG ); + InfoSubstituteControls( controls, labels ); + drawModWidthPD.option &= ~PDO_NORECORD; + drawModHeightPD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + } + break; + case SEG_STRLIN: + case SEG_BENCH: + case SEG_DIMLIN: + case SEG_TBLEDGE: + controls[0] = drawModLengthPD.control; + controls[1] = drawModAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Length"); + labels[1] = N_("Angle"); + ParamLoadControls( &drawModPG ); + InfoSubstituteControls( controls, labels ); + drawModLengthPD.option &= ~PDO_NORECORD; + drawModAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + case SEG_CRVLIN: + case SEG_FILCRCL: + controls[0] = drawModRadiusPD.control; + controls[1] = NULL; + labels[0] = N_("Radius"); + if ((drawModCmdContext.type == SEG_CRVLIN) && xx->segs[0].u.c.a1>0.0 && xx->segs[0].u.c.a1 <360.0) { + controls[1] = drawModArcAnglePD.control; + controls[2] = NULL; + labels[1] = N_("Arc Angle"); + } + ParamLoadControls( &drawModPG ); + InfoSubstituteControls( controls, labels ); + drawModArcAnglePD.option &= ~PDO_NORECORD; + if (drawModCmdContext.type == SEG_CRVLIN) + drawModArcAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + default: + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + break; + } + } else { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + case C_CMDMENU: + menuPos = pos; + wMenuPopupShow( drawModDelMI ); + wMenuPushEnable( drawModPointsMode,drawModCmdContext.rotate_state); + wMenuPushEnable( drawModriginMode,!drawModCmdContext.rotate_state); + wMenuPushEnable( drawModRound, FALSE); + wMenuPushEnable( drawModVertex, FALSE); + wMenuPushEnable( drawModSmooth, FALSE); + wMenuPushEnable( drawModDel, FALSE); + wMenuPushEnable( drawModFill, FALSE); + wMenuPushEnable( drawModEmpty, FALSE); + wMenuPushEnable( drawModClose, FALSE); + wMenuPushEnable( drawModOpen, FALSE); + wMenuPushEnable( drawModSolid, TRUE); + wMenuPushEnable( drawModDot, TRUE); + wMenuPushEnable( drawModDash, TRUE); + wMenuPushEnable( drawModDashDot, TRUE); + wMenuPushEnable( drawModDashDotDot, TRUE); + wMenuPushEnable( drawModCenterDot, TRUE); + wMenuPushEnable( drawModPhantom, TRUE); + if (!drawModCmdContext.rotate_state && (drawModCmdContext.type == SEG_POLY || drawModCmdContext.type == SEG_FILPOLY)) { + wMenuPushEnable( drawModDel,drawModCmdContext.prev_inx>=0); + if ((!drawModCmdContext.open && drawModCmdContext.prev_inx>=0) || + ((drawModCmdContext.prev_inx>0) && (drawModCmdContext.prev_inx=0)); + wMenuPushEnable( drawModCenter,drawModCmdContext.rotate_state); + break; + case C_TEXT: + ignoredDraw = trk ; + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + ignoredDraw = NULL; + if (rc == C_CONTINUE) break; + /* no break*/ + case C_FINISH: ignoredDraw = trk; - rc = DrawGeomModify( xx->orig, xx->angle, xx->segCnt, xx->segs, action, pos, GetTrkSelected(trk) ); - ignoredDraw = NULL; - if (action == C_UP) { + rc = DrawGeomModify( C_FINISH, pos, &drawModCmdContext ); + xx->angle = drawModCmdContext.angle; + xx->orig = drawModCmdContext.orig; + ignoredDraw = NULL; ComputeDrawBoundingBox( trk ); - DrawNewTrack( trk ); + DYNARR_RESET(trkSeg_t,tempSegs_da); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + case C_CANCEL: + case C_CONFIRM: + case C_TERMINATE: + rc = DrawGeomModify( action, pos, &drawModCmdContext ); + drawModCmdContext.state = MOD_NONE; + DYNARR_RESET(trkSeg_t,tempSegs_da); + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + break; + + default: + + break; } return rc; } @@ -768,7 +1774,7 @@ static BOOL_T StoreDraw( if (xx->segs[0].type == SEG_POLY || xx->segs[0].type == SEG_FILPOLY) { *data = xx->segs[0].u.p.pts; - *len = xx->segs[0].u.p.cnt* sizeof (coOrd); + *len = xx->segs[0].u.p.cnt* sizeof (pts_t); return TRUE; } return FALSE; @@ -789,6 +1795,275 @@ static BOOL_T ReplayDraw( return FALSE; } +static BOOL_T QueryDraw( track_p trk, int query ) +{ + struct extraData * xx = GetTrkExtraData(trk); + switch(query) { + case Q_IS_DRAW: + return TRUE; + case Q_IS_POLY: + if ((xx->segs[0].type == SEG_POLY) || (xx->segs[0].type == SEG_FILPOLY) ) { + return TRUE; + } + else + return FALSE; + case Q_IS_TEXT: + if (xx->segs[0].type== SEG_TEXT) return TRUE; + else return FALSE; + case Q_GET_NODES: + return TRUE; + case Q_CAN_PARALLEL: + if ((xx->segs[0].type == SEG_STRLIN) || (xx->segs[0].type == SEG_CRVLIN || + ((xx->segs[0].type == SEG_POLY) && (xx->segs[0].u.p.polyType == POLYLINE)) + )) return TRUE; + else return FALSE; + default: + return FALSE; + } +} + +static wBool_t CompareDraw( track_cp trk1, track_cp trk2 ) +{ + struct extraData *xx1 = GetTrkExtraData( trk1 ); + struct extraData *xx2 = GetTrkExtraData( trk2 ); + char * cp = message + strlen(message); + REGRESS_CHECK_POS( "Orig", xx1, xx2, orig ) + REGRESS_CHECK_ANGLE( "Angle", xx1, xx2, angle ) + REGRESS_CHECK_INT( "LineType", xx1, xx2, lineType ) + return CompareSegs( xx1->segs, xx1->segCnt, xx2->segs, xx2->segCnt ); +} + +static BOOL_T GetParamsDraw( int inx, track_p trk, coOrd pos, trackParams_t * params ) { + + struct extraData * xx = GetTrkExtraData(trk); + if (inx != PARAMS_NODES ) return FALSE; + DYNARR_RESET(coOrd,params->nodes); + BOOL_T back = FALSE; + coOrd start,end; + switch (xx->segs[0].type) { + case SEG_POLY: + if (xx->segs[0].u.p.polyType != POLYLINE) return FALSE; + REORIGIN(start,xx->segs[0].u.p.pts[0].pt,xx->angle,xx->orig); + REORIGIN(end,xx->segs[0].u.p.pts[xx->segs[0].u.p.cnt-1].pt,xx->angle,xx->orig); + if (FindDistance(pos,start)>FindDistance(pos,end)) back = TRUE; + for (int i=0;isegs[0].u.p.cnt;i++) { + DYNARR_APPEND(coOrd,params->nodes,xx->segs[0].u.p.cnt); + if (back) + DYNARR_LAST(coOrd,params->nodes) = xx->segs[0].u.p.pts[xx->segs[0].u.p.cnt-1-i].pt; + else + DYNARR_LAST(coOrd,params->nodes) = xx->segs[0].u.p.pts[i].pt; + REORIGIN(DYNARR_LAST(coOrd,params->nodes),DYNARR_LAST(coOrd,params->nodes),xx->angle,xx->orig); + } + params->lineOrig = DYNARR_N(coOrd,params->nodes,0); + params->lineEnd = DYNARR_LAST(coOrd,params->nodes); + return TRUE; + + case SEG_STRLIN:; + REORIGIN(start,xx->segs[0].u.l.pos[0],xx->angle,xx->orig); + REORIGIN(end,xx->segs[0].u.l.pos[1],xx->angle,xx->orig); + if (FindDistance(pos,start)>FindDistance(pos,end)) back = TRUE; + for (int i=0;i<2;i++) { + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),xx->segs[0].u.l.pos[back?1-i:i],xx->angle,xx->orig); + } + params->lineOrig = DYNARR_N(coOrd,params->nodes,0); + params->lineEnd = DYNARR_LAST(coOrd,params->nodes); + return TRUE; + + case SEG_CRVLIN:; + Translate(&start,xx->segs[0].u.c.center,xx->segs[0].u.c.a0,fabs(xx->segs[0].u.c.radius)); + REORIGIN(start,start,xx->angle,xx->orig); + Translate(&end,xx->segs[0].u.c.center,xx->segs[0].u.c.a0+xx->segs[0].u.c.a1,fabs(xx->segs[0].u.c.radius)); + REORIGIN(end,end,xx->angle,xx->orig); + if (FindDistance(start,pos) > FindDistance(end,pos)) back = TRUE; + if (fabs(xx->segs[0].u.c.radius) > 0.5) { + double min_angle = R2D(2*acos(1.0-(0.1/fabs(xx->segs[0].u.c.radius)))); //Error max is 0.1" + int number = (int) ceil(xx->segs[0].u.c.a1/min_angle); + double arc_size = xx->segs[0].u.c.a1/number; + for (int i=0;i<=number;i++) { + DYNARR_APPEND(coOrd,params->nodes,number); + if (back) + Translate(&DYNARR_LAST(coOrd,params->nodes),xx->segs[0].u.c.center,xx->segs[0].u.c.a0+xx->segs[0].u.c.a1-(i*arc_size),fabs(xx->segs[0].u.c.radius)); + else + Translate(&DYNARR_LAST(coOrd,params->nodes),xx->segs[0].u.c.center,xx->segs[0].u.c.a0+(i*arc_size),fabs(xx->segs[0].u.c.radius)); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),DYNARR_LAST(coOrd,params->nodes),xx->angle,xx->orig); + } + } else { + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),back?end:start,xx->angle,xx->orig); + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),back?start:end,xx->angle,xx->orig); + } + params->lineOrig = DYNARR_N(coOrd,params->nodes,0); + params->lineEnd = DYNARR_LAST(coOrd,params->nodes); + return TRUE; + + case SEG_BEZLIN: + REORIGIN(start,xx->segs[0].u.b.pos[0],xx->angle,xx->orig); + REORIGIN(end,xx->segs[0].u.b.pos[3],xx->angle,xx->orig); + if (FindDistance(pos,start) < FindDistance(pos,end)) + params->ep = 0; + else params->ep = 1; + BOOL_T back = FALSE; + coOrd curr_pos = params->bezierPoints[params->ep*3]; + BOOL_T first = TRUE; + for (int i = 0; isegs[0].bezSegs.cnt;i++) { + trkSeg_p segPtr = &DYNARR_N(trkSeg_t,xx->segs[0].bezSegs,params->ep?xx->segs[0].bezSegs.cnt-1-i:i); + if (segPtr->type == SEG_STRLIN) { + back = FindDistance(segPtr->u.l.pos[0],curr_pos)>FindDistance(segPtr->u.l.pos[1],curr_pos); + if (first) { + first = FALSE; + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),segPtr->u.l.pos[back],xx->angle,xx->orig); + } + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),segPtr->u.l.pos[1-back],xx->angle,xx->orig); + curr_pos = DYNARR_LAST(coOrd,params->nodes); + } else { + coOrd start,end; + Translate(&start,segPtr->u.c.center,segPtr->u.c.a0,segPtr->u.c.radius); + Translate(&end,segPtr->u.c.center,segPtr->u.c.a0+segPtr->u.c.a1,segPtr->u.c.radius); + back = FindDistance(start,curr_pos)>FindDistance(end,curr_pos); + if (fabs(segPtr->u.c.radius) > 0.2) { + double min_angle = 360*acos(1.0-(0.1/fabs(segPtr->u.c.radius)))/M_PI; //Error max is 0.1" + int number = (int)ceil(segPtr->u.c.a1/min_angle); + double arc_size = segPtr->u.c.a1/number; + for (int j=1-first;jnodes,number-first); + if (back == params->ep) + Translate(&DYNARR_LAST(coOrd,params->nodes),segPtr->u.c.center,segPtr->u.c.a0+(j*arc_size),fabs(segPtr->u.c.radius) ); + else + Translate(&DYNARR_LAST(coOrd,params->nodes),segPtr->u.c.center,segPtr->u.c.a0+segPtr->u.c.a1-(j*arc_size),fabs(segPtr->u.c.radius) ); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),DYNARR_LAST(coOrd,params->nodes),xx->angle,xx->orig); + } + first = FALSE; + } else { + if (first) { + first = FALSE; + DYNARR_APPEND(coOrd,params->nodes,2); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),start,xx->angle,xx->orig); + } + DYNARR_APPEND(coOrd,params->nodes,1); + REORIGIN(DYNARR_LAST(coOrd,params->nodes),end,xx->angle,xx->orig); + first = FALSE; + } + curr_pos = DYNARR_LAST(coOrd,params->nodes); + } + } + params->lineOrig = DYNARR_N(coOrd,params->nodes,0); + params->lineEnd = DYNARR_LAST(coOrd,params->nodes); + return TRUE; + + default: + return FALSE; + } + return FALSE; + + +} + +static BOOL_T MakeParallelDraw( + track_p trk, + coOrd pos, + DIST_T sep, + DIST_T factor, + track_p * newTrkR, + coOrd * p0R, + coOrd * p1R, + BOOL_T track) +{ + if (track) return FALSE; + struct extraData * xx = GetTrkExtraData(trk); + + ANGLE_T angle; + DIST_T rad; + coOrd p0,p1; + + switch (xx->segs[0].type) { + case SEG_STRLIN: + angle = FindAngle(xx->segs[0].u.l.pos[0],xx->segs[0].u.l.pos[1]); + if ( NormalizeAngle( FindAngle( xx->segs[0].u.l.pos[0], pos ) - angle ) < 180.0 ) + angle += 90; + else + angle -= 90; + Translate(&p0,xx->segs[0].u.l.pos[0], angle, sep); + Translate(&p1,xx->segs[0].u.l.pos[1], angle, sep); + tempSegs(0).color = xx->segs[0].color; + tempSegs(0).width = xx->segs[0].width; + tempSegs_da.cnt = 1; + tempSegs(0).type = SEG_STRLIN; + tempSegs(0).u.l.pos[0] = p0; + tempSegs(0).u.l.pos[1] = p1; + if (newTrkR) { + *newTrkR = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) ); + struct extraData * yy = GetTrkExtraData(*newTrkR); + yy->lineType = xx->lineType; + } + + if ( p0R ) *p0R = p0; + if ( p1R ) *p1R = p1; + return TRUE; + break; + case SEG_CRVLIN: + rad = FindDistance( pos, xx->segs[0].u.c.center ); + if ( rad > xx->segs[0].u.c.radius ) + rad = xx->segs[0].u.c.radius + sep; + else + rad = xx->segs[0].u.c.radius - sep; + tempSegs(0).color = xx->segs[0].color; + tempSegs(0).width = xx->segs[0].width; + tempSegs_da.cnt = 1; + tempSegs(0).type = SEG_CRVLIN; + tempSegs(0).u.c.center = xx->segs[0].u.c.center; + tempSegs(0).u.c.radius = rad; + tempSegs(0).u.c.a0 = xx->segs[0].u.c.a0; + tempSegs(0).u.c.a1 = xx->segs[0].u.c.a1; + if (newTrkR) { + *newTrkR = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) ); + struct extraData * yy = GetTrkExtraData(*newTrkR); + yy->lineType = xx->lineType; + } + if ( p0R ) PointOnCircle( p0R, xx->segs[0].u.c.center, rad, xx->segs[0].u.c.a0 ); + if ( p1R ) PointOnCircle( p1R, xx->segs[0].u.c.center, rad, xx->segs[0].u.c.a0+xx->segs[0].u.c.a1 ); + return TRUE; + break; + case SEG_POLY: + if (xx->segs[0].u.p.polyType != POLYLINE) return FALSE; + int inx2; + coOrd p = pos; + angle = GetAngleSegs(1,&xx->segs[0],&p,NULL,NULL,NULL,&inx2,NULL); + if ( NormalizeAngle( FindAngle( p, pos ) - angle ) < 180.0 ) { + sep = sep*1.0; + angle += 90; + } else { + angle -= 90; + sep = sep*1.0; + } + tempSegs(0).color = xx->segs[0].color; + tempSegs(0).width = xx->segs[0].width; + tempSegs_da.cnt = 1; + tempSegs(0).type = SEG_POLY; + tempSegs(0).u.p.polyType = POLYLINE; + tempSegs(0).u.p.pts = memdup( xx->segs[0].u.p.pts, xx->segs[0].u.p.cnt*sizeof (pts_t) ); + tempSegs(0).u.p.cnt = xx->segs[0].u.p.cnt; + for (int i=0;isegs[0].u.p.cnt;i++) { + Translate(&tempSegs(0).u.p.pts[i].pt,tempSegs(0).u.p.pts[i].pt,angle,sep); + } + if (newTrkR) { + *newTrkR = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) ); + struct extraData * yy = GetTrkExtraData(*newTrkR); + yy->lineType = xx->lineType; + if (tempSegs(0).u.p.pts) MyFree(tempSegs(0).u.p.pts); + } + if (p0R) *p0R = tempSegs(0).u.p.pts[0].pt; + if (p1R) *p1R = tempSegs(0).u.p.pts[tempSegs(0).u.p.cnt-1].pt; + return TRUE; + break; + default: + return FALSE; + } + return FALSE; +} static trackCmd_t drawCmds = { "DRAW", @@ -811,19 +2086,21 @@ static trackCmd_t drawCmds = { NULL, /* merge */ ModifyDraw, NULL, /* getLength */ - NULL, /* getTrackParams */ + GetParamsDraw, /* getTrackParams */ NULL, /* moveEndPt */ - NULL, /* query */ + QueryDraw, /* query */ UngroupDraw, FlipDraw, NULL, NULL, NULL, - NULL, /*Parallel*/ + MakeParallelDraw, /*Parallel*/ NULL, NULL, /*MakeSegs*/ ReplayDraw, - StoreDraw + StoreDraw, + NULL, + CompareDraw }; EXPORT BOOL_T OnTableEdgeEndPt( track_p trk, coOrd * pos ) @@ -918,19 +2195,12 @@ EXPORT BOOL_T GetClosestEndPt( track_p trk, coOrd * pos) } -static void DrawRedraw(void); static drawContext_t drawCmdContext = { InfoMessage, - DrawRedraw, + DoRedraw, &mainD, OP_LINE }; -static void DrawRedraw( void ) -{ - MainRedraw(); - MapRedraw(); -} - static wIndex_t benchChoice; static wIndex_t benchOrient; static wIndex_t dimArrowSize; @@ -939,10 +2209,10 @@ long lineWidth = 0; static wDrawColor benchColor; -static paramIntegerRange_t i0_100 = { 0, 100, 25 }; + static paramData_t drawPLs[] = { -#define drawWidthPD (drawPLs[0]) - { PD_LONG, &drawCmdContext.Width, "linewidth", PDO_NORECORD, &i0_100, N_("Line Width") }, +#define drawLineWidthPD (drawPLs[0]) + { PD_LONG, &drawCmdContext.line_Width, "linewidth", PDO_NORECORD, &i0_100, N_("Line Width") }, #define drawColorPD (drawPLs[1]) { PD_COLORLIST, &lineColor, "linecolor", PDO_NORECORD, NULL, N_("Color") }, #define drawBenchColorPD (drawPLs[2]) @@ -960,7 +2230,19 @@ static paramData_t drawPLs[] = { { PD_DROPLIST, &benchOrient, "benchorient", PDO_NOPREF|PDO_NORECORD|PDO_LISTINDEX, (void*)105, "", 0 }, #endif #define drawDimArrowSizePD (drawPLs[5]) - { PD_DROPLIST, &dimArrowSize, "arrowsize", PDO_NORECORD|PDO_LISTINDEX, (void*)80, N_("Size") } }; + { PD_DROPLIST, &dimArrowSize, "arrowsize", PDO_NORECORD|PDO_LISTINDEX, (void*)80, N_("Size") }, +#define drawLengthPD (drawPLs[6]) + { PD_FLOAT, &drawCmdContext.length, "Length", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Length") }, +#define drawWidthPD (drawPLs[7]) + { PD_FLOAT, &drawCmdContext.width, "BoxWidth", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Width") }, +#define drawAnglePD (drawPLs[8]) +#define drawAngleInx 8 + { PD_FLOAT, &drawCmdContext.angle, "Angle", PDO_NORECORD|BO_ENTER, &r360_360, N_("Angle") }, +#define drawRadiusPD (drawPLs[9]) + { PD_FLOAT, &drawCmdContext.radius, "Radius", PDO_DIM|PDO_NORECORD|BO_ENTER, &r0_10000, N_("Radius") }, +#define drawLineTypePD (drawPLs[10]) + { PD_DROPLIST, &drawCmdContext.lineType, "Type", PDO_DIM|PDO_NORECORD|BO_ENTER, (void*)0, N_("Line Type") }, +}; static paramGroup_t drawPG = { "draw", 0, drawPLs, sizeof drawPLs/sizeof drawPLs[0] }; static char * objectName[] = { @@ -976,21 +2258,22 @@ static char * objectName[] = { N_("Circle"), N_("Circle"), N_("Box"), - N_("Polyline"), + N_("Polygon"), N_("Filled Circle"), N_("Filled Circle"), N_("Filled Circle"), N_("Filled Box"), - N_("Polygon"), + N_("Filled Polygon"), N_("Bezier Line"), + N_("Polyline"), NULL}; static STATUS_T CmdDraw( wAction_t action, coOrd pos ) { static BOOL_T infoSubst = FALSE; - wControl_p controls[4]; - char * labels[3]; + wControl_p controls[5]; //Always needs a NULL last entry + char * labels[4]; static char labelName[40]; wAction_t act2 = (action&0xFF) | (bezCmdCreateLine<<8); @@ -1000,7 +2283,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) case C_START: ParamLoadControls( &drawPG ); /*drawContext = &drawCmdContext;*/ - drawWidthPD.option |= PDO_NORECORD; + drawLineWidthPD.option |= PDO_NORECORD; drawColorPD.option |= PDO_NORECORD; drawBenchColorPD.option |= PDO_NORECORD; drawBenchChoicePD.option |= PDO_NORECORD; @@ -1021,19 +2304,29 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) case OP_CURVE4: case OP_CIRCLE2: case OP_CIRCLE3: + case OP_BEZLIN: case OP_BOX: case OP_POLY: - case OP_BEZLIN: - controls[0] = drawWidthPD.control; + case OP_POLYLINE: + controls[0] = drawLineWidthPD.control; controls[1] = drawColorPD.control; + controls[2] = drawLineTypePD.control; controls[2] = NULL; sprintf( labelName, _("%s Line Width"), _(objectName[drawCmdContext.Op]) ); labels[0] = labelName; labels[1] = N_("Color"); + labels[2] = N_("Type"); + if ( wListGetCount( (wList_p)drawLineTypePD.control ) == 0 ) { + wListAddValue( (wList_p)drawLineTypePD.control, _("Solid"), NULL, NULL ); + wListAddValue( (wList_p)drawLineTypePD.control, _("Dot"), NULL, NULL ); + wListAddValue( (wList_p)drawLineTypePD.control, _("Dash"), NULL, NULL ); + wListAddValue( (wList_p)drawLineTypePD.control, _("Dash-Dot"), NULL, NULL ); + wListAddValue( (wList_p)drawLineTypePD.control, _("Dash-Dot-Dot"), NULL, NULL ); + } InfoSubstituteControls( controls, labels ); - drawWidthPD.option &= ~PDO_NORECORD; + drawLineWidthPD.option &= ~PDO_NORECORD; drawColorPD.option &= ~PDO_NORECORD; - lineWidth = drawCmdContext.Width; + drawLineTypePD.option &= ~PDO_NORECORD; break; case OP_FILLCIRCLE2: case OP_FILLCIRCLE3: @@ -1065,6 +2358,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) drawBenchColorPD.option &= ~PDO_NORECORD; drawBenchChoicePD.option &= ~PDO_NORECORD; drawBenchOrientPD.option &= ~PDO_NORECORD; + drawLengthPD.option &= ~PDO_NORECORD; break; case OP_DIMLINE: controls[0] = drawDimArrowSizePD.control; @@ -1081,9 +2375,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) drawDimArrowSizePD.option &= ~PDO_NORECORD; break; case OP_TBLEDGE: - InfoSubstituteControls( NULL, NULL ); InfoMessage( _("Drag to create Table Edge") ); - drawColorPD.option &= ~PDO_NORECORD; break; default: InfoSubstituteControls( NULL, NULL ); @@ -1091,8 +2383,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) } ParamGroupRecord( &drawPG ); if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); - DrawGeomMouse( C_START, pos, &drawCmdContext ); - + DrawGeomMouse( C_START, pos, &drawCmdContext); return C_CONTINUE; case wActionLDown: @@ -1106,7 +2397,10 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) drawCmdContext.Color = benchColor; } else if ( drawCmdContext.Op == OP_DIMLINE ) { + drawCmdContext.Color = wDrawColorBlack; drawCmdContext.benchOption = dimArrowSize; + } else if ( drawCmdContext.Op == OP_TBLEDGE ) { + drawCmdContext.Color = wDrawColorBlack; } else { drawCmdContext.Color = lineColor; } @@ -1114,39 +2408,132 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) InfoSubstituteControls( NULL, NULL ); infoSubst = FALSE; } + /* no break */ case wActionLDrag: ParamLoadData( &drawPG ); + /* no break */ case wActionMove: - case wActionLUp: case wActionRDown: case wActionRDrag: - case wActionRUp: - case wActionText: - case C_CMDMENU: if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); - if (!((MyGetKeyState() & WKEY_SHIFT) != 0)) { + if (!((MyGetKeyState() & WKEY_ALT) != magneticSnap)) { SnapPos( &pos ); } - return DrawGeomMouse( action, pos, &drawCmdContext ); + return DrawGeomMouse( action, pos, &drawCmdContext); + case wActionLUp: + case wActionRUp: + if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); + //if (!((MyGetKeyState() & WKEY_SHIFT) != 0)) { + // SnapPos( &pos ); Remove Snap at end of action - it will have been imposed in Geom if needed + //} + int rc = DrawGeomMouse( action, pos, &drawCmdContext); + // Put up text entry boxes ready for updates if the result was continue + if (rc == C_CONTINUE) { + switch( drawCmdContext.Op ) { + case OP_CIRCLE1: + case OP_CIRCLE2: + case OP_CIRCLE3: + case OP_FILLCIRCLE1: + case OP_FILLCIRCLE2: + case OP_FILLCIRCLE3: + controls[0] = drawRadiusPD.control; + controls[1] = NULL; + labels[0] = N_("Radius"); + ParamLoadControls( &drawPG ); + InfoSubstituteControls( controls, labels ); + drawRadiusPD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + case OP_CURVE1: + case OP_CURVE2: + case OP_CURVE3: + case OP_CURVE4: + if (drawCmdContext.ArcData.type == curveTypeCurve) { + controls[0] = drawRadiusPD.control; + controls[1] = drawAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Radius"); + labels[1] = N_("Arc Angle"); + } else { + controls[0] = drawLengthPD.control; + controls[1] = drawAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Length"); + labels[1] = N_("Angle"); + } + ParamLoadControls( &drawPG ); + InfoSubstituteControls( controls, labels ); + drawLengthPD.option &= ~PDO_NORECORD; + drawRadiusPD.option &= ~PDO_NORECORD; + drawAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + case OP_LINE: + case OP_BENCH: + case OP_TBLEDGE: + case OP_POLY: + case OP_FILLPOLY: + case OP_POLYLINE: + controls[0] = drawLengthPD.control; + controls[1] = drawAnglePD.control; + controls[2] = NULL; + labels[0] = N_("Seg Length"); + if (drawCmdContext.Op == OP_LINE || drawCmdContext.Op == OP_BENCH || drawCmdContext.Op == OP_TBLEDGE) + labels[1] = N_("Angle"); + else if (drawCmdContext.index > 0 ) + labels[1] = N_("Rel Angle"); + else + labels[1] = N_("Angle"); + ParamLoadControls( &drawPG ); + InfoSubstituteControls( controls, labels ); + drawLengthPD.option &= ~PDO_NORECORD; + drawAnglePD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + case OP_BOX: + case OP_FILLBOX: + controls[0] = drawLengthPD.control; + controls[1] = drawWidthPD.control; + controls[2] = NULL; + labels[0] = N_("Length"); + labels[1] = N_("Width"); + ParamLoadControls( &drawPG ); + InfoSubstituteControls( controls, labels ); + drawLengthPD.option &= ~PDO_NORECORD; + drawWidthPD.option &= ~PDO_NORECORD; + infoSubst = TRUE; + break; + default: + break; + } + } + return rc; case C_CANCEL: InfoSubstituteControls( NULL, NULL ); if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); - return DrawGeomMouse( action, pos, &drawCmdContext ); - + return DrawGeomMouse( action, pos, &drawCmdContext); + case C_TEXT: + if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(action, pos); + return DrawGeomMouse( action, pos, &drawCmdContext); case C_OK: if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); - return DrawGeomMouse( (0x0D<<8|wActionText), pos, &drawCmdContext ); + return DrawGeomMouse( (0x0D<<8|wActionText), pos, &drawCmdContext); + /*DrawOk( NULL );*/ case C_FINISH: if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); - return DrawGeomMouse( (0x0D<<8|wActionText), pos, &drawCmdContext ); + return DrawGeomMouse( (0x0D<<8|wActionText), pos, &drawCmdContext); /*DrawOk( NULL );*/ case C_REDRAW: if (drawCmdContext.Op == OP_BEZLIN) return CmdBezCurve(act2, pos); - return DrawGeomMouse( action, pos, &drawCmdContext ); + return DrawGeomMouse( action, pos, &drawCmdContext); + + case C_CMDMENU: + if (drawCmdContext.Op == OP_BEZLIN) return C_CONTINUE; + return DrawGeomMouse( action, pos, &drawCmdContext); default: return C_CONTINUE; @@ -1172,6 +2559,7 @@ static STATUS_T CmdDraw( wAction_t action, coOrd pos ) #include "bitmaps/dpoly.xpm" #include "bitmaps/dfilpoly.xpm" #include "bitmaps/dbezier.xpm" +#include "bitmaps/dpolyline.xpm" typedef struct { char **xpm; @@ -1195,16 +2583,18 @@ static drawData_t dcurveCmds[] = { { dbezier_xpm, OP_BEZLIN, N_("Bezier Curve"), N_("Draw Bezier"), "cmdDrawBezierCurve", ACCL_DRAWBEZLINE } }; static drawData_t dcircleCmds[] = { /*{ dcircle1_xpm, OP_CIRCLE1, "Circle Fixed Radius", "Draw Fixed Radius Circle", "cmdDrawCircleFixedRadius", ACCL_DRAWCIRCLE1 },*/ - { dcircle2_xpm, OP_CIRCLE3, N_("Circle Tangent"), N_("Draw Circle from Tangent"), "cmdDrawCircleTangent", ACCL_DRAWCIRCLE2 }, - { dcircle3_xpm, OP_CIRCLE2, N_("Circle Center"), N_("Draw Circle from Center"), "cmdDrawCircleCenter", ACCL_DRAWCIRCLE3 }, + { dcircle3_xpm, OP_CIRCLE3, N_("Circle Tangent"), N_("Draw Circle from Tangent"), "cmdDrawCircleTangent", ACCL_DRAWCIRCLE2 }, + { dcircle2_xpm, OP_CIRCLE2, N_("Circle Center"), N_("Draw Circle from Center"), "cmdDrawCircleCenter", ACCL_DRAWCIRCLE3 }, /*{ dflcrcl1_xpm, OP_FILLCIRCLE1, "Circle Filled Fixed Radius", "Draw Fixed Radius Filled Circle", "cmdDrawFilledCircleFixedRadius", ACCL_DRAWFILLCIRCLE1 },*/ - { dflcrcl2_xpm, OP_FILLCIRCLE3, N_("Circle Filled Tangent"), N_("Draw Filled Circle from Tangent"), "cmdDrawFilledCircleTangent", ACCL_DRAWFILLCIRCLE2 }, - { dflcrcl3_xpm, OP_FILLCIRCLE2, N_("Circle Filled Center"), N_("Draw Filled Circle from Center"), "cmdDrawFilledCircleCenter", ACCL_DRAWFILLCIRCLE3 } }; + { dflcrcl3_xpm, OP_FILLCIRCLE3, N_("Circle Filled Tangent"), N_("Draw Filled Circle from Tangent"), "cmdDrawFilledCircleTangent", ACCL_DRAWFILLCIRCLE2 }, + { dflcrcl2_xpm, OP_FILLCIRCLE2, N_("Circle Filled Center"), N_("Draw Filled Circle from Center"), "cmdDrawFilledCircleCenter", ACCL_DRAWFILLCIRCLE3 } }; static drawData_t dshapeCmds[] = { { dbox_xpm, OP_BOX, N_("Box"), N_("Draw Box"), "cmdDrawBox", ACCL_DRAWBOX }, { dfilbox_xpm, OP_FILLBOX, N_("Filled Box"), N_("Draw Filled Box"), "cmdDrawFilledBox", ACCL_DRAWFILLBOX }, - { dpoly_xpm, OP_POLY, N_("Poly Line"), N_("Draw Polyline"), "cmdDrawPolyline", ACCL_DRAWPOLYLINE }, - { dfilpoly_xpm, OP_FILLPOLY, N_("Polygon"), N_("Draw Polygon"), "cmdDrawPolygon", ACCL_DRAWPOLYGON } }; + { dpoly_xpm, OP_POLY, N_("Polygon"), N_("Draw Polygon"), "cmdDrawPolygon", ACCL_DRAWPOLY }, + { dfilpoly_xpm, OP_FILLPOLY, N_("Filled Polygon"), N_("Draw Filled Polygon"), "cmdDrawFilledPolygon", ACCL_DRAWFILLPOLYGON }, + { dpolyline_xpm, OP_POLYLINE, N_("PolyLine"), N_("Draw PolyLine"), "cmdDrawPolyline", ACCL_DRAWPOLYLINE }, +}; typedef struct { char * helpKey; @@ -1223,7 +2613,7 @@ static drawStuff_t drawStuff[4] = { { "cmdDrawLineSetCmd", N_("Straight Objects"), N_("Draw Straight Objects"), 4, dlineCmds }, { "cmdDrawCurveSetCmd", N_("Curved Lines"), N_("Draw Curved Lines"), 5, dcurveCmds }, { "cmdDrawCircleSetCmd", N_("Circle Lines"), N_("Draw Circles"), 4, dcircleCmds }, - { "cmdDrawShapeSetCmd", N_("Shapes"), N_("Draw Shapes"), 4, dshapeCmds} }; + { "cmdDrawShapeSetCmd", N_("Shapes"), N_("Draw Shapes"), 5, dshapeCmds} }; static void ChangeDraw( long changes ) @@ -1247,13 +2637,58 @@ static void DrawDlgUpdate( int inx, void * valueP ) { - if (drawCmdContext.Op == OP_BEZLIN) { - if ( (inx == 0 && pg->paramPtr[inx].valueP == &drawCmdContext.Width) || - (inx == 1 && pg->paramPtr[inx].valueP == &lineColor)) - { - lineWidth = drawCmdContext.Width; - UpdateParms(lineColor, lineWidth); - } + if (inx==3) { + if (drawCmdContext.Op == OP_BEZLIN) { + if ( (inx == 0 && pg->paramPtr[inx].valueP == &drawCmdContext.line_Width) || + (inx == 1 && pg->paramPtr[inx].valueP == &lineColor)) + { + lineWidth = drawCmdContext.line_Width; + UpdateParms(lineColor, lineWidth); + } + } + } + if (inx >=6 ) { + if (drawCmdContext.Op == OP_CIRCLE1 || + drawCmdContext.Op == OP_FILLCIRCLE1 || + drawCmdContext.Op == OP_CIRCLE2 || + drawCmdContext.Op == OP_FILLCIRCLE2 || + drawCmdContext.Op == OP_CIRCLE3 || + drawCmdContext.Op == OP_FILLCIRCLE3) { + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + if (drawCmdContext.Op == OP_CURVE1 || + drawCmdContext.Op == OP_CURVE2 || + drawCmdContext.Op == OP_CURVE3 || + drawCmdContext.Op == OP_CURVE4 ) { + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + if (drawCmdContext.Op == OP_LINE || + drawCmdContext.Op == OP_BENCH|| + drawCmdContext.Op == OP_TBLEDGE) { + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + + if (drawCmdContext.Op == OP_BOX || + drawCmdContext.Op == OP_FILLBOX ){ + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + + if (drawCmdContext.Op == OP_POLY || + drawCmdContext.Op == OP_FILLPOLY || + drawCmdContext.Op == OP_POLYLINE) { + coOrd pos = zero; + DrawGeomMouse(C_UPDATE,pos,&drawCmdContext); + } + ParamLoadControl(&drawPG,drawAngleInx); //Force Angle change out + //if (pg->paramPtr[inx].enter_pressed) { + // coOrd pos = zero; + // DrawGeomMouse((0x0D<<8)|(C_TEXT&0xFF),pos,&drawCmdContext); + // CmdDraw(C_START,pos); + //} } if ( inx >= 0 && pg->paramPtr[inx].valueP == &benchChoice ) @@ -1272,13 +2707,15 @@ EXPORT void InitCmdDraw( wMenu_p menu ) benchColor = wDrawFindColor( wRGB(255,192,0) ); ParamCreateControls( &drawPG, DrawDlgUpdate ); + ParamCreateControls( &drawModPG, DrawModDlgUpdate) ; + for ( inx1=0; inx1<4; inx1++ ) { dsp = &drawStuff[inx1]; ButtonGroupBegin( _(dsp->menuTitle), dsp->helpKey, _(dsp->stickyLabel) ); for ( inx2=0; inx2cnt; inx2++ ) { ddp = &dsp->data[inx2]; icon = wIconCreatePixMap( ddp->xpm ); - AddMenuButton( menu, CmdDraw, ddp->helpKey, _(ddp->cmdName), icon, LEVEL0_50, IC_STICKY|IC_POPUP2, ddp->acclKey, (void *)(intptr_t)ddp->OP ); + AddMenuButton( menu, CmdDraw, ddp->helpKey, _(ddp->cmdName), icon, LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ddp->acclKey, (void *)(intptr_t)ddp->OP ); } ButtonGroupEnd(); } @@ -1327,7 +2764,8 @@ EXPORT track_p NewText( ANGLE_T angle, char * text, CSIZE_T textSize, - wDrawColor color ) + wDrawColor color, + BOOL_T boxed) { trkSeg_t tempSeg; track_p trk; @@ -1339,6 +2777,7 @@ EXPORT track_p NewText( tempSeg.u.t.fontP = NULL; tempSeg.u.t.fontSize = textSize; tempSeg.u.t.string = MyStrdup( text ); + tempSeg.u.t.boxed = boxed; trk = MakeDrawFromSeg1( index, pos, angle, &tempSeg ); return trk; } @@ -1364,20 +2803,127 @@ EXPORT BOOL_T ReadText( char * line ) return FALSE; } - char * old = text; - text = ConvertFromEscapedText(text); - MyFree(old); - - trk = NewText( index, pos, angle, text, textSize, color ); + trk = NewText( index, pos, angle, text, textSize, color, FALSE ); SetTrkLayer( trk, layer ); MyFree(text); return TRUE; } +void MenuMode(int mode) { + if ( infoSubst ) { + InfoSubstituteControls( NULL, NULL ); + infoSubst = FALSE; + } + if (mode == 1) { + DrawGeomOriginMove(C_START,zero,&drawModCmdContext); + InfoMessage("Origin Mode"); + } else { + DrawGeomModify(C_START,zero,&drawModCmdContext); + InfoMessage("Points Mode"); + } +} + +void MenuEnter(int key) { + int action; + action = C_TEXT; + action |= key<<8; + if (drawModCmdContext.rotate_state) + DrawGeomOriginMove(action,zero,&drawModCmdContext); + else + DrawGeomModify(action,zero,&drawModCmdContext); +} + +void MenuLine(int key) { + struct extraData * xx = GetTrkExtraData(drawModCmdContext.trk); + if ( drawModCmdContext.type==SEG_STRLIN || drawModCmdContext.type==SEG_CRVLIN || drawModCmdContext.type==SEG_POLY ) { + switch(key) { + case '0': + xx->lineType = DRAWLINESOLID; + break; + case '1': + xx->lineType = DRAWLINEDASH; + break; + case '2': + xx->lineType = DRAWLINEDOT; + break; + case '3': + xx->lineType = DRAWLINEDASHDOT; + break; + case '4': + xx->lineType = DRAWLINEDASHDOTDOT; + break; + case '5': + xx->lineType = DRAWLINECENTER; + break; + case '6': + xx->lineType = DRAWLINEPHANTOM; + break; + } + MainRedraw(); // MenuLine + } +} + +EXPORT void SetLineType( track_p trk, int width ) { + if (QueryTrack(trk, Q_IS_DRAW)) { + struct extraData * xx = GetTrkExtraData(trk); + if ( xx->segs[0].type==SEG_STRLIN || xx->segs[0].type==SEG_CRVLIN || xx->segs[0].type==SEG_POLY) { + switch(width) { + case 0: + xx->lineType = DRAWLINESOLID; + break; + case 1: + xx->lineType = DRAWLINEDASH; + break; + case 2: + xx->lineType = DRAWLINEDOT; + break; + case 3: + xx->lineType = DRAWLINEDASHDOT; + break; + case 4: + xx->lineType = DRAWLINEDASHDOTDOT; + break; + case 5: + xx->lineType = DRAWLINECENTER; + break; + case 6: + xx->lineType = DRAWLINEPHANTOM; + break; + } + } + } +} EXPORT void InitTrkDraw( void ) { T_DRAW = InitObject( &drawCmds ); AddParam( "TABLEEDGE", ReadTableEdge ); AddParam( "TEXT", ReadText ); + + drawModDelMI = MenuRegister( "Modify Draw Edit Menu" ); + drawModClose = wMenuPushCreate( drawModDelMI, "", _("Close Polygon - 'g'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'g'); + drawModOpen = wMenuPushCreate( drawModDelMI, "", _("Make PolyLine - 'l'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'l'); + drawModFill = wMenuPushCreate( drawModDelMI, "", _("Fill Polygon - 'f'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'f'); + drawModEmpty = wMenuPushCreate( drawModDelMI, "", _("Empty Polygon - 'u'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'u'); + wMenuSeparatorCreate( drawModDelMI ); + drawModPointsMode = wMenuPushCreate( drawModDelMI, "", _("Points Mode - 'p'"), 0, (wMenuCallBack_p)MenuMode, (void*) 0 ); + drawModDel = wMenuPushCreate( drawModDelMI, "", _("Delete Selected Point - 'Del'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 127 ); + drawModVertex = wMenuPushCreate( drawModDelMI, "", _("Vertex Point - 'v'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'v' ); + drawModRound = wMenuPushCreate( drawModDelMI, "", _("Round Corner - 'r'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'r' ); + drawModSmooth = wMenuPushCreate( drawModDelMI, "", _("Smooth Corner - 's'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 's' ); + wMenuSeparatorCreate( drawModDelMI ); + drawModLinMI = wMenuMenuCreate( drawModDelMI, "", _("LineType...") ); + drawModSolid = wMenuPushCreate( drawModLinMI, "", _("Solid Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '0' ); + drawModDot = wMenuPushCreate( drawModLinMI, "", _("Dashed Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '1' ); + drawModDash = wMenuPushCreate( drawModLinMI, "", _("Dotted Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '2' ); + drawModDashDot = wMenuPushCreate( drawModLinMI, "", _("Dash-Dot Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '3' ); + drawModDashDotDot = wMenuPushCreate( drawModLinMI, "", _("Dash-Dot-Dot Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '4' ); + drawModCenterDot = wMenuPushCreate( drawModLinMI, "", _("Center-Dot Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '5' ); + drawModPhantom = wMenuPushCreate( drawModLinMI, "", _("Phantom-Dot Line"), 0, (wMenuCallBack_p)MenuLine, (void*) '6' ); + wMenuSeparatorCreate( drawModDelMI ); + drawModriginMode = wMenuPushCreate( drawModDelMI, "", _("Origin Mode - 'o'"), 0, (wMenuCallBack_p)MenuMode, (void*) 1 ); + drawModOrigin = wMenuPushCreate( drawModDelMI, "", _("Reset Origin - '0'"), 0, (wMenuCallBack_p)MenuEnter, (void*) '0' ); + drawModLast = wMenuPushCreate( drawModDelMI, "", _("Origin to Selected - 'l'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'l' ); + drawModCenter = wMenuPushCreate( drawModDelMI, "", _("Origin to Middle - 'm'"), 0, (wMenuCallBack_p)MenuEnter, (void*) 'm'); + } diff --git a/app/bin/celev.c b/app/bin/celev.c index 5a63a3a..1da4b22 100644 --- a/app/bin/celev.c +++ b/app/bin/celev.c @@ -29,6 +29,8 @@ #include "i18n.h" #include "param.h" #include "track.h" +#include "ccurve.h" +#include "utility.h" static wWin_p elevW; @@ -58,6 +60,71 @@ static paramData_t elevationPLs[] = { { PD_STRING, elevStationV, "station", PDO_DLGUNDERCMDBUTT|PDO_STRINGLIMITLENGTH, (void*)200, NULL, 0, 0, sizeof(elevStationV)} }; static paramGroup_t elevationPG = { "elev", 0, elevationPLs, sizeof elevationPLs/sizeof elevationPLs[0] }; +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) + +static void CreateSquareAnchor(coOrd p) { + DIST_T d = tempD.scale*0.25; + int i = anchors_da.cnt; + DYNARR_SET(trkSeg_t,anchors_da,i+4); + for (int j =0; j<4;j++) { + anchors(i+j).type = SEG_STRLIN; + anchors(i+j).color = wDrawColorBlue; + anchors(i+j).width = 0; + } + anchors(i).u.l.pos[0].x = anchors(i+2).u.l.pos[1].x = + anchors(i+3).u.l.pos[0].x = anchors(i+3).u.l.pos[1].x = p.x-d/2; + + anchors(i).u.l.pos[0].y = anchors(i).u.l.pos[1].y = + anchors(i+1).u.l.pos[0].y = anchors(i+3).u.l.pos[1].y = p.y-d/2; + + anchors(i).u.l.pos[1].x = + anchors(i+1).u.l.pos[0].x = anchors(i+1).u.l.pos[1].x = + anchors(i+2).u.l.pos[0].x = p.x+d/2; + + anchors(i+1).u.l.pos[1].y = + anchors(i+2).u.l.pos[0].y = anchors(i+2).u.l.pos[1].y = + anchors(i+3).u.l.pos[0].y = p.y+d/2; +} + +static void CreateEndAnchor(coOrd p, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; +} + +static void CreateSplitAnchor(coOrd pos, track_p t) { + DIST_T d = tempD.scale*0.1; + DIST_T w = tempD.scale/tempD.dpi*4; + int i; + ANGLE_T a = NormalizeAngle(GetAngleAtPoint(t,pos,NULL,NULL)+90.0); + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).color = wDrawColorBlue; + Translate(&anchors(i).u.l.pos[0],pos,a,GetTrkGauge(t)); + Translate(&anchors(i).u.l.pos[1],pos,a,-GetTrkGauge(t)); + anchors(i).width = w; + +} + + +void static CreateMoveAnchor(coOrd pos) { + DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pos,0,TRUE,wDrawColorBlue); + DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pos,90,TRUE,wDrawColorBlue); + DYNARR_APPEND(trkSeg_t,anchors_da,1); + CreateSquareAnchor(pos); +} static void LayoutElevW( paramData_t * pd, @@ -97,59 +164,16 @@ static int GetElevMode( void ) } -#ifdef LATER -static void DoElevRadio( long mode, void * context ) -{ - if ( mode < 0 || mode >= 7 ) - return; -#ifdef ELEVM - ParamLoadMessage( elevMessageM, "" ); -#endif - ParamControlActive( &elevationPG, I_HEIGHT, FALSE ); - ParamControlActive( &elevationPG, I_STATION, FALSE ); - switch ( mode ) { - case 0: - break; - case 1: - case 2: - ParamControlActive( &elevationPG, I_HEIGHT, TRUE ); - break; - case 3: - case 4: -#ifdef OLDELEV - if ( !( (rc0 == FDE_DEF && rc1 == FDE_DEF) || - (rc0 == FDE_DEF && rc1 == FDE_END) || - (rc0 == FDE_END && rc1 == FDE_DEF) ) ) { - ParamLoadMessage( &elevationPG, I_MSG, _("There are no reachable Defined Elevations") ); - ParamLoadControl( &elevationPG, I_MODE ); - return; - } -#endif - break; - case 5: - wControlActive( (wControl_p)elevStationS, TRUE ); - break; - } - elevModeV = mode; - DoElevUpdate( NULL, 1, NULL ); -} -#endif - static void DoElevUpdate( paramGroup_p pg, int inx, void * valueP ) { int oldMode, newMode; - coOrd pos; DIST_T elevNewValue, elevOldValue, diff; - DIST_T radius; if ( inx == 0 ) { long mode = *(long*)valueP; if ( mode < 0 || mode >= 7 ) return; -#ifdef ELEVM - ParamLoadMessage( elevMessageM, "" ); -#endif ParamControlActive( &elevationPG, I_HEIGHT, FALSE ); ParamControlActive( &elevationPG, I_STATION, FALSE ); switch ( mode ) { @@ -161,15 +185,6 @@ static void DoElevUpdate( paramGroup_p pg, int inx, void * valueP ) break; case 3: case 4: -#ifdef OLDELEV - if ( !( (rc0 == FDE_DEF && rc1 == FDE_DEF) || - (rc0 == FDE_DEF && rc1 == FDE_END) || - (rc0 == FDE_END && rc1 == FDE_DEF) ) ) { - ParamLoadMessage( &elevationPG, I_MSG, _("There are no reachable Defined Elevations") ); - ParamLoadControl( &elevationPG, I_MODE ); - return; - } -#endif break; case 5: ParamControlActive( &elevationPG, I_STATION, TRUE ); @@ -204,27 +219,14 @@ static void DoElevUpdate( paramGroup_p pg, int inx, void * valueP ) UndoStart( _("Set Elevation"), "Set Elevation" ); elevUndo = TRUE; } - pos = GetTrkEndPos( elevTrk, elevEp ); - radius = 0.05*mainD.scale; - if ( radius < trackGauge/2.0 ) - radius = trackGauge/2.0; - if ( (oldMode&ELEV_MASK)==ELEV_DEF || (oldMode&ELEV_MASK)==ELEV_IGNORE ) - DrawFillCircle( &tempD, pos, radius, - ((oldMode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore)); - HilightSelectedEndPt(FALSE, elevTrk, elevEp); UpdateTrkEndElev( elevTrk, elevEp, newMode, elevNewValue, elevStationV ); - HilightSelectedEndPt(TRUE, elevTrk, elevEp); - if ( (newMode&ELEV_MASK)==ELEV_DEF || (newMode&ELEV_MASK)==ELEV_IGNORE ) - DrawFillCircle( &tempD, pos, radius, - ((newMode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore)); + TempRedraw(); // DoElevUpdate } static void DoElevDone( void * arg ) { DoElevUpdate( NULL, 1, NULL ); - HilightElevations( FALSE ); - HilightSelectedEndPt( FALSE, elevTrk, elevEp ); elevTrk = NULL; Reset(); } @@ -250,7 +252,6 @@ static void ElevSelect( track_p trk, EPINX_T ep ) elevOldValue = 0.0; elevHeightV = 0.0; elevStationV[0] = 0; - HilightSelectedEndPt(FALSE, elevTrk, elevEp); elevTrk = trk; elevEp = ep; mode = GetTrkEndElevUnmaskedMode( trk, ep ); @@ -294,89 +295,26 @@ static void ElevSelect( track_p trk, EPINX_T ep ) } elevModeV = radio; ParamLoadControl( &elevationPG, I_MODE ); -#ifdef OLDELEV -if (oldElevationEvaluation) { - int dir; - ANGLE_T a; - int rc0, rc1; - DIST_T elev0, elev1, dist0, dist1; - a = GetTrkEndAngle( trk, ep ); - dir = ( a > 270 || a < 90 ); - rc0 = FindDefinedElev( trk, ep, dir, FALSE, &elev0, &dist0 ); - rc1 = FindDefinedElev( trk, ep, 1-dir, FALSE, &elev1, &dist1 ); - if ( rc0 == FDE_DEF ) { - sprintf( message, _("Elev = %s"), FormatDistance(elev0) ); - ParamLoadMessage( elev1ElevM, message ); - sprintf( message, _("Dist = %s"), FormatDistance(dist0) ); - ParamLoadMessage( elev1DistM, message ); -#ifdef LATER - if (dist0 > 0.1) - sprintf( message, "%0.1f%%", elev0/dist0 ); - else - sprintf( message, _("Undefined") ); - ParamLoadMessage( elev1GradeM, message ); -#endif - } else { - ParamLoadMessage( elev1ElevM, "" ); - ParamLoadMessage( elev1DistM, "" ); - /*ParamLoadMessage( elev1GradeM, "" );*/ - } - if ( rc1 == FDE_DEF ) { - sprintf( message, _("Elev = %s"), FormatDistance(elev1) ); - ParamLoadMessage( elev2ElevM, message ); - sprintf( message, _("Dist = %s"), FormatDistance(dist1) ); - ParamLoadMessage( elev2DistM, message ); -#ifdef LATER - if (dist1 > 0.1) - sprintf( message, "%0.1f%%", elev1/dist1 ); - else - sprintf( message, _("Undefined") ); - ParamLoadMessage( elev2GradeM, message ); -#endif - } else { - ParamLoadMessage( elev2ElevM, "" ); - ParamLoadMessage( elev2DistM, "" ); - /*ParamLoadMessage( elev2GradeM, "" );*/ - } + gradeOk = ComputeElev( trk, ep, FALSE, &elevX, &grade, TRUE ); computedOk = TRUE; - if (rc0 == FDE_DEF && rc1 == FDE_DEF) { - grade = (elev1-elev0)/(dist0+dist1); - elevX = elev0 + grade*dist0; - } else if (rc0 == FDE_DEF && rc1 == FDE_END) { - grade = 0.0; - elevX = elev0; - } else if (rc0 == FDE_END && rc1 == FDE_DEF) { - elevX = elev1; - grade = 0.0; - } else { - gradeOk = FALSE; - computedOk = FALSE; - } -} else { -#endif - gradeOk = ComputeElev( trk, ep, FALSE, &elevX, &grade ); - computedOk = TRUE; -#ifdef OLDELEV -} -#endif if (oldElevationEvaluation || computedOk) { - sprintf( message, "%0.2f%s", PutDim( elevX ), (units==UNITS_METRIC?"cm":"\"") ); + sprintf( message, "%0.2f%s", round(PutDim( elevX )*100.0)/100.0, (units==UNITS_METRIC?"cm":"\"") ); ParamLoadMessage( &elevationPG, I_COMPUTED, message ); if (gradeOk) { - sprintf( message, "%0.1f%%", fabs(grade*100) ); + sprintf( message, "%0.1f%%", fabs(round(grade*1000.0)/10.0) ); } else { if ( EndPtIsDefinedElev(trk,ep) ) { elev = GetElevation(trk); dist = GetTrkLength(trk,ep,-1); if (dist>0.1) - sprintf( message, "%0.1f%%", fabs((elev-elevX)/dist)*100.0 ); + sprintf( message, "%0.1f%%", fabs(round((elev-elevX)/dist)*1000.0)/10.0 ); else sprintf( message, _("Undefined") ); if ( (trk1=GetTrkEndTrk(trk,ep)) && (ep1=GetEndPtConnectedToMe(trk1,trk))>=0 ) { elev = GetElevation(trk1); dist = GetTrkLength(trk1,ep1,-1); if (dist>0.1) - sprintf( message+strlen(message), " - %0.1f%%", fabs((elev-elevX)/dist)*100.0 ); + sprintf( message+strlen(message), " - %0.1f%%", fabs(round((elev-elevX)/dist)*1000.0)/10.0 ); else sprintf( message+strlen(message), " - %s", _("Undefined") ); } @@ -390,7 +328,41 @@ if (oldElevationEvaluation) { ParamLoadControl( &elevationPG, I_HEIGHT ); } } - HilightSelectedEndPt(TRUE, elevTrk, elevEp); + wShow(elevW); +} + +static BOOL_T GetPointElev(track_p trk, coOrd pos, DIST_T * height) { + DIST_T len, len1, elev0, elev1, dist0, dist1; + if ( IsTrack( trk ) && GetTrkEndPtCnt(trk) == 2 ) { + dist0 = FindDistance(pos,GetTrkEndPos(trk,0)); + dist1 = FindDistance(pos,GetTrkEndPos(trk,1)); + if (EndPtIsDefinedElev(trk,0)) + elev0 = GetTrkEndElevHeight(trk,0); + else { + if (!GetTrkEndElevCachedHeight(trk,0,&elev0,&len)) { + if (GetTrkLength( trk, 0, 1 )<0.1) return FALSE; + ComputeElev( trk, 0, FALSE, &elev0, NULL, TRUE ); + } + } + if (EndPtIsDefinedElev(trk,1)) + elev1 = GetTrkEndElevHeight(trk,1); + else { + if (!GetTrkEndElevCachedHeight(trk,1,&elev1,&len1)) { + if (GetTrkLength( trk, 0, 1 )<0.1) return FALSE; + ComputeElev( trk, 0, FALSE, &elev0, NULL, TRUE ); + } + } + if (dist1+dist0 < 0.1) { + *height = elev0; + return TRUE; + } + *height = ((elev1-elev0)*(dist0/(dist0+dist1)))+elev0; + return TRUE; + } else if (GetTrkEndPtCnt(trk) == 1 && GetTrkEndElevCachedHeight(trk,0,&elev0,&len)) { + *height = elev0; + return TRUE; + } + return FALSE; } @@ -403,59 +375,129 @@ static STATUS_T CmdElevation( wAction_t action, coOrd pos ) switch (action) { case C_START: if ( elevW == NULL ) - elevW = ParamCreateDialog( &elevationPG, MakeWindowTitle(_("Elevation")), _("Done"), DoElevDone, NULL, TRUE, LayoutElevW, 0, DoElevUpdate ); + elevW = ParamCreateDialog( &elevationPG, MakeWindowTitle(_("Elevation")), _("Done"), DoElevDone, wHide, TRUE, LayoutElevW, 0, DoElevUpdate ); elevModeV = 0; elevHeightV = 0.0; elevStationV[0] = 0; ParamLoadControls( &elevationPG ); ParamGroupRecord( &elevationPG ); - wShow( elevW ); + //wShow( elevW ); ParamControlActive( &elevationPG, I_MODE, FALSE ); ParamControlActive( &elevationPG, I_HEIGHT, FALSE ); ParamControlActive( &elevationPG, I_STATION, FALSE ); ParamLoadMessage( &elevationPG, I_COMPUTED, "" ); ParamLoadMessage( &elevationPG, I_GRADE, "" ); - InfoMessage( _("Select End-Point") ); - HilightElevations( TRUE ); + InfoMessage( _("Click on end, +Shift to split, +Ctrl to move description") ); elevTrk = NULL; elevUndo = FALSE; + CmdMoveDescription( action, pos ); + TempRedraw(); // CmdElevation C_START return C_CONTINUE; - case C_RDOWN: - case C_RMOVE: - case C_RUP: - CmdMoveDescription( action-C_RDOWN+C_DOWN, pos ); - return C_CONTINUE; - case C_LCLICK: - if ((trk0 = OnTrack( &pos, TRUE, TRUE )) == NULL) { + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if (MyGetKeyState()&WKEY_CTRL) { + commandContext = (void*) 1; //Just end points + CmdMoveDescription( action, pos ); return C_CONTINUE; } - if ( (MyGetKeyState()&WKEY_SHIFT) ) { - ep0 = PickEndPoint( pos, trk0 ); - UndoStart( _("Split Track"), "SplitTrack( T%d[%d] )", GetTrkIndex(trk0), ep0 ); - oldTrackCount = trackCount; - if (!SplitTrack( trk0, pos, ep0, &trk1, FALSE )) + BOOL_T xing = FALSE; + coOrd p0 = pos, p2=pos; + if ((trk0 = OnTrack2(&p0,FALSE, TRUE, FALSE, NULL)) != NULL) { + EPINX_T ep0 = 0, ep1 = 1; + DIST_T elev0, elev1; + if (GetTrkEndPtCnt(trk0) == 2) { + if (!GetPointElev(trk0,p0,&elev0)) { + InfoMessage( _("Move to end or track crossing +Shift to split") ); + return C_CONTINUE; + } + } else { + InfoMessage( _("Move to end or track crossing") ); return C_CONTINUE; - ElevSelect( trk0, ep0 ); - UndoEnd(); - elevUndo = FALSE; - } else { - ep0 = PickEndPoint( pos, trk0 ); - ElevSelect( trk0, ep0 ); + } + if ((trk1 = OnTrack2(&p2,FALSE, TRUE, FALSE, trk0)) != NULL) { + if (IsClose(FindDistance(p0,p2))) { + if (GetEndPtConnectedToMe(trk0,trk1) == -1) { //Not simply connected to each other!!! + if (GetTrkEndPtCnt(trk1) == 2) { + if (GetPointElev(trk1,p2,&elev1)) { + if (MyGetKeyState()&WKEY_SHIFT) { + InfoMessage (_("Crossing - First %0.3f, Second %0.3f, Clearance %0.3f - Click to Split"), PutDim(elev0), PutDim(elev1), PutDim(fabs(elev0-elev1))); + } else + InfoMessage (_("Crossing - First %0.3f, Second %0.3f, Clearance %0.3f"), PutDim(elev0), PutDim(elev1), PutDim(fabs(elev0-elev1))); + } + CreateSquareAnchor(p2); + return C_CONTINUE; + } + } + } + } + if ((ep0 = PickEndPoint( p0, trk0 )) != -1) { + if (IsClose(FindDistance(GetTrkEndPos(trk0,ep0),pos))) { + CreateEndAnchor(GetTrkEndPos(trk0,ep0),FALSE); + InfoMessage (_("Track End elevation %0.3f"), PutDim(elev0)); + } else if ((MyGetKeyState()&WKEY_SHIFT) && QueryTrack(trk0,Q_MODIFY_CAN_SPLIT) + && !(QueryTrack(trk0,Q_IS_TURNOUT))) { + InfoMessage( _("Click to split here - elevation %0.3f"), PutDim(elev0)); + CreateSplitAnchor(p0,trk0); + } else { + InfoMessage( _("Track Point elevation %0.3f"), PutDim(elev0)); + CreateEndAnchor(p0,TRUE); + } + } else InfoMessage( _("Click on end, +Shift to split, +Ctrl to move description") ); + } else + InfoMessage( _("Click on end, +Shift to split, +Ctrl to move description") ); + return C_CONTINUE; + case C_DOWN: + case C_MOVE: + case C_UP: + if (MyGetKeyState()&WKEY_CTRL) { + commandContext = (void*) 1; //Just end points + CmdMoveDescription( action, pos ); + DYNARR_RESET(trkSeg_t,anchors_da); + elevTrk = NULL; return C_CONTINUE; } + /*no break*/ + case C_LCLICK: + ; + p0= pos; + if ((trk0 = OnTrack( &p0, TRUE, TRUE )) == NULL) { + wHide(elevW); + elevTrk = NULL; + InfoMessage( _("Click on end, +Shift to split, +Ctrl to move description") ); + } else { + ep0 = PickEndPoint( p0, trk0 ); + if (IsClose(FindDistance(GetTrkEndPos(trk0,ep0),pos))) { + InfoMessage( _("Point selected!") ); + ElevSelect( trk0, ep0 ); + } else if ( (MyGetKeyState()&WKEY_SHIFT) ) { + UndoStart( _("Split track"), "SplitTrack( T%d[%d] )", GetTrkIndex(trk0), ep0 ); + oldTrackCount = trackCount; + if (!QueryTrack(trk0,Q_IS_TURNOUT) && + !SplitTrack( trk0, p0, ep0, &trk1, FALSE )) + return C_CONTINUE; + InfoMessage( _("Track split!") ); + ElevSelect( trk0, ep0 ); + UndoEnd(); + elevUndo = FALSE; + } + } + DYNARR_RESET(trkSeg_t,anchors_da); return C_CONTINUE; case C_OK: DoElevDone(NULL); + InfoMessage( "" ); return C_TERMINATE; case C_CANCEL: - HilightElevations( FALSE ); - HilightSelectedEndPt( FALSE, elevTrk, elevEp ); elevTrk = NULL; wHide( elevW ); + InfoMessage( "" ); return C_TERMINATE; case C_REDRAW: DoElevHilight( NULL ); HilightSelectedEndPt( TRUE, elevTrk, elevEp ); + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + CmdMoveDescription( action, pos ); return C_CONTINUE; } return C_CONTINUE; @@ -469,6 +511,6 @@ static STATUS_T CmdElevation( wAction_t action, coOrd pos ) EXPORT void InitCmdElevation( wMenu_p menu ) { ParamRegister( &elevationPG ); - AddMenuButton( menu, CmdElevation, "cmdElevation", _("Elevation"), wIconCreatePixMap(elev_xpm), LEVEL0_50, IC_POPUP|IC_LCLICK, ACCL_ELEVATION, NULL ); + AddMenuButton( menu, CmdElevation, "cmdElevation", _("Elevation"), wIconCreatePixMap(elev_xpm), LEVEL0_50, IC_POPUP|IC_LCLICK|IC_RCLICK|IC_WANT_MOVE, ACCL_ELEVATION, NULL ); } diff --git a/app/bin/cgroup.c b/app/bin/cgroup.c index 0094564..1183e76 100644 --- a/app/bin/cgroup.c +++ b/app/bin/cgroup.c @@ -472,11 +472,12 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep Rotate( &orig, zero, xx->angle ); orig.x = xx->orig.x - orig.x; orig.y = xx->orig.y - orig.y; - trk1 = NewCompound( T_TURNOUT, 0, orig, xx->angle, xx->title, tempEndPts_da.cnt-epCnt1, &tempEndPts(epCnt1), pathPtr_da.cnt, &pathPtr(0), tempSegs_da.cnt, &tempSegs(0) ); + trk1 = NewCompound( T_TURNOUT, 0, orig, xx->angle, xx->title, tempEndPts_da.cnt-epCnt1, &tempEndPts(epCnt1), NULL, pathPtr_da.cnt, &pathPtr(0), tempSegs_da.cnt, &tempSegs(0) ); xx1 = GetTrkExtraData(trk1); xx1->ungrouped = TRUE; SetTrkVisible( trk1, TRUE ); + SetTrkNoTies( trk1, FALSE ); SetTrkBits( trk1, TB_SELECTED ); for ( segInx=0; segInxpaths; - pos1 = GetTrkEndPos(trk,ep1); - Rotate( &pos1, xx->orig, -xx->angle ); - pos1.x -= xx->orig.x; - pos1.y -= xx->orig.y; - pos2 = GetTrkEndPos(trk,ep2); - Rotate( &pos2, xx->orig, -xx->angle ); - pos2.x -= xx->orig.x; - pos2.y -= xx->orig.y; + trkPos[0] = GetTrkEndPos(trk,ep1); + Rotate( &trkPos[0], xx->orig, -xx->angle ); + trkPos[0].x -= xx->orig.x; + trkPos[0].y -= xx->orig.y; + trkPos[1] = GetTrkEndPos(trk,ep2); + Rotate( &trkPos[1], xx->orig, -xx->angle ); + trkPos[1].x -= xx->orig.x; + trkPos[1].y -= xx->orig.y; + DIST_T dist = 1000.0; + char * path = NULL; + char * pName = "Not Found"; while ( cp[0] ) { - cp += strlen(cp)+1; //Ignore Path Name + char * pName1 = cp; // Save path name + cp += strlen(cp)+1; while ( cp[0] ) { - cp0 = cp; - epN = -1; + int segInx; + int segEP; + coOrd segPos[2]; + // Check if this sub-path endpts match the requested endpts + char * path1 = cp; + + // get the seg indices for the start and end GetSegInxEP( cp[0], &segInx, &segEP ); - if ( CheckTurnoutEndPoint( &xx->segs[segInx], pos1, segEP ) ) - epN = 1; - else if ( CheckTurnoutEndPoint( &xx->segs[segInx], pos2, segEP ) ) - epN = 0; + segPos[0] = GetSegEndPt( &xx->segs[segInx], segEP, FALSE, NULL ); cp += strlen(cp); - if ( epN != -1 ) { - GetSegInxEP( cp[-1], &segInx, &segEP ); - if ( CheckTurnoutEndPoint( &xx->segs[segInx], epN==0?pos1:pos2, 1-segEP ) ) { - *flip = epN==0; // If its reversed, set up to be flipped or noted - return cp0; //Found path between EPs + GetSegInxEP( cp[-1], &segInx, &segEP ); + segPos[1] = GetSegEndPt( &xx->segs[segInx], 1-segEP, FALSE, NULL ); + + // Find the closest seg end + for ( int inx = 0; inx<2; inx++ ) { + // Check 1st end + DIST_T dist1 = FindDistance( trkPos[0], segPos[inx] ); + if ( dist1 < connectDistance && dist1 < dist ) { + // Closest so far, Check 2nd end + DIST_T dist2 = FindDistance( trkPos[1], segPos[1-inx] ); + if ( dist2 > dist1 ) + // 2nd end is further away + dist1 = dist2; + if ( dist1 < connectDistance && dist1 < dist ) { + // both ends are closest + dist = dist1; + path = path1; + pName = pName1; + *flip = (inx==1); + } } } cp++; } cp++; } - return NULL; +LOG( log_group, 3, (" %s: %d..%d Flip:%s\n", pName, path?path[0]:-1, path?path[strlen(path)-1]:-1, *flip?"T":"F" ) ); + return path; } @@ -754,7 +779,7 @@ static int GroupShortestPathFunc( return -1; case SPTC_ADD_TRK: -if (log_shortPath<=0||logTable(log_shortPath).level<4) LOG( log_group, 2, ( " T%d[%d]\n", GetTrkIndex(trk), ep2 ) ) + LOG( log_group, 4, ( " Add T%d[%d]\n", GetTrkIndex(trk), ep2 ) ) DYNARR_APPEND( pathElem_t, pathElem_da, 10 ); ppp = &pathElem(pathElem_da.cnt-1); for ( inx=0; inxep1 == ep1 || pp->ep2 == ep1 ) ) && ( ep2 < 0 || ( pp->ep1 == ep2 || pp->ep2 == ep2 ) ) ) { -LOG( log_group, 2, ( " Remove: duplicate path P%d\n", inx ) ) +LOG( log_group, 4, ( " Remove: duplicate path P%d\n", inx ) ) pathElem_da.cnt = pathElemStart; return 0; } @@ -814,7 +839,7 @@ LOG( log_group, 2, ( " Remove: duplicate path P%d\n", inx ) ) pp->ep1 = ep1; pp->ep2 = ep2; pathElemStart = pathElem_da.cnt; -LOG( log_group, 2, ( " Keep\n" ) ) +LOG( log_group, 4, ( " Keep\n" ) ) return 0; case SPTC_IGNNXTTRK: @@ -917,6 +942,87 @@ static BOOL_T CheckForBumper( return TRUE; } +typedef struct { + int inx; + wBool_t track; +} segInMap_t; +static dynArr_t segInMap_da; +#define segInMap(N) DYNARR_N( segInMap_t, segInMap_da, N) + +void AddToSegMap(int inx,wBool_t track) { + DYNARR_APPEND(segInMap_t,segInMap_da,10); + DYNARR_LAST(segInMap_t,segInMap_da).inx = inx; + DYNARR_LAST(segInMap_t,segInMap_da).track = track; +} + +void AddSegsToSegMap(int start, int end, wBool_t track) { + for (int i = start; i<= end; i++) { + AddToSegMap(i,track); + } +} + +static dynArr_t trackSegs_da; +#define trackSegs(N) DYNARR_N( trkSeg_t, trackSegs_da, N ) + + +trkSeg_p GetSegFromSegMap(int index) { + if (DYNARR_N( segInMap_t, segInMap_da, index).track) { + return &DYNARR_N(trkSeg_t,trackSegs_da,DYNARR_N( segInMap_t, segInMap_da, index).inx); + } else + return &DYNARR_N(trkSeg_t,tempSegs_da,DYNARR_N( segInMap_t, segInMap_da, index).inx); +} + +static dynArr_t outputSegs_da; +#define outputSegs(N) DYNARR_N( trkSeg_t, outputSegs_da, N) + +static void LogSeg( + trkSeg_p segP ) +{ + if ( segP == NULL ) { + LogPrintf( "\n" ); + return; + } + LogPrintf( "%c: ", segP->type ); + switch ( segP->type ) { + case SEG_STRTRK: + case SEG_STRLIN: + case SEG_DIMLIN: + case SEG_BENCH: + case SEG_TBLEDGE: + LogPrintf( "[ %0.3f %0.3f ] [ %0.3f %0.3f ]\n", + segP->u.l.pos[0].x, segP->u.l.pos[0].y, + segP->u.l.pos[1].x, segP->u.l.pos[1].y ); + break; + case SEG_CRVLIN: + case SEG_CRVTRK: + LogPrintf( "R:%0.3f [ %0.3f %0.3f } A0:%0.3f A1:%0.3f\n", + segP->u.c.radius, + segP->u.c.center.x, segP->u.c.center.y, + segP->u.c.a0, segP->u.c.a1 ); + break; + default: + LogPrintf( "%c:\n", segP->type ); + } +} +/* + * GroupOk: create a TURNOUT or STRUCTURE from the selected objects + * 1 - Add selected tracks to groupTrk[] + * - Add each group trk's segments to trackSeg[] or tempSegs[] + * - Add all segs to segInMap[] + * - if no track segments goto step 9 + * 2 - Collect boundary endPts and sort them in tempEndPts[] + * 3 - Find shortest path between all endPts (if it exists) + * - For each track we add to the shortest path tree + * capture the sub-path elements (FindPathBtwEP) in pathElem[] + * 4 - Flip tracks so sub-path elements match up + * 5 - Create conflict map + * 6 - Flip paths to minimize the number of flipped segments + * 7 - Build the path ('P') string + * 8 - Build segment list, adjust endPts in tempEndPts[] + * 9 - create new TURNOUT/STRUCTURE definition + * 10 - write defn to xtrkcad.cus + * 11 - optionally replace grouped tracks with new defn + */ static void GroupOk( void * junk ) { @@ -925,7 +1031,6 @@ static void GroupOk( void * junk ) int inx; EPINX_T ep, epCnt, epN; coOrd orig, size; - long oldOptions; FILE * f = NULL; BOOL_T rc = TRUE; track_p trk, trk1; @@ -937,17 +1042,7 @@ static void GroupOk( void * junk ) ANGLE_T angle, angleN; pathElem_t pathElemTemp; char * cp=NULL; -#ifdef SEGMAP - pathElem_p ppp1, ppp2; - int segInx1, segInx2; - coOrd pos1, pos2; - static dynArr_t segMap_da; -#define segMap(I,J) DYNARR_N( char, segMap_da, (2*(I)+0)*trackSegs_da.cnt+(J) ) -#define segAcc(I,J) DYNARR_N( char, segMap_da, (2*(I)+1)*trackSegs_da.cnt+(J) ) -#define segSum(I,J) DYNARR_N( char, segMap_da, (2*(groupTrk_da.cnt)+0)*trackSegs_da.cnt+(J) ) -#endif - static dynArr_t trackSegs_da; -#define trackSegs(N) DYNARR_N( trkSeg_t, trackSegs_da, N ) + trkSeg_p segPtr; int segCnt; static dynArr_t conflictMap_da; @@ -965,9 +1060,6 @@ static void GroupOk( void * junk ) signed char pathChar; char *oldLocale = NULL; -#ifdef SEGMAP - DYNARR_RESET( char, segMap_da ); -#endif DYNARR_RESET( trkSeg_t, trackSegs_da ); DYNARR_RESET( trkSeg_t, tempSegs_da ); DYNARR_RESET( groupTrk_t, groupTrk_da ); @@ -976,6 +1068,8 @@ static void GroupOk( void * junk ) DYNARR_RESET( trkEndPt_t, tempEndPts_da ); DYNARR_RESET( char, pathPtr_da ); + DYNARR_RESET( segInMap_t, segInMap_da); + ParamUpdate( &groupPG ); if ( groupManuf[0]==0 || groupDesc[0]==0 || groupPartno[0]==0 ) { NoticeMessage2( 0, MSG_GROUP_NONBLANK, _("Ok"), NULL ); @@ -991,9 +1085,10 @@ static void GroupOk( void * junk ) wDrawDelayUpdate( mainD.d, TRUE ); /* - * Collect tracks + * 1: Collect tracks */ trk = NULL; + int InInx = -1; while ( TrackIterate( &trk ) ) { if ( GetTrkSelected( trk ) ) { if ( IsTrack(trk) ) { @@ -1008,41 +1103,82 @@ static void GroupOk( void * junk ) if ( IsSegTrack(segPtr) ) { DYNARR_APPEND( trkSeg_t, trackSegs_da, 10 ); trackSegs(trackSegs_da.cnt-1) = *segPtr; + + AddToSegMap(trackSegs_da.cnt-1,TRUE); /* Single Track Seg - Note no Cornu*/ + RotateSegs( 1, &trackSegs(trackSegs_da.cnt-1), zero, xx->angle ); MoveSegs( 1, &trackSegs(trackSegs_da.cnt-1), xx->orig ); + } else { + int start = tempSegs_da.cnt; DrawSegs( &groupD, xx->orig, xx->angle, segPtr, 1, trackGauge, wDrawColorBlack ); + + AddSegsToSegMap(start,tempSegs_da.cnt-1,FALSE); /* Multiple Non-Track Segs */ } } } else if (GetTrkType(trk) == T_BEZIER || GetTrkType(trk) == T_BZRLIN ) { DYNARR_APPEND(trkSeg_t, trackSegs_da, 10); segPtr = &trackSegs(trackSegs_da.cnt-1); + GetBezierSegmentFromTrack(trk,segPtr); + + AddToSegMap(trackSegs_da.cnt-1,TRUE); // Add Single Bezier Track + } else if (GetTrkType(trk) == T_CORNU) { - GetBezierSegmentsFromCornu(trk,&trackSegs_da); //Only give back Bezier - cant be undone + + int start = trackSegs_da.cnt; + + GetBezierSegmentsFromCornu(trk,&trackSegs_da,TRUE); //Only give back Bezier - cant be undone + + AddSegsToSegMap(start,trackSegs_da.cnt-1,TRUE); /* Add Multiple Track Segs */ + } else { segCnt = tempSegs_da.cnt; - oldOptions = groupD.options; - groupD.options |= (DC_QUICK|DC_SIMPLE|DC_SEGTRACK); DrawTrack( trk, &groupD, wDrawColorBlack ); - groupD.options = oldOptions; DYNARR_APPEND( trkSeg_t, trackSegs_da, 10 ); segPtr = &trackSegs(trackSegs_da.cnt-1); *segPtr = tempSegs( segCnt ); + + AddToSegMap(trackSegs_da.cnt-1,TRUE); // Add One Track + if ( tempSegs_da.cnt != segCnt+1 || !IsSegTrack(segPtr) ) { NoticeMessage2( 0, MSG_CANNOT_GROUP_TRACK, _("Ok"), NULL ); wHide( groupW ); return; } + tempSegs_da.cnt = segCnt; } groupP->segEnd = trackSegs_da.cnt-1; } else { + int start = tempSegs_da.cnt; + DrawTrack( trk, &groupD, wDrawColorBlack ); + + AddSegsToSegMap(start,tempSegs_da.cnt-1,FALSE); /* Multiple Non-Track Segs */ } } } +if ( log_group >= 1 && logTable(log_group).level >= 4 ) { + LogPrintf( "Track Segs:\n"); + for ( int inx = 0; inx < trackSegs_da.cnt; inx++ ) { + LogPrintf( " %d: ", inx+1 ); + LogSeg( &trackSegs(inx) ); + } + LogPrintf( "Other Segs:\n"); + for ( int inx = 0; inx < tempSegs_da.cnt; inx++ ) { + LogPrintf( " %d: ", inx+1 ); + LogSeg( &tempSegs(inx) ); + } +} +if ( log_group >= 1 && logTable(log_group).level >= 3 ) { + LogPrintf( "Combined Segs:\n" ); + for ( int inx = 0; inx0 ) { if ( groupTrk_da.cnt > 128 ) { @@ -1084,6 +1220,17 @@ static void GroupOk( void * junk ) } } } +if ( log_group >= 1 && logTable(log_group).level >= 4 ) { + LogPrintf( "EndPts:\n" ); + for ( int inx=0; inxpos.x, endPtP->pos.y, endPtP->angle, endPtP->track?GetTrkIndex(endPtP->track):-1, endPtP->index ); + } +} + /* + * 2: Collect EndPts + */ if ( tempEndPts_da.cnt <= 0 ) { NoticeMessage( _("No endpts"), _("Ok"), NULL ); wDrawDelayUpdate( mainD.d, FALSE ); @@ -1140,10 +1287,7 @@ static void GroupOk( void * junk ) qsort( tempEndPts_da.ptr, tempEndPts_da.cnt, sizeof *endPtP, CmpEndPtAngle ); if ( NormalizeAngle( tempEndPts(0).angle - tempEndPts(tempEndPts_da.cnt-1).angle ) > NormalizeAngle( tempEndPts(1).angle - tempEndPts(0).angle ) ) { -#ifdef LATER - if ( endPtAngle-FindAngle(endPtOrig,tempEndPts(tempEndPts_da.cnt-1).pos) > - FindAngle(endPtOrig,tempEndPts(1).pos)-endPtAngle ) { -#endif + for ( ep=1; ep<(tempEndPts_da.cnt+1)/2; ep++ ) { trkEndPt_t tempEndPt; tempEndPt = tempEndPts(ep); @@ -1151,9 +1295,17 @@ static void GroupOk( void * junk ) tempEndPts(tempEndPts_da.cnt-ep) = tempEndPt; } } +if ( log_group >= 1 && logTable(log_group).level >= 3 ) { + LogPrintf( "Sorted EndPts:\n" ); + for ( int inx=0; inxpos.x, endPtP->pos.y, endPtP->angle, endPtP->track?GetTrkIndex(endPtP->track):-1, endPtP->index ); + } +} /* - * Find shortest Paths + * 3: Find shortest Paths */ for ( inx=0; inx= 1 && logTable(log_group).level >= 3 ) { + LogPrintf( "Shortest path:\n Group Tracks\n" ); + for ( int inx=0; inxtrk ), gtp->segStart+1, gtp->segEnd+1 ); + } + LogPrintf( " Path Elem\n" ); + for ( int inx=0; inxgroupInx, ppp->ep1, ppp->ep2, ppp->flip?"T":"F" ); + for ( PATHPTR_T cp = ppp->path; cp[0] || cp[1]; cp++ ) { + LogPrintf( " %d", *cp ); + } + LogPrintf( " 0\n" ); + } + LogPrintf( " Path\n" ); + for ( int inx=0; inxpathElemStart, pp->pathElemEnd, pp->ep1, pp->ep2, + pp->conflicts, pp->inGroup?"T":"F", pp->done?"T":"F" ); + } +} /* - * Flip paths so they align + * 4: Flip paths so they align */ if ( path_da.cnt == 0 ) { NoticeMessage( _("No paths"), _("Ok"), NULL ); @@ -1226,11 +1402,11 @@ LOG( log_group, 1, ( "P%d aligns flipped with P%d\n", pinx, pinx2 ) ); path(inx).done = TRUE; } } -if ( log_group >= 1 && logTable(log_group).level > log_group ) { +if ( log_group >= 1 && logTable(log_group).level >= 1 ) { LogPrintf( "Group Paths\n" ); for ( pinx=0; pinxep1, pp->ep2 ); + LogPrintf( " P%2d:%d.%d ", pinx, pp->ep1, pp->ep2 ); for ( pinx2=pp->pathElemEnd; pinx2>=pp->pathElemStart; pinx2-- ) { ppp = &pathElem(pinx2); LogPrintf( " %sT%d:%d.%d", ppp->flip?"-":"", GetTrkIndex(groupTrk(ppp->groupInx).trk), ppp->ep1, ppp->ep2 ); @@ -1239,62 +1415,9 @@ if ( log_group >= 1 && logTable(log_group).level > log_group ) { } } -#ifdef SEGMAP - DYNARR_SET( char, segMap_da, 2 * trackSegs_da.cnt * path_da.cnt + 2 ); - memset( segMap_da.ptr, 0, segMap_da.max * sizeof segMap(0,0) ); - for ( inx=0; inxpathElem_da.cnt-1; inx2>=0; inx2-- ) { - ppp = &pathElem(pp->pathElemStart+inx2); - groupP = &groupTrk(ppp->groupInx); - if ( GetTrkEndPtCnt(groupP->trk) == 2 ) { - segMap(inx,groupP->segStart) = 1; - continue; - } - cp = ppp->path; - if ( cp == NULL ) - continue; - segInx1 = cp[0]-1; - for ( ; *cp; cp++ ) - segMap(inx,groupP->segInx+cp[0]-1) = 1; - segInx2 = cp[-1]-1; - pos1 = GetSegEndPt( &trackSegs(groupP->segInx+segInx1), ppp->flip?1:0, FALSE, NULL ); - pos2 = GetSegEndPt( &trackSegs(groupP->segInx+segInx2), ppp->flip?0:1, FALSE, NULL ); - for ( inx3=0; inx3segCnt; inx3++ ) { - if ( inx3 == segInx1 || inx3 == segInx2 ) continue; - if ( segMap(inx,groupP->segInx+inx3) != 0 ) continue; - if ( CheckTurnoutEndPoint( &trackSegs(groupP->segInx+inx3), pos1, 0 ) ) - segMap(inx,inx3) = 2; - else if ( CheckTurnoutEndPoint( &trackSegs(groupP->segInx+inx3), pos2, 0 ) ) - segMap(inx,groupP->segInx+inx3) = 2; - } - } - } -if ( log_group >= 1 && logTable(log_group).level > log_group ) { - LogPrintf( "Path to Segment Map\n "); - for ( inx=0; inxtrk) ); - for ( inx2=1; inx2segCnt; inx2++ ) LogPrintf( "--" ); - } - LogPrintf( "\n " ); - for ( inx=0; inxsegCnt; inx2++ ) - LogPrintf( "%2d", inx2+1 ); - } - LogPrintf( "\n" ); - for ( inx=0; inx= 1 && logTable(log_group).level > log_group ) { } } -if ( log_group >= 1 && logTable(log_group).level > log_group ) { +if ( log_group >= 1 && logTable(log_group).level >= 3 ) { LogPrintf( "Group Map\n"); for ( pinx=0; pinx= 0; ginx++ ) - LogPrintf( " %d", groupMap(pinx,ginx) ); + LogPrintf( " %d: %d", ginx, groupMap(pinx,ginx) ); LogPrintf( "\n" ); } } -#ifdef SEGMAP - for ( inx=0; inxgroupInx < 0 ) continue; - for ( inx2=0; inx2= 1 && logTable(log_group).level > log_group ) { /* * Flip each segment that is used as flipped more than not */ +LOG( log_group, 3, ( "Flipping Segments:" ) ); for ( pinx=0; pinx= 0; ginx++ ) { pp = &path(groupMap(pinx,ginx)); + LOG( log_group, 3, (" Group Map(%d, %d): elem %d-%d, EP %d %d, Conflicts %d, inGrp %d, Done: %s\n", pinx, ginx, pp->pathElemStart, pp->pathElemEnd, pp->ep1, pp->ep2, pp->conflicts, pp->inGroup, pp->done?"T":"F" ) ); for ( pinx2=pp->pathElemEnd; pinx2>=pp->pathElemStart; pinx2-- ) { ppp = &pathElem( pinx2 ); + LOG( log_group, 3, (" PE %d: GI %d, EP %d %d, Flip %d =", pinx2, ppp->groupInx, ppp->ep1, ppp->ep2, ppp->flip )); groupP = &groupTrk( ppp->groupInx ); path = ppp->path; flip = ppp->flip; @@ -1453,7 +1556,9 @@ LOG( log_group, 1, ( "Flipping Segment %d\n", pinx+1 ) ); if ( flip1 ) pathChar = - pathChar; pathPtr(pathPtr_da.cnt-1) = pathChar; path += (flip?-1:1); + LOG( log_group, 3, (" %d", pathChar ) ); } + LOG( log_group, 3, ("\n") ); } DYNARR_APPEND( char, pathPtr_da, 10 ); pathPtr(pathPtr_da.cnt-1) = 0; @@ -1468,43 +1573,49 @@ LOG( log_group, 1, ( "Flipping Segment %d\n", pinx+1 ) ); groupSimpleTurnout: /* - * Copy and Reorigin Segments + * 8: Copy and Reorigin Segments - Start by putting them out in the original order */ - if ( tempSegs_da.cnt > 0 ) { - inx = trackSegs_da.cnt; - DYNARR_SET( trkSeg_t, trackSegs_da, trackSegs_da.cnt+tempSegs_da.cnt ); - memcpy( &trackSegs(inx), tempSegs_da.ptr, tempSegs_da.cnt*sizeof trackSegs(0) ); - CloneFilledDraw( tempSegs_da.cnt, &trackSegs(inx), TRUE ); + + + DYNARR_RESET(trkSeg_t, outputSegs_da); + for (int i=0; icustomInfo = xx->customInfo; -#endif f = OpenCustom("a"); if (f && to) { oldLocale = SaveLocale("C"); rc &= fprintf( f, "TURNOUT %s \"%s\"\n", curScaleName, PutTitle(to->title) )>0; -#ifdef LATER - if ( to->customInfo ) - rc &= fprintf( f, "\tU %s\n", to->customInfo )>0; -#endif - rc &= WriteCompoundPathsEndPtsSegs( f, path, trackSegs_da.cnt, &trackSegs(0), tempEndPts_da.cnt, &tempEndPts(0) ); + rc &= WriteCompoundPathsEndPtsSegs( f, path, outputSegs_da.cnt, &outputSegs(0), tempEndPts_da.cnt, &tempEndPts(0) ); } if ( groupReplace ) { + /* + * 11: Replace defn + */ UndoStart( _("Group Tracks"), "group" ); orig.x = - orig.x; orig.y = - orig.y; @@ -1528,8 +1639,7 @@ groupSimpleTurnout: trackCount--; } } - trk = NewCompound( T_TURNOUT, 0, orig, 0.0, to->title, tempEndPts_da.cnt, &tempEndPts(0), pathLen, (char *)path, trackSegs_da.cnt, &trackSegs(0) ); - SetTrkVisible( trk, TRUE ); + trk = NewCompound( T_TURNOUT, 0, orig, 0.0, to->title, tempEndPts_da.cnt, &tempEndPts(0), NULL, pathLen, (char *)path, outputSegs_da.cnt, &outputSegs(0) ); SetTrkVisible( trk, TRUE ); for ( ep=0; ep0; -#ifdef LATER - if ( to->customInfo ) - rc &= fprintf( f, "\tU %s\n", to->customInfo )>0; -#endif rc &= WriteSegs( f, tempSegs_da.cnt, &tempSegs(0) ); } if ( groupReplace ) { @@ -1570,7 +1677,7 @@ groupSimpleTurnout: } orig.x = - orig.x; orig.y = - orig.y; - trk = NewCompound( T_STRUCTURE, 0, orig, 0.0, groupTitle, 0, NULL, 0, "", tempSegs_da.cnt, &tempSegs(0) ); + trk = NewCompound( T_STRUCTURE, 0, orig, 0.0, groupTitle, 0, NULL, NULL, 0, "", tempSegs_da.cnt, &tempSegs(0) ); SetTrkVisible( trk, TRUE ); DrawNewTrack( trk ); EnableCommands(); @@ -1594,10 +1701,14 @@ EXPORT void DoGroup( void ) xx = NULL; groupSegCnt = 0; groupCompoundCount = 0; + groupOriginX = 0.0; + groupOriginY = 0.0; + BOOL_T isTurnout = FALSE; while ( TrackIterate( &trk ) ) { if ( GetTrkSelected( trk ) ) { trkType = GetTrkType(trk); + if ( IsTrack(trk) ) isTurnout = TRUE; if ( trkType == T_TURNOUT || trkType == T_STRUCTURE ) { xx = GetTrkExtraData(trk); groupSegCnt += xx->segCnt; @@ -1618,6 +1729,18 @@ EXPORT void DoGroup( void ) groupW = ParamCreateDialog( &groupPG, MakeWindowTitle(_("Group Objects")), _("Ok"), GroupOk, wHide, TRUE, NULL, F_BLOCK, NULL ); groupD.dpi = mainD.dpi; } + if (isTurnout) { + groupPLs[4].option |= PDO_DLGIGNORE; + wControlShow( groupPLs[4].control, FALSE ); + groupPLs[5].option |= PDO_DLGIGNORE; + wControlShow( groupPLs[5].control, FALSE ); + } else { + groupPLs[4].option &= ~PDO_DLGIGNORE; + wControlShow( groupPLs[4].control, TRUE ); + groupPLs[5].option &= ~PDO_DLGIGNORE; + wControlShow( groupPLs[5].control, TRUE ); + } + ParamLoadControls( &groupPG ); wShow( groupW ); } diff --git a/app/bin/chndldto.c b/app/bin/chndldto.c index fa88398..a0f2d6b 100644 --- a/app/bin/chndldto.c +++ b/app/bin/chndldto.c @@ -91,7 +91,6 @@ static STATUS_T CmdHandLaidTurnout( wAction_t action, coOrd pos ) Dhlt.normalP = Dhlt.reverseP = Dhlt.reverseP1 = pos; Dhlt.normalA = GetAngleAtPoint( Dhlt.normalT, Dhlt.normalP, NULL, NULL ); InfoMessage( _("Drag to set angle") ); - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); Dhlt.state = 1; pointC = pointP = pointP1 = reverseC = zero; return C_CONTINUE; @@ -102,7 +101,6 @@ static STATUS_T CmdHandLaidTurnout( wAction_t action, coOrd pos ) if (Dhlt.normalT == NULL) break; if (Dhlt.state == 1) { - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); Dhlt.reverseP1 = pos; Dhlt.reverseA = FindAngle( Dhlt.reverseP, Dhlt.reverseP1 ); Dhlt.frogA = NormalizeAngle( Dhlt.reverseA - Dhlt.normalA ); @@ -141,10 +139,8 @@ static STATUS_T CmdHandLaidTurnout( wAction_t action, coOrd pos ) Translate( &Dhlt.reverseP, Dhlt.reverseP, Dhlt.normalA+(right?+90:-90), trackGauge ); Translate( &Dhlt.reverseP1, Dhlt.reverseP1, Dhlt.normalA+(right?+90:-90), trackGauge ); } - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); return C_CONTINUE; } else if ( Dhlt.state == 2 ) { - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); tempSegs_da.cnt = 0; pointP = pos; if ((pointT = OnTrack( &pointP, TRUE, TRUE )) == NULL) @@ -273,7 +269,6 @@ PTRACE(( " a2=%0.1f rA1=%0.1f\n", angle2, reverseA1 )) if (action != C_UP) { dist = FindDistance( pointP, Dhlt.normalP ); InfoMessage( _("Length = %0.2f Angle = %0.2f Frog# = %0.2f"), dist, Dhlt.frogA, Dhlt.frogNo ); - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); return C_CONTINUE; } UndoStart( _("Create Hand Laid Turnout"), "Hndldto( T%d[%d] )", GetTrkIndex(pointT), pointEp0 ); @@ -334,7 +329,6 @@ PTRACE(( " a2=%0.1f rA1=%0.1f\n", angle2, reverseA1 )) DrawTrack( trk, &mainD, wDrawColorBlack ); for (trkpp=trks; *trkpp; trkpp++) DrawTrack( *trkpp, &mainD, wDrawColorBlack ); - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); Dhlt.state = 0; return C_TERMINATE; @@ -348,12 +342,6 @@ PTRACE(( " a2=%0.1f rA1=%0.1f\n", angle2, reverseA1 )) return C_CONTINUE; case C_CANCEL: - if (Dhlt.state >= 1) - DrawLine( &tempD, Dhlt.reverseP, Dhlt.reverseP1, 0, wDrawColorBlack ); - if (Dhlt.state >= 2) { - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - tempSegs_da.cnt = 0; - } return C_CONTINUE; } @@ -367,5 +355,5 @@ PTRACE(( " a2=%0.1f rA1=%0.1f\n", angle2, reverseA1 )) EXPORT void InitCmdHandLaidTurnout( wMenu_p menu ) { - AddMenuButton( menu, CmdHandLaidTurnout, "cmdHandLaidTurnout", _("HandLaidTurnout"), wIconCreatePixMap(hndldto_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_HNDLDTO, NULL ); + AddMenuButton( menu, CmdHandLaidTurnout, "cmdHandLaidTurnout", _("HandLaidTurnout"), wIconCreatePixMap(hndldto_xpm), LEVEL0_50, IC_STICKY|IC_INITNOTSTICKY|IC_POPUP2, ACCL_HNDLDTO, NULL ); } diff --git a/app/bin/chotbar.c b/app/bin/chotbar.c index 31a19ad..0b9a327 100644 --- a/app/bin/chotbar.c +++ b/app/bin/chotbar.c @@ -27,6 +27,7 @@ #include "compound.h" #include "fileio.h" #include "messages.h" +#include "ccornu.h" #include "track.h" EXPORT DIST_T curBarScale = -1; @@ -57,7 +58,7 @@ typedef struct { DIST_T labelW; coOrd size; coOrd orig; - BOOL_T isTrack; + BOOL_T isFixed; void * context; hotBarProc_t proc; DIST_T barScale; @@ -72,12 +73,15 @@ static int hotBarCurrEnds[2] = { -1, -1 }; #define hotBarCurrEnd (hotBarCurrEnds[programMode]) static DIST_T hotBarWidth = 0.0; -static void HotBarHighlight( int inx ) +static void HotBarHighlight( int inx, DIST_T fixed_x ) { wPos_t x0; - if ( inx >= hotBarCurrStart && inx < hotBarCurrEnd ) { - x0 = (wPos_t)((hotBarMap(inx).x-hotBarMap((int)hotBarCurrStart).x)*hotBarD.dpi); - wDrawFilledRectangle( hotBarD.d, x0, 0, (wPos_t)(hotBarMap(inx).w*hotBarD.dpi-2), hotBarHeight, wDrawColorBlack, wDrawOptTemp ); + if ( inx == 0 && hotBarMap_da.cnt>0 && hotBarMap(0).isFixed) { + x0 = (wPos_t)0; + wDrawFilledRectangle( hotBarD.d, x0, 0, (wPos_t)(hotBarMap(0).w*hotBarD.dpi-2), hotBarHeight, wDrawColorBlack, wDrawOptTransparent ); + } else if ( inx >= hotBarCurrStart && inx < hotBarCurrEnd ) { + x0 = (wPos_t)((hotBarMap(inx).x-hotBarMap((int)hotBarCurrStart).x + (inx>0?fixed_x:0))*hotBarD.dpi); + wDrawFilledRectangle( hotBarD.d, x0, 0, (wPos_t)(hotBarMap(inx).w*hotBarD.dpi-2), hotBarHeight, wDrawColorBlack, wDrawOptTransparent ); } } @@ -105,11 +109,38 @@ static void RedrawHotBar( wDraw_p dd, void * data, wPos_t w, wPos_t h ) if ( hotBarLabels && !hotBarFp ) hotBarFp = wStandardFont( F_HELV, FALSE, FALSE ); wPos_t textSize = wMessageGetHeight(0L); + DIST_T fixed_x = 0.0; + if (hotBarCurrStart>0 && hotBarMap_da.cnt>0 && hotBarMap(0).isFixed) { //Do fixed element first - Cornu + tbm = &hotBarMap(0); + barScale = tbm->barScale; + x = 0.0; + orig.y = hh/2.0*barScale - tbm->size.y/2.0 - tbm->orig.y; + if ( hotBarLabels ) { + orig.y += textSize/hotBarD.dpi*barScale; + if ( tbm->labelW > tbm->objectW ) { + fixed_x = tbm->labelW; + x += (tbm->labelW-tbm->objectW)/2; + } else fixed_x = tbm->objectW; + } else fixed_x = tbm->objectW; + x *= barScale; + orig.x = x; + hotBarD.scale = barScale; + hotBarD.size.x = barWidth*barScale; + hotBarD.size.y = barHeight*barScale; + tbm->proc( HB_DRAW, tbm->context, &hotBarD, &orig ); + if ( hotBarLabels ) { + hotBarD.scale = 1.0; + orig.x = 0.0; + orig.y = 2.0/hotBarD.dpi; //Draw Label under icon + DrawString( &hotBarD, orig, 0.0, tbm->proc( HB_BARTITLE, tbm->context, NULL, NULL ), hotBarFp, hotBarFs, drawColorBlack ); + } + + } for ( inx=hotBarCurrStart; inx < hotBarMap_da.cnt; inx++ ) { tbm = &hotBarMap(inx); barScale = tbm->barScale; - x = tbm->x - hotBarMap(hotBarCurrStart).x; - if ( x + tbm->w > barWidth ) { + x = tbm->x - hotBarMap(hotBarCurrStart).x + fixed_x; //Add space for fixed at start + if ( x + tbm->w + fixed_x > barWidth ) { break; } orig.y = hh/2.0*barScale - tbm->size.y/2.0 - tbm->orig.y; @@ -120,6 +151,7 @@ static void RedrawHotBar( wDraw_p dd, void * data, wPos_t w, wPos_t h ) } } x *= barScale; + x -= tbm->orig.x; orig.x = x; hotBarD.scale = barScale; hotBarD.size.x = barWidth*barScale; @@ -127,14 +159,15 @@ static void RedrawHotBar( wDraw_p dd, void * data, wPos_t w, wPos_t h ) tbm->proc( HB_DRAW, tbm->context, &hotBarD, &orig ); if ( hotBarLabels ) { hotBarD.scale = 1.0; - orig.x = tbm->x - hotBarMap(hotBarCurrStart).x; + orig.x = tbm->x - hotBarMap(hotBarCurrStart).x + fixed_x; orig.y = 2.0/hotBarD.dpi; //Draw Label under icon DrawString( &hotBarD, orig, 0.0, tbm->proc( HB_BARTITLE, tbm->context, NULL, NULL ), hotBarFp, hotBarFs, drawColorBlack ); } } hotBarCurrEnd = inx; - if (hotBarCurrSelect >= hotBarCurrStart && hotBarCurrSelect < hotBarCurrEnd ) - HotBarHighlight( hotBarCurrSelect ); + if ((hotBarCurrSelect==0 && hotBarMap_da.cnt>0 && hotBarMap(0).isFixed) || + ((hotBarCurrSelect >= hotBarCurrStart) && (hotBarCurrSelect < hotBarCurrEnd)) ) + HotBarHighlight( hotBarCurrSelect, fixed_x ); /* else hotBarCurrSelect = -1;*/ wControlActive( (wControl_p)hotBarRightB, hotBarCurrEnd < hotBarMap_da.cnt ); @@ -223,17 +256,33 @@ static void SelectHotBar( wDraw_p d, void * context, wAction_t action, wPos_t w, wMenuPopupShow( hotbarPopupM ); return; } - x = w/hotBarD.dpi + hotBarMap(hotBarCurrStart).x; - for ( inx=hotBarCurrStart; inx= hotBarMap(inx).x) && //leave spaces between buttons - (x <= hotBarMap(inx).x + hotBarMap(inx).w )) { - break; + inx = -1; + x = hotBarMap(0).x; + DIST_T fixed_x = 0.0; + if (hotBarCurrStart>0 && hotBarMap_da.cnt>0 && hotBarMap(0).isFixed) { + fixed_x = hotBarMap(0).w; + x = w/hotBarD.dpi + hotBarMap(0).x; + if ( (x>= hotBarMap(0).x) && + (x <=hotBarMap(0).w )) inx = 0; //Match on fixed + } + if (inx<0){ //NoMatch + x = w/hotBarD.dpi + hotBarMap(hotBarCurrStart).x; + for ( inx=hotBarCurrStart; inx= hotBarMap(inx).x + fixed_x) && //leave spaces between buttons + (x <= hotBarMap(inx).x + hotBarMap(inx).w + fixed_x )) { + break; + } } } + if (inx >= hotBarCurrEnd) return; tbm = &hotBarMap(inx); - px = (wPos_t)((tbm->x-hotBarMap(hotBarCurrStart).x)*hotBarD.dpi); + if (inx==0) { + px = (wPos_t)((tbm->x-hotBarMap(0).x)*hotBarD.dpi); + } else { + px = (wPos_t)(((tbm->x-hotBarMap(hotBarCurrStart).x)+fixed_x)*hotBarD.dpi); + } px += (wPos_t)(tbm->w*hotBarD.dpi/2); titleP = tbm->proc( HB_LISTTITLE, tbm->context, NULL, NULL ); px -= wLabelWidth( titleP ) / 2; @@ -243,12 +292,14 @@ static void SelectHotBar( wDraw_p d, void * context, wAction_t action, wPos_t w, pos.x = mainD.size.x+mainD.orig.x; pos.y = mainD.size.y+mainD.orig.y; if ( hotBarCurrSelect >= 0 ) { - HotBarHighlight( hotBarCurrSelect ); + //HotBarHighlight( hotBarCurrSelect ); hotBarCurrSelect = -1; + RedrawHotBar(hotBarD.d, NULL, 0, 0 ); } + tbm->proc( HB_SELECT, tbm->context, NULL, NULL ); hotBarCurrSelect = inx; - HotBarHighlight( hotBarCurrSelect ); + HotBarHighlight( hotBarCurrSelect, fixed_x ); if (recordF) { fprintf( recordF, "HOTBARSELECT %s\n", tbm->proc( HB_FULLTITLE, tbm->context, NULL, NULL ) ); } @@ -296,8 +347,9 @@ static void SelectHotBar( wDraw_p d, void * context, wAction_t action, wPos_t w, EXPORT void HotBarCancel( void ) { if ( hotBarCurrSelect >= 0 ) - HotBarHighlight( hotBarCurrSelect ); + //HotBarHighlight( hotBarCurrSelect ); hotBarCurrSelect = -1; + RedrawHotBar(hotBarD.d, NULL, 0, 0 ); } @@ -306,18 +358,23 @@ static BOOL_T HotBarSelectPlayback( char * line ) int inx; hotBarMap_t * tbm; while (*line && isspace((unsigned char)*line) ) line++; + DIST_T fixed_x = 0; for ( inx=0; inx0 && hotBarMap(0).isFixed) { + fixed_x = hotBarMap(0).w; + } if ( strcmp( tbm->proc( HB_FULLTITLE, tbm->context, NULL, NULL ), line) == 0) { if ( hotBarCurrSelect >= 0 ) { - HotBarHighlight( hotBarCurrSelect ); + //HotBarHighlight( hotBarCurrSelect ); + RedrawHotBar(hotBarD.d, NULL, 0, 0 ); } hotBarCurrSelect = inx; if ( hotBarCurrSelect < hotBarCurrStart || hotBarCurrSelect > hotBarCurrEnd ) { hotBarCurrStart = hotBarCurrSelect; RedrawHotBar( hotBarD.d, NULL, 0, 0 ); } - HotBarHighlight( hotBarCurrSelect ); + HotBarHighlight( hotBarCurrSelect, fixed_x ); hotBarMap(inx).proc( HB_SELECT, hotBarMap(inx).context, NULL, NULL ); FakeDownMouseState(); return TRUE; @@ -347,6 +404,7 @@ EXPORT void AddHotBarElement( coOrd size, coOrd orig, BOOL_T isTrack, + BOOL_T isFixed, DIST_T barScale, void * context, hotBarProc_t proc_p ) @@ -360,10 +418,13 @@ EXPORT void AddHotBarElement( } if (barScale <= 0) { - if (isTrack) + if (!isTrack) + barScale = size.y/((double)hotBarDrawHeight/hotBarD.dpi); + else if (isTrack) { barScale = (trackGauge>0.1)?trackGauge*24:10; - else - barScale = size.y/((double)hotBarDrawHeight/hotBarD.dpi-0.07); + if (size.y >= size.x) + barScale = size.y/((double)hotBarDrawHeight/hotBarD.dpi); + } } DYNARR_APPEND( hotBarMap_t, hotBarMap_da, 10 ); tbm = &hotBarMap(hotBarMap_da.cnt-1); @@ -376,6 +437,7 @@ EXPORT void AddHotBarElement( tbm->orig = orig; tbm->proc = proc_p; tbm->barScale = barScale; + tbm->isFixed = isFixed; tbm->w = tbm->objectW = size.x/barScale + 5.0/hotBarD.dpi; tbm->labelW = 0; tbm->x = hotBarWidth; @@ -409,6 +471,8 @@ static void ChangeHotBar( long changes ) DYNARR_RESET( hotBarMap_t, hotBarMap_da ); curContentsLabel[0] = '\0'; if ( programMode == MODE_DESIGN ) { + if (showFlexTrack) + AddHotBarCornu(); AddHotBarTurnouts(); AddHotBarStructures(); } else { @@ -446,6 +510,13 @@ EXPORT void LayoutHotBar( void * redraw ) wWinGetSize( mainW, &winWidth, &winHeight ); hotBarHeight = hotBarDrawHeight; + double scaleicon; + wPrefGetFloat(PREFSECTION, LARGEICON, &scaleicon, 1.0); + if (scaleicon<1.0) scaleicon=1.0; + if (scaleicon>2.0) scaleicon=2.0; + if (scaleicon>1.0) { + hotBarHeight = hotBarHeight*scaleicon; + } if ( hotBarLabels) { hotBarHeight += wMessageGetHeight(0L); } diff --git a/app/bin/cjoin.c b/app/bin/cjoin.c index 8cfa3d4..71f4dae 100644 --- a/app/bin/cjoin.c +++ b/app/bin/cjoin.c @@ -1,5 +1,5 @@ /* - * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cjoin.c,v 1.4 2008-03-06 19:35:05 m_fischer Exp $ + * $Header: /home/dave/Source/xtrkcad_5_1_2a/app/bin/RCS/cjoin.c,v 1.3 2019/07/24 15:11:51 dave Exp $ * * JOINS * @@ -39,7 +39,7 @@ #include "cselect.h" #include "fileio.h" - +static BOOL_T debug = 0; static int log_join = 0; typedef struct { curveType_e type; @@ -53,25 +53,18 @@ typedef struct { static struct { STATE_T state; int joinMoveState; + BOOL_T cornuMode; struct { TRKTYP_T realType; track_p trk; coOrd pos; EPINX_T ep; trackParams_t params; -#ifdef LATER - curveType_e type; - ANGLE_T angle; - coOrd lineOrig; - coOrd lineEnd; - coOrd arcP; - DIST_T arcR; - ANGLE_T arcA0, arcA1; -#endif } inp[2]; joinRes_t jRes; coOrd inp_pos[2]; easementData_t jointD[2]; + dynArr_t anchors; } Dj; @@ -169,7 +162,8 @@ LOG( log_join, 2, (" = CURVE @ Pc=[%0.3f %0.3f] R=%0.3f A0=%0.3f A1=%0.3f Fli d = D2R(res->arcA1); if (d < 0.0) d = 2*M_PI + d; - InfoMessage( _("Curved Track: Radius=%s Length=%s"), + if (!debug) + InfoMessage( _("Curved Track: Radius=%s Length=%s"), FormatDistance(res->arcR), FormatDistance(res->arcR*d) ); return TRUE; @@ -213,7 +207,7 @@ LOG( log_join, 3, (" p1=[%0.3f %0.3f] aa=%0.3f a=%0.3f\n", /* Straight: */ PointOnCircle( &pt, pos0, r0, a1); LOG( log_join, 2, (" = STRAIGHT [%0.3f %0.3f] [%0.3f %0.3f]\n", pt.x, pt.y, pos1.x, pos1.y ) ) - InfoMessage( _("Straight Track: Length=%s Angle=%0.3f"), + if (!debug) InfoMessage( _("Straight Track: Length=%s Angle=%0.3f"), FormatDistance(FindDistance( pt, pos1 )), PutAngle(FindAngle( pt, pos1 )) ); res->type = curveTypeStraight; res->pos[0]=pt; @@ -255,7 +249,7 @@ LOG( log_join, 3, (" A0=%0.3f A1=%0.3f R=%0.3f\n", res->arcA0, res->arcA1, d = D2R(res->arcA1); if (d < 0.0) d = 2*M_PI + d; - InfoMessage( _("Curved Track: Radius=%s Length=%s Angle=%0.3f"), + if (!debug) InfoMessage( _("Curved Track: Radius=%s Length=%s Angle=%0.3f"), FormatDistance(res->arcR), FormatDistance(res->arcR*d), PutAngle(res->arcA1) ); res->type = curveTypeCurve; } @@ -302,11 +296,11 @@ static STATUS_T AdjustJoint( switch ( Dj.inp[0].params.type ) { case curveTypeCurve: if (adjust) { - a0 = FindAngle( Dj.inp[0].params.arcP, Dj.jRes.pos[0] ) + - ((Dj.jointD[0].Scurve==TRUE || Dj.jointD[0].flip==FALSE)?0:+180); + a0 = FindAngle( Dj.inp[0].params.arcP, Dj.jRes.pos[0] ); Translate( &pc, Dj.inp[0].params.arcP, a0, Dj.jointD[0].x ); -LOG( log_join, 2, (" Move P0 X%0.3f A%0.3f P1 X%0.3f A%0.3f)\n", - Dj.jointD[0].x, a0, Dj.jointD[1].x, a1 ) ) +LOG( log_join, 2, (" Move P0 X%0.3f A%0.3f P1 X%0.3f A%0.3f SC%d FL%d\n", + Dj.jointD[0].x, a0, Dj.jointD[1].x, a1, + Dj.jointD[0].Scurve, Dj.jointD[0].flip ) ) } else { pc = Dj.inp[0].params.arcP; } @@ -368,7 +362,8 @@ LOG( log_join, 2, (" Move P0 X%0.3f A%0.3f P1 X%0.3f A%0.3f\n", } d -= l; if ( d <= minLength ) { - InfoMessage( _("Connecting track is too short by %0.3f"), PutDim(fabs(minLength-d)) ); + if (!debug) + InfoMessage( _("Connecting track is too short by %0.3f"), PutDim(fabs(minLength-d)) ); return FALSE; } @@ -415,7 +410,6 @@ static STATUS_T DoMoveToJoin( coOrd pos ) _("Click on an unselected End-Point"): _("Click on a selected End-Point") ); Dj.inp[0].pos = pos; - DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor ); return C_CONTINUE; } if ( GetTrkSelected(Dj.inp[0].trk) == GetTrkSelected(Dj.inp[1].trk) ) { @@ -423,7 +417,6 @@ static STATUS_T DoMoveToJoin( coOrd pos ) ? _("unselected") : _("selected") ); return C_CONTINUE; } - DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor ); if (GetTrkSelected(Dj.inp[0].trk)) MoveToJoin( Dj.inp[0].trk, Dj.inp[0].params.ep, Dj.inp[1].trk, Dj.inp[1].params.ep ); else @@ -432,6 +425,372 @@ static STATUS_T DoMoveToJoin( coOrd pos ) return C_TERMINATE; } +typedef enum {NO_LINE,FIRST_END,HAVE_LINE,HAVE_SECOND_LINE} LineState_t; + +static struct { + LineState_t line_state; + int joinMoveState; + track_p curr_line; + struct { + TRKTYP_T realType; + track_p line; + coOrd pos; + coOrd end; + int cnt; + } inp[2]; + joinRes_t jRes; + coOrd inp_pos[2]; + dynArr_t anchors_da; + trackParams_t params; + dynArr_t newLine; + } Dl; + +#define anchors(N) DYNARR_N(trkSeg_t,Dl.anchors_da,N) + +void AddAnchorEnd(coOrd p) { + DIST_T d = tempD.scale*0.15; + DYNARR_APPEND(trkSeg_t,Dl.anchors_da,1); + trkSeg_p a = &DYNARR_LAST(trkSeg_t,Dl.anchors_da); + a->type = SEG_CRVLIN; + a->width = 0; + a->u.c.a0 = 0.0; + a->u.c.a1 = 360.0; + a->u.c.center = p; + a->u.c.radius = d/2; + a->color = wDrawColorPowderedBlue; +} + + +static STATUS_T CmdJoinLine( + wAction_t action, + coOrd pos ) +/* + * Join 2 lines. + */ +{ + + switch (action&0xFF) { + case C_START: + InfoMessage( _("Left click - Select first draw object end") ); + Dl.line_state = NO_LINE; + Dl.joinMoveState = 0; + tempSegs_da.cnt = 0; + DYNARR_RESET(trkSeg_t,Dl.newLine); + Dl.curr_line = NULL; + return C_CONTINUE; + case wActionMove: + DYNARR_RESET(trkSeg_t,Dl.anchors_da); + Dl.curr_line = NULL; + coOrd pos1= pos; + Dl.curr_line = OnTrack( &pos1, FALSE, FALSE ); + if (!Dl.curr_line) return C_CONTINUE; + if (IsTrack(Dl.curr_line)) { + Dl.curr_line = NULL; + return C_CONTINUE; + } + if (!QueryTrack(Dl.curr_line,Q_GET_NODES)) { + Dl.curr_line = NULL; + return C_CONTINUE; + } + if (!GetTrackParams(PARAMS_NODES,Dl.curr_line,pos,&Dl.params)) { + Dl.curr_line = NULL; + return C_CONTINUE; + } + if ( (Dl.line_state != NO_LINE) && + (Dl.inp[0].line == Dl.curr_line) && + (IsClose(FindDistance(Dl.inp[0].pos,Dl.params.lineOrig)) ) ) { + Dl.curr_line = NULL; + } else { + AddAnchorEnd(Dl.params.lineOrig); + } + break; + case C_DOWN: + DYNARR_RESET(trkSeg_t,Dl.anchors_da); + Dl.curr_line = NULL; + if (Dl.line_state == NO_LINE) { + Dl.curr_line = OnTrack( &pos, FALSE, FALSE); + if (!Dl.curr_line || IsTrack(Dl.curr_line)) { + InfoMessage( _("Not a line - Try again") ); + return C_CONTINUE; + } + if (!QueryTrack(Dl.curr_line,Q_GET_NODES)) return C_CONTINUE; + if (!GetTrackParams(PARAMS_NODES,Dl.curr_line,pos,&Dl.params)) return C_CONTINUE; + Dl.line_state = HAVE_LINE; + Dl.inp[0].line = Dl.curr_line; + Dl.inp[0].pos = Dl.params.lineOrig; + Dl.inp[0].end = Dl.params.lineEnd; + DYNARR_SET(trkSeg_t,Dl.newLine,1); + + DYNARR_LAST(trkSeg_t,Dl.newLine).type = SEG_POLY; + DYNARR_LAST(trkSeg_t,Dl.newLine).color = wDrawColorBlack; + DYNARR_LAST(trkSeg_t,Dl.newLine).width = 0; + DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.polyType = POLYLINE; + DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts = MyMalloc(sizeof(pts_t)*Dl.params.nodes.cnt); + DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.cnt = Dl.params.nodes.cnt; + //Copy in reverse as we want this point to be last + for (int i=0;i0) + DrawSegs( &tempD, zero, 0.0, &anchors(0), Dl.anchors_da.cnt, trackGauge, wDrawColorPreviewSelected ); + break; + case C_TEXT: + case C_OK: + default:; + + } + + + return C_CONTINUE; + +} + +void AnchorTempLine(coOrd p0, coOrd p1) { + DYNARR_APPEND(trkSeg_t,Dj.anchors,1); + trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors); + p->type = SEG_STRLIN; + p->color = wDrawColorBlue; + p->width = 0.0; + p->u.l.pos[0] = p0; + p->u.l.pos[1] = p1; +} + +void AnchorTempCircle(coOrd center,DIST_T radius, ANGLE_T a0, ANGLE_T a1) { + DYNARR_APPEND(trkSeg_t,Dj.anchors,1); + trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors); + p->type = SEG_CRVLIN; + p->color = wDrawColorBlue; + p->width = 0.0; + p->u.c.a0 =a0; + p->u.c.a1 = a1; + p->u.c.radius = radius; + p->u.c.center = center; +} + +void AnchorPoint(coOrd center) { + DYNARR_APPEND(trkSeg_t,Dj.anchors,1); + trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors); + p->type = SEG_CRVLIN; + p->color = wDrawColorAqua; + p->width = 0.0; + p->u.c.a0 =0.0; + p->u.c.a1 = 360.0; + p->u.c.radius = mainD.scale/4; + p->u.c.center = center; +} + +static DIST_T desired_radius = 0.0; + +static paramFloatRange_t r_0_10000 = { 0.0, 100000.0 }; +static paramData_t joinPLs[] = { +#define joinRadPD (joinPLs[0]) +#define joinRadI 0 + { PD_FLOAT, &desired_radius, "radius", PDO_DIM, &r_0_10000, N_("Desired Radius") } +}; +static paramGroup_t joinPG = { "join-fixed", 0, joinPLs, sizeof joinPLs/sizeof joinPLs[0] }; + + + +BOOL_T AdjustPosToRadius(coOrd *pos, DIST_T desired_radius, ANGLE_T an0, ANGLE_T an1) { + coOrd point1,point2; + switch ( Dj.inp[1].params.type ) { + case curveTypeCurve: + if (Dj.inp[0].params.type == curveTypeStraight) { + coOrd newP, newP1; + //Offset curve by desired_radius + DIST_T newR1; + newR1 = Dj.inp[1].params.arcR + desired_radius*((fabs(an1-Dj.inp[1].params.arcA0)<1.0)?1:-1); + if (newR1<=0.0) { + if (debug) InfoMessage("Zero Radius C1"); + return FALSE; + } + //Offset line by desired_radius + Translate(&newP,Dj.inp[0].params.lineEnd,an0,desired_radius); + Translate(&newP1,Dj.inp[0].params.lineOrig,an0,desired_radius); + if (debug) + AnchorTempLine(newP,newP1); + //Intersect - this is the joining curve center + if (debug) + AnchorTempCircle(Dj.inp[1].params.arcP,newR1,Dj.inp[1].params.arcA0,Dj.inp[1].params.arcA1); + if (!FindArcAndLineIntersections(&point1,&point2,Dj.inp[1].params.arcP,newR1,newP,newP1)) + return FALSE; + } else if (Dj.inp[0].params.type == curveTypeCurve) { + //Offset curve by desired_radius + DIST_T newR0; + newR0 = Dj.inp[0].params.arcR + desired_radius*((fabs(an0-Dj.inp[0].params.arcA0)<1.0)?1:-1); + if (newR0<=0.0) { + if (debug) InfoMessage("Zero Radius C0"); + return FALSE; + } + //Offset curve by desired_radius + if (debug) + AnchorTempCircle(Dj.inp[0].params.arcP,newR0,Dj.inp[0].params.arcA0,Dj.inp[0].params.arcA1); + DIST_T newR1; + newR1 = Dj.inp[1].params.arcR + desired_radius*((fabs(an1-Dj.inp[1].params.arcA0)<1.0)?1:-1); + if (newR1<=0.0) { + if (debug) InfoMessage("Zero Radius C1"); + return FALSE; + } + //Intersect - this is the joining curve center + if (debug) + AnchorTempCircle(Dj.inp[1].params.arcP,newR1,Dj.inp[1].params.arcA0,Dj.inp[1].params.arcA1); + if (!FindArcIntersections(&point1,&point2,Dj.inp[0].params.arcP,newR0,Dj.inp[1].params.arcP,newR1)) + return FALSE; + } + if (debug) { + AnchorPoint(point1); + AnchorPoint(point2); + } + break; + case curveTypeStraight: + if (Dj.inp[0].params.type == curveTypeStraight) { + coOrd newI,newP0,newP01, newP1, newP11; + //Offset line1 by desired_radius + Translate(&newP0,Dj.inp[0].params.lineEnd,an0,desired_radius); + Translate(&newP01,Dj.inp[0].params.lineOrig,an0,desired_radius); + if (debug) + AnchorTempLine(newP0,newP01); + //Offset line2 by desired_radius + Translate(&newP1,Dj.inp[1].params.lineEnd,an1,desired_radius); + Translate(&newP11,Dj.inp[1].params.lineOrig,an1,desired_radius); + if (debug) + AnchorTempLine(newP1,newP11); + if (!FindIntersection(&newI,newP0,Dj.inp[0].params.angle,newP1,Dj.inp[1].params.angle)) + return FALSE; + point1 = point2 = newI; + } else if (Dj.inp[0].params.type == curveTypeCurve) { + coOrd newP, newP1; + //Offset curve by desired_radius + DIST_T newR0; + newR0 = Dj.inp[0].params.arcR + desired_radius*((fabs(an0-Dj.inp[0].params.arcA0)<1.0)?1:-1); + if (newR0<=0.0) { + if (debug) InfoMessage("Zero Radius C0"); + return FALSE; + } + if (debug) + AnchorTempCircle(Dj.inp[0].params.arcP,newR0,Dj.inp[0].params.arcA0,Dj.inp[0].params.arcA1); + //Offset line by desired_radius + Translate(&newP,Dj.inp[1].params.lineEnd,an1,desired_radius); + Translate(&newP1,Dj.inp[1].params.lineOrig,an1,desired_radius); + if (debug) + AnchorTempLine(newP,newP1); + //Intersect - this is the joining curve center + if (!FindArcAndLineIntersections(&point1,&point2,Dj.inp[0].params.arcP,newR0,newP,newP1)) + return FALSE; + } + if (debug) { + AnchorPoint(point1); + AnchorPoint(point2); + } + break; + default: + return FALSE; + } + if (FindDistance(*pos,point1)<=FindDistance(*pos,point2)) { + if (Dj.inp[1].params.type == curveTypeCurve) { + ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,point1); + Translate(pos,Dj.inp[1].params.arcP,a,Dj.inp[1].params.arcR); + } else { + Translate(pos,point1,NormalizeAngle(an1+180),desired_radius); + } + } else { + if (Dj.inp[1].params.type == curveTypeCurve) { + ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,point2); + Translate(pos,Dj.inp[1].params.arcP,a,Dj.inp[1].params.arcR); + } else + Translate(pos,point2,NormalizeAngle(an1+180),desired_radius); + } + + return TRUE; + +} + +void AddAnchorJoin(coOrd pos, ANGLE_T angle) { + DIST_T d = tempD.scale*0.15; + DYNARR_APPEND(trkSeg_t,Dj.anchors,1); + trkSeg_p a = &DYNARR_LAST(trkSeg_t,Dj.anchors); + a->type = SEG_CRVLIN; + a->width = 0; + a->u.c.a0 = 0.0; + a->u.c.a1 = 360.0; + a->u.c.center = pos; + a->u.c.radius = d/2; + a->color = wDrawColorBlue; + DYNARR_SET(trkSeg_t,Dj.anchors,Dj.anchors.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,Dj.anchors,Dj.anchors.cnt-5),pos,angle,FALSE,wDrawColorBlue); + +} + +static BOOL_T infoSubst = FALSE; +static track_p anchor_trk; +static coOrd anchor_pos; +static ANGLE_T anchor_angle = 0.0; static STATUS_T CmdJoin( wAction_t action, @@ -451,26 +810,63 @@ static STATUS_T CmdJoin( ANGLE_T a, a1; DIST_T eR[2]; BOOL_T ok; + wControl_p controls[2]; + char * labels[1]; switch (action&0xFF) { case C_START: + if (joinPLs[0].control==NULL) { + ParamCreateControls(&joinPG, NULL); + } if (selectedTrackCount==0) InfoMessage( _("Left click - join with track") ); else InfoMessage( _("Left click - join with track, Shift Left click - move to join") ); + DYNARR_RESET(trkSeg_t,Dj.anchors); Dj.state = 0; Dj.joinMoveState = 0; + Dj.cornuMode = FALSE; /*ParamGroupRecord( &easementPG );*/ - if (easementVal < 0) + infoSubst = FALSE; + anchor_trk = NULL; + if (easementVal < 0.0) return CmdCornu(action, pos); return C_CONTINUE; + + case wActionMove: + anchor_trk = NULL; + DYNARR_RESET(rkSeg_t,Dj.anchors); + if ((easementVal < 0) && Dj.joinMoveState == 0 ) + return CmdCornu(action, pos); + if ( Dj.state >= 2) return C_CONTINUE; + if ( (trk = OnTrack( &pos, FALSE, TRUE )) == NULL) + return C_CONTINUE; + if (!CheckTrackLayer( trk ) ) + return C_CONTINUE; + if ((Dj.state > 0) && (trk == Dj.inp[0].trk)) + return C_CONTINUE; + trackParams_t moveParams; + if (!GetTrackParams( PARAMS_1ST_JOIN, trk, pos, &moveParams )) + return C_CONTINUE; + ep = PickUnconnectedEndPointSilent(pos,trk); + if (ep <0) return C_CONTINUE; + if (IsClose(FindDistance(GetTrkEndPos(trk,ep),pos))) + anchor_angle = GetTrkEndAngle(trk,ep); + else + anchor_angle = FindAngle(pos,GetTrkEndPos(trk,ep)); + anchor_trk = trk; + anchor_pos = pos; + AddAnchorJoin(pos,anchor_angle); + break; case C_DOWN: - if ( (Dj.state == 0 && (MyGetKeyState() & WKEY_SHIFT) != 0) || Dj.joinMoveState != 0 ) + if ( !Dj.cornuMode && ((Dj.state == 0 && (MyGetKeyState() & WKEY_SHIFT) != 0) || Dj.joinMoveState != 0) ) return DoMoveToJoin( pos ); - if (easementVal < 0.0) + if (easementVal < 0.0 && Dj.joinMoveState == 0) { + Dj.cornuMode = TRUE; return CmdCornu(action, pos); + } DYNARR_SET( trkSeg_t, tempSegs_da, 3 ); tempSegs(0).color = drawColorBlack; @@ -495,10 +891,18 @@ LOG( log_join, 1, ("JOIN: 1st track %d @[%0.3f %0.3f]\n", Dj.inp[0].realType = GetTrkType(Dj.inp[0].trk); InfoMessage( _("Select 2nd track") ); Dj.state = 1; - DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor ); + wPrefGetFloat("misc", "desired_radius", &desired_radius, desired_radius); + controls[0] = joinRadPD.control; + controls[1] = NULL; + labels[0] = N_("Desired Radius"); + InfoSubstituteControls(controls, labels); + infoSubst = TRUE; + joinRadPD.option |= PDO_NORECORD; + ParamLoadControls(&joinPG); + ParamGroupRecord(&joinPG); return C_CONTINUE; } else { - if ( (Dj.inp[1].trk = OnTrack( &pos, TRUE, TRUE )) == NULL) + if ( (Dj.inp[1].trk = OnTrack( &pos, FALSE, TRUE )) == NULL) return C_CONTINUE; if (!CheckTrackLayer( Dj.inp[1].trk ) ) return C_CONTINUE; @@ -509,6 +913,10 @@ LOG( log_join, 1, ("JOIN: 1st track %d @[%0.3f %0.3f]\n", ErrorMessage( MSG_JOIN_SAME ); return C_CONTINUE; } + if (infoSubst) + InfoSubstituteControls(NULL, NULL); + infoSubst = FALSE; + Dj.inp[1].realType = GetTrkType(Dj.inp[1].trk); if ( IsCurveCircle( Dj.inp[0].trk ) ) Dj.inp[0].params.ep = PickArcEndPt( Dj.inp[0].params.arcP, Dj.inp[0].pos, pos ); @@ -519,21 +927,30 @@ LOG( log_join, 1, (" 2nd track %d, @[%0.3f %0.3f] EP0=%d EP1=%d\n", GetTrkIndex(Dj.inp[1].trk), Dj.inp[1].pos.x, Dj.inp[1].pos.y, Dj.inp[0].params.ep, Dj.inp[1].params.ep ) ) LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) ) - if ( GetTrkEndTrk(Dj.inp[0].trk,Dj.inp[0].params.ep) != NULL) { - ErrorMessage( MSG_TRK_ALREADY_CONN, _("First") ); - return C_CONTINUE; + BOOL_T only_merge = FALSE; + if ( (Dj.inp[0].params.ep >=0) && + (GetTrkEndTrk(Dj.inp[0].trk,Dj.inp[0].params.ep) != NULL)) { + if (GetTrkEndTrk(Dj.inp[0].trk,Dj.inp[0].params.ep) != Dj.inp[1].trk) { + only_merge = TRUE; + ErrorMessage( MSG_TRK_ALREADY_CONN, _("First") ); + return C_CONTINUE; + } } - if ( Dj.inp[1].params.ep >= 0 && - GetTrkEndTrk(Dj.inp[1].trk,Dj.inp[1].params.ep) != NULL) { - ErrorMessage( MSG_TRK_ALREADY_CONN, _("Second") ); - return C_CONTINUE; + if ( (Dj.inp[1].params.ep >= 0) && + (GetTrkEndTrk(Dj.inp[1].trk,Dj.inp[1].params.ep) != NULL)) { + if (GetTrkEndTrk(Dj.inp[1].trk,Dj.inp[1].params.ep) != Dj.inp[0].trk) { + only_merge = TRUE; + ErrorMessage( MSG_TRK_ALREADY_CONN, _("Second") ); + return C_CONTINUE; + } } - rc = C_CONTINUE; if ( MergeTracks( Dj.inp[0].trk, Dj.inp[0].params.ep, - Dj.inp[1].trk, Dj.inp[1].params.ep ) ) + Dj.inp[1].trk, Dj.inp[1].params.ep ) ) { + rc = C_TERMINATE; + } else if (only_merge) { rc = C_TERMINATE; - else if ( Dj.inp[0].params.ep >= 0 && Dj.inp[1].params.ep >= 0 ) { + } else if ( Dj.inp[0].params.ep >= 0 && Dj.inp[1].params.ep >= 0 ) { if ( Dj.inp[0].params.type == curveTypeStraight && Dj.inp[1].params.type == curveTypeStraight && ExtendStraightToJoin( Dj.inp[0].trk, Dj.inp[0].params.ep, @@ -544,7 +961,6 @@ LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) ) rc = C_TERMINATE; } if ( rc == C_TERMINATE ) { - DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor ); return rc; } if ( QueryTrack( Dj.inp[0].trk, Q_CANNOT_BE_ON_END ) || @@ -553,30 +969,103 @@ LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) ) return C_CONTINUE; } - DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor ); Dj.state = 2; Dj.jRes.flip = FALSE; } tempSegs_da.cnt = 0; + /* no break */ case C_MOVE: - if (easementVal < 0) + if (easementVal < 0 && Dj.cornuMode) return CmdCornu(action, pos); LOG( log_join, 3, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) ) if (Dj.state != 2) return C_CONTINUE; - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, drawColorBlack ); + DYNARR_RESET(trkSeg_t,Dj.anchors); + + + //Fix Pos onto the line of the second track + if (Dj.inp[1].params.type == curveTypeStraight) { + ANGLE_T a = NormalizeAngle(FindAngle(Dj.inp[1].params.lineOrig,pos)-Dj.inp[1].params.angle); + DIST_T d = FindDistance(Dj.inp[1].params.lineOrig,pos); + Translate(&pos,Dj.inp[1].params.lineOrig,Dj.inp[1].params.angle,d*cos(D2R(a))); + } else { + ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,pos); + Translate(&pos,Dj.inp[1].params.arcP,a,Dj.inp[1].params.arcR); + } + + if ((desired_radius != 0.0) && + ((Dj.inp[0].params.type == curveTypeStraight) || (Dj.inp[0].params.type == curveTypeCurve)) && + ((Dj.inp[1].params.type == curveTypeStraight) || (Dj.inp[1].params.type == curveTypeCurve)) && + Dj.jRes.type==curveTypeCurve + ) { + ANGLE_T na0=0.0,na1=0.0; + coOrd end0, end1; + ANGLE_T a0,a1; + end0 = GetTrkEndPos(Dj.inp[0].trk,Dj.inp[0].params.ep); + end1 = GetTrkEndPos(Dj.inp[1].trk,Dj.inp[1].params.ep); + if (Dj.inp[0].params.type == curveTypeStraight) { + a0 = DifferenceBetweenAngles(Dj.inp[0].params.angle,FindAngle(Dj.jRes.pos[0], pos)); + na0 = NormalizeAngle( Dj.inp[0].params.angle + + ((a0>0.0)?90.0:-90.0)); + } else { + na0 = Dj.inp[0].params.arcA0; + if (FindDistance(Dj.inp[0].params.arcP,pos)0.0)?90.0:-90.0)); + } else { + na1 = Dj.inp[1].params.arcA0; + if (FindDistance(Dj.inp[1].params.arcP,Dj.jRes.pos[0])Dj.inp[1].params.arcA0+Dj.inp[1].params.arcA1) || (a< Dj.inp[1].params.arcA0)) { + beyond = 1.0; + } + } + //Suppress result unless on track and close to user position (when on track) + if (beyond>-0.01 && IsClose(FindDistance(pos,pos1))) { + pos = pos1; + DYNARR_APPEND(trkSeg_t,Dj.anchors,1); + trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors); + p->type= SEG_CRVLIN; + p->width = 0; + p->color = wDrawColorBlue; + p->u.c.center = pos; + p->u.c.a1= 360.0; + p->u.c.a0 = 0.0; + p->u.c.radius = tempD.scale*0.25/2; + } + } + + } + + tempSegs_da.cnt = 0; tempSegs(0).color = drawColorBlack; ok = FALSE; /* Populate (Dj.inp[1]) */ + if ( QueryTrack(Dj.inp[1].trk,Q_REFRESH_JOIN_PARAMS_ON_MOVE) ) { if ( !GetTrackParams( PARAMS_2ND_JOIN, Dj.inp[1].trk, pos, &Dj.inp[1].params ) ) return C_CONTINUE; } + + beyond = 1.0; switch ( Dj.inp[1].params.type ) { case curveTypeCurve: @@ -798,16 +1287,14 @@ errorReturn: default: AbortProg( "Bad track type %d", Dj.jRes.type ); } - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, drawColorBlack ); if (!ok) Dj.jRes.type = curveTypeNone; return C_CONTINUE; case C_UP: - if (Dj.state == 0) { - if (easementVal<0) - return CmdCornu(action, pos); + if (easementVal<0 && Dj.cornuMode) + return CmdCornu(action, pos); else return C_CONTINUE; } @@ -815,12 +1302,10 @@ errorReturn: InfoMessage( _("Select 2nd track") ); return C_CONTINUE; } - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, drawColorBlack ); tempSegs(0).color = drawColorBlack; tempSegs_da.cnt = 0; if (Dj.jRes.type == curveTypeNone) { Dj.state = 1; - DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor ); InfoMessage( _("Select 2nd track") ); return C_CONTINUE; } @@ -845,7 +1330,10 @@ errorReturn: UndrawNewTrack( Dj.inp[1].trk ); ep = Dj.jRes.flip?1:0; Dj.state = 0; + DYNARR_RESET(trkSeg_t,Dj.anchors); rc = C_TERMINATE; + if (easementVal == 0.0) + wPrefSetFloat("misc", "desired_radius", desired_radius); if ( (!JoinTracks( Dj.inp[0].trk, Dj.inp[0].params.ep, Dj.inp_pos[0], trk, ep, Dj.jRes.pos[0], &Dj.jointD[0] ) ) || (!JoinTracks( Dj.inp[1].trk, Dj.inp[1].params.ep, Dj.inp_pos[1], @@ -856,24 +1344,34 @@ errorReturn: DrawNewTrack( Dj.inp[0].trk ); DrawNewTrack( Dj.inp[1].trk ); DrawNewTrack( trk ); + if (infoSubst) + InfoSubstituteControls(NULL, NULL); + infoSubst = FALSE; return rc; case C_CANCEL: - case C_REDRAW: - + if (infoSubst) + InfoSubstituteControls(NULL, NULL); + infoSubst = FALSE; + break; + case C_REDRAW: if ( Dj.joinMoveState == 1 || Dj.state == 1 ) { DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor ); - } else if (easementVal<0 ) - return CmdCornu(action,pos); - + } else if (easementVal<0 && Dj.joinMoveState == 0) + return CmdCornu(action,pos); + if (Dj.anchors.cnt) + DrawSegs(&tempD, zero, 0.0, &(((trkSeg_t *)Dj.anchors.ptr)[0]), Dj.anchors.cnt,trackGauge,wDrawColorBlack); DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); break; case C_TEXT: case C_OK: - if (easementVal<0 ) - return CmdCornu(action,pos); + if (easementVal<0 && Dj.cornuMode) + return CmdCornu(action,pos); + if (infoSubst) + InfoSubstituteControls(NULL, NULL); + infoSubst = FALSE; } @@ -889,10 +1387,14 @@ errorReturn: */ #include "bitmaps/join.xpm" +#include "bitmaps/joinline.xpm" void InitCmdJoin( wMenu_p menu ) { - joinCmdInx = AddMenuButton( menu, CmdJoin, "cmdJoin", _("Join"), wIconCreatePixMap(join_xpm), LEVEL0_50, IC_STICKY|IC_POPUP, ACCL_JOIN, NULL ); + ButtonGroupBegin( _("Join"), "cmdJoinSetCmd", _("Join") ); + joinCmdInx = AddMenuButton( menu, CmdJoin, "cmdJoinTrack", _("Join Track"), wIconCreatePixMap(join_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_JOIN, NULL ); + AddMenuButton( menu, CmdJoinLine, "cmdJoinLine", _("Join Lines"), wIconCreatePixMap(joinline_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_JOIN, NULL ); + ButtonGroupEnd(); log_join = LogFindIndex( "join" ); } diff --git a/app/bin/cmisc.c b/app/bin/cmisc.c index a353530..b41ae42 100644 --- a/app/bin/cmisc.c +++ b/app/bin/cmisc.c @@ -23,6 +23,7 @@ #include #include "common.h" +#include "utility.h" #include "cundo.h" #include "i18n.h" #include "messages.h" @@ -32,6 +33,10 @@ EXPORT wIndex_t describeCmdInx; EXPORT BOOL_T inDescribeCmd; +extern wIndex_t selectCmdInx; +extern wIndex_t joinCmdInx; +extern wIndex_t modifyCmdInx; + static track_p descTrk; static descData_p descData; static descUpdate_t descUpdateFunc; @@ -43,13 +48,16 @@ static BOOL_T descNeedDrawHilite; static wPos_t describeW_posy; static wPos_t describeCmdButtonEnd; +static wMenu_p descPopupM; + static unsigned int editableLayerList[NUM_LAYERS]; /**< list of non-frozen layers */ static int * layerValue; /**pointer to current Layer (int *) */ static paramFloatRange_t rdata = { 0, 0, 100, PDO_NORANGECHECK_HIGH|PDO_NORANGECHECK_LOW }; static paramIntegerRange_t idata = { 0, 0, 100, PDO_NORANGECHECK_HIGH|PDO_NORANGECHECK_LOW }; static paramTextData_t tdata = { 300, 150 }; -static char * pivotLabels[] = { N_("First"), N_("Middle"), N_("Second"), NULL }; +static char * pivotLabels[] = { N_("First"), N_("Middle"), N_("End"), NULL }; +static char * boxLabels[] = { "", NULL }; static paramData_t describePLs[] = { #define I_FLOAT_0 (0) { PD_FLOAT, NULL, "F1", 0, &rdata }, @@ -114,13 +122,15 @@ static paramData_t describePLs[] = { #define I_LAYER_N I_LAYER_0+1 #define I_COLOR_0 I_LAYER_N - { PD_COLORLIST, NULL, "C1", 0, NULL, N_("Color") }, + { PD_COLORLIST, NULL, "C1", PDO_NOPREF, NULL, N_("Color"), BC_HORZ|BC_NOBORDER }, #define I_COLOR_N I_COLOR_0+1 #define I_LIST_0 I_COLOR_N { PD_DROPLIST, NULL, "L1", 0, (void*)150, NULL, 0 }, { PD_DROPLIST, NULL, "L2", 0, (void*)150, NULL, 0 }, -#define I_LIST_N I_LIST_0+2 + { PD_DROPLIST, NULL, "L3", 0, (void*)150, NULL, 0 }, + { PD_DROPLIST, NULL, "L4", 0, (void*)150, NULL, 0 }, +#define I_LIST_N I_LIST_0+4 #define I_EDITLIST_0 I_LIST_N { PD_DROPLIST, NULL, "LE1", 0, (void*)150, NULL, BL_EDITABLE }, @@ -131,8 +141,15 @@ static paramData_t describePLs[] = { #define I_TEXT_N I_TEXT_0+1 #define I_PIVOT_0 I_TEXT_N - { PD_RADIO, NULL, "P1", 0, pivotLabels, N_("Pivot"), BC_HORZ|BC_NOBORDER, 0 } + { PD_RADIO, NULL, "P1", 0, pivotLabels, N_("Pivot"), BC_HORZ|BC_NOBORDER, 0 }, #define I_PIVOT_N I_PIVOT_0+1 + +#define I_TOGGLE_0 I_PIVOT_N + { PD_TOGGLE, NULL, "boxed1", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER }, + { PD_TOGGLE, NULL, "boxed2", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER }, + { PD_TOGGLE, NULL, "boxed3", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER }, + { PD_TOGGLE, NULL, "boxed4", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER }, +#define I_TOGGLE_N I_TOGGLE_0+4 }; static paramGroup_t describePG = { "describe", 0, describePLs, sizeof describePLs/sizeof describePLs[0] }; @@ -149,7 +166,7 @@ CreateEditableLayersList() int i = 0; int j = 0; - while (i <= NUM_LAYERS) { + while (i < NUM_LAYERS) { if (!GetLayerFrozen(i)) { editableLayerList[j++] = i; } @@ -179,7 +196,7 @@ SearchEditableLayerList(unsigned int layer) return (-1); } -static void DrawDescHilite(void) +static void DrawDescHilite(BOOL_T selected) { wPos_t x, y, w, h; @@ -194,7 +211,7 @@ static void DrawDescHilite(void) w = (wPos_t)((descSize.x/mainD.scale)*mainD.dpi+0.5); h = (wPos_t)((descSize.y/mainD.scale)*mainD.dpi+0.5); mainD.CoOrd2Pix(&mainD,descOrig,&x,&y); - wDrawFilledRectangle(mainD.d, x, y, w, h, descColor, wDrawOptTemp); + wDrawFilledRectangle(tempD.d, x, y, w, h, selected?descColor:wDrawColorBlue, wDrawOptTemp|wDrawOptTransparent); } @@ -221,10 +238,6 @@ static void DescribeUpdate( return; } - if ((ddp->mode&DESC_NOREDRAW) == 0) { - DrawDescHilite(); - } - if (!descUndoStarted) { UndoStart(_("Change Track"), "Change Track"); descUndoStarted = TRUE; @@ -252,7 +265,6 @@ static void DescribeUpdate( descOrig.y -= descBorder; descSize.x -= descOrig.x-descBorder; descSize.y -= descOrig.y-descBorder; - DrawDescHilite(); } for (inx = 0; inx < sizeof describePLs/sizeof describePLs[0]; inx++) { @@ -288,9 +300,6 @@ static void DescOk(void * junk) { wHide(describePG.win); - if (descTrk) { - DrawDescHilite(); - } if (layerValue && *layerValue>=0) { SetTrkLayer(descTrk, editableLayerList[*layerValue]); //int found that is really in the parm controls. } @@ -304,7 +313,7 @@ static void DescOk(void * junk) } descNeedDrawHilite = FALSE; - Reset(); + Reset(); // DescOk } @@ -326,10 +335,22 @@ static struct { /*STRING*/ { PD_STRING,0, I_STRING_0, I_STRING_N }, /*TEXT*/ { PD_TEXT, PDO_DLGNOLABELALIGN, I_TEXT_0, I_TEXT_N }, /*LIST*/ { PD_DROPLIST, PDO_LISTINDEX, I_LIST_0, I_LIST_N }, - /*EDITABLELIST*/{ PD_DROPLIST, 0, I_EDITLIST_0, I_EDITLIST_N } + /*EDITABLELIST*/{ PD_DROPLIST, 0, I_EDITLIST_0, I_EDITLIST_N }, + /*BOXED*/ { PD_TOGGLE, 0, I_TOGGLE_0, I_TOGGLE_N }, }; -static wControl_p AllocateButt(descData_p ddp, void * valueP, char * label, +/** + * An unused param element is selected from the list of pre-defined param elements and initialized + * for an element specific param. + * + * \param ddp Element specific param + * \param valueP the value pointer used by the element + * \param label the label assigned by the element + * \param sep ? + * \return the selected widget + */ + +static wControl_p AssignParamToDescribeDialog(descData_p ddp, void * valueP, char * label, wPos_t sep) { int inx; @@ -364,7 +385,7 @@ static wControl_p AllocateButt(descData_p ddp, void * valueP, char * label, } } - AbortProg("allocateButt: can't find %d", ddp->type); + AbortProg("AssignParamToDescribeDialog: can't find %d", ddp->type); return NULL; } @@ -465,13 +486,13 @@ void DoDescribe(char * title, track_p trk, descData_p data, descUpdate_t update) label = _(ddp->label); ddp->posy = describeW_posy; - ddp->control0 = AllocateButt(ddp, ddp->valueP, label, + ddp->control0 = AssignParamToDescribeDialog(ddp, ddp->valueP, label, (ddp->type == DESC_POS?3:3)); wControlActive(ddp->control0, ((ddp->mode|ro_mode)&DESC_RO)==0); switch (ddp->type) { case DESC_POS: - ddp->control1 = AllocateButt(ddp, + ddp->control1 = AssignParamToDescribeDialog(ddp, &((coOrd*)(ddp->valueP))->y, NULL, 0); @@ -523,9 +544,10 @@ EXPORT void DescribeCancel(void) { if (describePG.win && wWinIsVisible(describePG.win)) { if (descTrk) { - descUpdateFunc(descTrk, -1, descData, TRUE); - descTrk = NULL; - DrawDescHilite(); + if (!IsTrackDeleted(descTrk)) + descUpdateFunc(descTrk, -1, descData, TRUE); + descTrk = NULL; + } wHide(describePG.win); @@ -540,21 +562,27 @@ EXPORT void DescribeCancel(void) } -static STATUS_T CmdDescribe(wAction_t action, coOrd pos) +EXPORT STATUS_T CmdDescribe(wAction_t action, coOrd pos) { - track_p trk; + static track_p trk; char msg[STR_SIZE]; switch (action) { case C_START: InfoMessage(_("Select track to describe")); + wSetCursor(mainD.d,wCursorQuestion); descUndoStarted = FALSE; + trk = NULL; return C_CONTINUE; + case wActionMove: + trk = OnTrack(&pos, FALSE, FALSE); + return C_CONTINUE; + + case C_DOWN: if ((trk = OnTrack(&pos, FALSE, FALSE)) != NULL) { if (describePG.win && wWinIsVisible(describePG.win) && descTrk) { - DrawDescHilite(); descUpdateFunc(descTrk, -1, descData, TRUE); descTrk = NULL; } @@ -572,10 +600,10 @@ static STATUS_T CmdDescribe(wAction_t action, coOrd pos) descSize.x -= descOrig.x-descBorder; descSize.y -= descOrig.y-descBorder; descNeedDrawHilite = TRUE; - DrawDescHilite(); DescribeTrack(trk, msg, 255); inDescribeCmd = FALSE; InfoMessage(msg); + trk = NULL; } else { InfoMessage(""); } @@ -583,17 +611,31 @@ static STATUS_T CmdDescribe(wAction_t action, coOrd pos) return C_CONTINUE; case C_REDRAW: + if (describePG.win && wWinIsVisible(describePG.win) && descTrk) { - DrawDescHilite(); + DrawDescHilite(TRUE); + if (descTrk && QueryTrack(descTrk, Q_IS_DRAW)) { + DrawOriginAnchor(descTrk); + } + } else if (trk){ + DrawTrack(trk,&tempD,wDrawColorPreviewSelected); } + break; case C_CANCEL: DescribeCancel(); + wSetCursor(mainD.d,defaultCursor); return C_CONTINUE; + + case C_CMDMENU: + menuPos = pos; + if (!trk) wMenuPopupShow(descPopupM); + return C_CONTINUE; } + return C_CONTINUE; } @@ -601,11 +643,23 @@ static STATUS_T CmdDescribe(wAction_t action, coOrd pos) #include "bitmaps/describe.xpm" +extern wIndex_t selectCmdInx; +extern wIndex_t modifyCmdInx; +extern wIndex_t panCmdInx; + void InitCmdDescribe(wMenu_p menu) { describeCmdInx = AddMenuButton(menu, CmdDescribe, "cmdDescribe", _("Properties"), wIconCreatePixMap(describe_xpm), - LEVEL0, IC_CANCEL|IC_POPUP, ACCL_DESCRIBE, NULL); + LEVEL0, IC_CANCEL|IC_POPUP|IC_WANT_MOVE|IC_CMDMENU, ACCL_DESCRIBE, NULL); RegisterChangeNotification(DescChange); ParamRegister(&describePG); } +void InitCmdDescribe2(wMenu_p menu) +{ + descPopupM = MenuRegister( "Describe Context Menu" ); + wMenuPushCreate(descPopupM, "cmdSelectMode", GetBalloonHelpStr("cmdSelectMode"), 0, DoCommandB, (void*) (intptr_t) selectCmdInx); + wMenuPushCreate(descPopupM, "cmdModifyMode", GetBalloonHelpStr("cmdModifyMode"), 0, DoCommandB, (void*) (intptr_t) modifyCmdInx); + wMenuPushCreate(descPopupM, "cmdPanMode", GetBalloonHelpStr("cmdPanMode"), 0, DoCommandB, (void*) (intptr_t) panCmdInx); + +} diff --git a/app/bin/cmodify.c b/app/bin/cmodify.c index 11f4c06..8f82012 100644 --- a/app/bin/cmodify.c +++ b/app/bin/cmodify.c @@ -34,6 +34,9 @@ #include "param.h" #include "track.h" #include "utility.h" +#include "drawgeom.h" +#include "common.h" +#include "layout.h" static struct { track_p Trk; @@ -47,10 +50,65 @@ static struct { BOOL_T first; } Dex; +static wMenu_p modPopupM; + +extern wIndex_t selectCmdInx; +extern wIndex_t joinCmdInx; +extern wIndex_t describeCmdInx; + +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) static int log_modify; static BOOL_T modifyBezierMode; static BOOL_T modifyCornuMode; +static BOOL_T modifyDrawMode; +static BOOL_T modifyRulerMode; +static BOOL_T modifyExtendMode; + + +static void CreateEndAnchor(coOrd p, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; +} + +static void CreateCornuAnchor(coOrd p, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; +} + + +static void CreateRadiusAnchor(coOrd p, ANGLE_T a, BOOL_T bi) { + DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),p,a,bi,wDrawColorBlue); +} /* * Call cbezier.c CmdBezModify to alter Bezier Track and Lines. @@ -66,6 +124,7 @@ static STATUS_T ModifyBezier(wAction_t action, coOrd pos) { case C_UP: case C_OK: case C_TEXT: + case wActionMove: trackGauge = (IsTrack(Dex.Trk)?GetTrkGauge(Dex.Trk):0.0); rc = CmdBezModify(Dex.Trk, action, pos, trackGauge); break; @@ -89,12 +148,14 @@ static STATUS_T ModifyCornu(wAction_t action, coOrd pos) { STATUS_T rc = C_CONTINUE; if (Dex.Trk == NULL) return C_ERROR; //No track picked yet! switch (action&0xFF) { + case C_LCLICK: case C_START: case C_DOWN: case C_MOVE: case C_UP: case C_OK: case C_TEXT: + case wActionMove: trackGauge = (IsTrack(Dex.Trk)?GetTrkGauge(Dex.Trk):0.0); rc = CmdCornuModify(Dex.Trk, action, pos, trackGauge); break; @@ -110,7 +171,61 @@ static STATUS_T ModifyCornu(wAction_t action, coOrd pos) { return rc; } -static STATUS_T CmdModify( +/* + * Picking a DRAW will allow point modifications until terminated with "Enter" + */ +static STATUS_T ModifyDraw(wAction_t action, coOrd pos) { + STATUS_T rc = C_CONTINUE; + if (Dex.Trk == NULL) return C_ERROR; //No item picked yet! + switch (action&0xFF) { + case C_START: + case C_DOWN: + case C_MOVE: + case C_UP: + rc = ModifyTrack( Dex.Trk, action, pos ); + break; + case wActionMove: + rc = ModifyTrack( Dex.Trk, action, pos ); + break; + case C_TEXT: + //Delete or '0' - continues + if ((action>>8 !=32) && (action >>8 !=13)) + return ModifyTrack( Dex.Trk, action, pos ); + //Enter/Space does not + if ((action>>8 !=32) && (action>>8 != 13)) return C_CONTINUE; + /*no break*/ + case C_OK: + UndoStart( _("Modify Track"), "Modify( T%d[%d] )", GetTrkIndex(Dex.Trk), Dex.params.ep ); + UndoModify( Dex.Trk ); + rc = ModifyTrack( Dex.Trk, C_TEXT | (13<<8), pos ); + if (rc != C_CONTINUE) modifyDrawMode = FALSE; + UndoEnd(); + break; + case C_CANCEL: + case C_FINISH: + case C_CONFIRM: + case C_TERMINATE: + rc = ModifyTrack( Dex.Trk, action, pos ); + Dex.Trk = NULL; + modifyDrawMode = FALSE; + tempSegs_da.cnt = 0; + rc = C_CONTINUE; + break; + case C_REDRAW: + rc = ModifyTrack( Dex.Trk, action, pos ); + break; + case C_CMDMENU: + menuPos = pos; + rc = ModifyTrack( Dex.Trk, action, pos ); + break; + default: + break; + } + return rc; +} + + +STATUS_T CmdModify( wAction_t action, coOrd pos ) /* @@ -128,7 +243,7 @@ static STATUS_T CmdModify( EPINX_T inx; curveType_e curveType; static BOOL_T changeTrackMode; - static BOOL_T modifyRulerMode; + STATUS_T rc; static DIST_T trackGauge; @@ -143,7 +258,8 @@ static STATUS_T CmdModify( switch (action&0xFF) { case C_START: - InfoMessage( _("Select track to modify") ); + DYNARR_RESET(trkSeg_t,anchors_da); + InfoMessage( _("Select a track to modify, Left-Click change length, Right-Click to add flextrack") ); Dex.Trk = NULL; tempSegs_da.cnt = 0; /*ChangeParameter( &easementPD );*/ @@ -151,21 +267,28 @@ static STATUS_T CmdModify( changeTrackMode = modifyRulerMode = FALSE; modifyBezierMode = FALSE; modifyCornuMode = FALSE; + modifyDrawMode = FALSE; + modifyExtendMode = FALSE; return C_CONTINUE; case C_DOWN: + DYNARR_RESET(trkSeg_t,anchors_da); if (modifyBezierMode) return ModifyBezier(C_DOWN, pos); if (modifyCornuMode) return ModifyCornu(C_DOWN, pos); + if (modifyDrawMode) + return ModifyDraw(C_DOWN, pos); + /*no break*/ + case C_LDOUBLE: DYNARR_SET( trkSeg_t, tempSegs_da, 2 ); tempSegs(0).color = wDrawColorBlack; tempSegs(0).width = 0; tempSegs(1).color = wDrawColorBlack; tempSegs(1).width = 0; tempSegs_da.cnt = 0; - SnapPos( &pos ); Dex.Trk = OnTrack( &pos, TRUE, FALSE ); + //Dex.Trk = trk; if (Dex.Trk == NULL) { if ( ModifyRuler( C_DOWN, pos ) == C_CONTINUE ) modifyRulerMode = TRUE; @@ -173,6 +296,7 @@ static STATUS_T CmdModify( } if (!CheckTrackLayer( Dex.Trk ) ) { Dex.Trk = NULL; + return C_CONTINUE; } trackGauge = (IsTrack(Dex.Trk)?GetTrkGauge(Dex.Trk):0.0); @@ -185,21 +309,38 @@ static STATUS_T CmdModify( } return C_CONTINUE; //That's it } - if (QueryTrack( Dex.Trk, Q_IS_CORNU )) { //Bezier + if (QueryTrack( Dex.Trk, Q_IS_CORNU )) { //Cornu modifyCornuMode = TRUE; if (ModifyCornu(C_START, pos) != C_CONTINUE) { //Call Start with track - modifyCornuMode = FALSE; //Function rejected Bezier + modifyCornuMode = FALSE; //Function rejected Cornu Dex.Trk =NULL; tempSegs_da.cnt = 0; + } return C_CONTINUE; //That's it } - if ( (MyGetKeyState()&WKEY_SHIFT) && + if (QueryTrack( Dex.Trk, Q_IS_DRAW )) { + modifyDrawMode = TRUE; + if (ModifyDraw(C_START, pos) != C_CONTINUE) { + modifyDrawMode = FALSE; + Dex.Trk = NULL; + tempSegs_da.cnt = 0; + } + return C_CONTINUE; + } + + if ((action&0xFF) == C_LDOUBLE) return C_ERROR; + + if ((MyGetKeyState()&WKEY_CTRL)) goto extendTrack; + + + + if ( (MyGetKeyState()&WKEY_SHIFT) && //Free to change radius QueryTrack( Dex.Trk, Q_CAN_MODIFYRADIUS )&& - (inx=PickUnconnectedEndPoint(pos,Dex.Trk)) >= 0 ) { + ((inx=PickUnconnectedEndPoint(pos,Dex.Trk)) >= 0 )) { trk = Dex.Trk; - while ( (trk1=GetTrkEndTrk(trk,1-inx)) && + while ( (trk1=GetTrkEndTrk(trk,1-inx)) && //Means next track to mine even if can be end... QueryTrack(trk1, Q_CANNOT_BE_ON_END) ) { inx = GetEndPtConnectedToMe( trk1, trk ); trk = trk1; @@ -208,7 +349,8 @@ static STATUS_T CmdModify( UndoStart( _("Change Track"), "Change( T%d[%d] )", GetTrkIndex(Dex.Trk), Dex.params.ep ); inx = GetEndPtConnectedToMe( trk1, trk ); Dex.Trk = NULL; - DeleteTrack(trk, TRUE); + UndrawNewTrack( trk ); + DeleteTrack(trk, TRUE); //Get rid of original track if ( !GetTrkEndTrk( trk1, inx ) ) { Dex.Trk = trk1; Dex.pos00 = GetTrkEndPos( Dex.Trk, inx ); @@ -218,16 +360,70 @@ static STATUS_T CmdModify( } ErrorMessage( MSG_CANNOT_CHANGE ); } + ModifyTrack(Dex.Trk, C_START, pos); //Basically trim via Modify... rc = ModifyTrack( Dex.Trk, C_DOWN, pos ); if ( rc != C_CONTINUE ) { Dex.Trk = NULL; rc = C_CONTINUE; } - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - MainRedraw(); - MapRedraw(); return rc; + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if (modifyCornuMode) return ModifyCornu(wActionMove,pos); + if (modifyDrawMode) return ModifyDraw(wActionMove,pos); + if (modifyBezierMode) return ModifyBezier(wActionMove, pos); + track_p t; + if (((t=OnTrack(&pos,FALSE,TRUE))!= NULL) && CheckTrackLayerSilent( t )) { + EPINX_T ep = PickUnconnectedEndPointSilent(pos, t); + if (QueryTrack( t, Q_IS_CORNU )) { + CreateCornuAnchor(pos,FALSE); + } else if ( QueryTrack( t, Q_CAN_MODIFY_CONTROL_POINTS )) { + CreateRadiusAnchor(pos,NormalizeAngle(GetAngleAtPoint(t,pos,NULL,NULL)+90.0),TRUE); + CreateEndAnchor(pos,FALSE); + } else if (QueryTrack(t,Q_CAN_ADD_ENDPOINTS)){ //Turntable + trackParams_t tp; + if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE; + ANGLE_T a = tp.angle; + Translate(&pos,tp.ttcenter,a,tp.ttradius); + CreateRadiusAnchor(pos,a,FALSE); + } else if (QueryTrack(t,Q_CAN_EXTEND)) { + if (ep != -1) { + if (MyGetKeyState()&WKEY_CTRL) { + pos = GetTrkEndPos(t,ep); + CreateEndAnchor(pos,FALSE); + CreateRadiusAnchor(pos,GetTrkEndAngle(t,ep),FALSE); + CreateRadiusAnchor(pos,GetTrkEndAngle(t,ep)+90,TRUE); + } else { + CreateEndAnchor(pos,FALSE); + if ((MyGetKeyState()&WKEY_SHIFT) && //Shift Down + QueryTrack( t, Q_CAN_MODIFYRADIUS ) && // Straight or Curve + ((inx=PickUnconnectedEndPointSilent(pos,t)) >= 0 )) { //Which has an open end + if (GetTrkEndTrk(t,1-inx)) // Has to have a track on other end + CreateRadiusAnchor(pos,NormalizeAngle(GetAngleAtPoint(t,pos,NULL,NULL)+90.0),TRUE); + } + CreateRadiusAnchor(pos,GetAngleAtPoint(t,pos,NULL,NULL),TRUE); + } + } + } else if (ep>=0){ //Turnout + pos = GetTrkEndPos(t, ep); + CreateEndAnchor(pos,TRUE); + if ( (MyGetKeyState()&WKEY_CTRL)) { + CreateRadiusAnchor(pos,NormalizeAngle(GetTrkEndAngle(t,ep)),FALSE); + CreateRadiusAnchor(pos,GetTrkEndAngle(t,ep)+90,TRUE); + CreateEndAnchor(pos,TRUE); + } else { + CreateRadiusAnchor(pos,NormalizeAngle(GetTrkEndAngle(t,ep)),FALSE); + CreateEndAnchor(pos,TRUE); + } + } + } else if (((t=OnTrack(&pos,FALSE,FALSE))!= NULL) + && (!(GetLayerFrozen(GetTrkLayer(t)) && GetLayerModule(GetTrkLayer(t)))) + && (QueryTrack(t, Q_IS_DRAW ) && !QueryTrack(t, Q_IS_TEXT)) ) { + CreateEndAnchor(pos,FALSE); + } + return C_CONTINUE; + case C_MOVE: if ( modifyRulerMode ) return ModifyRuler( C_MOVE, pos ); @@ -237,21 +433,22 @@ static STATUS_T CmdModify( return ModifyBezier(C_MOVE, pos); if ( modifyCornuMode ) return ModifyCornu(C_MOVE, pos); - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); + if ( modifyDrawMode) + return ModifyDraw(C_MOVE, pos); + if (modifyExtendMode && (MyGetKeyState()&WKEY_CTRL)) + goto extendTrackMove; tempSegs_da.cnt = 0; + SnapPos( &pos ); rc = ModifyTrack( Dex.Trk, C_MOVE, pos ); if ( rc != C_CONTINUE ) { rc = C_CONTINUE; Dex.Trk = NULL; } - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - MainRedraw(); - MapRedraw(); return rc; - case C_UP: + DYNARR_RESET(trkSeg_t,anchors_da); if (Dex.Trk == NULL) return C_CONTINUE; if ( modifyRulerMode ) @@ -260,58 +457,71 @@ static STATUS_T CmdModify( return ModifyBezier( C_UP, pos); if (modifyCornuMode) return ModifyCornu(C_UP, pos); - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); + if (modifyDrawMode) + return ModifyDraw(C_UP, pos); + if ((MyGetKeyState()&WKEY_CTRL)) goto extendTrackUp; + tempSegs_da.cnt = 0; + SnapPos( &pos ); UndoStart( _("Modify Track"), "Modify( T%d[%d] )", GetTrkIndex(Dex.Trk), Dex.params.ep ); UndoModify( Dex.Trk ); rc = ModifyTrack( Dex.Trk, C_UP, pos ); UndoEnd(); - //changeTrackMode = FALSE; Dex.Trk = NULL; - MainRedraw(); - MapRedraw(); return rc; - case C_RDOWN: + case C_RDOWN: //This is same as context menu.... +extendTrack: + DYNARR_RESET(trkSeg_t,anchors_da); changeTrackMode = TRUE; + modifyExtendMode = TRUE; modifyRulerMode = FALSE; modifyBezierMode = FALSE; modifyCornuMode = FALSE; - Dex.Trk = OnTrack( &pos, TRUE, TRUE ); - if (Dex.Trk) { - if (!CheckTrackLayer( Dex.Trk ) ) { - Dex.Trk = NULL; - return C_CONTINUE; - } - trackGauge = GetTrkGauge( Dex.Trk ); - Dex.pos00 = pos; -CHANGE_TRACK: - if (GetTrackParams( PARAMS_EXTEND, Dex.Trk, Dex.pos00, &Dex.params)) { - if (Dex.params.ep == -1) { + modifyDrawMode = FALSE; + Dex.first = FALSE; + if (((action&0xFF) == C_RDOWN) || ((action&0xFF)== C_DOWN)) { + Dex.Trk = OnTrack( &pos, TRUE, TRUE ); + if (Dex.Trk) { + if (!CheckTrackLayer( Dex.Trk ) ) { Dex.Trk = NULL; return C_CONTINUE; - break; } - if (Dex.params.ep == 0) { - Dex.params.arcR = -Dex.params.arcR; + trackGauge = GetTrkGauge( Dex.Trk ); + Dex.pos00 = pos; + CHANGE_TRACK: + if (GetTrackParams( PARAMS_EXTEND, Dex.Trk, Dex.pos00, &Dex.params)) { + if (Dex.params.ep == -1) { + Dex.Trk = NULL; + return C_CONTINUE; + break; + } + if (Dex.params.ep == 0) { + Dex.params.arcR = -Dex.params.arcR; + } + Dex.pos00 = GetTrkEndPos(Dex.Trk,Dex.params.ep); + Dex.angle = GetTrkEndAngle( Dex.Trk,Dex.params.ep); + Translate( &Dex.pos00x, Dex.pos00, Dex.angle, 10.0 ); + LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n", + Dex.params.ep, Dex.pos00.x, Dex.pos00.y, Dex.angle ) ) + InfoMessage( _("Drag to add flex track") ); + } else { + return C_ERROR; } - Dex.pos00 = GetTrkEndPos(Dex.Trk,Dex.params.ep); - Dex.angle = GetTrkEndAngle( Dex.Trk,Dex.params.ep); - Translate( &Dex.pos00x, Dex.pos00, Dex.angle, 10.0 ); -LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n", - Dex.params.ep, Dex.pos00.x, Dex.pos00.y, Dex.angle ) ) - InfoMessage( _("Drag to create new track segment") ); } else { + InfoMessage ( _("No track to extend")); return C_ERROR; } + Dex.first = TRUE; + } else if (!Dex.Trk) { + InfoMessage ( _("No track selected")); + return C_ERROR; } - Dex.first = TRUE; - MainRedraw(); - MapRedraw(); /* no break */ case C_RMOVE: - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); +extendTrackMove: + DYNARR_RESET(trkSeg_t,anchors_da); tempSegs_da.cnt = 0; Dex.valid = FALSE; if (Dex.Trk == NULL) return C_CONTINUE; @@ -320,7 +530,8 @@ LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n", return C_CONTINUE; Dex.first = FALSE; Dex.pos01 = Dex.pos00; - if (Dex.params.type == curveTypeCornu) { //Restrict Cornu drag out to match end + + if (Dex.params.type == curveTypeCornu) { //Always Restrict Cornu drag out to match end ANGLE_T angle2 = NormalizeAngle(FindAngle(pos, Dex.pos00)-Dex.angle); if (angle2 > 90.0 && angle2 < 270.0) { if (Dex.params.cornuRadius[Dex.params.ep] == 0) { @@ -346,11 +557,6 @@ LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n", ErrorMessage( MSG_TRK_TOO_SHORT, "First ", PutDim(fabs(minLength-d)) ); return C_CONTINUE; } - a0 = Dex.angle + (Dex.jointD.negate?-90.0:+90.0); - Translate( &Dex.pos01, Dex.pos00, a0, Dex.jointD.x ); - Translate( &Dex.curveData.pos1, Dex.curveData.pos1, - a0, Dex.jointD.x ); -LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) ) } else { Dex.jointD.d1 = 0.0; } @@ -376,44 +582,55 @@ LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) ) return C_CONTINUE; } else if ( curveType == curveTypeCurve ) { Dex.r1 = Dex.curveData.curveRadius; - if ( easeR > 0.0 && Dex.r1 < easeR ) { - ErrorMessage( MSG_RADIUS_LSS_EASE_MIN, - FormatDistance( Dex.r1 ), FormatDistance( easeR ) ); - return C_CONTINUE; - } - if ( Dex.r1*2.0*M_PI*Dex.curveData.a1/360.0 > mapD.size.x+mapD.size.y ) { - ErrorMessage( MSG_CURVE_TOO_LARGE ); - return C_CONTINUE; - } - if ( NormalizeAngle( FindAngle( Dex.pos00, pos ) - Dex.angle ) > 180.0 ) - Dex.r1 = -Dex.r1; if ( QueryTrack( Dex.Trk, Q_IGNORE_EASEMENT_ON_EXTEND ) ) { - /* Ignore easements when extending turnouts */ + /* Ignore easements when extending turnouts or turntables */ Dex.jointD.x = Dex.jointD.r0 = Dex.jointD.r1 = Dex.jointD.l0 = Dex.jointD.l1 = Dex.jointD.d0 = Dex.jointD.d1 = 0.0; Dex.jointD.flip = Dex.jointD.negate = Dex.jointD.Scurve = FALSE; - } else { - if (ComputeJoint( Dex.params.arcR, Dex.r1, &Dex.jointD ) == E_ERROR) - return C_CONTINUE; - d = Dex.params.len - Dex.jointD.d0; - if (d <= minLength) { - ErrorMessage( MSG_TRK_TOO_SHORT, "First ", PutDim(fabs(minLength-d)) ); - return C_CONTINUE; + d = Dex.curveData.curveRadius * Dex.curveData.a1 * 2.0*M_PI/360.0; + } else { /* Easement code */ + if (easementVal<0.0) { //Cornu Join - need to estimate a "good" easement length + d = Dex.curveData.curveRadius * Dex.curveData.a1 * 2.0*M_PI/360.0; + Dex.jointD.d0 = Dex.jointD.d1 =0.75*72*12/GetTrkScale(Dex.Trk); //Easement 1.5 cars long to start + if (Dex.jointD.d0>(GetTrkLength(Dex.Trk,0,1)/2)) + Dex.jointD.d0 = GetTrkLength(Dex.Trk,0,1)/2; + if (Dex.jointD.d1>d/2) + Dex.jointD.d1 = d/2; + Dex.jointD.negate = DifferenceBetweenAngles(Dex.angle,FindAngle(Dex.pos00,pos))<0.0; + Dex.jointD.x = 2*trackGauge; //Signal an easement present to JoinTracks + } else { + if ( easeR > 0.0 && Dex.r1 < easeR ) { + ErrorMessage( MSG_RADIUS_LSS_EASE_MIN, + FormatDistance( Dex.r1 ), FormatDistance( easeR ) ); + return C_CONTINUE; + } + if ( Dex.r1*2.0*M_PI*Dex.curveData.a1/360.0 > mapD.size.x+mapD.size.y ) { + ErrorMessage( MSG_CURVE_TOO_LARGE ); + return C_CONTINUE; + } + if ( NormalizeAngle( FindAngle( Dex.pos00, pos ) - Dex.angle ) > 180.0 ) + Dex.r1 = - Dex.r1; + if (ComputeJoint( Dex.params.arcR, Dex.r1, &Dex.jointD ) == E_ERROR) + return C_CONTINUE; + d = Dex.params.len - Dex.jointD.d0; + if (d <= minLength) { + ErrorMessage( MSG_TRK_TOO_SHORT, "First ", PutDim(fabs(minLength-d)) ); + return C_CONTINUE; + } } + d -= Dex.jointD.d1; + a0 = Dex.angle + (Dex.jointD.negate?-90.0:+90.0); + Translate( &Dex.pos01, Dex.pos00, a0, Dex.jointD.x ); + Translate( &Dex.curveData.curvePos, Dex.curveData.curvePos, + a0, Dex.jointD.x ); +LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) ) } - d = Dex.curveData.curveRadius * Dex.curveData.a1 * 2.0*M_PI/360.0; - d -= Dex.jointD.d1; if (d <= minLength) { ErrorMessage( MSG_TRK_TOO_SHORT, "Extending ", PutDim(fabs(minLength-d)) ); return C_CONTINUE; } - a0 = Dex.angle + (Dex.jointD.negate?-90.0:+90.0); - Translate( &Dex.pos01, Dex.pos00, a0, Dex.jointD.x ); - Translate( &Dex.curveData.curvePos, Dex.curveData.curvePos, - a0, Dex.jointD.x ); -LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) ) tempSegs(0).type = SEG_CRVTRK; tempSegs(0).width = 0; tempSegs(0).u.c.center = Dex.curveData.curvePos; @@ -421,9 +638,9 @@ LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) ) tempSegs(0).u.c.a0 = Dex.curveData.a0; tempSegs(0).u.c.a1 = Dex.curveData.a1; tempSegs_da.cnt = 1; - d = D2R(Dex.curveData.a1); - if (d < 0.0) - d = 2*M_PI + d; + double da = D2R(Dex.curveData.a1); + if (da < 0.0) + da = 2*M_PI + da; a = NormalizeAngle( Dex.angle - FindAngle( Dex.pos00, Dex.curveData.curvePos ) ); if ( a < 180.0 ) a = NormalizeAngle( Dex.curveData.a0-90 ); @@ -433,17 +650,15 @@ LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) ) if (action != C_RDOWN) InfoMessage( _("Curve Track: Radius=%s Length=%s Angle=%0.3f"), FormatDistance( Dex.curveData.curveRadius ), - FormatDistance( Dex.curveData.curveRadius * d), + FormatDistance( Dex.curveData.curveRadius * da), Dex.curveData.a1 ); } - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - MainRedraw(); - MapRedraw(); return C_CONTINUE; case C_RUP: +extendTrackUp: changeTrackMode = FALSE; - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); + modifyExtendMode = FALSE; tempSegs_da.cnt = 0; if (Dex.Trk == NULL) return C_CONTINUE; if (!Dex.valid) @@ -453,22 +668,24 @@ LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) ) curveType = Dex.curveData.type; if ( curveType == curveTypeStraight ) { - if ( Dex.params.type == curveTypeStraight && Dex.params.len > 0 ) { - //UndrawNewTrack( Dex.Trk ); - UndoModify( Dex.Trk ); - AdjustStraightEndPt( Dex.Trk, Dex.params.ep, Dex.curveData.pos1 ); - UndoEnd(); - DrawNewTrack(Dex.Trk ); - MainRedraw(); - MapRedraw(); - return C_TERMINATE; + if (QueryTrack(Dex.Trk,Q_CAN_EXTEND)) //Check it isn't a turnout end.... + if ( Dex.params.type == curveTypeStraight && + FindDistance(Dex.pos01, Dex.curveData.pos1) > 0 ) { + UndoModify( Dex.Trk ); + AdjustStraightEndPt( Dex.Trk, Dex.params.ep, Dex.curveData.pos1 ); + UndoEnd(); + DrawNewTrack(Dex.Trk ); + return C_TERMINATE; } + if (FindDistance(Dex.pos01, Dex.curveData.pos1) == 0) return C_ERROR; +LOG( log_modify, 1, ("L = %0.3f, P0 = %0.3f, P1 = %0.3f\n", + Dex.params.len, Dex.pos01, Dex.curveData.pos1 ) ) trk = NewStraightTrack( Dex.pos01, Dex.curveData.pos1 ); inx = 0; } else if ( curveType == curveTypeCurve ) { -LOG( log_modify, 1, ("A0 = %0.3f, A1 = %0.3f\n", - Dex.curveData.a0, Dex.curveData.a1 ) ) +LOG( log_modify, 1, ("R = %0.3f, A0 = %0.3f, A1 = %0.3f\n", + Dex.curveData.curveRadius, Dex.curveData.a0, Dex.curveData.a1 ) ) trk = NewCurvedTrack( Dex.curveData.curvePos, Dex.curveData.curveRadius, Dex.curveData.a0, Dex.curveData.a1, 0 ); inx = PickUnconnectedEndPoint( Dex.pos01, trk ); @@ -478,39 +695,86 @@ LOG( log_modify, 1, ("A0 = %0.3f, A1 = %0.3f\n", } else { return C_ERROR; } - //UndrawNewTrack( Dex.Trk ); CopyAttributes( Dex.Trk, trk ); - JoinTracks( Dex.Trk, Dex.params.ep, Dex.pos00, trk, inx, Dex.pos01, &Dex.jointD ); + if (Dex.jointD.d1 == 0) { + DrawEndPt( &mainD, Dex.Trk, Dex.params.ep, wDrawColorWhite ); + ConnectTracks(Dex.Trk, Dex.params.ep, trk, inx); + DrawEndPt( &mainD, Dex.Trk, Dex.params.ep, wDrawColorBlack ); + } else { + UndrawNewTrack( Dex.Trk ); + JoinTracks( Dex.Trk, Dex.params.ep, Dex.pos00, trk, inx, Dex.pos01, &Dex.jointD ); + DrawNewTrack( Dex.Trk ); + } UndoEnd(); + tempSegs_da.cnt = 0; DrawNewTrack( trk ); - DrawNewTrack( Dex.Trk ); - Dex.Trk = NULL; - MainRedraw(); - MapRedraw(); return C_TERMINATE; case C_REDRAW: if (modifyBezierMode) return ModifyBezier(C_REDRAW, pos); if (modifyCornuMode) return ModifyCornu(C_REDRAW, pos); - if ( (!changeTrackMode) && Dex.Trk && !QueryTrack( Dex.Trk, Q_MODIFY_REDRAW_DONT_UNDRAW_TRACK ) ) - UndrawNewTrack( Dex.Trk ); + if (modifyDrawMode) return ModifyDraw(C_REDRAW, pos); DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + return C_CONTINUE; case C_TEXT: + if ((action>>8) == 'c') { + panCenter = pos; + LOG( log_pan, 2, ( "PanCenter:Mod-%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) ); + PanHere((void*)0); + return C_CONTINUE; + } + if ((action>>8) == 'e') { + DoZoomExtents(0); + } + if ((action>>8) == '0' || (action>>8 == 'o')) { + PanMenuEnter('o'); + } if ( !Dex.Trk ) return C_CONTINUE; if (modifyBezierMode) return ModifyBezier(action, pos); if (modifyCornuMode) return ModifyCornu(action, pos); + if (modifyDrawMode) + return ModifyDraw(action, pos); + return ModifyTrack( Dex.Trk, action, pos ); + + case C_CMDMENU: + if ( !Dex.Trk ) { + menuPos = pos; + wMenuPopupShow(modPopupM); + return C_CONTINUE; + } + if (modifyBezierMode) + return ModifyBezier(action, pos); + if (modifyCornuMode) + return ModifyCornu(action, pos); + if (modifyDrawMode) + return ModifyDraw(action, pos); return ModifyTrack( Dex.Trk, action, pos ); + case C_LCLICK: + if ( modifyDrawMode) { + rc = ModifyDraw(C_DOWN, pos); + if (rc == C_CONTINUE) + return ModifyDraw(C_UP, pos); + } + if (modifyCornuMode) + return ModifyCornu(action, pos); + /*no break*/ default: if (modifyBezierMode) return ModifyBezier(action, pos); if (modifyCornuMode) return ModifyCornu(action, pos); + if (modifyDrawMode) return ModifyDraw(action, pos); + if (Dex.Trk) + return ModifyTrack( Dex.Trk, action, pos ); return C_CONTINUE; } + return C_CONTINUE; } @@ -521,9 +785,21 @@ LOG( log_modify, 1, ("A0 = %0.3f, A1 = %0.3f\n", */ #include "bitmaps/extend.xpm" +extern wIndex_t panCmdInx; +extern wIndex_t selectCmdInx; +extern wIndex_t describeCmdInx; + void InitCmdModify( wMenu_p menu ) { - modifyCmdInx = AddMenuButton( menu, CmdModify, "cmdModify", _("Modify"), wIconCreatePixMap(extend_xpm), LEVEL0_50, IC_STICKY|IC_POPUP, ACCL_MODIFY, NULL ); + modifyCmdInx = AddMenuButton( menu, CmdModify, "cmdModify", _("Modify"), wIconCreatePixMap(extend_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE|IC_CMDMENU, ACCL_MODIFY, NULL ); log_modify = LogFindIndex( "modify" ); + modPopupM = MenuRegister( "Modify Context Menu" ); + wMenuPushCreate(modPopupM, "cmdSelectMode", GetBalloonHelpStr("cmdSelectMode"), 0, DoCommandB, (void*) (intptr_t) selectCmdInx); + wMenuPushCreate(modPopupM, "cmdDescribeMode", GetBalloonHelpStr("cmdDescribeMode"), 0, DoCommandB, (void*) (intptr_t) describeCmdInx); + wMenuPushCreate(modPopupM, "cmdPanMode", GetBalloonHelpStr("cmdPanMode"), 0, DoCommandB, (void*) (intptr_t) panCmdInx); + wMenuSeparatorCreate(modPopupM); + wMenuPushCreate(modPopupM, "", _("Zoom In"), 0,(wMenuCallBack_p) DoZoomUp, (void*) 1); + wMenuPushCreate(modPopupM, "", _("Zoom Out"), 0, (wMenuCallBack_p) DoZoomDown, (void*) 1); + wMenuPushCreate(modPopupM, "", _("Pan center - 'c'"), 0, (wMenuCallBack_p) PanHere, (void*) 3); } diff --git a/app/bin/cnote.c b/app/bin/cnote.c index 3cbd28d..0a015f1 100644 --- a/app/bin/cnote.c +++ b/app/bin/cnote.c @@ -1,5 +1,5 @@ /** \file cnote.c - * NOTE + * Main layout note */ /* XTrkCad - Model Railroad CAD @@ -21,26 +21,13 @@ */ #include -#include "cundo.h" #include "custom.h" +#include "dynstring.h" #include "fileio.h" #include "i18n.h" +#include "misc.h" #include "param.h" -#include "track.h" -#include "utility.h" - -static TRKTYP_T T_NOTE = -1; - -static wDrawBitMap_p note_bm; -struct extraData { - coOrd pos; - char * text; -}; - -extern BOOL_T inDescribeCmd; - -#define NOTEHIDE "CNOTE HIDE" -#define NOTEDONE "CNOTE DONE" +#include "include/utf8convert.h" static char * mainText = NULL; static wWin_p noteW; @@ -54,18 +41,6 @@ static paramData_t notePLs[] = { static paramGroup_t notePG = { "note", 0, notePLs, sizeof notePLs/sizeof notePLs[0] }; -static track_p NewNote(wIndex_t index, coOrd p, long size) -{ - track_p t; - struct extraData * xx; - t = NewTrack(index, T_NOTE, 0, sizeof *xx); - xx = GetTrkExtraData(t); - xx->pos = p; - xx->text = (char*)MyMalloc((int)size + 2); - SetBoundingBox(t, p, p); - return t; -} - void ClearNote(void) { if (mainText) { @@ -82,12 +57,6 @@ static void NoteOk(void * junk) len = wTextGetSize(noteT); mainText = (char*)MyMalloc(len+2); wTextGetText(noteT, mainText, len); - - if (mainText[len-1] != '\n') { - mainText[len++] = '\n'; - } - - mainText[len] = '\0'; } wHide(noteW); @@ -98,7 +67,7 @@ void DoNote(void) { if (noteW == NULL) { noteW = ParamCreateDialog(¬ePG, MakeWindowTitle(_("Note")), _("Ok"), NoteOk, - NULL, FALSE, NULL, F_RESIZE, NULL); + wHide, FALSE, NULL, F_NOTTRANSIENT|F_RESIZE, NULL); } wTextClear(noteT); @@ -109,365 +78,66 @@ void DoNote(void) } - -/***************************************************************************** - * NOTE OBJECT - */ - -static void DrawNote(track_p t, drawCmd_p d, wDrawColor color) -{ - struct extraData *xx = GetTrkExtraData(t); - coOrd p[4]; - - if (d->scale >= 16) { - return; - } - - if ((d->funcs->options & wDrawOptTemp) == 0) { - DrawBitMap(d, xx->pos, note_bm, color); - } else { - DIST_T dist; - dist = 0.1*d->scale; - p[0].x = p[1].x = xx->pos.x-dist; - p[2].x = p[3].x = xx->pos.x+dist; - p[1].y = p[2].y = xx->pos.y-dist; - p[3].y = p[0].y = xx->pos.y+dist; - DrawLine(d, p[0], p[1], 0, color); - DrawLine(d, p[1], p[2], 0, color); - DrawLine(d, p[2], p[3], 0, color); - DrawLine(d, p[3], p[0], 0, color); - } -} - -static DIST_T DistanceNote(track_p t, coOrd * p) -{ - struct extraData *xx = GetTrkExtraData(t); - DIST_T d; - d = FindDistance(*p, xx->pos); - - if (d < 1.0) { - return d; - } - - return 100000.0; -} - - -static struct { - coOrd pos; - unsigned int layer; -} noteData; -typedef enum { OR, LY, TX } noteDesc_e; -static descData_t noteDesc[] = { - /*OR*/ { DESC_POS, N_("Position"), ¬eData.pos }, - /*LY*/ { DESC_LAYER, N_("Layer"), ¬eData.layer }, - /*TX*/ { DESC_TEXT, NULL, NULL }, - { DESC_NULL } -}; - -static void UpdateNote(track_p trk, int inx, descData_p descUpd, - BOOL_T needUndoStart) -{ - struct extraData *xx = GetTrkExtraData(trk); - - switch (inx) { - case OR: - xx->pos = noteData.pos; - SetBoundingBox(trk, xx->pos, xx->pos); - MainRedraw(); - break; - - case LY: - SetTrkLayer(trk, noteData.layer); - MainRedraw(); - break; - - case -1: - if (wTextGetModified((wText_p)noteDesc[TX].control0)) { - int len; - - if (needUndoStart) { - UndoStart(_("Change Track"), "Change Track"); - } - - UndoModify(trk); - MyFree(xx->text); - len = wTextGetSize((wText_p)noteDesc[TX].control0); - xx->text = (char*)MyMalloc(len+2); - wTextGetText((wText_p)noteDesc[TX].control0, xx->text, len); - - if (xx->text[len-1] != '\n') { - xx->text[len++] = '\n'; - } - - xx->text[len] = '\0'; - } - MainRedraw(); - break; - - default: - break; - } -} - - -static void DescribeNote(track_p trk, char * str, CSIZE_T len) -{ - struct extraData * xx = GetTrkExtraData(trk); - strcpy(str, _("Note: ")); - len -= strlen(_("Note: ")); - str += strlen(_("Note: ")); - strncpy(str, xx->text, len); - - for (; *str; str++) { - if (*str=='\n') { - *str = ' '; - } - } - - noteData.pos = xx->pos; - noteDesc[TX].valueP = xx->text; - noteDesc[OR].mode = 0; - noteDesc[TX].mode = 0; - noteDesc[LY].mode = DESC_NOREDRAW; - DoDescribe(_("Note"), trk, noteDesc, UpdateNote); -} - -static void DeleteNote(track_p t) -{ - struct extraData *xx = GetTrkExtraData(t); - - if (xx->text) { - MyFree(xx->text); - } -} - -static BOOL_T WriteNote(track_p t, FILE * f) +BOOL_T WriteMainNote(FILE* f) { - struct extraData *xx = GetTrkExtraData(t); - int len; - BOOL_T addNL = FALSE; BOOL_T rc = TRUE; - len = strlen(xx->text); - - if (xx->text[len-1] != '\n') { - len++; - addNL = TRUE; + char *noteText = mainText; + + if (noteText && *noteText) { +#ifdef WINDOWS + char *out = NULL; + if (RequiresConvToUTF8(mainText)) { + unsigned cnt = strlen(mainText) * 2 + 1; + out = MyMalloc(cnt); + wSystemToUTF8(mainText, out, cnt); + noteText = out; + } +#endif // WINDOWS + + + char * sText = ConvertToEscapedText( noteText ); + rc &= fprintf(f, "NOTE MAIN 0 0 0 0 0 \"%s\"\n", sText )>0; + MyFree( sText ); + +#ifdef WINDOWS + if (out) { + MyFree(out); + } +#endif // WINDOWS } - - rc &= fprintf(f, "NOTE %d %d 0 0 %0.6f %0.6f 0 %d\n", GetTrkIndex(t), - GetTrkLayer(t), - xx->pos.x, xx->pos.y, len)>0; - rc &= fprintf(f, "%s%s", xx->text, addNL?"\n":"")>0; - rc &= fprintf(f, " END\n")>0; return rc; } +/** + * Read the layout main note + * + * \param line complete NOTE statement + */ -static void ReadNote(char * line) +BOOL_T ReadMainNote(char *line) { - coOrd pos; - DIST_T elev; - CSIZE_T size; - char * cp; - struct extraData *xx; - wIndex_t index; - wIndex_t layer; - int lineCount; - - if (strncmp(line, "NOTE MAIN", 9) == 0) { - if (!GetArgs(line+9, paramVersion<3?"d":"0000d", &size)) { - return; - } + long size; + char * sNote = NULL; - if (mainText) { - MyFree(mainText); - } - - mainText = (char*)MyMalloc(size+2); - cp = mainText; - } else { - track_p t; - - if (!GetArgs(line+5, paramVersion<3?"XXpYd":paramVersion<9?"dL00pYd":"dL00pfd", - &index, &layer, &pos, &elev, &size)) { - return; - } - - t = NewNote(index, pos, size+2); - SetTrkLayer(t, layer); - xx = GetTrkExtraData(t); - cp = xx->text; - } - - lineCount = 0; - - while (1) { - int len; - line = GetNextLine(); - - if (strncmp(line, " END", 7) == 0) { - break; - } - - len = strlen(line); - - if (size > 0 && size < len) { - InputError("NOTE text overflow", TRUE); - size = -1; - } - - if (size > 0) { - if (lineCount != 0) { - strcat(cp, "\n"); - cp++; - size--; - } - - strcpy(cp, line); - cp += len; - size -= len; - } - - lineCount++; - } - - if (cp[-1] != '\n') { - *cp++ = '\n'; + if (!GetArgs(line + 9, + paramVersion < 3 ? "l" : + paramVersion < 12 ? "0000l": + "0000lq", &size, &sNote)) { + return FALSE; } - *cp = '\0'; -} - - -static void MoveNote(track_p trk, coOrd orig) -{ - struct extraData * xx = GetTrkExtraData(trk); - xx->pos.x += orig.x; - xx->pos.y += orig.y; - SetBoundingBox(trk, xx->pos, xx->pos); -} - - -static void RotateNote(track_p trk, coOrd orig, ANGLE_T angle) -{ - struct extraData * xx = GetTrkExtraData(trk); - Rotate(&xx->pos, orig, angle); - SetBoundingBox(trk, xx->pos, xx->pos); -} - -static void RescaleNote(track_p trk, FLOAT_T ratio) -{ - struct extraData * xx = GetTrkExtraData(trk); - xx->pos.x *= ratio; - xx->pos.y *= ratio; -} - - -static trackCmd_t noteCmds = { - "NOTE", - DrawNote, - DistanceNote, - DescribeNote, - DeleteNote, - WriteNote, - ReadNote, - MoveNote, - RotateNote, - RescaleNote, - NULL, /* audit */ - NULL, /* getAngle */ - NULL, /* split */ - NULL, /* traverse */ - NULL, /* enumerate */ - NULL /* redraw */ -}; - - -BOOL_T WriteMainNote(FILE* f) -{ - BOOL_T rc = TRUE; - - if (mainText && *mainText) { - rc &= fprintf(f, "NOTE MAIN 0 0 0 0 %lu\n", strlen(mainText))>0; - rc &= fprintf(f, "%s", mainText)>0; - rc &= fprintf(f, " END\n")>0; + if (mainText) { + MyFree(mainText); } - return rc; + if ( paramVersion < 12 ) + mainText = ReadMultilineText(); + else + mainText = sNote; + return TRUE; } -/***************************************************************************** - * NOTE COMMAND - */ - - - -static STATUS_T CmdNote(wAction_t action, coOrd pos) -{ - static coOrd oldPos; - track_p trk; - struct extraData * xx; - const char* tmpPtrText; - static int state_on = FALSE; - - switch (action) { - case C_START: - InfoMessage(_("Place a note on the layout")); - return C_CONTINUE; - - case C_DOWN: - state_on = TRUE; - oldPos = pos; - MainRedraw(); - return C_CONTINUE; - - case C_MOVE: - oldPos = pos; - MainRedraw(); - return C_CONTINUE; - break; - - case C_UP: - UndoStart(_("New Note"), "New Note"); - state_on = FALSE; - MainRedraw(); - trk = NewNote(-1, pos, 2); - DrawNewTrack(trk); - xx = GetTrkExtraData(trk); - tmpPtrText = _("Replace this text with your note"); - xx->text = (char*)MyMalloc(strlen(tmpPtrText) + 1); - strcpy(xx->text, tmpPtrText); - inDescribeCmd = TRUE; - DescribeNote(trk, message, sizeof message); - inDescribeCmd = FALSE; - return C_CONTINUE; - - case C_REDRAW: - if (state_on) DrawBitMap(&tempD, oldPos, note_bm, normalColor); - return C_CONTINUE; - - case C_CANCEL: - DescribeCancel(); - return C_CONTINUE; - } - - return C_INFO; -} - - -#include "bitmaps/note.xbm" -#include "bitmaps/cnote.xpm" - -void InitCmdNote(wMenu_p menu) +void InitCmdNote() { ParamRegister(¬ePG); - AddMenuButton(menu, CmdNote, "cmdNote", _("Note"), wIconCreatePixMap(cnote_xpm), - LEVEL0_50, IC_POPUP2, ACCL_NOTE, NULL); -} - -void InitTrkNote(void) -{ - note_bm = wDrawBitMapCreate(mainD.d, note_width, note_width, 8, 8, note_bits); - T_NOTE = InitObject(¬eCmds); } diff --git a/app/bin/common.h b/app/bin/common.h index 255e8d7..2db961f 100644 --- a/app/bin/common.h +++ b/app/bin/common.h @@ -24,6 +24,7 @@ #define COMMON_H #include +#include #ifndef TRUE #define TRUE (1) @@ -46,6 +47,11 @@ typedef struct { POS_T x,y; } coOrd; +typedef struct { + coOrd pt; + int pt_type; +} pts_t; + typedef int INT_T; typedef int BOOL_T; @@ -61,6 +67,11 @@ typedef int TRKINX_T; typedef long DEBUGF_T; typedef int REGION_T; +enum paramFileState { PARAMFILE_UNLOADED = 0, PARAMFILE_NOTUSABLE, PARAMFILE_COMPATIBLE, PARAMFILE_FIT, PARAMFILE_MAXSTATE }; + +#define SCALE_ANY (-2) +#define SCALE_DEMO (-1) + typedef struct { int cnt; int max; @@ -108,6 +119,17 @@ typedef struct { } \ (DA).max = 0; \ (DA).cnt = 0; } +#define DYNARR_REMOVE(T,DA,I) \ + { \ + { if ((DA).cnt-1 > I) { \ + for (int i=I;i<(DA).cnt-1;i++) { \ + (((T*)(DA).ptr)[i])= (((T*)(DA).ptr)[i+1]); \ + } \ + } \ + } \ + if ((DA.cnt)>=I) (DA).cnt--; \ + } + #ifdef WINDOWS #define M_PI 3.14159 diff --git a/app/bin/compound.c b/app/bin/compound.c index d1a16f5..627d2ef 100644 --- a/app/bin/compound.c +++ b/app/bin/compound.c @@ -38,6 +38,7 @@ #include "track.h" #include "utility.h" #include "messages.h" +#include "include/paramfile.h" /***************************************************************************** * @@ -45,6 +46,25 @@ * */ +//Convert the internal path segment into the external one - which is based on the index count of only the track segments + +char ConvertPathSegToExternal(char signed pp, int segCnt,trkSeg_p segs) { + + char signed new_pp; + int old_inx; + EPINX_T old_EP; + GetSegInxEP(pp,&old_inx,&old_EP); + int j = old_inx; + for (int i=0;i0; - for ( pp+=strlen((char *)pp)+1; pp[0]!=0||pp[1]!=0; pp++ ) - rc &= fprintf( f, " %d", *pp )>0; + for ( pp+=strlen((char *)pp)+1; pp[0]!=0 || pp[1]!=0; pp++ ) + rc &= fprintf( f, " %d", ConvertPathSegToExternal(pp[0],segCnt,segs) )>0; rc &= fprintf( f, "\n" )>0; } for ( i=0; ioptions&DC_GROUP) ) + if ( (d->options&DC_SIMPLE) ) return; if ( xx->special == TOpier ) { desc = xx->u.pier.name; @@ -340,18 +361,25 @@ void DrawCompoundDescription( DIST_T CompoundDescriptionDistance( coOrd pos, - track_p trk ) + track_p trk, + coOrd * dpos, + BOOL_T show_hidden, + BOOL_T * hidden) { struct extraData *xx = GetTrkExtraData(trk); coOrd p1; if (GetTrkType(trk) != T_TURNOUT && GetTrkType(trk) != T_STRUCTURE) return 100000; - if ( (GetTrkBits( trk ) & TB_HIDEDESC) != 0 ) + if ( ((GetTrkBits( trk ) & TB_HIDEDESC) != 0 ) && !show_hidden) return 100000; p1 = xx->descriptionOrig; + coOrd offset = xx->descriptionOff; + if ( (GetTrkBits( trk ) & TB_HIDEDESC) != 0 ) offset = zero; Rotate( &p1, zero, xx->angle ); - p1.x += xx->orig.x + xx->descriptionOff.x; - p1.y += xx->orig.y + xx->descriptionOff.y; + p1.x += xx->orig.x + offset.x; + p1.y += xx->orig.y + offset.y; + if (hidden) *hidden = (GetTrkBits( trk ) & TB_HIDEDESC); + *dpos = p1; return FindDistance( p1, pos ); } @@ -370,6 +398,7 @@ STATUS_T CompoundDescriptionMove( case C_DOWN: editMode = TRUE; REORIGIN( p0, xx->descriptionOrig, xx->angle, xx->orig ) + DrawCompoundDescription( trk, &mainD, wDrawColorWhite ); case C_MOVE: case C_UP: @@ -383,13 +412,15 @@ STATUS_T CompoundDescriptionMove( if (action == C_UP) { editMode = FALSE; } - MainRedraw(); - MapRedraw(); + if ( action == C_UP ) { + DrawCompoundDescription( trk, &mainD, color ); + } return action==C_UP?C_TERMINATE:C_CONTINUE; break; case C_REDRAW: if (editMode) { - DrawLine( &tempD, p0, p1, 0, wDrawColorBlack ); + DrawCompoundDescription( trk, &tempD, wDrawColorBlue ); + DrawLine( &tempD, p0, p1, 0, wDrawColorBlue ); } } @@ -405,6 +436,18 @@ STATUS_T CompoundDescriptionMove( * */ +EXPORT void SetSegInxEP( + signed char * segChar, + int segInx, + EPINX_T segEP ) +{ + if (segEP == 1) { + * segChar = -(segInx+1); + } else { + * segChar = (segInx+1); + } + +} EXPORT void GetSegInxEP( signed char segChar, @@ -482,6 +525,7 @@ static struct { FLOAT_T elev[4]; coOrd orig; ANGLE_T angle; + descPivot_t pivot; char manuf[STR_SIZE]; char name[STR_SIZE]; char partno[STR_SIZE]; @@ -490,9 +534,10 @@ static struct { long pathCnt; FLOAT_T grade; DIST_T length; + drawLineType_e linetype; unsigned int layerNumber; } compoundData; -typedef enum { E0, A0, C0, R0, Z0, E1, A1, C1, R1, Z1, E2, A2, C2, R2, Z2, E3, A3, C3, R3, Z3, GR, OR, AN, MN, NM, PN, EC, SC, LY } compoundDesc_e; +typedef enum { E0, A0, C0, R0, Z0, E1, A1, C1, R1, Z1, E2, A2, C2, R2, Z2, E3, A3, C3, R3, Z3, GR, OR, AN, PV, MN, NM, PN, LT, SC, LY } compoundDesc_e; static descData_t compoundDesc[] = { /*E0*/ { DESC_POS, N_("End Pt 1: X,Y"), &compoundData.endPt[0] }, /*A0*/ { DESC_ANGLE, N_("Angle"), &compoundData.endAngle[0] }, @@ -517,10 +562,11 @@ static descData_t compoundDesc[] = { /*GR*/ { DESC_FLOAT, N_("Grade"), &compoundData.grade }, /*OR*/ { DESC_POS, N_("Origin: X,Y"), &compoundData.orig }, /*AN*/ { DESC_ANGLE, N_("Angle"), &compoundData.angle }, +/*PV*/ { DESC_PIVOT, N_("Pivot"), &compoundData.pivot }, /*MN*/ { DESC_STRING, N_("Manufacturer"), &compoundData.manuf, sizeof(compoundData.manuf)}, /*NM*/ { DESC_STRING, N_("Name"), &compoundData.name, sizeof(compoundData.name) }, /*PN*/ { DESC_STRING, N_("Part No"), &compoundData.partno, sizeof(compoundData.partno)}, -/*EC*/ { DESC_LONG, N_("# End Pts"), &compoundData.epCnt }, +/*LT*/ { DESC_LIST, N_("LineType"), &compoundData.linetype }, /*SC*/ { DESC_LONG, N_("# Segments"), &compoundData.segCnt }, /*LY*/ { DESC_LAYER, N_("Layer"), &compoundData.layerNumber }, { DESC_NULL } }; @@ -539,7 +585,11 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee BOOL_T titleChanged, flipped, ungrouped, split; char * newTitle; - if ( inx == -1 ) { + switch ( inx ) { + case -1: + case MN: + case NM: + case PN: titleChanged = FALSE; ParseCompoundTitle( xtitle(xx), &mP, &mL, &nP, &nL, &pP, &pL ); if (mP == NULL) mP = ""; @@ -616,7 +666,7 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee GetBoundingBox( trk, &hi, &lo ); if ( labelScale >= mainD.scale && !OFF_MAIND( lo, hi ) ) { - DrawCompoundDescription( trk, &tempD, GetTrkColor(trk,&tempD) ); + DrawCompoundDescription( trk, &mainD, wDrawColorWhite ); } /*sprintf( message, "%s\t%s\t%s", manufS, nameS, partnoS );*/ if (xx->title) MyFree(xx->title); @@ -626,12 +676,13 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee xx->split = split; if ( labelScale >= mainD.scale && !OFF_MAIND( lo, hi ) ) { - DrawCompoundDescription( trk, &tempD, GetTrkColor(trk,&tempD) ); + DrawCompoundDescription( trk, &mainD, GetTrkColor(trk,&tempD) ); } return; } UndrawNewTrack( trk ); + coOrd orig; switch ( inx ) { case OR: pos.x = compoundData.orig.x - xx->orig.x; @@ -643,17 +694,31 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee case A1: case A2: case A3: - if (inx==E3) ep=3; - else if (inx==E2) ep=2; - else if (inx==E1) ep=1; + if (inx==A3) ep=3; + else if (inx==A2) ep=2; + else if (inx==A1) ep=1; else ep=0; - RotateTrack( trk, xx->orig, NormalizeAngle( compoundData.endAngle[ep]-xx->angle ) ); + RotateTrack( trk, GetTrkEndPos(trk,ep), NormalizeAngle( compoundData.endAngle[ep]-GetTrkEndAngle(trk,ep) ) ); ComputeCompoundBoundingBox( trk ); - compoundData.angle = xx->angle; - compoundDesc[AN].mode |= DESC_CHANGE; break; case AN: - RotateTrack( trk, xx->orig, NormalizeAngle( compoundData.angle-xx->angle ) ); + orig = xx->orig; + GetBoundingBox(trk,&hi,&lo); + switch (compoundData.pivot) { + case DESC_PIVOT_MID: + orig.x = (hi.x-lo.x)/2+lo.x; + orig.y = (hi.y-lo.y)/2+lo.y; + break; + case DESC_PIVOT_SECOND: + orig.x = (hi.x-lo.x)/2+lo.x; + orig.y = (hi.y-lo.y)/2+lo.y; + orig.x = (orig.x - xx->orig.x)*2+xx->orig.x; + orig.y = (orig.y - xx->orig.y)*2+xx->orig.y; + break; + default: + break; + } + RotateTrack( trk, orig, NormalizeAngle( compoundData.angle-xx->angle ) ); ComputeCompoundBoundingBox( trk ); break; case E0: @@ -680,7 +745,7 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee break; for (int i=0;i minLength ) compoundData.grade = fabs( (compoundData.elev[0]-compoundData.elev[1])/compoundData.length )*100.0; @@ -719,6 +784,13 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee compoundDesc[i*(E1-E0)+C0].mode |= DESC_CHANGE; } } + compoundData.orig = xx->orig; + compoundDesc[OR].mode |= DESC_CHANGE; + compoundData.angle = xx->angle; + compoundDesc[AN].mode |= DESC_CHANGE; + break; + case LT: + xx->lineType = compoundData.linetype; break; default: break; @@ -839,9 +911,10 @@ void DescribeCompound( compoundDesc[MN].mode = compoundDesc[NM].mode = compoundDesc[PN].mode = 0 /*DESC_NOREDRAW*/; - compoundDesc[EC].mode = compoundDesc[SC].mode = DESC_RO; compoundDesc[LY].mode = DESC_NOREDRAW; + compoundDesc[PV].mode = 0; + compoundData.pivot = DESC_PIVOT_FIRST; if (compoundData.epCnt >0) { for (int i=0;(i minLength && compoundData.epCnt > 1) compoundData.grade = fabs( (compoundData.elev[0]-compoundData.elev[1])/compoundData.length )*100.0; else compoundData.grade = 0.0; + if (GetTrkEndPtCnt(trk) == 0) { + compoundDesc[LT].mode = 0; + } else + compoundDesc[LT].mode = DESC_IGNORE; + DoDescribe(trackType, trk, compoundDesc, UpdateCompound); + if ( compoundDesc[LT].control0!=NULL) { + wListClear( (wList_p)compoundDesc[LT].control0 ); + wListAddValue( (wList_p)compoundDesc[LT].control0, _("Solid"), NULL, (void*)0 ); + wListAddValue( (wList_p)compoundDesc[LT].control0, _("Dash"), NULL, (void*)1 ); + wListAddValue( (wList_p)compoundDesc[LT].control0, _("Dot"), NULL, (void*)2 ); + wListAddValue( (wList_p)compoundDesc[LT].control0, _("DashDot"), NULL, (void*)3 ); + wListAddValue( (wList_p)compoundDesc[LT].control0, _("DashDotDot"), NULL, (void*)4 ); + wListAddValue( (wList_p)compoundDesc[LT].control0, _("CenterDot"), NULL, (void*)5 ); + wListAddValue( (wList_p)compoundDesc[LT].control0, _("PhantomDot"), NULL, (void*)6 ); + wListSetIndex( (wList_p)compoundDesc[LT].control0, compoundData.linetype ); + } + } @@ -880,6 +972,7 @@ void DeleteCompound( struct extraData *xx = GetTrkExtraData(t); FreeFilledDraw( xx->segCnt, xx->segs ); MyFree( xx->segs ); + xx->segs = NULL; } @@ -891,6 +984,7 @@ BOOL_T WriteCompound( EPINX_T ep, epCnt; long options; long position = 0; + drawLineType_e lineType = 0; PATHPTR_T path; BOOL_T rc = TRUE; @@ -918,10 +1012,11 @@ BOOL_T WriteCompound( position++; } } - rc &= fprintf(f, "%s %d %d %ld %ld 0 %s %d %0.6f %0.6f 0 %0.6f \"%s\"\n", + lineType = xx->lineType; + rc &= fprintf(f, "%s %d %d %ld %ld %d %s %d %0.6f %0.6f 0 %0.6f \"%s\"\n", GetTrkTypeName(t), - GetTrkIndex(t), GetTrkLayer(t), options, position, - GetTrkScaleName(t), GetTrkVisible(t), + GetTrkIndex(t), GetTrkLayer(t), options, position, lineType, + GetTrkScaleName(t), GetTrkVisible(t)|(GetTrkNoTies(t)?1<<2:0)|(GetTrkBridge(t)?1<<3:0), xx->orig.x, xx->orig.y, xx->angle, PutTitle(xtitle(xx)) )>0; for (ep=0; epu.pier.height, xx->u.pier.name )>0; + break; + default: ; } @@ -950,6 +1047,34 @@ BOOL_T WriteCompound( * */ +EXPORT void SetCompoundLineType( track_p trk, int width ) { + struct extraData * xx = GetTrkExtraData(trk); + switch(width) { + case 0: + xx->lineType = DRAWLINESOLID; + break; + case 1: + xx->lineType = DRAWLINEDASH; + break; + case 2: + xx->lineType = DRAWLINEDOT; + break; + case 3: + xx->lineType = DRAWLINEDASHDOT; + break; + case 4: + xx->lineType = DRAWLINEDASHDOTDOT; + break; + case 5: + xx->lineType = DRAWLINECENTER; + break; + case 6: + xx->lineType = DRAWLINEPHANTOM; + break; + } +} + + EXPORT track_p NewCompound( TRKTYP_T trkType, @@ -959,6 +1084,7 @@ EXPORT track_p NewCompound( char * title, EPINX_T epCnt, trkEndPt_t * epp, + DIST_T * radii, int pathLen, char * paths, wIndex_t segCnt, @@ -994,13 +1120,23 @@ EXPORT track_p NewCompound( FixUpBezierSegs(xx->segs,xx->segCnt); ComputeCompoundBoundingBox( trk ); SetDescriptionOrig( trk ); - for ( ep=0; epspecial = TOcurved; +// xx->u.curved.radii.max = 0; +// xx->u.curved.radii.cnt = 0; +// DYNARR_SET(DIST_T,xx->u.curved.radii,epCnt); +// } + for ( ep=0; epu.curved.radii,ep) = radii[ep]; +// } + } return trk; } -void ReadCompound( +BOOL_T ReadCompound( char * line, TRKTYP_T trkType ) { @@ -1017,26 +1153,28 @@ void ReadCompound( char *cp; long options = 0; long position = 0; + long lineType = 0; PATHPTR_T path=NULL; if (paramVersion<3) { if ( !GetArgs( line, "dXsdpfq", &index, &layer, scale, &visible, &orig, &angle, &title ) ) - return; + return FALSE; } else if (paramVersion <= 5 && trkType == T_STRUCTURE) { if ( !GetArgs( line, "dL00sdpfq", &index, &layer, scale, &visible, &orig, &angle, &title ) ) - return; + return FALSE; } else { - if ( !GetArgs( line, paramVersion<9?"dLll0sdpYfq":"dLll0sdpffq", - &index, &layer, &options, &position, scale, &visible, &orig, &elev, &angle, &title ) ) - return; + if ( !GetArgs( line, paramVersion<9?"dLlldsdpYfq":"dLlldsdpffq", + &index, &layer, &options, &position, &lineType, scale, &visible, &orig, &elev, &angle, &title ) ) + return FALSE; } if (paramVersion >=3 && paramVersion <= 5 && trkType == T_STRUCTURE) strcpy( scale, curScaleName ); DYNARR_RESET( trkEndPt_t, tempEndPts_da ); pathCnt = 0; - ReadSegs(); + if ( !ReadSegs() ) + return FALSE; path = pathPtr; if ( tempEndPts_da.cnt > 0 && pathCnt <= 1 ) { pathCnt = 10; @@ -1051,9 +1189,17 @@ void ReadCompound( UpdateTitleMark( title, LookupScale(scale) ); } } - trk = NewCompound( trkType, index, orig, angle, title, 0, NULL, pathCnt, (char *)path, tempSegs_da.cnt, &tempSegs(0) ); + trk = NewCompound( trkType, index, orig, angle, title, 0, NULL, NULL, pathCnt, (char *)path, tempSegs_da.cnt, &tempSegs(0) ); SetEndPts( trk, 0 ); - SetTrkVisible(trk, visible); + if ( paramVersion < 3 ) { + SetTrkVisible(trk, visible!=0); + SetTrkNoTies(trk, FALSE); + SetTrkBridge(trk, FALSE); + } else { + SetTrkVisible(trk, visible&2); + SetTrkNoTies(trk, visible&4); + SetTrkBridge(trk, visible&8); + } SetTrkScale(trk, LookupScale( scale )); SetTrkLayer(trk, layer); SetTrkWidth(trk, (int)(options&3)); @@ -1062,68 +1208,27 @@ void ReadCompound( xx->flipped = (int)((options&0x10)!=0); xx->ungrouped = (int)((options&0x20)!=0); xx->split = (int)((options&0x40)!=0); + xx->lineType = lineType; xx->descriptionOff = descriptionOff; if ( ( options & 0x80 ) != 0 ) SetTrkBits( trk, TB_HIDEDESC ); -#ifdef LATER - trk = NewTrack( index, trkType, 0, sizeof (*xx) + 1 ); - SetEndPts( trk, 0 ); - xx = GetTrkExtraData(trk); - SetTrkVisible(trk, visible); - SetTrkScale(trk, LookupScale( scale )); - SetTrkLayer(trk, layer); - SetTrkWidth(trk, (int)(options&3)); - xx->orig = orig; - xx->angle = angle; - xx->customInfo = NULL; - xx->handlaid = (int)((options>>3)&0x01); - xx->flipped = (int)((options>>4)&0x01); - xx->segCnt = tempSegs_da.cnt; - xx->segs = MyMalloc( (tempSegs_da.cnt)*sizeof xx->segs[0] ); - if (paramVersion<6 && strlen( title ) > 2) { - cp = strchr( title, '\t' ); - if (cp != NULL) { - cp = strchr( cp, '\t' ); - } - if (cp == NULL) { - UpdateTitleMark(title, GetTrkScale(trk)); - } - } - xx->title = title; - if ( GetTrkEndPtCnt(trk) > 0 && pathCnt <= 1 ) { - xx->pathLen = 10; - xx->paths = xx->pathCurr = (PATHPTR_T)Malloc( xx->pathLen ); - memcpy( xx->paths, "Normal\01\0\0", xx->pathLen ); - } else { - xx->pathLen = pathCnt; - if (pathCnt > 0) { - xx->paths = xx->pathCurr = (PATHPTR_T)Malloc( pathCnt ); - memcpy( xpaths(xx), pathPtr, pathCnt ); - } else { - xx->paths = xx->pathCurr = NULL; - } - } - xx->segCnt = tempSegs_da.cnt; - memcpy( xx->segs, tempSegs_da.ptr, tempSegs_da.cnt * sizeof *xx->segs ); - - ComputeCompoundBoundingBox( trk ); - SetDescriptionOrig( trk ); - xx->descriptionOff = descriptionOff; -#endif if (tempSpecial[0] != '\0') { if (strncmp( tempSpecial, ADJUSTABLE, strlen(ADJUSTABLE) ) == 0) { xx->special = TOadjustable; - GetArgs( tempSpecial+strlen(ADJUSTABLE), "ff", - &xx->u.adjustable.minD, &xx->u.adjustable.maxD ); + if ( !GetArgs( tempSpecial+strlen(ADJUSTABLE), "ff", + &xx->u.adjustable.minD, &xx->u.adjustable.maxD ) ) + return FALSE; } else if (strncmp( tempSpecial, PIER, strlen(PIER) ) == 0) { xx->special = TOpier; - GetArgs( tempSpecial+strlen(PIER), "fq", - &xx->u.pier.height, &xx->u.pier.name ); + if ( !GetArgs( tempSpecial+strlen(PIER), "fq", + &xx->u.pier.height, &xx->u.pier.name ) ) + return FALSE; } else { InputError("Unknown special case", TRUE); + return FALSE; } } if (pathCnt > 0) { @@ -1138,7 +1243,7 @@ void ReadCompound( } } xx->pathCurr = path; - + return TRUE; } void MoveCompound( @@ -1217,12 +1322,12 @@ void FlipCompound( mP && strcmp( mP, mfg ) == 0 && nP && pP ) { if ( strcmp( nP, descL ) == 0 && strcmp( pP, partL ) == 0 ) { sprintf( message, "%s\t%s\t%s", mfg, descR, partR ); - xx->title = strdup( message ); + xx->title = MyStrdup( message ); return; } if ( strcmp( nP, descR ) == 0 && strcmp( pP, partR ) == 0 ) { sprintf( message, "%s\t%s\t%s", mfg, descL, partL ); - xx->title = strdup( message ); + xx->title = MyStrdup( message ); return; } } diff --git a/app/bin/compound.h b/app/bin/compound.h index 4845f78..b4c63ca 100644 --- a/app/bin/compound.h +++ b/app/bin/compound.h @@ -26,7 +26,7 @@ #include "common.h" #include "track.h" -typedef enum { TOnormal, TOadjustable, TOpierInfo, TOpier, TOcarDesc, TOlast } TOspecial_e; +typedef enum { TOnormal, TOadjustable, TOpierInfo, TOpier, TOcarDesc, TOlast, TOcurved } TOspecial_e; typedef struct { char * name; @@ -44,6 +44,9 @@ typedef union { FLOAT_T height; char * name; } pier; + struct { + dynArr_t radii; + } curved; } turnoutInfo_u; typedef struct turnoutInfo_t{ @@ -91,6 +94,8 @@ struct extraData { PATHPTR_T pathCurr; wIndex_t segCnt; trkSeg_t * segs; + DIST_T * radii; + drawLineType_e lineType; }; #endif @@ -111,6 +116,7 @@ extern turnoutInfo_t * curStructure; #define ADJUSTABLE "adjustable" #define PIER "pier" +#define CURVED "curvedends" /* compound.c */ #define FIND_TURNOUT (1<<11) @@ -129,14 +135,15 @@ void DrawCompoundDescription( track_p, drawCmd_p, wDrawColor ); DIST_T DistanceCompound( track_p, coOrd * ); void DescribeCompound( track_p, char *, CSIZE_T ); void DeleteCompound( track_p ); -track_p NewCompound( TRKTYP_T, TRKINX_T, coOrd, ANGLE_T, char *, EPINX_T, trkEndPt_t *, int, char *, wIndex_t, trkSeg_p ); +track_p NewCompound( TRKTYP_T, TRKINX_T, coOrd, ANGLE_T, char *, EPINX_T, trkEndPt_t *, DIST_T *, int, char *, wIndex_t, trkSeg_p ); BOOL_T WriteCompound( track_p, FILE * ); -void ReadCompound( char *, TRKTYP_T ); +BOOL_T ReadCompound( char *, TRKTYP_T ); void MoveCompound( track_p, coOrd ); void RotateCompound( track_p, coOrd, ANGLE_T ); void RescaleCompound( track_p, FLOAT_T ); void FlipCompound( track_p, coOrd, ANGLE_T ); BOOL_T EnumerateCompound( track_p ); +void SetCompoundLineType( track_p trk, int width ); /* cgroup.c */ void UngroupCompound( track_p ); @@ -147,27 +154,34 @@ void DoGroup( void ); void UpdateTitleMark( char *, SCALEINX_T ); void DoUpdateTitles( void ); BOOL_T RefreshCompound( track_p, BOOL_T ); +wIndex_t FindListItemByContext( wList_p, void *); + /* cturnout.c */ EPINX_T TurnoutPickEndPt( coOrd p, track_p ); +BOOL_T SplitTurnoutCheck(track_p,coOrd,EPINX_T ep,track_p *,EPINX_T *,EPINX_T *,BOOL_T check, coOrd *, ANGLE_T *); void GetSegInxEP( signed char, int *, EPINX_T * ); +void SetSegInxEP( signed char *, int, EPINX_T) ; wIndex_t CheckPaths( wIndex_t, trkSeg_p, PATHPTR_T ); -turnoutInfo_t * CreateNewTurnout( char *, char *, wIndex_t, trkSeg_p, wIndex_t, PATHPTR_T, EPINX_T, trkEndPt_t *, wBool_t ); +turnoutInfo_t * CreateNewTurnout( char *, char *, wIndex_t, trkSeg_p, wIndex_t, PATHPTR_T, EPINX_T, trkEndPt_t *, DIST_T *, wBool_t ); +void DeleteTurnoutParams(int fileInx); turnoutInfo_t * TurnoutAdd( long, SCALEINX_T, wList_p, coOrd *, EPINX_T ); STATUS_T CmdTurnoutAction( wAction_t, coOrd ); BOOL_T ConnectAdjustableTracks( track_p trk1, EPINX_T ep1, track_p trk2, EPINX_T ep2 ); track_p NewHandLaidTurnout( coOrd, ANGLE_T, coOrd, ANGLE_T, coOrd, ANGLE_T, ANGLE_T ); void NextTurnoutPosition( track_p trk ); - +enum paramFileState GetTrackCompatibility(int paramFileIndex, SCALEINX_T scaleIndex); /* ctodesgn.c */ void EditCustomTurnout( turnoutInfo_t *, turnoutInfo_t * ); long ComputeTurnoutRoadbedSide( trkSeg_p, int, int, ANGLE_T, DIST_T ); /* cstruct.c */ turnoutInfo_t * CreateNewStructure( char *, char *, wIndex_t, trkSeg_p, BOOL_T ); +enum paramFileState GetStructureCompatibility(int paramFileIndex, SCALEINX_T scaleIndex); turnoutInfo_t * StructAdd( long, SCALEINX_T, wList_p, coOrd * ); STATUS_T CmdStructureAction( wAction_t, coOrd ); BOOL_T StructLoadCarDescList( wList_p ); +void DeleteStructures(int fileIndex); /* cstrdsgn.c */ void EditCustomStructure( turnoutInfo_t * ); diff --git a/app/bin/cparalle.c b/app/bin/cparalle.c index 8e70408..27276b1 100644 --- a/app/bin/cparalle.c +++ b/app/bin/cparalle.c @@ -30,162 +30,274 @@ #include "param.h" #include "track.h" #include "utility.h" +#include "layout.h" static struct { track_p Trk; coOrd orig; + track_p anchor_Trk; } Dpa; static DIST_T parSeparation = 1.0; +static double parSepFactor = 0.0; +static long parType = 0; -static paramFloatRange_t r_0o1_100 = { 0.1, 100.0, 100 }; +enum PAR_TYPE_E { PAR_TRACK, PAR_LINE }; + +static paramFloatRange_t r_0o1_100 = { 0.0, 100.0, 100 }; +static paramFloatRange_t r_0_10 = { 0.0, 10.0 }; static paramData_t parSepPLs[] = { #define parSepPD (parSepPLs[0]) - { PD_FLOAT, &parSeparation, "separation", PDO_DIM|PDO_NOPREF|PDO_NOPREF, &r_0o1_100, N_("Separation") } }; +#define parSepI 0 + { PD_FLOAT, &parSeparation, "separation", PDO_DIM, &r_0o1_100, N_("Separation") }, +#define parFactorPD (parSepPLs[1]) +#define parFactorI 1 + { PD_FLOAT, &parSepFactor, "factor", 0, &r_0_10, N_("Radius Factor") } +}; static paramGroup_t parSepPG = { "parallel", 0, parSepPLs, sizeof parSepPLs/sizeof parSepPLs[0] }; -static STATUS_T CmdParallel( wAction_t action, coOrd pos ) +static STATUS_T CmdParallel(wAction_t action, coOrd pos) { - DIST_T d; - track_p t=NULL; - coOrd p; - static coOrd p0, p1; - ANGLE_T a; - track_p t0, t1; - EPINX_T ep0=-1, ep1=-1; - wControl_p controls[2]; - char * labels[1]; - - switch (action) { - - case C_START: - if (parSepPD.control==NULL) { - ParamCreateControls( &parSepPG, NULL ); - } - sprintf( message, "parallel-separation-%s", curScaleName ); - parSeparation = ceil(13.0*12.0/curScaleRatio); - wPrefGetFloat( "misc", message, &parSeparation, parSeparation ); - ParamLoadControls( &parSepPG ); - ParamGroupRecord( &parSepPG ); - controls[0] = parSepPD.control; - controls[1] = NULL; - labels[0] = N_("Separation"); - InfoSubstituteControls( controls, labels ); - /*InfoMessage( "Select track" );*/ - return C_CONTINUE; - - case C_DOWN: - if ( parSeparation <= 0.0 ) { - ErrorMessage( MSG_PARALLEL_SEP_GTR_0 ); - return C_ERROR; - } - controls[0] = parSepPD.control; - controls[1] = NULL; - labels[0] = N_("Separation"); - InfoSubstituteControls( controls, labels ); - ParamLoadData( &parSepPG ); - Dpa.orig = pos; - Dpa.Trk = OnTrack( &Dpa.orig, TRUE, TRUE ); - if (!Dpa.Trk) { - return C_CONTINUE; - } - if ( !QueryTrack( Dpa.Trk, Q_CAN_PARALLEL ) ) { - Dpa.Trk = NULL; - InfoMessage(_(" Track doesn't support parallel")); - return C_CONTINUE; - } - /* in case query has changed things (eg joint) */ - /* - * this seems to cause problems so I commented it out - * until further investigation shows the necessity - */ - //Dpa.Trk = OnTrack( &Dpa.orig, TRUE, TRUE ); - tempSegs_da.cnt = 0; - - case C_MOVE: - - if (Dpa.Trk == NULL) return C_CONTINUE; - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - if ( !MakeParallelTrack( Dpa.Trk, pos, parSeparation, NULL, &p0, &p1 ) ) { - Dpa.Trk = NULL; - return C_CONTINUE; - } - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - return C_CONTINUE; - - case C_UP: - if (Dpa.Trk == NULL) return C_CONTINUE; - DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - p = p0; - if ((t0=OnTrack( &p, FALSE, TRUE )) != NULL) { - ep0 = PickEndPoint( p, t0 ); - if ( GetTrkEndTrk(t0,ep0) != NULL ) { - t0 = NULL; - } else { - p = GetTrkEndPos( t0, ep0 ); - d = FindDistance( p, p0 ); - if ( d > connectDistance ) + DIST_T d; + track_p t=NULL; + coOrd p; + static coOrd p0, p1; + ANGLE_T a; + track_p t0, t1; + EPINX_T ep0=-1, ep1=-1; + wControl_p controls[4]; + char * labels[3]; + static DIST_T parRFactor; + + parType = (long)commandContext; + + switch (action&0xFF) { + + case C_START: + if (parSepPLs[0].control==NULL) { + ParamCreateControls(&parSepPG, NULL); + } + if (parType == PAR_TRACK) { + sprintf(message, "parallel-separation-%s", curScaleName); + parSeparation = ceil(13.0*12.0/curScaleRatio); + } else { + sprintf(message, "parallel-line-separation-%s", curScaleName); + parSeparation = 5.0*12.0/curScaleRatio; + } + wPrefGetFloat("misc", message, &parSeparation, parSeparation); + ParamLoadControls(&parSepPG); + ParamGroupRecord(&parSepPG); + parSepPD.option |= PDO_NORECORD; + parFactorPD.option |= PDO_NORECORD; + controls[0] = parSepPD.control; + if (parType == PAR_TRACK) + controls[1] = parFactorPD.control; + else + controls[1] = NULL; + controls[2] = NULL; + labels[0] = N_("Separation"); + labels[1] = N_("Radius Factor"); + InfoSubstituteControls(controls, labels); + parSepPD.option &= ~PDO_NORECORD; + parFactorPD.option &= ~PDO_NORECORD; + Dpa.anchor_Trk = NULL; + tempSegs_da.cnt = 0; + return C_CONTINUE; + + case wActionMove: + tempSegs_da.cnt = 0; + Dpa.anchor_Trk = NULL; + if (parType == PAR_TRACK) + Dpa.anchor_Trk = OnTrack(&pos, FALSE, TRUE); + else + Dpa.anchor_Trk = OnTrack(&pos, FALSE, FALSE); + + if (!Dpa.anchor_Trk) { + return C_CONTINUE; + } + if (Dpa.anchor_Trk && !CheckTrackLayerSilent(Dpa.anchor_Trk)) { + Dpa.anchor_Trk = NULL; + return C_CONTINUE; + } + if (!QueryTrack(Dpa.anchor_Trk, Q_CAN_PARALLEL)) { + Dpa.anchor_Trk = NULL; + return C_CONTINUE; + } + break; + case C_DOWN: + Dpa.anchor_Trk = NULL; + tempSegs_da.cnt = 0; + if (parSeparation < 0.0) { + ErrorMessage(MSG_PARALLEL_SEP_GTR_0); + return C_ERROR; + } + + controls[0] = parSepPD.control; + controls[1] = parFactorPD.control; + controls[2] = NULL; + labels[0] = N_("Separation"); + labels[1] = N_("Radius factor"); + InfoSubstituteControls(controls, labels); + ParamLoadData(&parSepPG); + Dpa.orig = pos; + if (parType == PAR_TRACK) + Dpa.Trk = OnTrack(&pos, FALSE, TRUE); + else + Dpa.Trk = OnTrack(&pos, FALSE, FALSE); //Also lines for line + if (!Dpa.Trk) { + return C_CONTINUE; + } + if (!QueryTrack(Dpa.Trk, Q_CAN_PARALLEL)) { + Dpa.Trk = NULL; + InfoMessage(_(" Track/Line doesn't support parallel")); + wBeep(); + return C_CONTINUE; + } + + parRFactor = (2864.0*(double)parSepFactor)/curScaleRatio; + + if ((parType == PAR_TRACK) && (parSeparation == 0.0)) { + DIST_T orig_gauge = GetTrkGauge(Dpa.Trk); + DIST_T new_gauge = GetScaleTrackGauge(GetLayoutCurScale()); + if (orig_gauge == new_gauge) { + ErrorMessage(MSG_PARALLEL_SEP_GTR_0); + return C_ERROR; + } + parSeparation = fabs(orig_gauge/2-new_gauge/2); + parRFactor = 0.0; + } else if (parType != PAR_TRACK) + parRFactor = 0.0; + /* in case query has changed things (eg joint) */ + /* + * this seems to cause problems so I commented it out + * until further investigation shows the necessity + */ + //Dpa.Trk = OnTrack( &Dpa.orig, TRUE, TRUE ); + tempSegs_da.cnt = 0; + /* no break */ + + case C_MOVE: + if (Dpa.Trk == NULL) { + return C_CONTINUE; + } + tempSegs_da.cnt = 0; + if (!MakeParallelTrack(Dpa.Trk, pos, parSeparation, parRFactor, NULL, &p0, &p1, + parType == PAR_TRACK)) { + Dpa.Trk = NULL; + return C_CONTINUE; + } + return C_CONTINUE; + + case C_UP: + Dpa.anchor_Trk = NULL; + if (Dpa.Trk == NULL) { + return C_CONTINUE; + } + t0=t1=NULL; + if (parType == PAR_TRACK) { + p = p0; + tempSegs_da.cnt = 0; + if ((t0=OnTrack(&p, FALSE, TRUE)) != NULL) { + ep0 = PickEndPoint(p, t0); + if (GetTrkEndTrk(t0,ep0) != NULL) { t0 = NULL; + } else { + p = GetTrkEndPos(t0, ep0); + d = FindDistance(p, p0); + if (d > connectDistance) { + t0 = NULL; + } + } } - } - p = p1; - if ((t1=OnTrack( &p, FALSE, TRUE )) != NULL) { - ep1 = PickEndPoint( p, t1 ); - if ( GetTrkEndTrk(t1,ep1) != NULL ) { - t1 = NULL; - } else { - p = GetTrkEndPos( t1, ep1 ); - d = FindDistance( p, p1 ); - if ( d > connectDistance ) + p = p1; + if ((t1=OnTrack(&p, FALSE, TRUE)) != NULL) { + ep1 = PickEndPoint(p, t1); + if (GetTrkEndTrk(t1,ep1) != NULL) { t1 = NULL; + } else { + p = GetTrkEndPos(t1, ep1); + d = FindDistance(p, p1); + if (d > connectDistance) { + t1 = NULL; + } + } } - } - UndoStart( _("Create Parallel Track"), "newParallel" ); - if ( !MakeParallelTrack( Dpa.Trk, pos, parSeparation, &t, NULL, NULL ) ) { - return C_TERMINATE; - } - CopyAttributes( Dpa.Trk, t ); - if ( t0 ) { - a = NormalizeAngle( GetTrkEndAngle( t0, ep0 ) - GetTrkEndAngle( t, 0 ) + (180.0+connectAngle/2.0) ); - if (a < connectAngle) { - DrawEndPt( &mainD, t0, ep0, wDrawColorWhite ); - ConnectTracks( t0, ep0, t, 0 ); - DrawEndPt( &mainD, t0, ep0, wDrawColorBlack ); + } + UndoStart(_("Create Parallel Track"), "newParallel"); + if (!MakeParallelTrack(Dpa.Trk, pos, parSeparation, parRFactor, &t, NULL, NULL, + parType == PAR_TRACK)) { + tempSegs_da.cnt = 0; + return C_TERMINATE; + } + if (parType == PAR_TRACK) { + if (GetTrkGauge(Dpa.Trk)> parSeparation) { + SetTrkNoTies(t, TRUE); + } + //CopyAttributes( Dpa.Trk, t ); Don't force scale or track width or Layer + SetTrkBits(t,(GetTrkBits(t)&TB_HIDEDESC) | (GetTrkBits(Dpa.Trk)&~TB_HIDEDESC)); + + if (t0) { + a = NormalizeAngle(GetTrkEndAngle(t0, ep0) - GetTrkEndAngle(t, + 0) + (180.0+connectAngle/2.0)); + if (a < connectAngle) { + DrawEndPt(&mainD, t0, ep0, wDrawColorWhite); + ConnectTracks(t0, ep0, t, 0); + DrawEndPt(&mainD, t0, ep0, wDrawColorBlack); + } } - } - if ( t1 ) { - a = NormalizeAngle( GetTrkEndAngle( t1, ep1 ) - GetTrkEndAngle( t, 1 ) + (180.0+connectAngle/2.0) ); - if (a < connectAngle) { - DrawEndPt( &mainD, t1, ep1, wDrawColorWhite ); - ConnectTracks( t1, ep1, t, 1 ); - DrawEndPt( &mainD, t1, ep1, wDrawColorBlack ); + if (t1) { + a = NormalizeAngle(GetTrkEndAngle(t1, ep1) - GetTrkEndAngle(t, + 1) + (180.0+connectAngle/2.0)); + if (a < connectAngle) { + DrawEndPt(&mainD, t1, ep1, wDrawColorWhite); + ConnectTracks(t1, ep1, t, 1); + DrawEndPt(&mainD, t1, ep1, wDrawColorBlack); + } } - } - DrawNewTrack( t ); - UndoEnd(); - InfoSubstituteControls( NULL, NULL ); - sprintf( message, "parallel-separation-%s", curScaleName ); - wPrefSetFloat( "misc", message, parSeparation ); - return C_TERMINATE; - - case C_REDRAW: - return C_CONTINUE; - - case C_CANCEL: - InfoSubstituteControls( NULL, NULL ); - return C_TERMINATE; - - } - return C_CONTINUE; + } + DrawNewTrack(t); + UndoEnd(); + InfoSubstituteControls(NULL, NULL); + if (parType == PAR_TRACK) + sprintf(message, "parallel-separation-%s", curScaleName); + else + sprintf(message, "parallel-line-separation-%s", curScaleName); + wPrefSetFloat("misc", message, parSeparation); + tempSegs_da.cnt = 0; + return C_TERMINATE; + + case C_REDRAW: + if (Dpa.anchor_Trk) { + DrawTrack(Dpa.anchor_Trk,&tempD, + wDrawColorPreviewSelected); //Special color means THICK3 as well + } + if (tempSegs_da.cnt>0) { + DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, + wDrawColorBlack ); + } + return C_CONTINUE; + + case C_CANCEL: + Dpa.anchor_Trk = NULL; + tempSegs_da.cnt = 0; + InfoSubstituteControls(NULL, NULL); + return C_TERMINATE; + + } + return C_CONTINUE; } #include "bitmaps/parallel.xpm" +#include "bitmaps/parallel-line.xpm" EXPORT void InitCmdParallel( wMenu_p menu ) { - AddMenuButton( menu, CmdParallel, "cmdParallel", _("Parallel"), wIconCreatePixMap(parallel_xpm), LEVEL0_50, IC_STICKY|IC_POPUP, ACCL_PARALLEL, NULL ); + ButtonGroupBegin( _("Parallel"), "cmdParallelSetCmd", _("Parallel") ); + AddMenuButton( menu, CmdParallel, "cmdParallelTrack", _("Parallel Track"), wIconCreatePixMap(parallel_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_PARALLEL, (void*)0 ); + AddMenuButton( menu, CmdParallel, "cmdParallelLine", _("Parallel Line"), wIconCreatePixMap(parallel_line_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_PARALLEL, (void*)1 ); + ButtonGroupEnd(); ParamRegister( &parSepPG ); } diff --git a/app/bin/cprint.c b/app/bin/cprint.c index 88a9151..066e649 100644 --- a/app/bin/cprint.c +++ b/app/bin/cprint.c @@ -25,8 +25,10 @@ #include #include #include +#include #include "custom.h" +#include "dynstring.h" #include "fileio.h" #include "i18n.h" #include "layout.h" @@ -69,6 +71,7 @@ struct { static long printGaudy = 1; static long printRegistrationMarks = 1; +static long printPageNumbers = 1; static long printPhysSize = FALSE; static long printFormat = PORTRAIT; static long printOrder = 0; @@ -85,7 +88,8 @@ static long iPrintScale = 16; static coOrd maxPageSize; static coOrd realPageSize; -static wWin_p printWin; +static wWin_p printWin = NULL; +static wWin_p printMarginWin = NULL; static wMenu_p printGridPopupM; @@ -98,16 +102,21 @@ static void DoResetGrid( void ); static void DoPrintSetup( void ); static void PrintClear( void ); static void PrintMaxPageSize( void ); +static void SelectAllPages(void); +static void DoPrintMargin(void); +static bool PrintPageNumber( wPos_t x, wPos_t y, DIST_T width, DIST_T height ); +static bool PrintNextPageNumbers(int x, int y, DIST_T pageW, DIST_T pageH); static char * printFormatLabels[] = { N_("Portrait"), N_("Landscape"), NULL }; static char * printOrderLabels[] = { N_("Normal"), N_("Reverse"), NULL }; static char * printGaudyLabels[] = { N_("Engineering Data"), NULL }; -static char * printRegistrationMarksLabels[] = { N_("Print Registration Marks"), NULL }; +static char * printRegistrationMarksLabels[] = { N_("Registration Marks (in 1:1 scale only)"), NULL }; +static char * printPageNumberLabels[] = { N_("Page Numbers"), NULL }; static char * printPhysSizeLabels[] = { N_("Ignore Page Margins"), NULL }; -static char * printGridLabels[] = { N_("Print Snap Grid"), NULL }; -static char * printRulerLabels[] = { N_("Print Rulers"), NULL }; -static char * printRoadbedLabels[] = { N_("Print Roadbed Outline"), NULL }; -static char * printCenterLineLabels[] = { N_("Print Centerline below Scale 1:1"), NULL }; +static char * printGridLabels[] = { N_("Snap Grid"), NULL }; +static char * printRulerLabels[] = { N_("Rulers"), NULL }; +static char * printRoadbedLabels[] = { N_("Roadbed Outline"), NULL }; +static char * printCenterLineLabels[] = { N_("Centerline below Scale 1:1"), NULL }; static paramIntegerRange_t rminScale_999 = { 1, 999, 0, PDO_NORANGECHECK_HIGH }; static paramFloatRange_t r0_ = { 0, 0, 0, PDO_NORANGECHECK_HIGH }; static paramFloatRange_t r1_ = { 1, 0, 0, PDO_NORANGECHECK_HIGH }; @@ -122,34 +131,41 @@ static paramData_t printPLs[] = { /*4*/ { PD_BUTTON, (void*)PrintSnapShot, "snapshot", PDO_DLGHORZ, NULL, N_("Snap Shot") }, /*5*/ { PD_RADIO, &printFormat, "format", 0, printFormatLabels, N_("Page Format"), BC_HORZ|BC_NOBORDER, (void*)1 }, /*6*/ { PD_RADIO, &printOrder, "order", PDO_DLGBOXEND, printOrderLabels, N_("Print Order"), BC_HORZ|BC_NOBORDER }, - -/*7*/ { PD_TOGGLE, &printGaudy, "style", PDO_DLGNOLABELALIGN, printGaudyLabels, NULL, BC_HORZ|BC_NOBORDER, (void*)1 }, -/*8*/ { PD_TOGGLE, &printPhysSize, "physsize", PDO_DLGNOLABELALIGN, printPhysSizeLabels, NULL, BC_HORZ|BC_NOBORDER, (void*)1 }, +/*7*/ { PD_MESSAGE, N_("Print "), NULL, PDO_DLGRESETMARGIN| PDO_DLGNOLABELALIGN, (void*)0 }, +/*8*/ { PD_TOGGLE, &printGaudy, "style", PDO_DLGNOLABELALIGN, printGaudyLabels, NULL, BC_HORZ|BC_NOBORDER, (void*)1 }, #define I_REGMARKS (9) /*9*/ { PD_TOGGLE, &printRegistrationMarks, "registrationMarks", PDO_DLGNOLABELALIGN, printRegistrationMarksLabels, NULL, BC_HORZ|BC_NOBORDER }, -#define I_GRID (10) -/*10*/ { PD_TOGGLE, &printGrid, "grid", PDO_DLGNOLABELALIGN, printGridLabels, NULL, BC_HORZ|BC_NOBORDER }, -#define I_RULER (11) -/*11*/ { PD_TOGGLE, &printRuler, "ruler", PDO_DLGNOLABELALIGN, printRulerLabels, NULL, BC_HORZ|BC_NOBORDER }, -#define I_CENTERLINE (12) -/*12*/ { PD_TOGGLE, &printCenterLine, "centerLine", PDO_DLGNOLABELALIGN, printCenterLineLabels, NULL, BC_HORZ|BC_NOBORDER }, -#define I_ROADBED (13) -/*13*/{ PD_TOGGLE, &printRoadbed, "roadbed", PDO_DLGNOLABELALIGN, printRoadbedLabels, NULL, BC_HORZ|BC_NOBORDER }, -#define I_ROADBEDWIDTH (14) -/*14*/{ PD_FLOAT, &printRoadbedWidth, "roadbedWidth", PDO_DIM|PDO_DLGBOXEND, &r0_, N_("Width") }, -/*15*/{ PD_FLOAT, &newPrintGrid.orig.x, "origx", PDO_DIM|PDO_DLGRESETMARGIN, &r_10_99999, N_("Origin: X"), 0, (void*)2 }, -/*16*/ { PD_FLOAT, &newPrintGrid.orig.y, "origy", PDO_DIM, &r_10_99999, N_("Y"), 0, (void*)2 }, -/*17*/ { PD_BUTTON, (void*)DoResetGrid, "reset", PDO_DLGHORZ, NULL, N_("Reset") }, -/*18*/ { PD_FLOAT, &newPrintGrid.angle, "origa", PDO_ANGLE|PDO_DLGBOXEND, &r0_360, N_("Angle"), 0, (void*)2 }, -/*19*/ { PD_BUTTON, (void*)DoPrintSetup, "setup", PDO_DLGCMDBUTTON, NULL, N_("Setup") }, -/*20*/ { PD_BUTTON, (void*)PrintClear, "clear", 0, NULL, N_("Clear") }, -#define I_PAGECNT (21) -/*21*/ { PD_MESSAGE, N_("0 pages"), NULL, 0, (void*)80 }, -/*22*/ { PD_MESSAGE, N_("selected"), NULL, 0, (void*)80 } +#define I_PAGENUMBERS (10) +/*10*/ { PD_TOGGLE, &printPageNumbers, "pageNumbers", PDO_DLGNOLABELALIGN, printPageNumberLabels, NULL, BC_HORZ | BC_NOBORDER }, +#define I_GRID (11) +/*11*/ { PD_TOGGLE, &printGrid, "grid", PDO_DLGNOLABELALIGN, printGridLabels, NULL, BC_HORZ|BC_NOBORDER }, +#define I_RULER (12) +/*12*/ { PD_TOGGLE, &printRuler, "ruler", PDO_DLGNOLABELALIGN, printRulerLabels, NULL, BC_HORZ|BC_NOBORDER }, +#define I_CENTERLINE (13) +/*13*/ { PD_TOGGLE, &printCenterLine, "centerLine", PDO_DLGNOLABELALIGN, printCenterLineLabels, NULL, BC_HORZ|BC_NOBORDER }, +#define I_ROADBED (14) +/*14*/{ PD_TOGGLE, &printRoadbed, "roadbed", PDO_DLGNOLABELALIGN, printRoadbedLabels, NULL, BC_HORZ|BC_NOBORDER }, +#define I_ROADBEDWIDTH (15) +/*15*/{ PD_FLOAT, &printRoadbedWidth, "roadbedWidth", PDO_DIM , &r0_, N_(" Width") }, +/*16*/ { PD_TOGGLE, &printPhysSize, "physsize", PDO_DLGNOLABELALIGN, printPhysSizeLabels, NULL, BC_HORZ | BC_NOBORDER, (void*)1 }, +/*17*/ { PD_BUTTON, (void*)DoPrintMargin, "margin", PDO_DLGHORZ|PDO_DLGBOXEND, NULL, N_("Margins") }, +/*18*/{ PD_FLOAT, &newPrintGrid.orig.x, "origx", PDO_DIM|PDO_DLGRESETMARGIN, &r_10_99999, N_("Origin: X"), 0, (void*)2 }, +/*19*/ { PD_FLOAT, &newPrintGrid.orig.y, "origy", PDO_DIM, &r_10_99999, N_("Y"), 0, (void*)2 }, +/*20*/ { PD_BUTTON, (void*)DoResetGrid, "reset", PDO_DLGHORZ, NULL, N_("Reset") }, +/*21*/ { PD_FLOAT, &newPrintGrid.angle, "origa", PDO_ANGLE|PDO_DLGBOXEND, &r0_360, N_("Angle"), 0, (void*)2 }, +/*22*/ { PD_BUTTON, (void*)DoPrintSetup, "setup", PDO_DLGCMDBUTTON, NULL, N_("Setup") }, +/*23*/ { PD_BUTTON, (void*)SelectAllPages, "selall", 0, NULL, N_("Select All") }, +/*24*/ { PD_BUTTON, (void*)PrintClear, "clear", 0, NULL, N_("Clear") }, +#define I_PAGECNT (25) +/*25*/ { PD_MESSAGE, N_("0 pages"), NULL, 0, (void*)80 }, +/*26*/ { PD_MESSAGE, N_("selected"), NULL, 0, (void*)80 } }; static paramGroup_t printPG = { "print", PGO_PREFMISCGROUP, printPLs, sizeof printPLs/sizeof printPLs[0] }; +static struct { + double top, right, bottom, left; +} printMargin = { 0.0, 0.0, 0.0, 0.0 }; /***************************************************************************** * @@ -157,6 +173,23 @@ static paramGroup_t printPG = { "print", PGO_PREFMISCGROUP, printPLs, sizeof pri * */ +/** + * Update the dialog with the current number of selected pages. + * + */ + +static void +UpdatePageCount() +{ + DynString msg; + DynStringMalloc(&msg, 0); + + DynStringPrintf(&msg, (pageCount == 1?_("%d page"):_("%d pages")), pageCount); + ParamLoadMessage(&printPG, I_PAGECNT, DynStringToCStr(&msg)); + ParamDialogOkActive(&printPG, pageCount != 0); + + DynStringFree(&msg); +} static void ChangeDim( void ) { @@ -208,9 +241,7 @@ static void ChangeDim( void ) bm.orig = currPrintGrid.orig; bm.size = currPrintGrid.size; bm.angle = currPrintGrid.angle; - sprintf( message, _("%d pages"), pageCount ); - ParamLoadMessage( &printPG, I_PAGECNT, message ); - ParamDialogOkActive( &printPG, pageCount!=0 ); + UpdatePageCount(); } @@ -237,7 +268,7 @@ LOG1( log_print, ( "MarkPage( %d, %d )\n", x, y) ) Rotate( &p[2], currPrintGrid.orig, currPrintGrid.angle ); Rotate( &p[3], currPrintGrid.orig, currPrintGrid.angle ); LOG( log_print, 2, ( "MP(%d,%d) [%0.3f %0.3f] x [%0.3f %0.3f]\n", x, y, p[0].x, p[0].y, p[2].x, p[2].y ) ) - DrawHilightPolygon( &mainD, p, 4 ); + DrawHilightPolygon( &tempD, p, 4 ); } @@ -256,10 +287,7 @@ static void SelectPage( coOrd pos ) selected = BITMAP( bm, x, y ); pageCount += (selected?-1:1); BITMAP( bm, x, y ) = !selected; - MarkPage( x, y ); - sprintf( message, _("%d pages"), pageCount ); - ParamLoadMessage( &printPG, I_PAGECNT, message ); - ParamDialogOkActive( &printPG, pageCount!=0 ); + UpdatePageCount(); } @@ -351,11 +379,11 @@ static void PrintGaudyBox( DrawLine( &page_d, p00, p10, 0, wDrawColorBlack ); p00.y = p10.y = 0.5; DrawLine( &page_d, p00, p10, 0, wDrawColorBlack ); - p00.y = 0.5; - p01.y = 1.0; + //p00.y = 0.5; + //p01.y = 1.0; p00.x = 0.05; p00.y = 0.5+0.05; fp = wStandardFont( F_TIMES, TRUE, TRUE ); - DrawString( &page_d, p00, 0.0, sProdName, fp, 30.0, wDrawColorBlack ); + DrawString( &page_d, p00, 0.0, sProdName, fp, 22.0, wDrawColorBlack ); p00.y = 0.5; p01.y = 1.0; p00.x = p01.x = (157.0/72.0)+0.1; @@ -365,17 +393,17 @@ static void PrintGaudyBox( fp = wStandardFont( F_TIMES, FALSE, FALSE ); p00.x = pageW-((157.0/72.0)+0.05); p00.y = 0.5+0.25+0.05; - DrawString( &page_d, p00, 0.0, dat, fp, 16.0, wDrawColorBlack ); + DrawString( &page_d, p00, 0.0, dat, fp, 14.0, wDrawColorBlack ); p00.y = 0.5+0.05; - DrawTextSize( &mainD, GetLayoutTitle(), fp, 16.0, FALSE, &textsize ); + DrawTextSize( &mainD, GetLayoutTitle(), fp, 14.0, FALSE, &textsize ); p00.x = (pageW/2.0)-(textsize.x/2.0); p00.y = 0.75+0.05; - DrawString( &page_d, p00, 0.0, GetLayoutTitle(), fp, 16.0, wDrawColorBlack ); - DrawTextSize( &mainD, GetLayoutSubtitle(), fp, 16.0, FALSE, &textsize ); + DrawString( &page_d, p00, 0.0, GetLayoutTitle(), fp, 14.0, wDrawColorBlack ); + DrawTextSize( &mainD, GetLayoutSubtitle(), fp, 14.0, FALSE, &textsize ); p00.x = (pageW/2.0)-(textsize.x/2.0); p00.y = 0.50+0.05; - DrawString( &page_d, p00, 0.0, GetLayoutSubtitle(), fp, 16.0, wDrawColorBlack ); + DrawString( &page_d, p00, 0.0, GetLayoutSubtitle(), fp, 12.0, wDrawColorBlack ); sprintf( dat, _("PrintScale 1:%ld Room %s x %s Model Scale %s File %s"), (long)printScale, @@ -383,7 +411,7 @@ static void PrintGaudyBox( FormatDistance( roomSize.y ), curScaleName, GetLayoutFilename() ); p00.x = 0.05; p00.y = 0.25+0.05; - DrawString( &page_d, p00, 0.0, dat, fp, 16.0, wDrawColorBlack ); + DrawString( &page_d, p00, 0.0, dat, fp, 14.0, wDrawColorBlack ); } @@ -414,12 +442,7 @@ static void PrintPlainBox( DrawLine( &page_d, p11, p01, 0, wDrawColorBlack ); DrawLine( &page_d, p01, p00, 0, wDrawColorBlack ); - fp = wStandardFont( F_HELV, FALSE, FALSE ); - sprintf( tmp, "[%d,%d]", x, y ); - p00.x = pageW/2.0 - 20.0/72.0; - p00.y = pageH - 10.0/72.0; - DrawString( &page_d, p00, 0.0, tmp, fp, 4.0, wDrawColorBlack ); - + fp = wStandardFont(F_HELV, FALSE, FALSE); sprintf( tmp, "[%0.2f,%0.2f]", corners[0].x, corners[0].y ); p00.x = 4.0/72.0; p00.y = 4.0/72.0; @@ -482,7 +505,6 @@ static void PrintUpdate( int inx0 ) { int inx; - DrawPrintGrid(); ParamLoadData( &printPG ); if (newPrintGrid.size.x > maxPageSize.x+0.01 || @@ -504,17 +526,17 @@ static void PrintUpdate( int inx0 ) ParamLoadControl( &printPG, inx ); } ChangeDim(); - DrawPrintGrid(); } static void SetPageSize( BOOL_T doScale ) { WDOUBLE_T temp, x, y; - if (printPhysSize) - wPrintGetPhysSize( &x, &y ); - else - wPrintGetPageSize( &x, &y ); + wPrintGetPageSize( &x, &y ); + if (!printPhysSize) { + x -= (printMargin.left+printMargin.right); + y -= (printMargin.top+printMargin.bottom); + } maxPageSize.x = x; maxPageSize.y = y; realPageSize = maxPageSize; @@ -534,6 +556,22 @@ static void SetPageSize( BOOL_T doScale ) } } +/** + * Select all pages for printing. + * + */ + +static void SelectAllPages(void) +{ + for (int y = bm.y0; y < bm.y1; y++) { + for (int x = bm.x0; x < bm.x1; x++) { + BITMAP(bm, x, y) = TRUE; + } + } + pageCount = (bm.x1 - bm.x0) * (bm.y1 - bm.y0); + UpdatePageCount(); + TempRedraw(); // SelectAllPages +} static void PrintMaxPageSize( void ) /* @@ -542,13 +580,12 @@ static void PrintMaxPageSize( void ) * (depending on paper size, scale and orientation) */ { - DrawPrintGrid(); SetPageSize( TRUE ); currPrintGrid.size = maxPageSize; newPrintGrid = currPrintGrid; ParamLoadControls( &printPG ); ChangeDim(); - DrawPrintGrid(); + TempRedraw(); // PrintMaxSize wShow( printWin); } @@ -563,10 +600,152 @@ static void DoPrintScale( void ) PrintEnableControls(); } +/* + * Printer Margins + */ + +static void PrintMarginReset(); + +static paramFloatRange_t r0_1 = { 0.0, 1.0, 50 }; +static paramData_t printMarginPLs[] = { +#define I_PM_FIRST (0) + { PD_FLOAT, &printMargin.top, "marginT", PDO_DIM|PDO_NOPREF, &r0_1, NULL, 0, NULL }, + { PD_FLOAT, &printMargin.right, "marginR", PDO_DIM|PDO_NOPREF, &r0_1, NULL, 0, NULL }, + { PD_FLOAT, &printMargin.bottom, "marginB", PDO_DIM|PDO_NOPREF, &r0_1, NULL, 0, NULL }, + { PD_FLOAT, &printMargin.left, "marginL", PDO_DIM|PDO_NOPREF, &r0_1, NULL, 0, NULL }, +#define I_PM_COUNT (4) +#define I_PM_MESSAGE (4) + { PD_MESSAGE, NULL, NULL, 0, NULL }, +#define I_PM_RESET (5) + { PD_BUTTON, (void*) PrintMarginReset, "marginReset", PDO_DLGCMDBUTTON, NULL, N_("Reset") } }; +static paramGroup_t printMarginPG = { "printMargin", PGO_PREFMISCGROUP|PGO_NODEFAULTPROC, printMarginPLs, sizeof printMarginPLs/sizeof printMarginPLs[0] }; + +static wLines_t aPmLines[] = { + { 1, 25, 11, 94, 11 }, + { 1, 94, 11, 94, 111 }, + { 1, 94, 111, 25, 111 }, + { 1, 25, 111, 25, 11 }}; +static int pmxoff=14; +static int pmyoff=5; + +static void PrintMarginLayout( + paramData_t * pd, + int index, + wPos_t colX, + wPos_t * w, + wPos_t * h ) +{ + if ( index < I_PM_FIRST || index > (I_PM_MESSAGE) ) + return; + if ( index == I_PM_MESSAGE ) { + *h = wControlGetPosY( printMarginPLs[I_PM_FIRST+2].control ) + wControlGetHeight( printMarginPLs[I_PM_FIRST+2].control ); + return; + } + wPos_t x0, y0; + x0 = (aPmLines[index-I_PM_FIRST].x0+aPmLines[index-I_PM_FIRST].x1)/2; + y0 = (aPmLines[index-I_PM_FIRST].y0+aPmLines[index-I_PM_FIRST].y1)/2; + x0 -= pmxoff; + y0 -= pmyoff; +// y0 += wControlGetPosY( printMarginPLs[0].control ) + wControlGetHeight( printMarginPLs[0].control ); +// x0 -= wControlGetWidth( printMarginPLs[index-I_PM_FIRST].control )/2; +// y0 -= wControlGetHeight( printMarginPLs[index-I_PM_FIRST].control )/2; + *w = x0; + *h = y0; +} + + +static const char * sPrinterName = NULL; + +static BOOL_T SetMargins() +{ + double top, right, bottom, left; + wPrintGetMargins( &top, &right, &bottom, &left ); + sprintf( message, "%s-marginT", sPrinterName ); + wPrefGetFloat( "printer", message, &printMargin.top, top ); + sprintf( message, "%s-marginR", sPrinterName ); + wPrefGetFloat( "printer", message, &printMargin.right, right ); + sprintf( message, "%s-marginB", sPrinterName ); + wPrefGetFloat( "printer", message, &printMargin.bottom, bottom ); + sprintf( message, "%s-marginL", sPrinterName ); + wPrefGetFloat( "printer", message, &printMargin.left, left ); + ParamLoadControls( &printMarginPG ); + return + fabs( top - printMargin.top ) >= 0.001 || + fabs( right - printMargin.right ) >= 0.001 || + fabs( bottom - printMargin.bottom ) >= 0.001 || + fabs( left - printMargin.left ) >= 0.001; +} + + +static void DoPrintMarginOk( void * context ) +{ + wHide( printMarginWin ); + sprintf( message, "%s-marginT", sPrinterName ); + wPrefSetFloat( "printer", message, printMargin.top ); + sprintf( message, "%s-marginR", sPrinterName ); + wPrefSetFloat( "printer", message, printMargin.right ); + sprintf( message, "%s-marginB", sPrinterName ); + wPrefSetFloat( "printer", message, printMargin.bottom ); + sprintf( message, "%s-marginL", sPrinterName ); + wPrefSetFloat( "printer", message, printMargin.left ); + SetPageSize( TRUE ); + for ( int inx = 0; inx < sizeof printPLs/sizeof printPLs[0]; inx++ ) { + if ( printPLs[inx].context == (void*)2 ) + ParamLoadControl( &printPG, inx ); + } + DoPrintScale(); +} + +static void PrintMarginDlgUpdate( paramGroup_p pg, int index, void * context ) +{ + wControlActive( printMarginPLs[I_PM_RESET].control, TRUE ); +} + +static void PrintMarginReset() +{ + wPrintGetMargins( &printMargin.top, &printMargin.right, &printMargin.bottom, &printMargin.left ); + ParamLoadControls( &printMarginPG ); + wControlActive( printMarginPLs[I_PM_RESET].control, FALSE ); +} + +static void DoPrintMargin( void ) +{ + sPrinterName = wPrintGetName(); + while ( *sPrinterName == '\0' ) { + int rc = NoticeMessage( MSG_NO_PRINTER_SELECTED, _("Ok"), _("Cancel") ); + if ( rc <= 0 ) + return; + DoPrintSetup(); + } + if ( printMarginWin == NULL ) { + wPos_t x=10, y=10; + printMarginWin = ParamCreateDialog( &printMarginPG, MakeWindowTitle(_("Print Margins")), _("Ok"), DoPrintMarginOk, NULL, TRUE, PrintMarginLayout, F_BLOCK, PrintMarginDlgUpdate ); + if ( printMarginWin == NULL ) + return; + for ( int i=0; i pageSize.y) { @@ -665,11 +842,10 @@ static void PrintSnapShot( void ) ChangeDim(); pageCount = 1; BITMAP(bm,0,0) = TRUE; - DrawPrintGrid(); - ParamLoadMessage( &printPG, I_PAGECNT, _("1 page") ); - ParamDialogOkActive( &printPG, TRUE ); + UpdatePageCount(); PrintEnableControls(); wShow( printWin ); + TempRedraw(); // PrintSnapShot } @@ -729,20 +905,167 @@ static void DrawRegistrationMarks( drawCmd_p d ) } } +/** + * Format the page coordinates. Also handle cases where the coordinates are + * out of range. + * + * \param x x position + * \param y y position + * \return TRUE + */ + +static char * +FormatPageNumber(int x, int y) +{ + DynString formatted; + char *result; + + DynStringMalloc(&formatted, 16); + if (x > 0 && x <= bm.x1 && y > 0 && y <= bm.y1) { + DynStringPrintf(&formatted, "(%d/%d)", x, y); + } else { + DynStringCatCStr(&formatted, "(-/-)"); + } + + result = strdup(DynStringToCStr(&formatted)); + DynStringFree(&formatted); + + return (result); +} + +/** + * Print the page number in the center of the page + * + * \param x page index x-direction + * \param y page index y-direction + * \param width page width + * \param height page height + * \return TRUE + */ + +static bool +PrintPageNumber(wPos_t x, wPos_t y, DIST_T width, DIST_T height) +{ + coOrd printPosition; + coOrd textSize; + + char *positionText; + wFont_p fp = wStandardFont(F_HELV, TRUE, FALSE); + wFontSize_t fs = 64.0; + + positionText = FormatPageNumber(x + 1, y + 1); + + // even though we're printing into page_d, mainD must be used here + DrawTextSize(&mainD, positionText, fp, fs, TRUE, &textSize); + + if (printFormat == PORTRAIT) { + printPosition.x = (width - textSize.x) / 2; + printPosition.y = (height - textSize.y) / 2; + } else { + printPosition.x = (height - textSize.x) / 2; + printPosition.y = (width - textSize.y) / 2; + } + + page_d.funcs->options |= wDrawOutlineFont; + DrawString(&page_d, printPosition, 0.0, positionText, fp, fs, + wDrawColorGray(70)); + page_d.funcs->options &= ~wDrawOutlineFont; + + free(positionText); + + return (TRUE); +} + +/** + * Print the page number of an adjoining page at a specified position + * + * \param x page index x-direction + * \param y page index y-direction + * \param position page position + */ + +void +PrintNextPageNumberAt(int x, int y, coOrd position) +{ + char *pageNumber; + wFont_p fp = wStandardFont(F_HELV, FALSE, FALSE); + wFontSize_t fs = 8.0; + + pageNumber = FormatPageNumber(x, y); + DrawString(&page_d, position, 0.0, pageNumber, fp, fs, wDrawColorBlack); + free(pageNumber); +} + +/** + * Print the page numbers of all four adjoining pages (left, right, above, below) + * + * \param x page index of current page x + * \param y page index of current page y + * \param pageW width of page + * \param pageH height of page + * + * \return TRUE + */ + +static bool +PrintNextPageNumbers(int x, int y, DIST_T pageW, DIST_T pageH) +{ + coOrd p00; + + // above + if (printFormat == PORTRAIT) { + p00.x = pageW / 2.0 - 20.0 / 72.0; + p00.y = pageH - 10.0 / 72.0; + } else { + p00.x = pageH / 2.0 - 20.0 / 72.0; + p00.y = pageW - 10.0 / 72.0; + } + PrintNextPageNumberAt(x + 1, y + 2, p00); + + // below + if (printFormat == PORTRAIT) { + p00.y = 10.0 / 72.0; + } else { + p00.y = 10.0 / 72.0; + } + PrintNextPageNumberAt(x + 1, y, p00); + + // right + if (printFormat == PORTRAIT) { + p00.y = pageH / 2 + 10.0 / 72.0; + p00.x = pageW - 20.0 / 72.0; + } else { + p00.y = pageW / 2 + 10.0 / 72.0; + p00.x = pageH - 20.0 / 72.0; + } + PrintNextPageNumberAt(x + 2, y + 1, p00); + + // left + if (printFormat == PORTRAIT) { + p00.x = 10.0 / 72.0; + } else { + p00.x = 10.0 / 72.0; + } + PrintNextPageNumberAt(x, y + 1, p00); + return (TRUE); +} static BOOL_T PrintPage( int x, int y ) { - coOrd orig, p[4], minP, maxP; + coOrd orig, p[4], psave[4], minP, maxP; int i; coOrd clipOrig, clipSize; - wFont_p fp; coOrd roomSize; if (BITMAP(bm,x,y)) { orig.x = currPrintGrid.orig.x + x*currPrintGrid.size.x; orig.y = currPrintGrid.orig.y + y*currPrintGrid.size.y; + if (printPhysSize) { + orig.x += printMargin.left; + orig.y += printMargin.bottom; + } Rotate( &orig, currPrintGrid.orig, currPrintGrid.angle ); p[0] = p[1] = p[2] = p[3] = orig; p[1].x = p[2].x = orig.x + currPrintGrid.size.x; @@ -774,6 +1097,9 @@ static BOOL_T PrintPage( Translate( &print_d.orig, orig, currPrintGrid.angle+180.0, printScale ); print_d.size.y += printScale; } + for (int i=0;i<4;i++) { + psave[i] = p[i]; + } if (printRotate) { rotateCW = (printFormat != PORTRAIT); if (rotateCW) { @@ -798,7 +1124,7 @@ static BOOL_T PrintPage( page_d.size.x = print_d.size.x/printScale; page_d.size.y = print_d.size.y/printScale; } - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); print_d.scale = printScale; if (print_d.d == NULL) AbortProg( "wPrintPageStart" ); @@ -814,8 +1140,7 @@ static BOOL_T PrintPage( if (printRotate && rotateCW) { print_d.size.x += printScale; } - } else if (printRegistrationMarks) - PrintPlainBox( x, y, p ); + } if (printRotate) { wPrintClip( (wPos_t)(clipOrig.y*print_d.dpi), (wPos_t)(clipOrig.x*print_d.dpi), (wPos_t)(clipSize.y*print_d.dpi), (wPos_t)(clipSize.x*print_d.dpi) ); @@ -827,7 +1152,7 @@ static BOOL_T PrintPage( p[1].x = p[2].x = roomSize.x; p[0].y = p[1].y = 0.0; p[2].y = p[3].y = roomSize.y; - fp = wStandardFont( F_TIMES, FALSE, FALSE ); + DrawRuler( &print_d, p[0], p[1], 0.0, TRUE, FALSE, wDrawColorBlack ); DrawRuler( &print_d, p[0], p[3], 0.0, TRUE, TRUE, wDrawColorBlack ); DrawRuler( &print_d, p[1], p[2], 0.0, FALSE, FALSE, wDrawColorBlack ); @@ -885,6 +1210,7 @@ static BOOL_T PrintPage( DrawRuler( &print_d, p[0], p[1], minP.x, FALSE, TRUE, wDrawColorBlack ); } } + if (printGrid) DrawSnapGrid( &print_d, mapD.size, FALSE ); roadbedWidth = printRoadbed?printRoadbedWidth:0.0; @@ -892,10 +1218,15 @@ static BOOL_T PrintPage( DrawTracks( &print_d, print_d.scale, minP, maxP ); if (printRegistrationMarks && printScale == 1) DrawRegistrationMarks( &print_d ); + if (printRegistrationMarks) + PrintPlainBox( x, y, psave ); + + if (printPageNumbers) { + PrintPageNumber(x, y, page_d.size.x, page_d.size.y); + PrintNextPageNumbers(x, y, page_d.size.x, page_d.size.y); + } if ( !wPrintPageEnd( print_d.d ) ) return FALSE; - /*BITMAP(bm,x,y) = 0;*/ - MarkPage( x, y ); } return TRUE; } @@ -920,9 +1251,9 @@ static void DoPrintPrint( void * junk ) wPrefGetInteger( "print", "nodecoration", &noDecoration, 0 ); print_d.CoOrd2Pix = page_d.CoOrd2Pix = mainD.CoOrd2Pix; - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); if (!wPrintDocStart(GetLayoutTitle(), pageCount, &copies )) { - wSetCursor( wCursorNormal ); + wSetCursor( mainD.d, defaultCursor ); return; } if (copies <= 0) @@ -940,42 +1271,38 @@ static void DoPrintPrint( void * junk ) for (y=bm.y0; y= copies) BITMAP(bm,x,y) = 0; } } quitPrinting: wPrintDocEnd(); - wSetCursor( wCursorNormal ); + wSetCursor( mainD.d, defaultCursor ); Reset(); /* undraws grid, resets pagecount, etc */ } static void DoResetGrid( void ) { - DrawPrintGrid(); currPrintGrid.orig = zero; currPrintGrid.angle = 0.0; ChangeDim(); newPrintGrid = currPrintGrid; ParamLoadControls( &printPG ); - DrawPrintGrid(); + TempRedraw(); // DoResetGrid } static void PrintGridRotate( void * pangle ) { ANGLE_T angle = (ANGLE_T)(long)pangle; - DrawPrintGrid(); currPrintGrid.orig = cmdMenuPos; - currPrintGrid.angle += angle; + currPrintGrid.angle += angle/1000; newPrintGrid = currPrintGrid; ParamLoadControls( &printPG ); ChangeDim(); - DrawPrintGrid(); + TempRedraw(); // PrintGridRotate } /***************************************************************************** @@ -1008,6 +1335,7 @@ static void PrintDlgUpdate( else if ( pg->paramPtr[inx].context == (void*)2 ) PrintUpdate( inx ); ParamControlActive( &printPG, I_RULER, currPrintGrid.angle == 0 ); + TempRedraw(); // PrintDlgUpdate } static STATUS_T CmdPrint( @@ -1038,6 +1366,8 @@ static STATUS_T CmdPrint( print_d.scale = printScale; printWin = ParamCreateDialog( &printPG, MakeWindowTitle(_("Print")), _("Print"), DoPrintPrint, (paramActionCancelProc)Reset, TRUE, NULL, 0, PrintDlgUpdate ); } + sPrinterName = wPrintGetName(); + SetMargins(); wShow( printWin ); SetPageSize( TRUE ); if (currPrintGrid.size.x == 0.0) { @@ -1050,17 +1380,15 @@ static STATUS_T CmdPrint( currPrintGrid.size.y = maxPageSize.y; newPrintGrid = currPrintGrid; ParamLoadControls( &printPG ); - DrawPrintGrid(); pageCount = 0; + UpdatePageCount(); LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrintGrid.size.y ) ) PrintChange( CHANGE_MAP|CHANGE_UNITS ); - ParamGroupRecord( &printPG ); - ParamLoadMessage( &printPG, I_PAGECNT, "0 pages" ); - ParamDialogOkActive( &printPG, FALSE ); ChangeDim(); InfoMessage( _("Select pages to print, or drag to move print grid") ); downShift = FALSE; ParamControlActive( &printPG, I_RULER, currPrintGrid.angle == 0 ); + TempRedraw(); // CmdPrint C_START return C_CONTINUE; case C_DOWN: @@ -1083,10 +1411,8 @@ LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrin if (downShift) { rc = GridAction( action, pos, &newPrintGrid.orig, &newPrintGrid.angle ); ParamLoadControls( &printPG ); - DrawPrintGrid(); currPrintGrid = newPrintGrid; ChangeDim(); - DrawPrintGrid(); downShift = FALSE; } return C_CONTINUE; @@ -1115,10 +1441,8 @@ LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrin if (downShift) { rc = GridAction( action, pos, &newPrintGrid.orig, &newPrintGrid.angle ); ParamLoadControls( &printPG ); - DrawPrintGrid(); currPrintGrid = newPrintGrid; ChangeDim(); - DrawPrintGrid(); downShift = FALSE; ParamControlActive( &printPG, I_RULER, currPrintGrid.angle == 0 ); } @@ -1126,13 +1450,13 @@ LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrin case C_REDRAW: DrawPrintGrid(); + rc = GridAction( action, pos, &newPrintGrid.orig, &newPrintGrid.angle ); return C_TERMINATE; case C_CANCEL: if (printWin == NULL) return C_TERMINATE; PrintClear(); - DrawPrintGrid(); wHide( printWin ); return C_TERMINATE; @@ -1141,6 +1465,7 @@ LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrin return C_TERMINATE; case C_CMDMENU: + menuPos = pos; wMenuPopupShow( printGridPopupM ); return C_CONTINUE; @@ -1157,7 +1482,8 @@ EXPORT wIndex_t InitCmdPrint( wMenu_p menu ) RegisterChangeNotification( PrintChange ); printGridPopupM = MenuRegister( "Print Grid Rotate" ); AddRotateMenu( printGridPopupM, PrintGridRotate ); - return InitCommand( menu, CmdPrint, N_("Print..."), NULL, LEVEL0, IC_LCLICK|IC_POPUP2|IC_CMDMENU, ACCL_PRINT ); + ParamRegister( &printMarginPG ); + return InitCommand( menu, CmdPrint, N_("Print..."), NULL, LEVEL0, IC_LCLICK|IC_POPUP3|IC_CMDMENU, ACCL_PRINT ); } /***************************************************************************** diff --git a/app/bin/cprofile.c b/app/bin/cprofile.c index 49c3289..4f375ed 100644 --- a/app/bin/cprofile.c +++ b/app/bin/cprofile.c @@ -21,6 +21,7 @@ */ #include +#include #include "custom.h" #include "cselect.h" @@ -105,19 +106,21 @@ static BOOL_T printVert = TRUE; static wMenu_p profilePopupM; static track_p profilePopupTrk; static EPINX_T profilePopupEp; -static wMenuToggle_p profilePopupToggles[3]; +static wMenuToggle_p profilePopupToggles[3]; -static int log_profile = 0; +static int log_profile = 0; #define LABELH (labelH*fontSize/screenProfileFontSize) +#define LABELW (labelW*fontSize/screenProfileFontSize) #define PBB(FS) (2.0*(labelH*(FS)/screenProfileFontSize+3.0/mainD.dpi)) #define PBT (10.0/mainD.dpi) -#define PBR (30.0/mainD.dpi) -#define PBL (20.0/mainD.dpi) +#define PBR(FS) (1.0*(labelW*(FS)/screenProfileFontSize+3.0/mainD.dpi)) +#define PBL(FS) (1.0*(labelW*(FS)/screenProfileFontSize+3.0/mainD.dpi)) static FLOAT_T labelH; +static FLOAT_T labelW; -track_p pathStartTrk; +track_p pathStartTrk; EPINX_T pathStartEp; track_p pathEndTrk; EPINX_T pathEndEp; @@ -126,330 +129,467 @@ EPINX_T pathEndEp; #define NOP typedef struct { - track_p trk; - EPINX_T ep; - DIST_T elev; - DIST_T dist; - BOOL_T defined; /* from prev PE to current */ - } profElem_t, *profElem_p; -static dynArr_t profElem_da; -#define profElem(N) DYNARR_N( profElem_t, profElem_da, N ) + track_p trk; + EPINX_T ep; + DIST_T elev; + DIST_T dist; + BOOL_T defined; /* from prev PE to current */ +} profElem_t, *profElem_p; + +static dynArr_t profElem_da; +static profElem_p copyOfprofElem; + +#define profElem(N) DYNARR_N( profElem_t, profElem_da, N ) typedef struct { - DIST_T dist; - char * name; - } station_t, *station_p; -static dynArr_t station_da; + DIST_T dist; + char * name; +} station_t, *station_p; +static dynArr_t station_da; + #define station(N) DYNARR_N( station_t, station_da, N ) + struct { - DIST_T totalD, minE; - int minC, maxC, incrC; - DIST_T scaleX, scaleY; - } prof; -static void DrawProfile( drawCmd_p D, wFontSize_t fontSize, BOOL_T printVert ) + DIST_T totalD, minE; + int minC, maxC, incrC; + DIST_T scaleX, scaleY; +} prof; + + +/** + * Creates a copy of profile elements + */ + +static void +CreateCopyProfileElements() { - coOrd pl, pt, pb; - int inx; - DIST_T grade; - wFont_p fp; - static dynArr_t points_da; -#define points(N) DYNARR_N( coOrd, points_da, N ) - wDrawWidth lw; - station_p ps; - coOrd textsize; - - lw = (wDrawWidth)(D->dpi*2.0/mainD.dpi); - fp = wStandardFont( F_HELV, FALSE, FALSE ); - DYNARR_RESET( coOrd, points_da ); - - pb.x = pt.x = 0; - pb.y = prof.minE; pt.y = GetDim(prof.maxC); - DrawLine( D, pb, pt, 0, snapGridColor ); - pb.x = pt.x = prof.totalD; - DrawLine( D, pb, pt, 0, snapGridColor ); - pb.x = 0; - pt.x = prof.totalD; - for (inx=prof.minC; inx<=prof.maxC; inx+=prof.incrC) { - pt.y = pb.y = GetDim(inx); - DrawLine( D, pb, pt, 0, snapGridColor ); - pl.x = -(PBL-3.0/mainD.dpi)/prof.scaleX*D->scale; - pl.y = pb.y-LABELH/2/prof.scaleY*D->scale; - sprintf( message, "%d", inx ); - DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); - } - if ( profElem_da.cnt <= 0 ) - return; - - for (inx=0; inx 1 ) { - DYNARR_APPEND( coOrd, points_da, 10 ); - pt.x = prof.totalD; - points(points_da.cnt-1) = pt; - DYNARR_APPEND( coOrd, points_da, 10 ); - pb.x = 0; - points(points_da.cnt-1) = pb; - DrawFillPoly( D, points_da.cnt, &points(0), profileColorFill ); - DrawLine( D, pb, pt, lw, borderColor ); - } + if (copyOfprofElem) { + MyFree(copyOfprofElem); + } + + copyOfprofElem = MyMalloc(profElem_da.cnt * sizeof(profElem_t)); + if (!copyOfprofElem) { + AbortProg("Couldn't allocate memory for profile copy\n"); + } + for (int i = 0; i < profElem_da.cnt; i++) { + copyOfprofElem[i] = profElem(i); + } +} - pt.y = prof.minE-(2*LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale; - for (inx=0; inxname, fp, fontSize, FALSE, &textsize ); - pt.x = ps->dist - textsize.x/2.0/prof.scaleX*D->scale; - if (pt.x < -PBR) - pt.x = -(PBR-3/mainD.dpi)/prof.scaleX*D->scale; - else if (pt.x+textsize.x > prof.totalD) - pt.x = prof.totalD-(textsize.x-3/mainD.dpi)/prof.scaleX*D->scale; - DrawString( D, pt, 0.0, ps->name, fp, fontSize*D->scale, borderColor ); - } +/** + * Destroys the copy of profile elements + */ - pb.x = 0.0; pb.y = prof.minE; - pt = points(0); - DrawLine( D, pb, pt, lw, borderColor ); - sprintf( message, "%0.1f", PutDim(profElem(0).elev) ); - if (printVert) { - pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale; - pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale; - DrawString( D, pl, 270.0, message, fp, fontSize*D->scale, borderColor ); - } else { - pl.x = pt.x+2.0/mainD.dpi/prof.scaleX*D->scale; - pl.y = pt.y; - if (profElem_da.cnt>1 && profElem(0).elev < profElem(1).elev ) - pl.y -= LABELH/prof.scaleY*D->scale; - DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); - } - pl = pt; - - for (inx=1; inx 0.1) { - grade = fabs(profElem(inx).elev-profElem(inx-1).elev)/ - (profElem(inx).dist-profElem(inx-1).dist); - sprintf( message, "%0.1f%%", grade*100.0 ); - DrawTextSize( &mainD, message, fp, fontSize, FALSE, &textsize ); - pl.x = (points(inx).x+points(inx-1).x)/2.0; - pl.y = (points(inx).y+points(inx-1).y)/2.0; - if (printVert) { - pl.x += (LABELH/2)/prof.scaleX*D->scale; - pl.y += ((LABELH/2)*grade/prof.scaleX + 2.0/mainD.dpi/prof.scaleY)*D->scale; - DrawString( D, pl, 270.0, message, fp, fontSize*D->scale, borderColor ); - } else { - pl.x -= (textsize.x/2)/prof.scaleX*D->scale; - pl.y += (textsize.x/2)*grade/prof.scaleX*D->scale; - DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); - } - } - if (units==UNITS_ENGLISH) { - if (prof.totalD > 240) - sprintf( message, "%d'", ((int)floor(profElem(inx).dist)+6)/12 ); - else - sprintf( message, "%d'%d\"", ((int)floor(profElem(inx).dist+0.5))/12, ((int)floor(profElem(inx).dist+0.5))%12 ); - } else { - if (PutDim(prof.totalD) > 10000) - sprintf( message, "%0.0fm", (PutDim(profElem(inx).dist)+50)/100.0 ); - else if (PutDim(prof.totalD) > 100) - sprintf( message, "%0.1fm", (PutDim(profElem(inx).dist)+5)/100.0 ); - else - sprintf( message, "%0.2fm", (PutDim(profElem(inx).dist)+0.5)/100.0 ); - } - DrawTextSize( &mainD, message, fp, fontSize, FALSE, &textsize ); - pl.x = pb.x-(textsize.x/2)/prof.scaleX*D->scale; - pl.y = prof.minE-(LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale; - DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); - sprintf( message, "%0.1f", PutDim(profElem(inx).elev) ); - if (printVert) { - pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale; - pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale; - DrawString( D, pl, 270.0, message, fp, fontSize*D->scale, borderColor ); - } else { - pl.x = pt.x + 2.0/mainD.dpi/prof.scaleX*D->scale; - pl.y = pt.y; - if ( inx != profElem_da.cnt-1 && profElem(inx).elev < profElem(inx+1).elev ) - pl.y -= LABELH/prof.scaleY*D->scale; - DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); +static void +DestroyCopyOfProfileElements() +{ + if (copyOfprofElem) { + MyFree(copyOfprofElem); + copyOfprofElem = NULL; + } +} + + +/** + * Draw profile + * + * \param D The drawCmd_p to use. + * \param fontSize Size of the font. + * \param printVert print vertical. + */ + +static void DrawProfile(drawCmd_p D, wFontSize_t fontSize, BOOL_T printVert) +{ + coOrd pl, pt, pb; + int inx; + DIST_T grade; + wFont_p fp; + static dynArr_t points_da; +#define points(N) DYNARR_N( coOrd, points_da, N ) + wDrawWidth lw; + station_p ps; + coOrd textsize; + + lw = (wDrawWidth)(D->dpi*1.0/mainD.dpi); + fp = wStandardFont(F_HELV, FALSE, FALSE); + DYNARR_RESET(pts_t, points_da); + + pb.x = pt.x = 0; + pb.y = prof.minE; + pt.y = GetDim(prof.maxC); + DrawLine(D, pb, pt, 0, snapGridColor); + pb.x = pt.x = prof.totalD; + DrawLine(D, pb, pt, 0, snapGridColor); + pb.x = 0; + pt.x = prof.totalD; + + // Draw horizontal grid and y scale + for (inx=prof.minC; inx<=prof.maxC; inx+=prof.incrC) { + coOrd textsize; + // grid line + pt.y = pb.y = GetDim(inx); + DrawLine(D, pb, pt, 0, snapGridColor); + // scale + sprintf(message, "%d", inx); + DrawTextSize(&mainD, message, wStandardFont(F_HELV, FALSE, FALSE), + screenProfileFontSize, FALSE, &textsize); + pl.x = ((-3.0/mainD.dpi) - textsize.y*0.5 - textsize.x) / prof.scaleX*D->scale; + pl.y = pb.y-LABELH/2/prof.scaleY*D->scale; + + DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor); + } + + // show the measurement units + sprintf(message, "%s", units == UNITS_ENGLISH ? "in." : "cm"); + DrawTextSize(&mainD, message, wStandardFont(F_HELV, FALSE, FALSE), + screenProfileFontSize, FALSE, &textsize); + pl.x = ((-3.0 / mainD.dpi) - textsize.y*0.5 - textsize.x) / + prof.scaleX*D->scale; + pl.y += LABELH * 1.5 / prof.scaleY*D->scale; + DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor); + + if (profElem_da.cnt <= 0) { + return; + } + + for (inx=0; inx 1) { + DYNARR_APPEND(coOrd, points_da, 10); + pt.x = prof.totalD; + points(points_da.cnt-1) = pt; + DYNARR_APPEND(pts_t, points_da, 10); + pb.x = 0; + points(points_da.cnt-1) = pb; + DrawPoly(D, points_da.cnt, points_da.ptr, NULL, profileColorFill, 1, 1, 0); + } + + pt.y = prof.minE-(2*LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale; + for (inx=0; inxname, fp, fontSize, FALSE, &textsize); + pt.x = ps->dist - textsize.x/2.0/prof.scaleX*D->scale; + if (pt.x < -PBR(screenProfileFontSize)) { + pt.x = -(PBR(screenProfileFontSize)-3/mainD.dpi)/prof.scaleX*D->scale; + } else if (pt.x+textsize.x > prof.totalD) { + pt.x = prof.totalD-(textsize.x-3/mainD.dpi)/prof.scaleX*D->scale; + } + DrawString(D, pt, 0.0, ps->name, fp, fontSize*D->scale, borderColor); + } + + pb.x = 0.0; + pb.y = prof.minE; + + // mark the starting point for the profile + pt = points(0); + DrawLine(D, pb, pt, lw, snapGridColor); + DrawArc(D, pt, 0.05, 0, 360, TRUE, 2, wDrawColorGrey40); + if (units==UNITS_ENGLISH) { + sprintf(message, "%0.1f", PutDim(profElem(0).elev)+0.05); + } else { + sprintf(message, "%0.1f", PutDim(profElem(0).elev)+0.05); + } + if (printVert) { + pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale; + pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale + GetDim(prof.incrC) / 16;; + DrawString(D, pl, 270.0, message, fp, fontSize*D->scale, borderColor); + } else { + pl.x = pt.x+2.0/mainD.dpi/prof.scaleX*D->scale + GetDim(prof.incrC) / 16;; + pl.y = pt.y; + if (profElem_da.cnt>1 && profElem(0).elev < profElem(1).elev) { + pl.y -= LABELH/prof.scaleY*D->scale; + } + DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor); + } + pl = pt; + + for (inx=1; inxoptions; + + D->options = D->options | DC_DOT; + DrawLine(D, pb, pt, lw, borderColor); + D->options = oldOptions; } - pl = pt; - } + + // draw grade line + DrawLine(D, pl, pt, lw*2, (profElem(inx).defined ? profileColorDefinedProfile : + profileColorUndefinedProfile)); + // draw the markers + DrawArc(D, pt, 0.05, 0, 360, TRUE, 2, wDrawColorGrey40); + + if (profElem(inx).dist > 0.1) { + grade = fabs(profElem(inx).elev-profElem(inx-1).elev)/ + (profElem(inx).dist-profElem(inx-1).dist); + sprintf(message, "%0.1f%%", round(grade*1000.0)/10.0); + DrawTextSize(&mainD, message, fp, fontSize, FALSE, &textsize); + pl.x = (points(inx).x+points(inx-1).x)/2.0; + pl.y = (points(inx).y+points(inx-1).y)/2.0; + if (printVert) { + pl.x += (LABELH/2)/prof.scaleX*D->scale; + pl.y += ((LABELH/2)*grade/prof.scaleX + 2.0/mainD.dpi/prof.scaleY)*D->scale; + DrawString(D, pl, 270.0, message, fp, fontSize*D->scale, borderColor); + } else { + pl.x -= (textsize.x/2)/prof.scaleX*D->scale; + pl.y += (textsize.x/2)*grade/prof.scaleX*D->scale; + DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor); + } + } + if (units==UNITS_ENGLISH) { + if (prof.totalD > 240) { + sprintf(message, "%0.1f'", (round((profElem(inx).dist/12.0)*10.0)/10.0)); + } else { + sprintf(message, "%d'%0.1f\"", (int)floor((profElem(inx).dist)/12.0), + round(fmod(profElem(inx).dist,12.0)*10.0)/10.0); + } + } else { + if (PutDim(prof.totalD) > 10000) { + sprintf(message, "%0.1fm", (round(PutDim(profElem(inx).dist)/10.0)/10.0)); + } else if (PutDim(prof.totalD) > 100) { + sprintf(message, "%0.2fm", (round(PutDim(profElem(inx).dist))/100.0)); + } else { + sprintf(message, "%0.1fcm", round(PutDim(profElem(inx).dist)+0.5)); + } + } + DrawTextSize(&mainD, message, fp, fontSize, FALSE, &textsize); + pl.x = pb.x-(textsize.x/2)/prof.scaleX*D->scale; + pl.y = prof.minE-(LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale; + DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor); + sprintf(message, "%0.1f", round(PutDim(profElem(inx).elev)*100.0)/100.0); + if (printVert) { + pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale; + pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale+GetDim(prof.incrC) / 16; + DrawString(D, pl, 270.0, message, fp, fontSize*D->scale, borderColor); + } else { + pl.x = pt.x + 2.0/mainD.dpi/prof.scaleX*D->scale + GetDim(prof.incrC) / 16; + pl.y = pt.y; + if (inx != profElem_da.cnt-1 && profElem(inx).elev < profElem(inx+1).elev) { + pl.y -= LABELH/prof.scaleY*D->scale; + } + DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor); + } + pl = pt; + } } -static void ProfilePix2CoOrd( drawCmd_p, wPos_t, wPos_t, coOrd * ); -static void ProfileCoOrd2Pix( drawCmd_p, coOrd, wPos_t*, wPos_t* ); +static void ProfilePix2CoOrd(drawCmd_p, wPos_t, wPos_t, coOrd *); +static void ProfileCoOrd2Pix(drawCmd_p, coOrd, wPos_t*, wPos_t*); static drawCmd_t screenProfileD = { - NULL, - &screenDrawFuncs, - DC_NOCLIP, - 1.0, - 0.0, - {0.0,0.0}, {0.0,0.0}, - ProfilePix2CoOrd, ProfileCoOrd2Pix }; + NULL, + &screenDrawFuncs, + DC_NOCLIP, + 1.0, + 0.0, + {0.0,0.0}, {0.0,0.0}, + ProfilePix2CoOrd, ProfileCoOrd2Pix +}; static void ProfilePix2CoOrd( - drawCmd_p d, - wPos_t xx, - wPos_t yy, - coOrd * pos ) + drawCmd_p d, + wPos_t xx, + wPos_t yy, + coOrd * pos) { - pos->x = (xx/d->dpi+d->orig.x)/prof.scaleX; - pos->y = (yy/d->dpi+d->orig.y)/prof.scaleY+prof.minE; + pos->x = (xx/d->dpi+d->orig.x)/prof.scaleX; + pos->y = (yy/d->dpi+d->orig.y)/prof.scaleY+prof.minE; } + static void ProfileCoOrd2Pix( - drawCmd_p d, - coOrd pos, - wPos_t *xx, - wPos_t *yy ) + drawCmd_p d, + coOrd pos, + wPos_t *xx, + wPos_t *yy) { - wPos_t x, y; - x = (wPos_t)((((pos.x*prof.scaleX)/d->scale-d->orig.x)*d->dpi+0.5)); - y = (wPos_t)(((((pos.y-prof.minE)*prof.scaleY)/d->scale-d->orig.y)*d->dpi+0.5)); - if ( d->angle == 0 ) { - *xx = x; - *yy = y; - } else if ( d->angle == -90.0 ) { - /* L->P */ - *xx = y; - *yy = -x; - } else { - /* P->L */ - *xx = -y; - *yy = x; - } + wPos_t x, y; + x = (wPos_t)((((pos.x*prof.scaleX)/d->scale-d->orig.x)*d->dpi+0.5)); + y = (wPos_t)(((((pos.y-prof.minE)*prof.scaleY)/d->scale-d->orig.y)*d->dpi+0.5)); + if (d->angle == 0) { + *xx = x; + *yy = y; + } else if (d->angle == -90.0) { + /* L->P */ + *xx = y; + *yy = -x; + } else { + /* P->L */ + *xx = -y; + *yy = x; + } } +/** + * Redraw profile window + */ -static void RedrawProfileW( void ) +static void RedrawProfileW(void) { - wPos_t ww, hh; - coOrd size; - int inx, divC; - DIST_T maxE, rngE; - profElem_t *p; - wFont_p fp; - POS_T w; - coOrd textsize; - - wDrawClear( screenProfileD.d ); - wDrawGetSize( screenProfileD.d, &ww, &hh ); - screenProfileD.size.x = (ww)/screenProfileD.dpi; - screenProfileD.size.y = (hh)/screenProfileD.dpi; - screenProfileD.orig.x = -PBL; - screenProfileD.orig.y = -PBB(screenProfileFontSize); - - /* Calculate usable dimension of canvas */ - size = screenProfileD.size; - size.x -= (PBL); - size.y -= (PBB(screenProfileFontSize)); + wPos_t ww, hh; + coOrd size; + int divC; + DIST_T maxE, rngE; + profElem_t *p; + wFont_p fp; + POS_T w; + coOrd textsize; + char *pTestString; + + wDrawDelayUpdate(screenProfileD.d, TRUE); + wDrawClear(screenProfileD.d); + + // get the size of the window area in pixels and convert to inches + wDrawGetSize(screenProfileD.d, &ww, &hh); + screenProfileD.size.x = (ww)/screenProfileD.dpi; + screenProfileD.size.y = (hh)/screenProfileD.dpi; + + // calculate positions for labels??? + fp = wStandardFont(F_HELV, FALSE, FALSE); + screenProfileD.orig.x = -PBL(screenProfileFontSize); + screenProfileD.orig.y = -PBB(screenProfileFontSize); + + /* Calculate usable dimension of canvas in inches */ + size = screenProfileD.size; + size.x -= (PBL(screenProfileFontSize)); + size.y -= (PBB(screenProfileFontSize)); + + /* make sure there is enough space to show the rightmost coordinate value*/ + if (units == UNITS_ENGLISH) { + if (prof.totalD > 240.0) { + pTestString = "9999'"; + } else { + pTestString = "999'11\""; + } + } else { + if (PutDim(prof.totalD) > 10000.0) { + pTestString = "999m"; + } else { + if (PutDim(prof.totalD) > 100.0) { + pTestString = "99.9m"; + } else { + pTestString = "9.99m"; + } + } + } + DrawTextSize(&mainD, pTestString, fp, screenProfileFontSize, FALSE, &textsize); + size.x -= textsize.x / 2; + size.y -= textsize.y * 1.5 ; + + + // now we have the size of the profile area #ifdef WINDOWS - if (printVert) { - size.x -= PBR/4.0; - size.y -= PBT; - } else + if (printVert) { + size.x -= PBR(screenProfileFontSize)/4.0; + size.y -= PBT; + } else #endif - { - size.x -= PBR; - size.y -= PBT; - } - if ( size.x < 0.1 || size.y < 0.1 ) - return; - - /* Calculate range of data values */ - if (profElem_da.cnt<=0) { - prof.totalD = 0.0; - prof.minE = 0.0; - maxE = 1.0; - } else { - maxE = prof.minE = profElem(0).elev; - prof.totalD = profElem(profElem_da.cnt-1).dist; - for (inx=1; inxelevelev; - if (p->elev>maxE) - maxE = p->elev; - } - } - - /* Calculate number of grid lines */ - prof.minC = (int)floor(PutDim(prof.minE)); - prof.maxC = (int)ceil(PutDim(maxE)); - if ( prof.maxC-prof.minC <= 0 ) - prof.maxC = prof.minC+1; - divC = (int)floor(size.y/labelH); - if ( divC < 1 ) - divC = 1; - prof.incrC = (prof.maxC-prof.minC+divC-1)/divC; - if ( prof.incrC < 1 ) - prof.incrC = 1; - prof.maxC = prof.minC + (prof.maxC-prof.minC+prof.incrC-1)/prof.incrC * prof.incrC; - - /* Reset bounds based on intergal values */ - prof.minE = GetDim(prof.minC); - rngE = GetDim(prof.maxC) - prof.minE; - if (rngE < 1.0) - rngE = 1.0; - - /* Compute vert scale */ - prof.scaleY = size.y/rngE; - sprintf( message, "%0.2f", maxE ); - fp = wStandardFont( F_HELV, FALSE, FALSE ); - DrawTextSize( &mainD, message, fp, screenProfileFontSize, FALSE, &textsize ); - w = textsize.x; - w -= PBT; - w += 4.0/screenProfileD.dpi; - w -= (GetDim(prof.maxC)-maxE)*prof.scaleY; - if (w > 0) { - size.y -= w; - prof.scaleY = size.y/rngE; - } - - /* Compute horz scale */ - if (prof.totalD <= 0.1) { - prof.totalD = size.x; - } - prof.scaleX = size.x/prof.totalD; - -#ifdef LATER - D->size.x /= prof.scaleX; - D->size.x -= D->orig.x; - D->size.y /= prof.scaleY; - D->size.y -= D->orig.y; - D->size.y += prof.minE; -#endif - - DrawProfile( &screenProfileD, screenProfileFontSize, + { + size.x -= PBR(screenProfileFontSize); + size.y -= PBT; + } + + if (size.x < 0.1 || size.y < 0.1) { + wDrawDelayUpdate(screenProfileD.d, FALSE); + return; + } + + /* Calculate range of data values */ + if (profElem_da.cnt<=0) { + prof.totalD = 0.0; + prof.minE = 0.0; + maxE = 1.0; + } else { + maxE = prof.minE = profElem(0).elev; + prof.totalD = profElem(profElem_da.cnt-1).dist; + for (int inx=1; inxelevelev; + } + if (p->elev>maxE) { + maxE = p->elev; + } + } + } + + /* Calculate number of grid lines */ + prof.minC = (int)floor(PutDim(prof.minE)); + prof.maxC = (int)ceil(PutDim(maxE)); + if (prof.maxC-prof.minC <= 0) { + prof.maxC = prof.minC+1; + } + divC = (int)floor(size.y/labelH); + if (divC < 1) { + divC = 1; + } + prof.incrC = (prof.maxC-prof.minC+divC-1)/divC; + if (prof.incrC < 1) { + prof.incrC = 1; + } + prof.maxC = prof.minC + (prof.maxC-prof.minC+prof.incrC-1)/prof.incrC * + prof.incrC; + + /* Reset bounds based on intergal values */ + prof.minE = GetDim(prof.minC); + rngE = GetDim(prof.maxC) - prof.minE; + if (rngE < 1.0) { + rngE = 1.0; + } + + /* Compute vert scale */ + prof.scaleY = size.y/rngE; + sprintf(message, "%0.2f", maxE); + + DrawTextSize(&mainD, message, fp, screenProfileFontSize, FALSE, &textsize); + w = textsize.x; + w -= PBT; + w += 4.0/screenProfileD.dpi; + w -= (GetDim(prof.maxC)-maxE)*prof.scaleY; + if (w > 0) { + size.y -= w; + prof.scaleY = size.y/rngE; + } + + /* Compute horz scale */ + if (prof.totalD <= 0.1) { + prof.totalD = size.x; + } + prof.scaleX = size.x/prof.totalD; + + DrawProfile(&screenProfileD, screenProfileFontSize, #ifdef WINDOWS - printVert + printVert #else - FALSE + FALSE #endif - ); + ); + wDrawDelayUpdate(screenProfileD.d, FALSE); } + static drawCmd_t printProfileD = { - NULL, - &printDrawFuncs, - DC_PRINT|DC_NOCLIP, - 1.0, - 0.0, - {0.0,0.0}, {1.0,1.0}, - ProfilePix2CoOrd, ProfileCoOrd2Pix }; + NULL, + &printDrawFuncs, + DC_PRINT | DC_NOCLIP, + 1.0, + 0.0, + {0.0,0.0}, {1.0,1.0}, + ProfilePix2CoOrd, ProfileCoOrd2Pix +}; /** * This is the print function for the track height profile. The paper @@ -457,94 +597,95 @@ static drawCmd_t printProfileD = { * Eg. is the windows is wider than high, the printout will be in * landscape. * \todo Rework the layout of the printout - * This function is (at least for me) hard to comprehend with all the - * fiddling around with the ccordinates. Also the filled area is a - * waste of toner or ink. * * \param junk IN * \return */ -static void DoProfilePrint( void * junk ) +static void DoProfilePrint(void * junk) { - coOrd size, p[4]; - int copies; - WDOUBLE_T w, h, screenRatio, printRatio, titleH; - wFont_p fp; - coOrd screenSize; - coOrd textsize; - - if (!wPrintDocStart( _("Profile"), 1, &copies )) - return; - printProfileD.d = wPrintPageStart(); - if (printProfileD.d == NULL) - return; - printProfileD.dpi = wDrawGetDPI( printProfileD.d ); - wPrintGetPageSize( &w, &h ); - printProfileD.orig.x = -PBL; - printProfileD.orig.y = -PBB(printProfileFontSize); - printProfileD.angle = 0.0; - screenRatio = screenProfileD.size.y/screenProfileD.size.x; - screenSize.x = prof.totalD*prof.scaleX; - screenSize.y = GetDim(prof.maxC-prof.minC)*prof.scaleY; - screenRatio = screenSize.y/screenSize.x; - printProfileD.size.x = w; - printProfileD.size.y = h; - sprintf( message, _("%s Profile: %s"), sProdName, GetLayoutTitle() ); - fp = wStandardFont( F_TIMES, FALSE, FALSE ); - DrawTextSize( &mainD, message, fp, 24, FALSE, &textsize ); - titleH = textsize.y + 6.0/mainD.dpi; - if (screenRatio < 1.0 && w < h ) { - /* Landscape -> Portrait */ - printProfileD.angle = -90.0; - printProfileD.orig.x += h; - size.x = h; - size.y = w; - } else if (screenRatio > 1.0 && w > h ) { - /* Portrait -> Landscape */ - printProfileD.angle = 90.0; - printProfileD.orig.y += w; - size.x = h; - size.y = w; - } else { - size.x = w; - size.y = h; - } - size.y -= titleH+(printVert?PBT*2:PBT)+PBB(printProfileFontSize); - size.x -= 4.0/mainD.dpi+PBL+(printVert?PBR/4.0:PBR); - printRatio = size.y/size.x; - if (printRatio < screenRatio) { - printProfileD.scale = screenSize.y/size.y; - size.x = screenSize.x/printProfileD.scale; - } else { - printProfileD.scale = screenSize.x/size.x; - printProfileD.orig.y -= size.y; - size.y = screenSize.y/printProfileD.scale; - printProfileD.orig.y += size.y; - } + coOrd size, p[4]; + int copies; + WDOUBLE_T w, h, screenRatio, printRatio, titleH; + wFont_p fp; + coOrd screenSize; + coOrd textsize; + + if (!wPrintDocStart(_("Profile"), 1, &copies)) { + return; + } + printProfileD.d = wPrintPageStart(); + if (printProfileD.d == NULL) { + return; + } + printProfileD.dpi = wDrawGetDPI(printProfileD.d); + wPrintGetPageSize(&w, &h); + printProfileD.orig.x = -PBL(printProfileFontSize); + printProfileD.orig.y = -PBB(printProfileFontSize); + printProfileD.angle = 0.0; + screenRatio = screenProfileD.size.y/screenProfileD.size.x; + screenSize.x = prof.totalD*prof.scaleX; + screenSize.y = GetDim(prof.maxC-prof.minC)*prof.scaleY; + screenRatio = screenSize.y/screenSize.x; + printProfileD.size.x = w; + printProfileD.size.y = h; + sprintf(message, _("%s Profile: %s"), sProdName, GetLayoutTitle()); + fp = wStandardFont(F_TIMES, FALSE, FALSE); + DrawTextSize(&mainD, message, fp, 24, FALSE, &textsize); + titleH = textsize.y + 6.0/mainD.dpi; + if (screenRatio < 1.0 && w < h) { + /* Landscape -> Portrait */ + printProfileD.angle = -90.0; + printProfileD.orig.x += h; + size.x = h; + size.y = w; + } else if (screenRatio > 1.0 && w > h) { + /* Portrait -> Landscape */ + printProfileD.angle = 90.0; + printProfileD.orig.y += w; + size.x = h; + size.y = w; + } else { + size.x = w; + size.y = h; + } + size.y -= titleH+(printVert?PBT*2:PBT)+PBB(printProfileFontSize); + size.x -= 4.0/mainD.dpi+PBL(printProfileFontSize)+(printVert?PBR( + printProfileFontSize)/4.0:PBR(printProfileFontSize)); + printRatio = size.y/size.x; + if (printRatio < screenRatio) { + printProfileD.scale = screenSize.y/size.y; + size.x = screenSize.x/printProfileD.scale; + } else { + printProfileD.scale = screenSize.x/size.x; + printProfileD.orig.y -= size.y; + size.y = screenSize.y/printProfileD.scale; + printProfileD.orig.y += size.y; + } #define PRINT_ABS2PAGEX(X) (((X)*printProfileD.scale)/prof.scaleX) #define PRINT_ABS2PAGEY(Y) (((Y)*printProfileD.scale)/prof.scaleY+prof.minE) - p[0].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT)+0.05); - p[0].x = PRINT_ABS2PAGEX((size.x-textsize.x)/2.0); - if ( p[0].x < 0 ) - p[0].x = 0; - DrawString( &printProfileD, p[0], 0, message, fp, 24*printProfileD.scale, borderColor ); - p[0].x = p[3].x = PRINT_ABS2PAGEX((-PBL)+2.0/mainD.dpi); - p[0].y = p[1].y = PRINT_ABS2PAGEY(-PBB(printProfileFontSize)); - p[1].x = p[2].x = PRINT_ABS2PAGEX(size.x+(printVert?PBR/4.0:PBR)); - p[2].y = p[3].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT)); - DrawLine( &printProfileD, p[0], p[1], 0, drawColorBlack ); - DrawLine( &printProfileD, p[1], p[2], 0, drawColorBlack ); - DrawLine( &printProfileD, p[2], p[3], 0, drawColorBlack ); - DrawLine( &printProfileD, p[3], p[0], 0, drawColorBlack ); - - DrawProfile( &printProfileD, printProfileFontSize, printVert ); - wPrintPageEnd( printProfileD.d ); - wPrintDocEnd(); + p[0].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT)+0.05); + p[0].x = PRINT_ABS2PAGEX((size.x-textsize.x)/2.0); + if (p[0].x < 0) { + p[0].x = 0; + } + DrawString(&printProfileD, p[0], 0, message, fp, 24*printProfileD.scale, + borderColor); + p[0].x = p[3].x = PRINT_ABS2PAGEX((-PBL(printProfileFontSize))+2.0/mainD.dpi); + p[0].y = p[1].y = PRINT_ABS2PAGEY(-PBB(printProfileFontSize)); + p[1].x = p[2].x = PRINT_ABS2PAGEX(size.x+(printVert?PBR( + printProfileFontSize)/4.0:PBR(printProfileFontSize))); + p[2].y = p[3].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT)); + DrawLine(&printProfileD, p[0], p[1], 0, drawColorBlack); + DrawLine(&printProfileD, p[1], p[2], 0, drawColorBlack); + DrawLine(&printProfileD, p[2], p[3], 0, drawColorBlack); + DrawLine(&printProfileD, p[3], p[0], 0, drawColorBlack); + + DrawProfile(&printProfileD, printProfileFontSize, printVert); + wPrintPageEnd(printProfileD.d); + wPrintDocEnd(); } - - /************************************************************************** * * Window Handlers @@ -553,201 +694,218 @@ static void DoProfilePrint( void * junk ) static wWin_p profileW; - static BOOL_T profileUndo = FALSE; -static void DoProfileDone( void * ); -static void DoProfileClear( void * ); -static void DoProfilePrint( void * ); -static void DoProfileChangeMode( void * ); -static void SelProfileW( wIndex_t, coOrd ); +static void DoProfileChange(void *junk); +static void DoProfileReset(void *junk); +static void DoProfileDone(void *); +static void DoProfileClear(void *); +static void DoProfilePrint(void *); +static void DoProfileChangeMode(void *); +static void SelProfileW(wIndex_t, coOrd); +static void CloseProfileWindow(paramGroup_p pg, int event, void *data); static paramDrawData_t profileDrawData = { 300, 150, (wDrawRedrawCallBack_p)RedrawProfileW, SelProfileW, &screenProfileD }; static paramData_t profilePLs[] = { - { PD_DRAW, NULL, "canvas", PDO_DLGRESIZE, &profileDrawData }, + { PD_DRAW, NULL, "canvas", PDO_DLGRESIZE, &profileDrawData }, #define I_PROFILEMSG (1) - { PD_MESSAGE, NULL, NULL, PDO_DLGIGNOREX, (void*)300 }, - { PD_BUTTON, (void*)DoProfileClear, "clear", PDO_DLGCMDBUTTON, NULL, N_("Clear") }, - { PD_BUTTON, (void*)DoProfilePrint, "print", 0, NULL, N_("Print") } }; + { PD_MESSAGE, NULL, NULL, PDO_DLGIGNOREX, (void*)300 }, +#define I_CHANGEBUTTON 2 + { PD_BUTTON, (void*)DoProfileChange, "change", PDO_DLGCMDBUTTON, NULL, N_("Change") }, +#define I_RESETBUTTON 3 + { PD_BUTTON, (void*)DoProfileReset, "reset", PDO_DLGCMDBUTTON, NULL, N_("Reset") }, +#define I_CLEARBUTTON 4 + { PD_BUTTON, (void*)DoProfileClear, "clear", PDO_DLGCMDBUTTON, NULL, N_("Clear") }, +#define I_PRINTBUTTON 5 + { PD_BUTTON, (void*)DoProfilePrint, "print", 0, NULL, N_("Print") } +}; static paramGroup_t profilePG = { "profile", 0, profilePLs, sizeof profilePLs/sizeof profilePLs[0] }; +#define CHANGEBUTTON ((wButton_p)profilePLs[I_CHANGEBUTTON].control) +#define RESETBUTTON ((wButton_p)profilePLs[I_RESETBUTTON].control) +#define CLEARBUTTON ((wButton_p)profilePLs[I_CLEARBUTTON].control) +#define PRINTBUTTON ((wButton_p)profilePLs[I_PRINTBUTTON].control) -static void ProfileTempDraw( int inx, DIST_T elev ) +static void SelProfileW( + wIndex_t action, + coOrd pos) { - coOrd p0, p1; -#ifdef LATER - p0.x = profElem(inx).dist*prof.scaleX; - p0.y = (elev-prof.minE)*prof.scaleY; - screenProfileD.funcs = &tempDrawFuncs; - if (inx > 0) { - p1.x = profElem(inx-1).dist*prof.scaleX; - p1.y = (profElem(inx-1).elev-prof.minE)*prof.scaleY; - DrawLine( &screenProfileD, p0, p1, 2, borderColor ); - } - if (inx < profElem_da.cnt-1) { - p1.x = profElem(inx+1).dist*prof.scaleX; - p1.y = (profElem(inx+1).elev-prof.minE)*prof.scaleY; - DrawLine( &screenProfileD, p0, p1, 2, borderColor ); - } - screenProfileD.funcs = &screenDrawFuncs; -#endif - p0.x = profElem(inx).dist; - p0.y = elev; - screenProfileD.funcs = &tempDrawFuncs; - if (inx > 0) { - p1.x = profElem(inx-1).dist; - p1.y = profElem(inx-1).elev; - DrawLine( &screenProfileD, p0, p1, 2, borderColor ); - } - if (inx < profElem_da.cnt-1) { - p1.x = profElem(inx+1).dist; - p1.y = profElem(inx+1).elev; - DrawLine( &screenProfileD, p0, p1, 2, borderColor ); - } - screenProfileD.funcs = &screenDrawFuncs; + DIST_T dist; + static DIST_T oldElev; + static int inx; + DIST_T elev; + + if (profElem_da.cnt <= 0) { + return; + } + + dist = pos.x; + elev = pos.y; + + switch (action&0xFF) { + case C_DOWN: + for (inx=0; inx dist-profElem(inx-1).dist) { + inx--; + } + break; + } + } + if (inx >= profElem_da.cnt) { + inx = profElem_da.cnt-1; + } + sprintf(message, _("Elev = %0.1f"), round(PutDim(elev)*10.0)/10.0); + ParamLoadMessage(&profilePG, I_PROFILEMSG, message); + oldElev = elev; + RedrawProfileW(); + break; + case C_MOVE: + if (inx < 0) { + break; + } + if (profElem_da.cnt == 1) { + sprintf(message, _("Elev = %0.1f"), round(PutDim(elev)*10.0)/10.0); + } else if (inx == 0) { + sprintf(message, _("Elev=%0.2f %0.1f%%"), + round(PutDim(elev)*100.0)/100.0, + round(fabs(((profElem(inx+1).elev-elev) / (profElem(inx+1).dist-profElem( + inx).dist)) * 1000.0))/10.0); + } else if (inx == profElem_da.cnt-1) { + sprintf(message, _("%0.1f%% Elev = %0.2f"), + round(fabs(((profElem(inx-1).elev-elev) / (profElem(inx).dist-profElem( + inx-1).dist)) * 1000.0))/10.0, + round(PutDim(elev)*100.0)/100.0); + } else { + sprintf(message, _("%0.1f%% Elev = %0.2f %0.1f%%"), + round(fabs(((profElem(inx-1).elev-elev) / (profElem(inx).dist-profElem( + inx-1).dist)) * 1000.0))/10.0, + round(PutDim(elev)*100.0)/100.0, + round(fabs((profElem(inx+1).elev-elev) / (profElem(inx+1).dist-profElem( + inx).dist)) * 1000.0)/10.0); + } + ParamLoadMessage(&profilePG, I_PROFILEMSG, message); + oldElev = elev; + profElem(inx).elev = oldElev; + RedrawProfileW(); + wPause(500l); + break; + case C_UP: + if (profileUndo == FALSE) { + UndoStart(_("Profile Command"), "Profile - set elevation"); + profileUndo = TRUE; + } + if (profElem(inx).trk) { + UpdateTrkEndElev(profElem(inx).trk, profElem(inx).ep, ELEV_DEF|ELEV_VISIBLE, + oldElev, NULL); + } + profElem(inx).elev = oldElev; + RedrawProfileW(); + ParamLoadMessage(&profilePG, I_PROFILEMSG, _("Drag to change Elevation")); + inx = -1; + break; + default: + break; + } } - -static void SelProfileW( - wIndex_t action, - coOrd pos ) +static void HilightProfileElevations(BOOL_T show) { - DIST_T dist; - static DIST_T oldElev; - static int inx; - DIST_T elev; - - if (profElem_da.cnt <= 0) - return; + /*if ( profElem_da.cnt <= 0 ) {*/ + HilightElevations(show); + /*} else { + }*/ +} - dist = pos.x; - elev = pos.y; +/** + * + * + * \param pg The page. + * \param event The event. + * \param [in,out] data If non-null, the data. + */ +void +CloseProfileWindow(paramGroup_p pg, int event, void *data) +{ + Reset(); + return; +} -#ifdef LATER - if (recordF) - RecordMouse( "PROFILEMOUSE", action, dist, elev ); -#endif - switch (action&0xFF) { - case C_DOWN: - for (inx=0; inx dist-profElem(inx-1).dist) - inx--; - break; +/** + * Undo the changes made in the profile window to the layout. + */ + +static void +ResetChanges() +{ + if (copyOfprofElem) { + for (int i = 0; i < profElem_da.cnt; i++) { + profElem(i) = copyOfprofElem[i]; + if (profElem(i).trk) { + UpdateTrkEndElev(profElem(i).trk, profElem(i).ep, ELEV_DEF | ELEV_VISIBLE, + copyOfprofElem[i].elev, NULL); } } - if (inx >= profElem_da.cnt) - inx = profElem_da.cnt-1; - sprintf(message, _("Elev = %0.1f"), PutDim(elev) ); - ParamLoadMessage( &profilePG, I_PROFILEMSG, message ); - oldElev = elev; - ProfileTempDraw( inx, elev ); - break; - case C_MOVE: - if ( inx < 0 ) - break; - ProfileTempDraw( inx, oldElev ); - if (profElem_da.cnt == 1 ) { - sprintf(message, _("Elev = %0.1f"), PutDim(elev) ); - } else if (inx == 0) { - sprintf( message, _("Elev=%0.2f %0.1f%%"), - PutDim(elev), - fabs( profElem(inx+1).elev-elev ) / (profElem(inx+1).dist-profElem(inx).dist) * 100.0 ); - } else if (inx == profElem_da.cnt-1) { - sprintf( message, _("%0.1f%% Elev = %0.2f"), - fabs( profElem(inx-1).elev-elev ) / (profElem(inx).dist-profElem(inx-1).dist) * 100.0, - PutDim(elev) ); - } else { - sprintf( message, _("%0.1f%% Elev = %0.2f %0.1f%%"), - fabs( profElem(inx-1).elev-elev ) / (profElem(inx).dist-profElem(inx-1).dist) * 100.0, - PutDim(elev), - fabs( profElem(inx+1).elev-elev ) / (profElem(inx+1).dist-profElem(inx).dist) * 100.0 ); - } - ParamLoadMessage( &profilePG, I_PROFILEMSG, message ); - oldElev = elev; - ProfileTempDraw( inx, oldElev ); - break; - case C_UP: - if (profileUndo == FALSE) { - UndoStart( _("Profile Command"), "Profile - set elevation" ); - profileUndo = TRUE; - } - if (profElem(inx).trk) { - UpdateTrkEndElev( profElem(inx).trk, profElem(inx).ep, ELEV_DEF|ELEV_VISIBLE, oldElev, NULL ); - } - profElem(inx).elev = oldElev; - RedrawProfileW(); - ParamLoadMessage( &profilePG, I_PROFILEMSG, _("Drag to change Elevation") ); - inx = -1; - break; - default: - break; } } +/** + * Executes the profile reset operation. All elevations are copied from the + * backup, the main drawing area and the profile window are updated + * + * \param [in,out] junk + */ -#ifdef LATER -static BOOL_T ProfilePlayback( char * line ) +static void +DoProfileReset(void *junk) { - int action; - wPos_t x, y; - coOrd pos; - - if ( !GetArgs( line, "dp", &action, &pos ) ) { - return FALSE; - } else { - x = (wPos_t)(((pos.x*prof.scaleX)-screenProfileD.orig.x)*screenProfileD.dpi+0.5); - y = (wPos_t)((((pos.y-prof.minE)*prof.scaleY)-screenProfileD.orig.y)*screenProfileD.dpi+0.5); - PlaybackMouse( selProfileW, &screenProfileD, (wAction_t)action, x, y, drawColorBlack ); + if (profileUndo == 0) { + profileUndo = TRUE; + UndoStart(_("Profile Command"), "Profile"); } - return TRUE; + ResetChanges(); + RedrawProfileW(); + TempRedraw(); } -#endif - +/** + * Confirm the changes made in the profile window + * + * \param [in,out] junk If non-null, the junk. + */ -static void HilightProfileElevations( BOOL_T show ) +static void +DoProfileChange(void *junk) { - /*if ( profElem_da.cnt <= 0 ) {*/ - HilightElevations( show ); - /*} else { - }*/ + DestroyCopyOfProfileElements(); + TempRedraw(); } -static void DoProfileDone( void * junk ) +static void DoProfileDone(void * junk) { -#ifdef LATER - HilightProfileElevations( FALSE ); - wHide( profileW ); - ClrAllTrkBits( TB_PROFILEPATH ); - MainRedraw(); - MapRedraw(); -#endif - Reset(); + Reset(); } -static void DoProfileClear( void * junk ) +static void DoProfileClear(void * junk) { - profElem_da.cnt = 0; - station_da.cnt = 0; - if (ClrAllTrkBits( TB_PROFILEPATH )) { - MainRedraw(); - MapRedraw(); - } - pathStartTrk = pathEndTrk = NULL; - RedrawProfileW(); + ResetChanges(); + profElem_da.cnt = 0; + station_da.cnt = 0; + ClrAllTrkBitsRedraw(TB_PROFILEPATH, TRUE); + pathStartTrk = pathEndTrk = NULL; + RedrawProfileW(); } -static void DoProfileChangeMode( void * junk ) +static void DoProfileChangeMode(void * junk) { - if (profElem_da.cnt<=0) { - InfoMessage( _("Select a Defined Elevation to start Profile") ); - } else { - InfoMessage( _("Select a Defined Elevation to extend Profile") ); - } + if (profElem_da.cnt<=0) { + InfoMessage(_("Select a Defined Elevation to start Profile")); + } else { + InfoMessage(_("Select a Defined Elevation to extend Profile")); + } } /************************************************************************** @@ -756,17 +914,17 @@ static void DoProfileChangeMode( void * junk ) * **************************************************************************/ -static BOOL_T PathListEmpty( void ) +static BOOL_T PathListEmpty(void) { - return pathStartTrk == NULL; + return pathStartTrk == NULL; } -static BOOL_T PathListSingle( void ) +static BOOL_T PathListSingle(void) { - return pathStartTrk != NULL && - ( pathEndTrk == NULL || - ( GetTrkEndTrk(pathEndTrk,pathEndEp) == pathStartTrk && - GetTrkEndTrk(pathStartTrk,pathStartEp) == pathEndTrk ) ); + return pathStartTrk != NULL && + (pathEndTrk == NULL || + (GetTrkEndTrk(pathEndTrk,pathEndEp) == pathStartTrk && + GetTrkEndTrk(pathStartTrk,pathStartEp) == pathEndTrk)); } @@ -774,102 +932,106 @@ static int profileShortestPathMatch; static DIST_T profileShortestPathDist; static int ProfileShortestPathFunc( - SPTF_CMD cmd, - track_p trk, - EPINX_T ep, - EPINX_T ep0, - DIST_T dist, - void * data ) + SPTF_CMD cmd, + track_p trk, + EPINX_T ep, + EPINX_T ep0, + DIST_T dist, + void * data) { - track_p trkN; - EPINX_T epN; - int rc0=0; - int pathMatch; - - switch (cmd) { - case SPTC_TERMINATE: - rc0 = 1; - break; - - case SPTC_MATCH: - if ( EndPtIsIgnoredElev(trk,ep) ) - break; - if ( PathListSingle() ) { - if ( trk == pathStartTrk && ep == pathStartEp ) { - pathMatch = 2; - } else if ( trk == pathEndTrk && ep == pathEndEp ) { - pathMatch = 3; - } else { - break; - } - } else if ( ( trkN = GetTrkEndTrk(trk,ep) ) == NULL ) { - break; - } else { - epN = GetEndPtConnectedToMe( trkN, trk ); - if ( trkN == pathStartTrk && epN == pathStartEp ) { - pathMatch = 1; - } else if ( trkN == pathEndTrk && epN == pathEndEp ) { - pathMatch = 2; - } else if ( trkN == pathStartTrk && trkN == pathEndTrk ) { - pathMatch = 2; - } else if ( trkN == pathStartTrk ) { - pathMatch = 1; - } else if ( trkN == pathEndTrk ) { - pathMatch = 2; - } else { - break; - } - } - if ( profileShortestPathMatch < 0 || profileShortestPathDist > dist ) { -LOG( log_shortPath, 4, ( " Match=%d", pathMatch ) ) - profileShortestPathMatch = pathMatch; - profileShortestPathDist = dist; - } - rc0 = 1; - break; - - case SPTC_MATCHANY: - rc0 = -1; - break; - - case SPTC_IGNNXTTRK: - if ( EndPtIsIgnoredElev(trk,ep) ) - rc0 = 1; - else if ( (GetTrkBits(trk)&TB_PROFILEPATH)!=0 ) - rc0 = 1; - else if ( (!EndPtIsDefinedElev(trk,ep)) && GetTrkEndTrk(trk,ep)==NULL ) - rc0 = 1; - else - rc0 = 0; - break; - - case SPTC_ADD_TRK: -if (log_shortPath<=0||logTable(log_shortPath).level<4) LOG( log_profile, 4, ( " ADD_TRK T%d:%d", GetTrkIndex(trk), ep ) ) - SetTrkBits( trk, TB_PROFILEPATH ); - DrawTrack( trk, &mainD, profilePathColor ); - rc0 = 0; - break; - - case SPTC_VALID: - rc0 = 1; - break; - - default: - break; - } - return rc0; + int rc0=0; + int pathMatch; + + switch (cmd) { + track_p trkN; + case SPTC_TERMINATE: + rc0 = 1; + break; + + case SPTC_MATCH: + if (EndPtIsIgnoredElev(trk,ep)) { + break; + } + if (PathListSingle()) { + if (trk == pathStartTrk && ep == pathStartEp) { + pathMatch = 2; + } else if (trk == pathEndTrk && ep == pathEndEp) { + pathMatch = 3; + } else { + break; + } + } else if ((trkN = GetTrkEndTrk(trk,ep)) == NULL) { + break; + } else { + EPINX_T epN; + epN = GetEndPtConnectedToMe(trkN, trk); + if (trkN == pathStartTrk && epN == pathStartEp) { + pathMatch = 1; + } else if (trkN == pathEndTrk && epN == pathEndEp) { + pathMatch = 2; + } else if (trkN == pathStartTrk && trkN == pathEndTrk) { + pathMatch = 2; + } else if (trkN == pathStartTrk) { + pathMatch = 1; + } else if (trkN == pathEndTrk) { + pathMatch = 2; + } else { + break; + } + } + if (profileShortestPathMatch < 0 || profileShortestPathDist > dist) { + LOG(log_shortPath, 4, (" Match=%d", pathMatch)) + profileShortestPathMatch = pathMatch; + profileShortestPathDist = dist; + } + rc0 = 1; + break; + + case SPTC_MATCHANY: + rc0 = -1; + break; + + case SPTC_IGNNXTTRK: + if (EndPtIsIgnoredElev(trk,ep)) { + rc0 = 1; + } else if ((GetTrkBits(trk)&TB_PROFILEPATH)!=0) { + rc0 = 1; + } else if ((!EndPtIsDefinedElev(trk,ep)) && GetTrkEndTrk(trk,ep)==NULL) { + rc0 = 1; + } else { + rc0 = 0; + } + break; + + case SPTC_ADD_TRK: + if (log_shortPath<=0|| + logTable(log_shortPath).level<4) LOG(log_profile, 4, (" ADD_TRK T%d:%d", + GetTrkIndex(trk), ep)) + SetTrkBits(trk, TB_PROFILEPATH); + DrawTrack(trk, &mainD, profilePathColor); + rc0 = 0; + break; + + case SPTC_VALID: + rc0 = 1; + break; + + default: + break; + } + return rc0; } static int FindProfileShortestPath( - track_p trkN, - EPINX_T epN ) + track_p trkN, + EPINX_T epN) { -LOG( log_profile, 4, ( "Searching from T%d:%d to T%d:%d or T%d:%d\n", - GetTrkIndex(trkN), epN, - pathStartTrk?GetTrkIndex(pathStartTrk):-1, pathStartTrk?pathStartEp:-1, - pathEndTrk?GetTrkIndex(pathEndTrk):-1, pathEndTrk?pathEndEp:-1 ) ) - profileShortestPathMatch = -1; - return FindShortestPath( trkN, epN, TRUE, ProfileShortestPathFunc, NULL ); + LOG(log_profile, 4, ("Searching from T%d:%d to T%d:%d or T%d:%d\n", + GetTrkIndex(trkN), epN, + pathStartTrk?GetTrkIndex(pathStartTrk):-1, pathStartTrk?pathStartEp:-1, + pathEndTrk?GetTrkIndex(pathEndTrk):-1, pathEndTrk?pathEndEp:-1)) + profileShortestPathMatch = -1; + return FindShortestPath(trkN, epN, TRUE, ProfileShortestPathFunc, NULL); } @@ -884,502 +1046,494 @@ LOG( log_profile, 4, ( "Searching from T%d:%d to T%d:%d or T%d:%d\n", #define ONPATH_END (1<<1) #define ONPATH_MID (1<<2) #define ONPATH_BRANCH (1<<3) -static int OnPath( track_p trk, EPINX_T ep ) +static int OnPath(track_p trk, EPINX_T ep) { - track_p trk0; - if ( GetTrkBits(trk)&TB_PROFILEPATH ) { - trk0 = GetTrkEndTrk( profilePopupTrk, profilePopupEp ); - if ( trk0 && (GetTrkBits(trk0)&TB_PROFILEPATH) ) { - return ONPATH_MID; - } - if ( ( trk == pathStartTrk && ep == pathStartEp ) || - ( trk == pathStartTrk && ep == pathStartEp ) ) { - return ONPATH_END; - } - return ONPATH_BRANCH; - } - return ONPATH_NOT; + if (GetTrkBits(trk)&TB_PROFILEPATH) { + track_p trk0; + trk0 = GetTrkEndTrk(profilePopupTrk, profilePopupEp); + if (trk0 && (GetTrkBits(trk0)&TB_PROFILEPATH)) { + return ONPATH_MID; + } + if (trk == pathStartTrk && ep == pathStartEp) { + return ONPATH_END; + } + return ONPATH_BRANCH; + } + return ONPATH_NOT; } -static BOOL_T PathListCheck( void ) +static BOOL_T PathListCheck(void) { - track_p trk; - if (PathListEmpty() || PathListSingle()) - return TRUE; - if (!(GetTrkBits(pathStartTrk)&TB_PROFILEPATH)) { - ErrorMessage( MSG_PST_NOT_ON_PATH ); - return FALSE; - } - if (!(GetTrkBits(pathEndTrk)&TB_PROFILEPATH)) { - ErrorMessage( MSG_PET_NOT_ON_PATH ); - return FALSE; - } - trk = GetTrkEndTrk(pathStartTrk,pathStartEp); - if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) { - ErrorMessage( MSG_INV_PST_ON_PATH ); - return FALSE; - } - trk = GetTrkEndTrk(pathEndTrk,pathEndEp); - if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) { - ErrorMessage( MSG_INV_PET_ON_PATH ); - return FALSE; - } - return TRUE; + track_p trk; + if (PathListEmpty() || PathListSingle()) { + return TRUE; + } + if (!(GetTrkBits(pathStartTrk)&TB_PROFILEPATH)) { + ErrorMessage(MSG_PST_NOT_ON_PATH); + return FALSE; + } + if (!(GetTrkBits(pathEndTrk)&TB_PROFILEPATH)) { + ErrorMessage(MSG_PET_NOT_ON_PATH); + return FALSE; + } + trk = GetTrkEndTrk(pathStartTrk,pathStartEp); + if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) { + ErrorMessage(MSG_INV_PST_ON_PATH); + return FALSE; + } + trk = GetTrkEndTrk(pathEndTrk,pathEndEp); + if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) { + ErrorMessage(MSG_INV_PET_ON_PATH); + return FALSE; + } + return TRUE; } static void RemoveTracksFromPath( - track_p *Rtrk, - EPINX_T *Rep, - track_p trkEnd, - EPINX_T epEnd ) + track_p *Rtrk, + EPINX_T *Rep, + track_p trkEnd, + EPINX_T epEnd) { - EPINX_T ep2; - track_p trk = *Rtrk, trkN; - EPINX_T ep = *Rep; - - PASSERT( "removeTracksFromPath", trk, NOP ); - PASSERT( "removeTracksFromPath", !PathListSingle(), NOP ); - while (1) { - DrawTrack( trk, &mainD, drawColorWhite ); - ClrTrkBits( trk, TB_PROFILEPATH ); - DrawTrack( trk, &mainD, drawColorBlack ); - - if (trk == trkEnd) { - pathStartTrk = trkEnd; - pathStartEp = epEnd; - pathEndTrk = GetTrkEndTrk(pathStartTrk,pathStartEp); - if (pathEndTrk) - pathEndEp = GetEndPtConnectedToMe(pathEndTrk,pathStartTrk); - return; - } - - ep2 = GetNextTrkOnPath( trk, ep ); - PASSERT( "removeTracksFromPath", ep2 >= 0,NOP ); - trkN = GetTrkEndTrk(trk,ep2); - PASSERT( "removeTracksFromPath", trkN != NULL, NOP ); - ep = GetEndPtConnectedToMe(trkN,trk); - trk = trkN; - if (EndPtIsDefinedElev(trk,ep)) { - *Rtrk = trk; - *Rep = ep; - return; - } - } + track_p trk = *Rtrk, trkN; + EPINX_T ep = *Rep; + + PASSERT("removeTracksFromPath", trk, NOP); + PASSERT("removeTracksFromPath", !PathListSingle(), NOP); + while (1) { + EPINX_T ep2; + DrawTrack(trk, &mainD, drawColorWhite); + ClrTrkBits(trk, TB_PROFILEPATH); + DrawTrack(trk, &mainD, drawColorBlack); + + if (trk == trkEnd) { + pathStartTrk = trkEnd; + pathStartEp = epEnd; + pathEndTrk = GetTrkEndTrk(pathStartTrk,pathStartEp); + if (pathEndTrk) { + pathEndEp = GetEndPtConnectedToMe(pathEndTrk,pathStartTrk); + } + return; + } + + ep2 = GetNextTrkOnPath(trk, ep); + PASSERT("removeTracksFromPath", ep2 >= 0,NOP); + trkN = GetTrkEndTrk(trk,ep2); + PASSERT("removeTracksFromPath", trkN != NULL, NOP); + ep = GetEndPtConnectedToMe(trkN,trk); + trk = trkN; + if (EndPtIsDefinedElev(trk,ep)) { + *Rtrk = trk; + *Rep = ep; + return; + } + } } -static void ChkElev( track_p trk, EPINX_T ep, EPINX_T ep2, DIST_T dist, BOOL_T * defined ) +static void ChkElev(track_p trk, EPINX_T ep, EPINX_T ep2, DIST_T dist, + BOOL_T * defined) { - profElem_p p; - station_p s; - EPINX_T epDefElev = -1, ep1; - int mode; - BOOL_T undefined; - - mode = GetTrkEndElevMode( trk, ep ); - if (mode == ELEV_DEF) { - epDefElev = ep; - } else if (mode == ELEV_STATION) { - DYNARR_APPEND( station_t, station_da, 10 ); - s = &station(station_da.cnt-1); - s->dist = dist; - s->name = GetTrkEndElevStation(trk,ep); - } - undefined = FALSE; - if (epDefElev<0) { - if ( (trk == pathStartTrk && ep == pathStartEp) || - (trk == pathEndTrk && ep == pathEndEp) ) { - epDefElev = ep; - } - } - if (epDefElev<0) { - if (ep == ep2 || - GetTrkEndElevMode(trk,ep2) != ELEV_DEF ) - for ( ep1=0; ep1=0) { - DYNARR_APPEND( profElem_t, profElem_da, 10 ); - p = &profElem(profElem_da.cnt-1); - p->trk = trk; - p->ep = epDefElev; - p->dist = dist; - if (GetTrkEndElevMode(trk,epDefElev) == ELEV_DEF) - p->elev = GetTrkEndElevHeight(trk,epDefElev); - else - ComputeElev( trk, epDefElev, TRUE, &p->elev, NULL ); - p->defined = *defined; - *defined = TRUE; - } else if (undefined) { - *defined = FALSE; - } + profElem_p p; + station_p s; + EPINX_T epDefElev = -1; + int mode; + BOOL_T undefined; + + mode = GetTrkEndElevMode(trk, ep); + if (mode == ELEV_DEF) { + epDefElev = ep; + } else if (mode == ELEV_STATION) { + DYNARR_APPEND(station_t, station_da, 10); + s = &station(station_da.cnt-1); + s->dist = dist; + s->name = GetTrkEndElevStation(trk,ep); + } + undefined = FALSE; + if (epDefElev<0) { + if ((trk == pathStartTrk && ep == pathStartEp) || + (trk == pathEndTrk && ep == pathEndEp)) { + epDefElev = ep; + } + } + if (epDefElev<0) { + if (ep == ep2 || + GetTrkEndElevMode(trk,ep2) != ELEV_DEF) + for (EPINX_T ep1=0; ep1=0) { + DYNARR_APPEND(profElem_t, profElem_da, 10); + p = &profElem(profElem_da.cnt-1); + p->trk = trk; + p->ep = epDefElev; + p->dist = dist; + if (GetTrkEndElevMode(trk,epDefElev) == ELEV_DEF) { + p->elev = GetTrkEndElevHeight(trk,epDefElev); + } else { + ComputeElev(trk, epDefElev, TRUE, &p->elev, NULL, TRUE); + } + p->defined = *defined; + *defined = TRUE; + } else if (undefined) { + *defined = FALSE; + } } -static void ComputeProfElem( void ) +static void ComputeProfElem(void) { - track_p trk = pathStartTrk, trkN; - EPINX_T ep = pathStartEp, ep2; - BOOL_T go; - DIST_T dist; - BOOL_T defined; - - profElem_da.cnt = 0; - station_da.cnt = 0; - dist = 0; - defined = TRUE; - if (PathListEmpty()) - return; - ChkElev( trk, ep, ep, dist, &defined ); - if (PathListSingle()) - return; - go = TRUE; - while ( go ) { - if (trk == pathEndTrk) { - go = FALSE; - ep2 = pathEndEp; - } else { - ep2 = GetNextTrkOnPath( trk, ep ); - PASSERT( "computeProfElem", ep2 >= 0, NOP ); - } - dist += GetTrkLength( trk, ep, ep2 ); - ChkElev( trk, ep2, ep, dist, &defined ); - if (!go) - break; - trkN = GetTrkEndTrk(trk,ep2); - ep = GetEndPtConnectedToMe(trkN,trk); - trk = trkN; - } + track_p trk = pathStartTrk, trkN; + EPINX_T ep = pathStartEp, ep2; + BOOL_T go; + DIST_T dist; + BOOL_T defined; + + profElem_da.cnt = 0; + station_da.cnt = 0; + dist = 0; + defined = TRUE; + if (PathListEmpty()) { + return; + } + ChkElev(trk, ep, ep, dist, &defined); + if (PathListSingle()) { + return; + } + go = TRUE; + while (go) { + if (trk == pathEndTrk) { + go = FALSE; + ep2 = pathEndEp; + } else { + ep2 = GetNextTrkOnPath(trk, ep); + //PASSERT( "computeProfElem", ep2 >= 0, NOP ); + } + dist += GetTrkLength(trk, ep, ep2); + ChkElev(trk, ep2, ep, dist, &defined); + if (!go) { + break; + } + trkN = GetTrkEndTrk(trk,ep2); + ep = GetEndPtConnectedToMe(trkN,trk); + trk = trkN; + } } -static void DumpProfElems( void ) +static void DumpProfElems(void) { - track_p trk, trkN; - EPINX_T ep, ep2; - BOOL_T go; - - trk = pathStartTrk; - ep = pathStartEp; - - if (pathStartTrk==NULL) lprintf( "s--:- e--:-" ); - else if (pathEndTrk == NULL) lprintf( "sT%d:%d e--:-", GetTrkIndex(pathStartTrk), pathStartEp ); - else lprintf( "sT%d:%d eT%d:%d", GetTrkIndex(pathStartTrk), pathStartEp, GetTrkIndex(pathEndTrk), pathEndEp ); - lprintf( " { " ); - go = TRUE; - if (!PathListSingle()) - while ( trk ) { - if (trk==pathEndTrk) { - ep2 = pathEndEp; - go = FALSE; - } else { - ep2 = GetNextTrkOnPath( trk, ep ); - PASSERT( "computeProfElem", ep2 >= 0, NOP ); - } - lprintf( "T%d:%d:%d ", GetTrkIndex(trk), ep, ep2 ); - if (!go) - break; - trkN = GetTrkEndTrk(trk,ep2); - ep = GetEndPtConnectedToMe(trkN,trk); - trk = trkN; - } - lprintf( "}" ); + track_p trk, trkN; + EPINX_T ep; + BOOL_T go; + + trk = pathStartTrk; + ep = pathStartEp; + + if (pathStartTrk==NULL) { + lprintf("s--:- e--:-"); + } else if (pathEndTrk == NULL) { + lprintf("sT%d:%d e--:-", GetTrkIndex(pathStartTrk), pathStartEp); + } else { + lprintf("sT%d:%d eT%d:%d", GetTrkIndex(pathStartTrk), pathStartEp, + GetTrkIndex(pathEndTrk), pathEndEp); + } + lprintf(" { "); + go = TRUE; + if (!PathListSingle()) + while (trk) { + EPINX_T ep2; + if (trk==pathEndTrk) { + ep2 = pathEndEp; + go = FALSE; + } else { + ep2 = GetNextTrkOnPath(trk, ep); + PASSERT("computeProfElem", ep2 >= 0, NOP); + } + lprintf("T%d:%d:%d ", GetTrkIndex(trk), ep, ep2); + if (!go) { + break; + } + trkN = GetTrkEndTrk(trk,ep2); + ep = GetEndPtConnectedToMe(trkN,trk); + trk = trkN; + } + lprintf("}"); } -static void ProfileSelect( track_p trkN, EPINX_T epN ) +static void ProfileSelect(track_p trkN, EPINX_T epN) { - track_p trkP; - EPINX_T epP=-1; - int rc; - -if (log_profile>=1) { - DumpProfElems(); - lprintf( " @ T%d:%d ", GetTrkIndex(trkN), epN ); - if (log_profile>=2) lprintf("\n"); - } - -#ifdef LATER - if (!EndPtIsDefinedElev(trkN, epN)) { - ErrorMessage( MSG_EP_NOT_DEP ); - return; - } -#endif - - trkP = GetTrkEndTrk( trkN, epN ); - if (trkP) - epP = GetEndPtConnectedToMe( trkP, trkN ); - - if (!PathListCheck()) - return; - - HilightProfileElevations( FALSE ); - - if ( PathListEmpty() ) { - pathStartTrk = trkN; - pathStartEp = epN; - pathEndTrk = trkP; - pathEndEp = epP; -LOG( log_profile, 2, ("Adding first element\n") ) - - } else if ( PathListSingle() && - ( ( trkN == pathStartTrk && epN == pathStartEp ) || - ( trkP && trkP == pathStartTrk && epP == pathStartEp ) ) ) { - pathStartTrk = pathEndTrk = NULL; -LOG( log_profile, 2, ("Clearing list\n") ) - - } else if ( (trkN == pathStartTrk && epN == pathStartEp ) || - (trkP && trkP == pathStartTrk && epP == pathStartEp) ) { - RemoveTracksFromPath( &pathStartTrk, &pathStartEp, pathEndTrk, pathEndEp ); -LOG( log_profile, 2, ("Removing first element\n") ) - - } else if ( (trkN == pathEndTrk && epN == pathEndEp) || - (trkP && trkP == pathEndTrk && epP == pathEndEp) ) { - RemoveTracksFromPath( &pathEndTrk, &pathEndEp, pathStartTrk, pathStartEp ); -LOG( log_profile, 2, ("Removing last element\n") ) - - } else if ( (GetTrkBits(trkN)&TB_PROFILEPATH) || (trkP && (GetTrkBits(trkP)&TB_PROFILEPATH)) ) { - ErrorMessage( MSG_EP_ON_PATH ); - HilightProfileElevations( TRUE ); - return; - - } else if ( ( rc = FindProfileShortestPath( trkN, epN ) ) > 0 ) { - if (!(GetTrkBits(trkN)&TB_PROFILEPATH)) { - PASSERT( "profileSelect", trkP != NULL, NOP ); - trkN = trkP; - epN = epP; -LOG( log_profile, 2, ("Invert selected EP\n") ) - } - - switch (profileShortestPathMatch) { - case 1: - /* extend Start */ - pathStartTrk = trkN; - pathStartEp = epN; -LOG( log_profile, 2, ( "Prepending Path\n" ) ) - break; - case 2: - /* extend End */ - pathEndTrk = trkN; - pathEndEp = epN; -LOG( log_profile, 2, ( "Appending Path\n" ) ) - break; - case 3: - /* need to flip */ - pathStartTrk = pathEndTrk; - pathStartEp = pathEndEp; - pathEndTrk = trkN; - pathEndEp = epN; -LOG( log_profile, 2, ( "Flip/Appending Path\n" ) ) - break; - default: - AbortProg( "findPaths:1" ); - } - - } else { - ErrorMessage( MSG_NO_PATH_TO_EP ); - HilightProfileElevations( TRUE ); - return; - } - - HilightProfileElevations( TRUE ); - ComputeProfElem(); - RedrawProfileW(); - DoProfileChangeMode( NULL ); -if (log_profile>=1) { - lprintf( " = " ); - DumpProfElems(); - lprintf( "\n" ); - } - PathListCheck(); + track_p trkP; + EPINX_T epP=-1; + int rc; + + if (log_profile>=1) { + DumpProfElems(); + lprintf(" @ T%d:%d ", GetTrkIndex(trkN), epN); + if (log_profile>=2) { + lprintf("\n"); + } + } + + trkP = GetTrkEndTrk(trkN, epN); + if (trkP) { + epP = GetEndPtConnectedToMe(trkP, trkN); + } + + if (!PathListCheck()) { + return; + } + + if (PathListEmpty()) { + pathStartTrk = trkN; + pathStartEp = epN; + pathEndTrk = trkP; + pathEndEp = epP; + LOG(log_profile, 2, ("Adding first element\n")) + + } else if (PathListSingle() && + ((trkN == pathStartTrk && epN == pathStartEp) || + (trkP && trkP == pathStartTrk && epP == pathStartEp))) { + pathStartTrk = pathEndTrk = NULL; + LOG(log_profile, 2, ("Clearing list\n")) + + } else if ((trkN == pathStartTrk && epN == pathStartEp) || + (trkP && trkP == pathStartTrk && epP == pathStartEp)) { + RemoveTracksFromPath(&pathStartTrk, &pathStartEp, pathEndTrk, pathEndEp); + LOG(log_profile, 2, ("Removing first element\n")) + + } else if ((trkN == pathEndTrk && epN == pathEndEp) || + (trkP && trkP == pathEndTrk && epP == pathEndEp)) { + RemoveTracksFromPath(&pathEndTrk, &pathEndEp, pathStartTrk, pathStartEp); + LOG(log_profile, 2, ("Removing last element\n")) + + } else if ((GetTrkBits(trkN)&TB_PROFILEPATH) || (trkP && + (GetTrkBits(trkP)&TB_PROFILEPATH))) { + ErrorMessage(MSG_EP_ON_PATH); + return; + + } else if ((rc = FindProfileShortestPath(trkN, epN)) > 0) { + if (!(GetTrkBits(trkN)&TB_PROFILEPATH)) { + PASSERT("profileSelect", trkP != NULL, NOP); + trkN = trkP; + epN = epP; + LOG(log_profile, 2, ("Invert selected EP\n")) + } + + switch (profileShortestPathMatch) { + case 1: + /* extend Start */ + pathStartTrk = trkN; + pathStartEp = epN; + LOG(log_profile, 2, ("Prepending Path\n")) + break; + case 2: + /* extend End */ + pathEndTrk = trkN; + pathEndEp = epN; + LOG(log_profile, 2, ("Appending Path\n")) + break; + case 3: + /* need to flip */ + pathStartTrk = pathEndTrk; + pathStartEp = pathEndEp; + pathEndTrk = trkN; + pathEndEp = epN; + LOG(log_profile, 2, ("Flip/Appending Path\n")) + break; + default: + AbortProg("findPaths:1"); + } + + } else { + ErrorMessage(MSG_NO_PATH_TO_EP); + return; + } + + DestroyCopyOfProfileElements(); + ComputeProfElem(); + CreateCopyProfileElements(); + + RedrawProfileW(); + DoProfileChangeMode(NULL); + if (log_profile>=1) { + lprintf(" = "); + DumpProfElems(); + lprintf("\n"); + } + PathListCheck(); } -static void ProfileSubCommand( wBool_t set, void* pcmd ) +static void ProfileSubCommand(wBool_t set, void* pcmd) { - long cmd = (long)pcmd; - int mode; - coOrd pos = oldMarker; - DIST_T elev; - DIST_T radius; - - if ((profilePopupTrk = OnTrack( &pos, TRUE, TRUE )) == NULL || - (profilePopupEp = PickEndPoint( pos, profilePopupTrk )) < 0) - return; - if (profileUndo==0) { - profileUndo = TRUE; - UndoStart(_("Profile Command"), "Profile"); - } - radius = 0.05*mainD.scale; - if ( radius < trackGauge/2.0 ) - radius = trackGauge/2.0; - pos = GetTrkEndPos( profilePopupTrk, profilePopupEp ); - mode = GetTrkEndElevMode( profilePopupTrk, profilePopupEp ); - if ( (mode&ELEV_MASK)==ELEV_DEF || (mode&ELEV_MASK)==ELEV_IGNORE ) - DrawFillCircle( &tempD, pos, radius, - ((mode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore)); - if ( (mode&ELEV_MASK)==ELEV_DEF ) - - DrawEndPt2( &mainD, profilePopupTrk, profilePopupEp, drawColorWhite ); - elev = 0.0; - switch (cmd) { - case 0: - /* define */ - ComputeElev( profilePopupTrk, profilePopupEp, TRUE, &elev, NULL ); - mode = ELEV_DEF|ELEV_VISIBLE; - break; - case 1: - /* ignore */ - mode = ELEV_IGNORE|ELEV_VISIBLE; - break; - case 2: - default: - /* none */ - mode = ELEV_NONE; - break; - } - UpdateTrkEndElev( profilePopupTrk, profilePopupEp, mode, elev, NULL ); - if ( (mode&ELEV_MASK)==ELEV_DEF || (mode&ELEV_MASK)==ELEV_IGNORE ) - DrawFillCircle( &tempD, pos, radius, - ((mode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore)); - ComputeProfElem(); - RedrawProfileW(); + long cmd = (long)pcmd; + int mode; + coOrd pos = oldMarker; + DIST_T elev; + DIST_T radius; + + if ((profilePopupTrk = OnTrack(&pos, TRUE, TRUE)) == NULL || + (profilePopupEp = PickEndPoint(pos, profilePopupTrk)) < 0) { + return; + } + if (profileUndo==0) { + profileUndo = TRUE; + UndoStart(_("Profile Command"), "Profile"); + } + radius = 0.05*mainD.scale; + if (radius < trackGauge/2.0) { + radius = trackGauge/2.0; + } + pos = GetTrkEndPos(profilePopupTrk, profilePopupEp); + mode = GetTrkEndElevMode(profilePopupTrk, profilePopupEp); + + elev = 0.0; + switch (cmd) { + case 0: + /* define */ + ComputeElev(profilePopupTrk, profilePopupEp, TRUE, &elev, NULL, TRUE); + mode = ELEV_DEF|ELEV_VISIBLE; + break; + case 1: + /* ignore */ + mode = ELEV_IGNORE|ELEV_VISIBLE; + break; + case 2: + default: + /* none */ + mode = ELEV_NONE; + break; + } + UpdateTrkEndElev(profilePopupTrk, profilePopupEp, mode, elev, NULL); + ComputeProfElem(); + RedrawProfileW(); + TempRedraw(); // ProfileSubCommand } -static STATUS_T CmdProfile( wAction_t action, coOrd pos ) +static STATUS_T CmdProfile(wAction_t action, coOrd pos) { - track_p trk0; - EPINX_T ep0; - coOrd textsize; - - switch (action) { - case C_START: - if ( profileW == NULL ) { - profileColorDefinedProfile = drawColorBlue; - profileColorUndefinedProfile = drawColorRed; - profileColorFill = drawColorAqua; - DrawTextSize( &mainD, "999", wStandardFont( F_HELV, FALSE, FALSE ), screenProfileFontSize, FALSE, &textsize ); - labelH = textsize.y; - profileW = ParamCreateDialog( &profilePG, MakeWindowTitle(_("Profile")), _("Done"), DoProfileDone, (paramActionCancelProc)Reset, TRUE, NULL, F_RESIZE, NULL ); - } - ParamLoadControls( &profilePG ); - ParamGroupRecord( &profilePG ); - wShow( profileW ); - ParamLoadMessage( &profilePG, I_PROFILEMSG, _("Drag to change Elevation") ); - HilightProfileElevations( TRUE ); - profElem_da.cnt = 0; - station_da.cnt = 0; - RedrawProfileW(); - if ( ClrAllTrkBits( TB_PROFILEPATH ) ) { - MainRedraw(); - MapRedraw(); - } - pathStartTrk = NULL; - SetAllTrackSelect( FALSE ); - profileUndo = FALSE; - InfoMessage( _("Select a Defined Elevation to start profile") ); - return C_CONTINUE; - case C_LCLICK: - InfoMessage( "" ); - if ((trk0 = OnTrack( &pos, TRUE, TRUE )) != NULL) { - ep0 = PickEndPoint( pos, trk0 ); - if ( ep0 >= 0 ) { - ProfileSelect( trk0, ep0 ); - } - } - return C_CONTINUE; - case C_CMDMENU: - if ((profilePopupTrk = OnTrack( &pos, TRUE, TRUE )) != NULL ) { - profilePopupEp = PickEndPoint( pos, profilePopupTrk ); - if (profilePopupEp >= 0) { - int mode; - mode = GetTrkEndElevMode( profilePopupTrk, profilePopupEp ); - if (mode != ELEV_DEF && mode != ELEV_IGNORE && mode != ELEV_NONE ) { - ErrorMessage( MSG_CHANGE_ELEV_MODE ); - } else { - wMenuToggleEnable( profilePopupToggles[1], TRUE ); - if ( OnPath( profilePopupTrk, profilePopupEp ) & (ONPATH_END|ONPATH_MID) ) - wMenuToggleEnable( profilePopupToggles[1], FALSE ); - wMenuToggleSet( profilePopupToggles[0], mode == ELEV_DEF ); - wMenuToggleSet( profilePopupToggles[1], mode == ELEV_IGNORE ); - wMenuToggleSet( profilePopupToggles[2], mode == ELEV_NONE ); - wMenuPopupShow( profilePopupM ); - } - } - } -#ifdef LATER - InfoMessage( "" ); - if ((trk0 = OnTrack( &pos, TRUE, TRUE )) == NULL) - return C_CONTINUE; - ep0 = PickEndPoint( pos, trk0 ); - if (ep0 < 0) - return C_CONTINUE; - if (profileMode == 0) { - ; - } else { - ProfileIgnore( trk0, ep0 ); - } - DoProfileChangeMode( NULL ); -#endif - return C_CONTINUE; - case C_OK: - DoProfileDone(NULL); - return C_TERMINATE; - case C_CANCEL: - wHide(profileW); - HilightProfileElevations( FALSE ); - if (ClrAllTrkBits(TB_PROFILEPATH)) { - MainRedraw(); - MapRedraw(); - } - return C_TERMINATE; - case C_REDRAW: - if ( wWinIsVisible(profileW) ) { - HilightProfileElevations( wWinIsVisible(profileW) ); - /*RedrawProfileW();*/ - } - return C_CONTINUE; - } - return C_CONTINUE; + track_p trk0; + coOrd textsize; + + switch (action) { + case C_START: + if (profileW == NULL) { + profileColorDefinedProfile = drawColorBlue; + profileColorUndefinedProfile = drawColorRed; + profileColorFill = drawColorGrey80; + DrawTextSize(&mainD, "999.9", wStandardFont(F_HELV, FALSE, FALSE), + screenProfileFontSize, FALSE, &textsize); + labelH = textsize.y; + labelW = textsize.x; + profileW = ParamCreateDialog(&profilePG, MakeWindowTitle(_("Profile")), NULL, + NULL, wHide, TRUE, NULL, F_RESIZE, CloseProfileWindow); + } + ParamLoadControls(&profilePG); + ParamGroupRecord(&profilePG); + wShow(profileW); + ParamLoadMessage(&profilePG, I_PROFILEMSG, _("Drag to change Elevation")); + profElem_da.cnt = 0; + station_da.cnt = 0; + RedrawProfileW(); + ClrAllTrkBitsRedraw(TB_PROFILEPATH, TRUE); + pathStartTrk = NULL; + SetAllTrackSelect(FALSE); + profileUndo = FALSE; + InfoMessage(_("Select a Defined Elevation to start profile")); + TempRedraw(); // CmdProfile C_START + return C_CONTINUE; + case C_LCLICK: + InfoMessage(""); + if ((trk0 = OnTrack(&pos, TRUE, TRUE)) != NULL) { + EPINX_T ep0; + ep0 = PickEndPoint(pos, trk0); + if (ep0 >= 0) { + ProfileSelect(trk0, ep0); + } + } + return C_CONTINUE; + case C_CMDMENU: + if ((profilePopupTrk = OnTrack(&pos, TRUE, TRUE)) != NULL) { + profilePopupEp = PickEndPoint(pos, profilePopupTrk); + if (profilePopupEp >= 0) { + int mode; + mode = GetTrkEndElevMode(profilePopupTrk, profilePopupEp); + if (mode != ELEV_DEF && mode != ELEV_IGNORE && mode != ELEV_NONE) { + ErrorMessage(MSG_CHANGE_ELEV_MODE); + } else { + wMenuToggleEnable(profilePopupToggles[1], TRUE); + if (OnPath(profilePopupTrk, profilePopupEp) & (ONPATH_END|ONPATH_MID)) { + wMenuToggleEnable(profilePopupToggles[1], FALSE); + } + wMenuToggleSet(profilePopupToggles[0], mode == ELEV_DEF); + wMenuToggleSet(profilePopupToggles[1], mode == ELEV_IGNORE); + wMenuToggleSet(profilePopupToggles[2], mode == ELEV_NONE); + menuPos = pos; + wMenuPopupShow(profilePopupM); + } + } + } + return C_CONTINUE; + case C_OK: + DoProfileDone(NULL); + return C_TERMINATE; + case C_CANCEL: + wHide(profileW); + ClrAllTrkBitsRedraw(TB_PROFILEPATH, TRUE); + return C_TERMINATE; + case C_REDRAW: + if (wWinIsVisible(profileW)) { + HilightProfileElevations(wWinIsVisible(profileW)); + } + return C_CONTINUE; + } + return C_CONTINUE; } -static void ProfileChange( long changes ) +static void ProfileChange(long changes) { - if ( (changes & CHANGE_UNITS) && screenProfileD.d ) - RedrawProfileW(); + if ((changes & CHANGE_UNITS) && screenProfileD.d) { + RedrawProfileW(); + } } - #include "bitmaps/profile.xpm" -EXPORT void InitCmdProfile( wMenu_p menu ) +EXPORT void InitCmdProfile(wMenu_p menu) { - log_profile = LogFindIndex( "profile" ); - ParamRegister( &profilePG ); -#ifdef LATER - AddPlaybackProc( "PROFILEMOUSE", (playbackProc_p)profilePlayback, NULL ); -#endif - AddMenuButton( menu, CmdProfile, "cmdProfile", _("Profile"), wIconCreatePixMap(profile_xpm), LEVEL0_50, IC_LCLICK|IC_CMDMENU|IC_POPUP2, ACCL_PROFILE, NULL ); - profilePopupM = MenuRegister( "Profile Mode" ); - profilePopupToggles[0] = wMenuToggleCreate( profilePopupM, "", _("Define"), 0, FALSE, ProfileSubCommand, (void*)0 ); - profilePopupToggles[1] = wMenuToggleCreate( profilePopupM, "", _("Ignore"), 0, FALSE, ProfileSubCommand, (void*)1 ); - profilePopupToggles[2] = wMenuToggleCreate( profilePopupM, "", _("None"), 0, FALSE, ProfileSubCommand, (void*)2 ); - RegisterChangeNotification( ProfileChange ); + log_profile = LogFindIndex("profile"); + ParamRegister(&profilePG); + + AddMenuButton(menu, CmdProfile, "cmdProfile", _("Profile"), + wIconCreatePixMap(profile_xpm), LEVEL0_50, IC_LCLICK|IC_CMDMENU|IC_POPUP3, + ACCL_PROFILE, NULL); + profilePopupM = MenuRegister("Profile Mode"); + profilePopupToggles[0] = wMenuToggleCreate(profilePopupM, "", _("Define"), 0, + FALSE, ProfileSubCommand, (void*)0); + profilePopupToggles[1] = wMenuToggleCreate(profilePopupM, "", _("Ignore"), 0, + FALSE, ProfileSubCommand, (void*)1); + profilePopupToggles[2] = wMenuToggleCreate(profilePopupM, "", _("None"), 0, + FALSE, ProfileSubCommand, (void*)2); + RegisterChangeNotification(ProfileChange); } diff --git a/app/bin/cpull.c b/app/bin/cpull.c index d7f7c80..7f27864 100644 --- a/app/bin/cpull.c +++ b/app/bin/cpull.c @@ -60,6 +60,9 @@ static dynArr_t section_da; #define section(N) DYNARR_N( section_t, section_da, N ) static double contribL, contribR; +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) + typedef enum { freeEnd, connectedEnd, loopEnd } ending_e; @@ -452,12 +455,15 @@ static void PullTracks( int cnt1, cnt2; int rc; - if (QueryTrack(trk1,Q_CAN_ADD_ENDPOINTS) || QueryTrack(trk2,Q_CAN_ADD_ENDPOINTS)) { + if (QueryTrack(trk1,Q_CAN_ADD_ENDPOINTS)) { ConnectTurntableTracks(trk1, ep1, trk2, ep2 ); return; + } else if (QueryTrack(trk2,Q_CAN_ADD_ENDPOINTS)) { + ConnectTurntableTracks(trk2, ep2, trk1, ep1 ); + return; } - if (ep1<0 || ep1<0 ) return; + if (ep1<0 || ep2<0 ) return; if (ConnectAbuttingTracks( trk1, ep1, trk2, ep2 )) return; @@ -589,57 +595,202 @@ printf("T%d [%0.3f %0.3f %0.3f]\n", GetTrkIndex(trk1), p1.x, p1.y, a1 ); InfoMessage( _("%d tracks moved"), cnt ); } +static void CreateConnectAnchor(EPINX_T ep, track_p t, BOOL_T shift) { + coOrd pos = GetTrkEndPos(t,ep); + DIST_T d = tempD.scale*0.15; + DIST_T w = tempD.scale/tempD.dpi*4; + ANGLE_T a = GetTrkEndAngle(t,ep); + int i; + if (!shift) { + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.l.pos[0] = pos; + Translate(&anchors(i).u.l.pos[1],pos,a+90,-GetTrkGauge(t)); + Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a,-d); + anchors(i).width = w; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.l.pos[0] = pos; + Translate(&anchors(i).u.l.pos[1],pos,a+90,GetTrkGauge(t)); + Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a,-d); + anchors(i).width = w; + } else { + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).color = wDrawColorBlue; + Translate(&anchors(i).u.l.pos[0],pos,a+90,GetTrkGauge(t)); + Translate(&anchors(i).u.l.pos[0],anchors(i).u.l.pos[0],a,d); + Translate(&anchors(i).u.l.pos[1],pos,a+90,-GetTrkGauge(t)); + Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a,-d); + anchors(i).width = w; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).color = wDrawColorBlue; + Translate(&anchors(i).u.l.pos[0],pos,a+90,GetTrkGauge(t)); + Translate(&anchors(i).u.l.pos[0],anchors(i).u.l.pos[0],a,-d); + Translate(&anchors(i).u.l.pos[1],pos,a+90,-GetTrkGauge(t)); + Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a,d); + anchors(i).width = w; + } +} + +STATUS_T ConnectMultiple() { + int countTracksR0 =0,countTracksR1 =0, possibleEndPoints =0; + if (selectedTrackCount==0) { + ErrorMessage(_("Connect Multiple Tracks - Select multiple tracks to join first")); + return C_CONTINUE; + } + if (NoticeMessage(_("Try to Connect all Selected Tracks?"), _("Yes"), _("No"))<=0) return C_CONTINUE; + track_p trk1 = NULL; + track_p trk2 = NULL; + EPINX_T ep1,ep2; + ANGLE_T a; + DIST_T d; + UndoStart( _("ReConnect"),"Try to reconnect all selected tracks"); + for (int i=0;i<2;i++) { // Try twice - in case later joins help earlier ones and to try close ones first + while ( TrackIterate( &trk1 ) ) { + BOOL_T found = FALSE; + if ( GetTrkSelected( trk1 ) ) { + for (ep1=0; ep10 && (d<3.0 && a<7.5))) { // Match PullTracks criteria in round 2 + PullTracks(trk1,ep1,trk2,ep2); + if (GetTrkEndTrk( trk2, ep2 )) { + found = TRUE; + if (i==0) + countTracksR0++; + else + countTracksR1++; + break; //Stop looking + } else if (i==1) possibleEndPoints++; + } + } + } + if (found) break; //Next EndPoint + } + } + } + } + } + UndoEnd(); + NoticeMessage(_("Round 1 %d and Round 2 %d tracks connected, %d close pairs of end Points were not connected"), _("Ok"), NULL, countTracksR0, countTracksR1, possibleEndPoints); + return C_TERMINATE; +} + +static wMenu_p pullPopupM; static STATUS_T CmdPull( wAction_t action, coOrd pos ) { - static track_p trk1; - static EPINX_T ep1; + static track_p trk1, t1, t2; + static BOOL_T t_turn1, t_turn2; + static EPINX_T ep1, t_ep1, t_ep2; track_p trk2; EPINX_T ep2; static BOOL_T turntable; int countTracksR0 = 0, countTracksR1 = 0, possibleEndPoints = 0; BOOL_T found = FALSE; - ANGLE_T a; - DIST_T d; - switch (action) { + switch (action&0xFF) { case C_START: if (selectedTrackCount==0) - InfoMessage( _("Select first end-point to connect") ); + InfoMessage( _("Select first endpoint or turntable to connect, +Shift to tighten") ); else - InfoMessage( _("Select first end-point to connect, or Right-Click for connecting selected tracks") ); + InfoMessage( _("Select first endpoint to connect, or Right-Click for connecting selected tracks (not turntable)") ); trk1 = NULL; turntable = FALSE; + t1 = t2 = NULL; + t_turn1 = t_turn2 = FALSE; return C_CONTINUE; + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if ((MyGetKeyState() & WKEY_SHIFT) == 0 ) { + if (trk1 == NULL) { + if ((t1= OnTrack( &pos, FALSE, TRUE )) != NULL) { + if ((t_ep1 = PickUnconnectedEndPointSilent( pos, t1 )) < 0) { + if (QueryTrack(t1, Q_CAN_ADD_ENDPOINTS)) { + DrawTrack(t1,&mainD,wDrawColorBlue); + t_turn1 = TRUE; + } else t1 = NULL; + } + if (t1 && t_ep1 >=0) + CreateConnectAnchor(t_ep1,t1,FALSE); + } + } else { + if (t1 != NULL) { + if (t_turn1) DrawTrack(t1,&mainD,wDrawColorBlue); + else CreateConnectAnchor(t_ep1,t1,FALSE); + } + if ((t2= OnTrackIgnore( &pos, FALSE, TRUE, t1 )) != NULL) { + if ((t_ep2 = PickUnconnectedEndPointSilent( pos, t2 )) < 0) { + if (QueryTrack(t2, Q_CAN_ADD_ENDPOINTS)) { + DrawTrack(t2,&mainD,wDrawColorBlue); + t_turn2 = TRUE; + } else t2 = NULL; + } + if (t2 && t_ep2 >=0) + CreateConnectAnchor(t_ep2,t2,FALSE); + } + + } + } else { //Shift, tighten + t1 = OnTrack( &pos, FALSE, TRUE ); + if (t1 == NULL) + return C_CONTINUE; + t_ep1 = PickUnconnectedEndPointSilent( pos, t1 ); + if ( t_ep1 < 0 ) + return C_CONTINUE; + CreateConnectAnchor(t_ep1,t1,TRUE); + } + break; + case C_LCLICK: - if ( (MyGetKeyState() & WKEY_SHIFT) == 0 ) { + if ( (MyGetKeyState() & WKEY_SHIFT) == 0 ) { //No shift - try and join if (trk1 == NULL) { - if ((trk1 = OnTrack( &pos, TRUE, FALSE )) != NULL) { + if ((trk1 = OnTrack( &pos, TRUE, TRUE )) != NULL) { if ((ep1 = PickUnconnectedEndPoint( pos, trk1 )) < 0) { if (QueryTrack(trk1, Q_CAN_ADD_ENDPOINTS)) { turntable = TRUE; ep1 = -1; } else trk1 = NULL; } else { - InfoMessage( _("Select second end-point to connect") ); + InfoMessage( _("Select second endpoint or turntable to connect") ); } } } else { - if ((trk2 = OnTrack( &pos, TRUE, FALSE )) != NULL) { + if ((trk2 = OnTrackIgnore( &pos, TRUE, TRUE, trk1 )) != NULL) { + if (trk2 == trk1) { + InfoMessage( _("Same Track! - please select another") ); + return C_CONTINUE; + } if ((ep2 = PickUnconnectedEndPoint( pos, trk2 )) >= 0 ) { PullTracks( trk1, ep1, trk2, ep2 ); trk1 = NULL; inError = TRUE; return C_TERMINATE; } - if (!turntable && QueryTrack(trk2, Q_CAN_ADD_ENDPOINTS)) { + if (!turntable && QueryTrack(trk2, Q_CAN_ADD_ENDPOINTS)) { /*Second end a turntable */ ep2 = -1; turntable = TRUE; PullTracks( trk2, ep2, trk1, ep1); @@ -651,7 +802,7 @@ static STATUS_T CmdPull( } } } else { - trk1 = OnTrack( &pos, TRUE, FALSE ); + trk1 = OnTrack( &pos, TRUE, TRUE ); if (trk1 == NULL) return C_CONTINUE; ep1 = PickUnconnectedEndPoint( pos, trk1 ); @@ -664,56 +815,23 @@ static STATUS_T CmdPull( } return C_CONTINUE; - case C_RCLICK: - if (selectedTrackCount==0) { - ErrorMessage(_("Connect Multiple Tracks - Select multiple tracks to join first")); - return C_CONTINUE; - } - if (NoticeMessage(_("Try to Connect all Selected Tracks?"), _("Yes"), _("No"))<=0) return C_CONTINUE; - trk1 = NULL; - trk2 = NULL; - UndoStart( _("ReConnect"),"Try to reconnect all selected tracks"); - for (int i=0;i<2;i++) { // Try twice - in case later joins help earlier ones and to try close ones first - while ( TrackIterate( &trk1 ) ) { - found = FALSE; - if ( GetTrkSelected( trk1 ) ) { - for (ep1=0; ep10 && (d<3.0 && a<7.5))) { // Match PullTracks criteria in round 2 - PullTracks(trk1,ep1,trk2,ep2); - if (GetTrkEndTrk( trk2, ep2 )) { - found = TRUE; - if (i==0) - countTracksR0++; - else - countTracksR1++; - break; //Stop looking - } else if (i==1) possibleEndPoints++; - } - } - } - if (found) break; //Next EndPoint - } - } - } - } - } - UndoEnd(); - NoticeMessage(_("Round 1 %d and Round 2 %d tracks connected, %d close pairs of end Points were not connected"), _("Ok"), NULL, countTracksR0, countTracksR1, possibleEndPoints); - return C_TERMINATE; - case C_REDRAW: + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + if (t1 && t_turn1) + DrawTrack(t1,&tempD,wDrawColorBlue); + if (t2 && t_turn2) + DrawTrack(t2,&tempD,wDrawColorBlue); return C_CONTINUE; + case C_TEXT: + if (action>>8 == 'S') { + wBool_t rc = ConnectMultiple(); + MainRedraw(); // CmdPull: ConnectMultiple + return rc; + } + break; + case C_CANCEL: return C_TERMINATE; @@ -723,16 +841,35 @@ static STATUS_T CmdPull( case C_CONFIRM: return C_CONTINUE; + case C_CMDMENU: + menuPos = pos; + wMenuPopupShow( pullPopupM ); + return C_CONTINUE; + break; + + default: return C_CONTINUE; } + return C_CONTINUE; } #include "bitmaps/pull.xpm" +wMenuPush_p pullConnectMultiple; + +void pullMenuEnter(int key) { + int action; + action = C_TEXT; + action |= key<<8; + CmdPull(action,zero); +} + void InitCmdPull( wMenu_p menu ) { - AddMenuButton( menu, CmdPull, "cmdConnect", _("Connect Two Tracks"), wIconCreatePixMap(pull_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP2|IC_RCLICK, ACCL_CONNECT, NULL ); + AddMenuButton( menu, CmdPull, "cmdConnect", _("Connect Two Tracks"), wIconCreatePixMap(pull_xpm), LEVEL0_50, IC_STICKY|IC_INITNOTSTICKY|IC_LCLICK|IC_POPUP3|IC_CMDMENU|IC_WANT_MOVE, ACCL_CONNECT, NULL ); + pullPopupM = MenuRegister( "Connect Options" ); + pullConnectMultiple = wMenuPushCreate( pullPopupM, "", _("Connect All Selected - 'S'"), 0, (wMenuCallBack_p)pullMenuEnter, (void*) 'S'); } diff --git a/app/bin/cruler.c b/app/bin/cruler.c index b1addc6..d3f2926 100644 --- a/app/bin/cruler.c +++ b/app/bin/cruler.c @@ -62,43 +62,34 @@ static STATUS_T CmdRuler( wAction_t action, coOrd pos ) case C_START: switch (Dr.state) { case DR_OFF: - DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); Dr.state = DR_ON; InfoMessage( "%s", FormatDistance( FindDistance( Dr.pos0, Dr.pos1 ) ) ); break; case DR_ON: - DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); Dr.state = DR_OFF; break; } - MainRedraw(); return C_CONTINUE; case C_DOWN: - if (Dr.state == DR_ON) { - DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); - } Dr.pos0 = Dr.pos1 = pos; Dr.state = DR_ON; - DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); InfoMessage( "0.0" ); - MainRedraw(); return C_CONTINUE; case C_MOVE: - DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); Dr.pos1 = pos; - DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); InfoMessage( "%s", FormatDistance( FindDistance( Dr.pos0, Dr.pos1 ) ) ); - MainRedraw(); return C_CONTINUE; case C_UP: inError = TRUE; - MainRedraw(); return C_TERMINATE; case C_REDRAW: + if (Dr.state == DR_ON) { + DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); + } return C_CONTINUE; case C_CANCEL: @@ -126,21 +117,22 @@ STATUS_T ModifyRuler( return C_ERROR; } case C_MOVE: - DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); if ( Dr.modifyingEnd == 0 ) { Dr.pos0 = pos; } else { Dr.pos1 = pos; } - DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); InfoMessage( "%s", FormatDistance( FindDistance( Dr.pos0, Dr.pos1 ) ) ); - MainRedraw(); return C_CONTINUE; case C_UP: return C_CONTINUE; + case C_REDRAW: + DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack ); + break; default: return C_ERROR; } + return C_CONTINUE; } diff --git a/app/bin/cselect.c b/app/bin/cselect.c index 8ff68c0..4e4e8eb 100644 --- a/app/bin/cselect.c +++ b/app/bin/cselect.c @@ -23,9 +23,11 @@ #include #include +#include "draw.h" #include "ccurve.h" #include "tcornu.h" #include "tbezier.h" +#include "track.h" #define PRIVATE_EXTRADATA #include "compound.h" #include "cselect.h" @@ -38,6 +40,10 @@ #include "param.h" #include "track.h" #include "utility.h" +#include "draw.h" +#include "misc.h" +#include "trackx.h" + #include "bitmaps/bmendpt.xbm" #include "bitmaps/bma0.xbm" @@ -59,10 +65,12 @@ struct extraData { char junk[2000]; }; static wDrawBitMap_p endpt_bm; static wDrawBitMap_p angle_bm[4]; +track_p IsInsideABox(coOrd pos); + +static track_p moveDescTrk; +static coOrd moveDescPos; - long quickMove = 0; - BOOL_T importMove = 0; - int incrementalDrawLimit = 20; +int incrementalDrawLimit = 20; static int microCount = 0; static dynArr_t tlist_da; @@ -71,12 +79,169 @@ static dynArr_t tlist_da; #define TlistAppend( T ) \ { DYNARR_APPEND( track_p, tlist_da, 10 );\ Tlist(tlist_da.cnt-1) = T; } -static track_p *tlist2 = NULL; + +BOOL_T TListSearch(track_p T) { + for (int i=0;i 0 && selectedTrackCount == 0 ) + if ( inx > 0 && (selectedTrackCount == 0) && !display_only ) return; trk = Tlist(inx); if (inx!=0 && - GetTrkSelected(trk)) + GetTrkSelected(trk)) { + if (display_only) + DrawTrack(trk,&tempD,wDrawColorPreviewSelected ); + continue; + } else if (GetTrkSelected(trk)) { + if (display_only) + DrawTrack(trk,&tempD,wDrawColorPreviewUnselected); continue; + } for (ep=0; ep0) { @@ -341,6 +669,7 @@ EXPORT void SelectDelete( void ) wDrawDelayUpdate( mainD.d, TRUE ); wDrawDelayUpdate( mapD.d, TRUE ); DoSelectedTracks( DeleteTrack ); + DoRedraw(); // SelectDelete wDrawDelayUpdate( mainD.d, FALSE ); wDrawDelayUpdate( mapD.d, FALSE ); selectedTrackCount = 0; @@ -368,8 +697,10 @@ static BOOL_T FlipHidden( track_p trk, BOOL_T junk ) if ( drawTunnel == 0 ) flipHiddenDoSelectRecount = TRUE; if (GetTrkVisible(trk)) { - ClrTrkBits( trk, TB_VISIBLE|(drawTunnel==0?TB_SELECTED:0) ); - } else { + ClrTrkBits( trk, TB_VISIBLE|(drawTunnel==0?(TB_SELECTED|TB_SELREDRAW):0) ); + ClrTrkBits (trk, TB_BRIDGE); + ClrTrkBits (trk, TB_NOTIES); +; } else { SetTrkBits( trk, TB_VISIBLE ); } /*DrawNewTrack( trk );*/ @@ -382,6 +713,29 @@ static BOOL_T FlipHidden( track_p trk, BOOL_T junk ) return TRUE; } +static BOOL_T FlipBridge( track_p trk, BOOL_T junk ) +{ + UndoModify( trk ); + if (GetTrkBridge(trk)) { + ClrTrkBits( trk, TB_BRIDGE ); + } else { + SetTrkBits( trk, TB_BRIDGE ); + SetTrkBits( trk, TB_VISIBLE); + } + return TRUE; +} + +static BOOL_T FlipTies( track_p trk, BOOL_T junk ) +{ + UndoModify( trk ); + if (GetTrkNoTies(trk)) { + ClrTrkBits( trk, TB_NOTIES ); + } else { + SetTrkBits( trk, TB_NOTIES ); + SetTrkBits( trk, TB_VISIBLE ); + } + return TRUE; +} EXPORT void SelectTunnel( void ) { @@ -401,6 +755,39 @@ EXPORT void SelectTunnel( void ) SelectRecount(); } +EXPORT void SelectBridge( void ) +{ + if (SelectedTracksAreFrozen()) + return; + if (selectedTrackCount>0) { + flipHiddenDoSelectRecount = FALSE; + UndoStart( _("Bridge Tracks "), "bridge" ); + wDrawDelayUpdate( mainD.d, TRUE ); + DoSelectedTracks( FlipBridge ); + wDrawDelayUpdate( mainD.d, FALSE ); + UndoEnd(); + } else { + ErrorMessage( MSG_NO_SELECTED_TRK ); + } + MainRedraw(); // SelectBridge +} + +EXPORT void SelectTies( void ) +{ + if (SelectedTracksAreFrozen()) + return; + if (selectedTrackCount>0) { + flipHiddenDoSelectRecount = FALSE; + UndoStart( _("Ties Tracks "), "noties" ); + wDrawDelayUpdate( mainD.d, TRUE ); + DoSelectedTracks( FlipTies ); + wDrawDelayUpdate( mainD.d, FALSE ); + UndoEnd(); + } else { + ErrorMessage( MSG_NO_SELECTED_TRK ); + } + MainRedraw(); // SelectTies +} void SelectRecount( void ) { @@ -445,6 +832,7 @@ EXPORT void SelectCurrentLayer( void ) SelectOneTrack( trk, TRUE ); } } + RedrawSelectedTracksBoundary(); } @@ -530,8 +918,7 @@ EXPORT void DoRefreshCompound( void ) DoSelectedTracks( RefreshCompound ); RefreshCompound( NULL, FALSE ); UndoEnd(); - MainRedraw(); - MapRedraw(); + MainRedraw(); // DoRefreshCompound } else { ErrorMessage( MSG_NO_SELECTED_TRK ); } @@ -539,15 +926,12 @@ EXPORT void DoRefreshCompound( void ) static drawCmd_t tempSegsD = { - NULL, &tempSegDrawFuncs, DC_GROUP, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix }; + NULL, &tempSegDrawFuncs, 0, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix }; EXPORT void WriteSelectedTracksToTempSegs( void ) { track_p trk; - long oldOptions; DYNARR_RESET( trkSeg_t, tempSegs_da ); tempSegsD.dpi = mainD.dpi; - oldOptions = tempSegDrawFuncs.options; - tempSegDrawFuncs.options = wDrawOptTemp; for ( trk=NULL; TrackIterate(&trk); ) { if ( GetTrkSelected( trk ) ) { if ( IsTrack( trk ) ) @@ -557,7 +941,6 @@ EXPORT void WriteSelectedTracksToTempSegs( void ) SetTrkBits( trk, TB_SELECTED ); } } - tempSegDrawFuncs.options = oldOptions; } static char rescaleFromScale[20]; @@ -619,6 +1002,7 @@ static BOOL_T RescaleDoIt( track_p trk, BOOL_T junk ) { EPINX_T ep, ep1; track_p trk1; + UndrawNewTrack( trk ); UndoModify(trk); if ( rescalePercent != 100.0 ) { for (ep=0; eporig, d->size, lo, hi ) ) continue; } + if (color != wDrawColorWhite) + ClrTrkBits(trk, TB_UNDRAWN); DrawTrack( trk, d, color ); + if (color == wDrawColorWhite) + SetTrkBits( trk, TB_UNDRAWN ); } /*wDrawDelayUpdate( d->d, FALSE );*/ } @@ -865,7 +1221,7 @@ static ANGLE_T moveAngle; static coOrd moveD_hi, moveD_lo; static drawCmd_t moveD = { - NULL, &tempDrawFuncs, DC_SIMPLE, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix }; + NULL, &tempSegDrawFuncs, DC_SIMPLE, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix }; @@ -884,61 +1240,56 @@ static void AccumulateTracks( void ) coOrd lo, hi; /*wDrawDelayUpdate( moveD.d, TRUE );*/ - if (quickMove == MOVE_FAST) - moveD.options |= DC_QUICK; - for ( inx = 0; inx= moveD_lo.x && - lo.y <= moveD_hi.y && hi.y >= moveD_lo.y ) { - if (quickMove != MOVE_QUICK) { -#if defined(WINDOWS) && ! defined(WIN32) - if ( tempSegs_da.cnt+100 > 65500 / sizeof(*(trkSeg_p)NULL) ) { - ErrorMessage( MSG_TOO_MANY_SEL_TRKS ); - - quickMove = MOVE_QUICK; - } else -#endif - DrawTrack( trk, &moveD, wDrawColorBlack ); - } - tlist2[inx] = NULL; - movedCnt++; + movedCnt =0; + for ( inx = 0; inx= moveD_lo.x && + lo.y <= moveD_hi.y && hi.y >= moveD_lo.y ) { + if (!QueryTrack(trk,Q_IS_CORNU)) + DrawTrack( trk, &moveD, wDrawColorBlack ); } + movedCnt++; } - } - moveD.options &= ~DC_QUICK; + } InfoCount( movedCnt ); /*wDrawDelayUpdate( moveD.d, FALSE );*/ } +static void AddEndCornus() { + for (int i=0;i=0;j--) { + tc = GetTrkEndTrk(trk,j); + if (tc && !GetTrkSelected(tc) && QueryTrack(tc,Q_IS_CORNU) && !QueryTrack(trk,Q_IS_CORNU)) { //On end and cornu + SelectOneTrack( tc, TRUE ); + DYNARR_APPEND(track_p,tlist_da,1); //Add to selected list + DYNARR_LAST(track_p,tlist_da) = tc; + } + } + } +} + static void GetMovedTracks( BOOL_T undraw ) { - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); DYNARR_RESET( track_p, tlist_da ); DoSelectedTracks( AddSelectedTrack ); - tlist2 = (track_p*)MyRealloc( tlist2, (tlist_da.cnt+1) * sizeof *(track_p*)0 ); - if (tlist_da.ptr) - memcpy( tlist2, tlist_da.ptr, (tlist_da.cnt) * sizeof *(track_p*)0 ); - tlist2[tlist_da.cnt] = NULL; + AddEndCornus(); //Include Cornus that are attached at ends of selected DYNARR_RESET( trkSeg_p, tempSegs_da ); - moveD = mainD; - moveD.funcs = &tempSegDrawFuncs; - moveD.options = DC_SIMPLE; - tempSegDrawFuncs.options = wDrawOptTemp; moveOrig = mainD.orig; movedCnt = 0; InfoCount(0); - wSetCursor( wCursorNormal ); + wSetCursor( mainD.d, defaultCursor ); moveD_hi = moveD_lo = mainD.orig; moveD_hi.x += mainD.size.x; moveD_hi.y += mainD.size.y; AccumulateTracks(); if (undraw) { DrawSelectedTracksD( &mainD, wDrawColorWhite ); - /*DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, - trackGauge, wDrawColorBlack );*/ } } @@ -989,48 +1340,50 @@ static void DrawMovedTracks( void ) { int inx; track_p trk; - track_p other; - EPINX_T i; - coOrd pos; - wDrawBitMap_p bm; - ANGLE_T a; - int ia; - - if ( quickMove != MOVE_QUICK) { - DrawSegs( &tempD, moveOrig, moveAngle, &tempSegs(0), tempSegs_da.cnt, - 0.0, wDrawColorBlack ); - return; - } + dynArr_t cornu_segs; + + DrawSegs( &tempD, moveOrig, moveAngle, &tempSegs(0), tempSegs_da.cnt, + 0.0, wDrawColorBlack ); + for ( inx=0; inx=0; i--) { - pos = GetTrkEndPos(trk,i); - if (!move0B) { - Rotate( &pos, zero, moveAngle ); - } - pos.x += moveOrig.x; - pos.y += moveOrig.y; - if ((other=GetTrkEndTrk(trk,i)) == NULL || - !GetTrkSelected(other)) { - bm = endpt_bm; - } else if (other != NULL && GetTrkIndex(trk) < GetTrkIndex(other)) { - a = GetTrkEndAngle(trk,i)+22.5; - if (!move0B) - a += moveAngle; - a = NormalizeAngle( a ); - if (a>=180.0) - a -= 180.0; - ia = (int)(a/45.0); - bm = angle_bm[ia]; - } else { - continue; + if (QueryTrack(trk,Q_IS_CORNU)) { + DYNARR_RESET(trkSeg_t,cornu_segs); + coOrd pos[2]; + DIST_T radius[2]; + ANGLE_T angle[2]; + coOrd center[2]; + trackParams_t trackParams; + if (GetTrackParams(PARAMS_CORNU, trk, zero, &trackParams)) { + for (int i=0;i<2;i++) { + pos[i] = trackParams.cornuEnd[i]; + center[i] = trackParams.cornuCenter[i]; + angle[i] = trackParams.cornuAngle[i]; + radius[i] = trackParams.cornuRadius[i]; + if (!GetTrkEndTrk(trk,i) || + (GetTrkEndTrk(trk,i) && GetTrkSelected(GetTrkEndTrk(trk,i)))) { + if (!move0B) { + Rotate( &pos[i], zero, moveAngle ); + Rotate( ¢er[i],zero, moveAngle ); + angle[i] = NormalizeAngle(angle[i]+moveAngle); + } + pos[i].x += moveOrig.x; + pos[i].y += moveOrig.y; + center[i].x +=moveOrig.x; + center[i].y +=moveOrig.y; + } + } + CallCornu0(&pos[0],¢er[0],&angle[0],&radius[0],&cornu_segs, FALSE); + trkSeg_p cornu_p = &DYNARR_N(trkSeg_t,cornu_segs,0); + + DrawSegsO(&tempD, trk, zero, 0.0, cornu_p,cornu_segs.cnt, + GetTrkGauge(trk), wDrawColorBlack, DTS_LEFT|DTS_RIGHT ); } - if ( !OFF_MAIND( pos, pos ) ) - DrawBitMap( &tempD, pos, bm, selectedColor ); + } + } + return; } @@ -1041,7 +1394,8 @@ static void MoveTracks( BOOL_T rotate, coOrd base, coOrd orig, - ANGLE_T angle ) + ANGLE_T angle, + BOOL_T undo) { track_p trk, trk1; EPINX_T ep, ep1; @@ -1051,48 +1405,47 @@ static void MoveTracks( DIST_T endRadius; coOrd endCenter; - wSetCursor( wCursorWait ); + wSetCursor( mainD.d, wCursorWait ); /*UndoStart( "Move/Rotate Tracks", "move/rotate" );*/ if (tlist_da.cnt <= incrementalDrawLimit) { - DrawMapBoundingBox( FALSE ); - if (eraseFirst) + if (eraseFirst) { DrawSelectedTracksD( &mainD, wDrawColorWhite ); - DrawSelectedTracksD( &mapD, wDrawColorWhite ); + DrawSelectedTracksD( &mapD, wDrawColorWhite ); + } } for ( inx=0; inx incrementalDrawLimit) { - DoRedraw(); - } else { - DrawSelectedTracksD( &mainD, wDrawColorBlack ); - DrawSelectedTracksD( &mapD, wDrawColorBlack ); - DrawMapBoundingBox( TRUE ); } - wSetCursor( wCursorNormal ); - UndoEnd(); - tempSegDrawFuncs.options = 0; + ClrAllTrkBits(TB_UNDRAWN); + DoRedraw(); + wSetCursor( mainD.d, defaultCursor ); + if (undo) UndoEnd(); InfoCount( trackCount ); } @@ -1159,7 +1528,7 @@ void MoveToJoin( angle += 180.0; angle = NormalizeAngle( angle ); GetMovedTracks( FALSE ); - MoveTracks( TRUE, TRUE, TRUE, base, orig, angle ); + MoveTracks( TRUE, TRUE, TRUE, base, orig, angle, TRUE ); UndrawNewTrack( trk0 ); UndrawNewTrack( trk1 ); ConnectTracks( trk0, ep0, trk1, ep1 ); @@ -1176,6 +1545,145 @@ void FreeTempStrings() { } } } + + +wBool_t FindEndIntersection(coOrd base, coOrd orig, ANGLE_T angle, track_p * t1, EPINX_T * ep1, track_p * t2, EPINX_T * ep2) { + *ep1 = -1; + *ep2 = -1; + *t1 = NULL; + *t2 = NULL; + for ( int inx=0; inx=0) { + DIST_T d = FindDistance(pos1,GetTrkEndPos(tt,epp)); + if (IsClose(d)) { + *ep1 = epp; + *ep2 = i; + *t1 = tt; + *t2 = ts; + return TRUE; + } + } else { + epp = PickEndPoint(pos2,tt); //Any close end point (even joined) + if (epp>=0) { + ct = GetTrkEndTrk(tt,epp); + if (ct && GetTrkSelected(ct)) { //Point is junction to selected track - so will be broken + DIST_T d = FindDistance(pos1,GetTrkEndPos(tt,epp)); + if (IsClose(d)) { + *ep1 = epp; + *ep2 = i; + *t1 = tt; + *t2 = ts; + return TRUE; + } + } + } + } + } + } + } + } + return FALSE; +} + +void DrawHighlightLayer(int layer) { + track_p ts = NULL; + BOOL_T initial = TRUE; + coOrd layer_hi = zero,layer_lo = zero; + while ( TrackIterate( &ts ) ) { + if ( !GetLayerVisible( GetTrkLayer( ts))) continue; + if (!GetTrkSelected(ts)) continue; + if (GetTrkLayer(ts) != layer) continue; + coOrd hi,lo; + GetBoundingBox(ts, &hi, &lo); + if (initial) { + layer_hi = hi; + layer_lo = lo; + initial = FALSE; + } else { + if (layer_hi.x < hi.x ) layer_hi.x = hi.x; + if (layer_hi.y < hi.y ) layer_hi.y = hi.y; + if (layer_lo.x > lo.x ) layer_lo.x = lo.x; + if (layer_lo.y > lo.y ) layer_lo.y = lo.y; + } + } + wPos_t margin = (wPos_t)(10.5*mainD.scale/mainD.dpi); + layer_hi.x +=margin; + layer_hi.y +=margin; + layer_lo.x -=margin; + layer_lo.y -=margin; + + wPos_t rect[4][2]; + int type[4]; + coOrd top_left, bot_right; + top_left.x = layer_lo.x; top_left.y = layer_hi.y; + bot_right.x = layer_hi.x; bot_right.y = layer_lo.y; + type[0] = type[1] = type[2] = type[3] = 0; + mainD.CoOrd2Pix(&mainD,layer_lo,&rect[0][0],&rect[0][1]); + mainD.CoOrd2Pix(&mainD,top_left,&rect[1][0],&rect[1][1]); + mainD.CoOrd2Pix(&mainD,layer_hi,&rect[2][0],&rect[2][1]); + mainD.CoOrd2Pix(&mainD,bot_right,&rect[3][0],&rect[3][1]); + wDrawPolygon(tempD.d,rect,(wPolyLine_e *)type,4,wDrawColorPowderedBlue,0,wDrawLineDash,wDrawOptTemp,0,0); +} + +void SetUpMenu2(coOrd pos, track_p trk) { + wMenuPushEnable( menuPushModify,FALSE); + wMenuPushEnable(descriptionMI,FALSE); + wMenuPushEnable( rotateAlignMI, FALSE ); + wMenuPushEnable( hideMI, FALSE ); + wMenuPushEnable( bridgeMI, FALSE ); + wMenuPushEnable( tiesMI, FALSE ); + if ((trk) && + QueryTrack(trk,Q_CAN_ADD_ENDPOINTS)) { //Turntable snap to center if within 1/4 radius + trackParams_t trackParams; + if (GetTrackParams(PARAMS_CORNU, trk, pos, &trackParams)) { + DIST_T dist = FindDistance(pos, trackParams.ttcenter); + if (dist < trackParams.ttradius/4) { + cmdMenuPos = trackParams.ttcenter; + } + } + } + if (trk && !QueryTrack( trk, Q_IS_DRAW )) { + wMenuPushEnable( hideMI, TRUE ); + wMenuPushEnable( bridgeMI, TRUE ); + wMenuPushEnable( tiesMI, TRUE ); + } + if (trk) { + wMenuPushEnable( menuPushModify, + (QueryTrack( trk, Q_CAN_MODIFY_CONTROL_POINTS ) || + QueryTrack( trk, Q_IS_CORNU ) || + (QueryTrack( trk, Q_IS_DRAW ) && !QueryTrack( trk, Q_IS_TEXT )) || + QueryTrack( trk, Q_IS_ACTIVATEABLE))); + } + if ((trk)) { + wMenuPushEnable(descriptionMI, QueryTrack( trk, Q_HAS_DESC )); + moveDescTrk = trk; + moveDescPos = pos; + } + if (selectedTrackCount>0) + wMenuPushEnable( rotateAlignMI, TRUE ); +} + static STATUS_T CmdMove( wAction_t action, @@ -1185,9 +1693,16 @@ static STATUS_T CmdMove( static coOrd orig; static int state; - switch( action&0xFF) { + static EPINX_T ep1; + static EPINX_T ep2; + static track_p t1; + static track_p t2; + static BOOL_T doingMove; + + switch( action & 0xFF) { case C_START: + DYNARR_RESET(trkSeg_t,anchors_da); if (selectedTrackCount == 0) { ErrorMessage( MSG_NO_SELECTED_TRK ); return C_TERMINATE; @@ -1197,63 +1712,123 @@ static STATUS_T CmdMove( } InfoMessage( _("Drag to move selected tracks - Shift+Ctrl+Arrow micro-steps the move") ); state = 0; + ep1 = -1; + ep2 = -1; + doingMove = FALSE; + break; + + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + CreateMoveAnchor(pos); break; case C_DOWN: + DYNARR_RESET(trkSeg_t,anchors_da); + if (doingMove) { + doingMove = FALSE; + UndoEnd(); + } + if (SelectedTracksAreFrozen()) { return C_TERMINATE; } UndoStart( _("Move Tracks"), "move" ); base = zero; orig = pos; - GetMovedTracks(quickMove != MOVE_QUICK); + + GetMovedTracks(TRUE); SetMoveD( TRUE, base, 0.0 ); - //DrawMovedTracks(); drawCount = 0; state = 1; - MainRedraw(); - MapRedraw(); return C_CONTINUE; case C_MOVE: + DYNARR_RESET(trkSeg_t,anchors_da); + ep1=-1; + ep2=-1; drawEnable = enableMoveDraw; - //DrawMovedTracks(); base.x = pos.x - orig.x; base.y = pos.y - orig.y; SnapPos( &base ); SetMoveD( TRUE, base, 0.0 ); - //DrawMovedTracks(); + if (((MyGetKeyState()&(WKEY_ALT)) == 0) == magneticSnap) { // ALT + if (FindEndIntersection(base,zero,0.0,&t1,&ep1,&t2,&ep2)) { + coOrd pos2 = GetTrkEndPos(t2,ep2); + pos2.x +=base.x; + pos2.y +=base.y; + CreateEndAnchor(pos2,FALSE); + CreateEndAnchor(GetTrkEndPos(t1,ep1),TRUE); + } + } #ifdef DRAWCOUNT InfoMessage( " [%s %s] #%ld", FormatDistance(base.x), FormatDistance(base.y), drawCount ); #else InfoMessage( " [%s %s]", FormatDistance(base.x), FormatDistance(base.y) ); #endif drawEnable = TRUE; - MainRedraw(); - MapRedraw(); return C_CONTINUE; case C_UP: + DYNARR_RESET(trkSeg_t,anchors_da); state = 0; - //DrawMovedTracks(); FreeTempStrings(); - MoveTracks( quickMove==MOVE_QUICK, TRUE, FALSE, base, zero, 0.0 ); + if (t1 && ep1>=0 && t2 && ep2>=0) { + MoveToJoin(t2,ep2,t1,ep1); + } else { + MoveTracks( FALSE, TRUE, FALSE, base, zero, 0.0, TRUE ); + } + ep1 = -1; + ep2 = -1; + tlist_da.cnt = 0; return C_TERMINATE; case C_CMDMENU: - wMenuPopupShow( selectPopup1M ); - return C_CONTINUE; - - case C_REDRAW: - /* DO_REDRAW */ - if ( state == 0 ) - break; - DrawSelectedTracksD( &mainD, wDrawColorWhite ); + if (doingMove) UndoEnd(); + doingMove = FALSE; + base = pos; + track_p trk = OnTrack(&pos, FALSE, FALSE); //Note pollutes pos if turntable + if ((trk) && + QueryTrack(trk,Q_CAN_ADD_ENDPOINTS)) { //Turntable snap to center if within 1/4 radius + trackParams_t trackParams; + if (GetTrackParams(PARAMS_CORNU, trk, pos, &trackParams)) { + DIST_T dist = FindDistance(base, trackParams.ttcenter); + if (dist < trackParams.ttradius/4) { + cmdMenuPos = trackParams.ttcenter; + } + } + } + moveDescPos = pos; + moveDescTrk = trk; + SetUpMenu2(pos,trk); + menuPos = pos; + wMenuPopupShow( selectPopup2M ); + return C_CONTINUE; + + case C_TEXT: + if ((action>>8) == 'c') { + panCenter = pos; + LOG( log_pan, 2, ( "PanCenter:Sel-%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) ); + PanHere((void*)0); + } + if ((action>>8) == 'e') { + DoZoomExtents(0); + } + if ((action>>8) == '0' || (action>>8 == 'o')) { + PanMenuEnter('o'); + } + break; + case C_REDRAW: + /* DO_REDRAW */ + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + if ( state == 0 ) + break; DrawMovedTracks(); + break; case wActionExtKey: if (state) return C_CONTINUE; if (SelectedTracksAreFrozen()) return C_TERMINATE; if ((MyGetKeyState() & - (WKEY_SHIFT | WKEY_CTRL)) == (WKEY_SHIFT | WKEY_CTRL)) { + (WKEY_SHIFT | WKEY_CTRL)) == (WKEY_SHIFT | WKEY_CTRL)) { //Both base = zero; DIST_T w = tempD.scale/tempD.dpi; switch((wAccelKey_e) action>>8) { @@ -1275,21 +1850,35 @@ static STATUS_T CmdMove( } drawEnable = enableMoveDraw; - GetMovedTracks(quickMove!=MOVE_QUICK); - UndoStart( _("Move Tracks"), "move" ); + GetMovedTracks(TRUE); + if (!doingMove) UndoStart( _("Move Tracks"), "move" ); + doingMove = TRUE; SetMoveD( TRUE, base, 0.0 ); - DrawSelectedTracksD( &mainD, wDrawColorWhite ); - MoveTracks( quickMove==MOVE_QUICK, TRUE, FALSE, base, zero, 0.0 ); + MoveTracks( FALSE, TRUE, FALSE, base, zero, 0.0, FALSE ); ++microCount; if (microCount>5) { microCount = 0; - MainRedraw(); - MapRedraw(); + MainRedraw(); // Micro step move } return C_CONTINUE; } break; + case C_FINISH: + if (doingMove) { + doingMove = FALSE; + UndoEnd(); + } + tlist_da.cnt = 0; + break; + case C_CONFIRM: + case C_CANCEL: + if (doingMove) { + doingMove = FALSE; + UndoUndo(); + } + tlist_da.cnt = 0; + break; default: break; } @@ -1297,13 +1886,18 @@ static STATUS_T CmdMove( } -wMenuPush_p rotateAlignMI; -int rotateAlignState = 0; -static void RotateAlign( void ) +static int rotateAlignState = 0; + +static void RotateAlign( BOOL_T align ) { - rotateAlignState = 1; - InfoMessage( _("Click on selected object to align") ); + rotateAlignState = 0; + if (align) { + rotateAlignState = 1; + doingAlign = TRUE; + mode = MOVE; + InfoMessage( _("Align: Click on a selected object to be aligned") ); + } } static STATUS_T CmdRotate( @@ -1311,18 +1905,27 @@ static STATUS_T CmdRotate( coOrd pos ) { static coOrd base; + static coOrd orig_base; static coOrd orig; static ANGLE_T angle; static BOOL_T drawnAngle; static ANGLE_T baseAngle; + static BOOL_T clockwise; + static BOOL_T direction_set; static track_p trk; ANGLE_T angle1; coOrd pos1; static int state; + static EPINX_T ep1; + static EPINX_T ep2; + static track_p t1; + static track_p t2; + switch( action ) { case C_START: + DYNARR_RESET(trkSeg_t,anchors_da); state = 0; if (selectedTrackCount == 0) { ErrorMessage( MSG_NO_SELECTED_TRK ); @@ -1334,8 +1937,15 @@ static STATUS_T CmdRotate( InfoMessage( _("Drag to rotate selected tracks, Shift+RightClick for QuickRotate Menu") ); wMenuPushEnable( rotateAlignMI, TRUE ); rotateAlignState = 0; + ep1 = -1; + ep2 = -1; + break; + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + CreateRotateAnchor(pos); break; case C_DOWN: + DYNARR_RESET(trkSeg_t,anchors_da); state = 1; if (SelectedTracksAreFrozen()) { return C_TERMINATE; @@ -1357,12 +1967,15 @@ static STATUS_T CmdRotate( } } } - GetMovedTracks(FALSE); + CreateRotateAnchor(orig); + GetMovedTracks(TRUE); SetMoveD( FALSE, base, angle ); + /*DrawLine( &mainD, base, orig, 0, wDrawColorBlack ); DrawMovedTracks(FALSE, orig, angle);*/ } else { pos1 = pos; + drawnAngle = FALSE; onTrackInSplit = TRUE; trk = OnTrack( &pos, TRUE, FALSE ); onTrackInSplit = FALSE; @@ -1396,13 +2009,13 @@ static STATUS_T CmdRotate( } GetMovedTracks(TRUE); SetMoveD( FALSE, orig, angle ); - //DrawMovedTracks(); } } - MainRedraw(); - MapRedraw(); return C_CONTINUE; case C_MOVE: + DYNARR_RESET(trkSeg_t,anchors_da); + ep1=-1; + ep2=-1; if ( rotateAlignState == 1 ) return C_CONTINUE; if ( rotateAlignState == 2 ) { @@ -1416,7 +2029,6 @@ static STATUS_T CmdRotate( ErrorMessage( MSG_2ND_TRACK_MUST_BE_UNSELECTED ); return C_CONTINUE; } - //DrawMovedTracks(); angle1 = NormalizeAngle( GetAngleAtPoint( trk, pos, NULL, NULL ) ); angle = NormalizeAngle(angle1-baseAngle); if ( angle > 90 && angle < 270 ) @@ -1427,65 +2039,95 @@ static STATUS_T CmdRotate( InfoMessage( _("Angle %0.3f"), angle1 ); SetMoveD( FALSE, orig, angle ); /*printf( "angle 2 = %0.3f\n", angle );*/ - //DrawMovedTracks(); - MainRedraw(); - MapRedraw(); return C_CONTINUE; } - if ( FindDistance( orig, pos ) > (6.0/75.0)*mainD.scale ) { - drawEnable = enableMoveDraw; - if (drawnAngle) { - DrawLine( &tempD, base, orig, 0, wDrawColorBlack ); - DrawMovedTracks(); - } else if (quickMove != MOVE_QUICK) { - DrawSelectedTracksD( &mainD, wDrawColorWhite ); - } + ANGLE_T diff_angle = 0.0; + base = pos; + drawEnable = enableMoveDraw; + if ( FindDistance( orig, pos ) > (20.0/75.0)*mainD.scale ) { + ANGLE_T old_angle = angle; angle = FindAngle( orig, pos ); if (!drawnAngle) { baseAngle = angle; drawnAngle = TRUE; + direction_set = FALSE; + } else { + if (!direction_set) { + if (DifferenceBetweenAngles(baseAngle,angle)>=0) clockwise = TRUE; + else clockwise = FALSE; + direction_set = TRUE; + } else { + if (clockwise) { + if (DifferenceBetweenAngles(baseAngle,angle)<0 && fabs(DifferenceBetweenAngles(baseAngle, old_angle))<5) + clockwise = FALSE; + } else { + if (DifferenceBetweenAngles(baseAngle,angle)>=0 && fabs(DifferenceBetweenAngles(baseAngle,old_angle))<5) + clockwise = TRUE; + } + } + } + orig_base = base = pos; + //angle = NormalizeAngle( angle-baseAngle ); + diff_angle = DifferenceBetweenAngles(baseAngle,angle); + if ( (MyGetKeyState() & (WKEY_CTRL|WKEY_SHIFT)) == (WKEY_CTRL|WKEY_SHIFT) ) { //Both Shift+Ctrl + if (clockwise) { + if (diff_angle<0) diff_angle+=360; + } else { + if (diff_angle>0) diff_angle-=360; + } + diff_angle = floor((diff_angle+7.5)/15.0)*15.0; + angle = baseAngle+diff_angle; } - base = pos; - angle = NormalizeAngle( angle-baseAngle ); - if ( MyGetKeyState()&WKEY_CTRL ) { - angle = NormalizeAngle(floor((angle+7.5)/15.0)*15.0); - Translate( &base, orig, angle+baseAngle, FindDistance(orig,pos) ); + Translate( &base, orig, angle, FindDistance(orig,pos) ); //Line one + Translate( &orig_base,orig, baseAngle, FindDistance(orig,pos)<=(60.0/75.00*mainD.scale)?FindDistance(orig,pos):60.0/75.00*mainD.scale ); //Line two + SetMoveD( FALSE, orig, NormalizeAngle( angle-baseAngle ) ); + if (((MyGetKeyState()&(WKEY_ALT)) == WKEY_ALT) != magneticSnap) { //Just Shift + if (FindEndIntersection(zero,orig,NormalizeAngle( angle-baseAngle ),&t1,&ep1,&t2,&ep2)) { + coOrd pos2 = GetTrkEndPos(t2,ep2); + coOrd pos1 = GetTrkEndPos(t1,ep1); + Rotate(&pos2,orig,NormalizeAngle( angle-baseAngle )); + CreateEndAnchor(pos2,FALSE); + CreateEndAnchor(pos1,TRUE); + } } - DrawLine( &tempD, base, orig, 0, wDrawColorBlack ); - SetMoveD( FALSE, orig, angle ); - //DrawMovedTracks(); + #ifdef DRAWCOUNT - InfoMessage( _(" Angle %0.3f #%ld"), angle, drawCount ); + InfoMessage( _("Angle %0.3f #%ld"), fabs(diff_angle), drawCount ); #else - InfoMessage( _(" Angle %0.3f"), angle ); + InfoMessage( _("Angle %0.3f %s"), fabs(diff_angle), clockwise?"Clockwise":"Counter-Clockwise" ); #endif wFlush(); drawEnable = TRUE; - } - MainRedraw(); - MapRedraw(); + } else + InfoMessage( _("Origin Set. Drag away to set start angle")); + return C_CONTINUE; + case C_UP: + DYNARR_RESET(trkSeg_t,anchors_da); state = 0; - if ( rotateAlignState == 1 ) { - if ( trk && GetTrkSelected(trk) ) { - InfoMessage( _("Click on the 2nd Unselected object") ); - rotateAlignState = 2; - } - return C_CONTINUE; - } - FreeTempStrings(); - if ( rotateAlignState == 2 ) { - //DrawMovedTracks(); - MoveTracks( quickMove==MOVE_QUICK, FALSE, TRUE, zero, orig, angle ); + if (t1 && ep1>=0 && t2 && ep2>=0) { + MoveToJoin(t2,ep2,t1,ep1); + CleanSegs(&tempSegs_da); rotateAlignState = 0; - } else if (drawnAngle) { - DrawLine( &tempD, base, orig, 0, wDrawColorBlack ); - //DrawMovedTracks(); - MoveTracks( quickMove==MOVE_QUICK, FALSE, TRUE, zero, orig, angle ); + } else { + if ( rotateAlignState == 1 ) { + if ( trk && GetTrkSelected(trk) ) { + InfoMessage( _("Align: Click on the 2nd unselected object") ); + rotateAlignState = 2; + } + return C_CONTINUE; + } + CleanSegs(&tempSegs_da); + if ( rotateAlignState == 2 ) { + MoveTracks( FALSE, FALSE, TRUE, zero, orig, angle, TRUE ); + rotateAlignState = 0; + } else if (drawnAngle) { + MoveTracks( FALSE, FALSE, TRUE, zero, orig, NormalizeAngle( angle-baseAngle ), TRUE ); + } } - MainRedraw(); - MapRedraw(); + UndoEnd(); + tlist_da.cnt = 0; return C_TERMINATE; case C_CMDMENU: @@ -1501,16 +2143,65 @@ static STATUS_T CmdRotate( } } } + moveDescPos = pos; + moveDescTrk = trk; + SetUpMenu2(pos,trk); + menuPos = pos; wMenuPopupShow( selectPopup2M ); return C_CONTINUE; + case C_TEXT: + if ((action>>8) == 'd') { + panCenter = pos; + LOG( log_pan, 2, ( "PanCenter:Sel-%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) ); + PanHere((void*)0); + } + if ((action>>8) == 'e') { + DoZoomExtents(0); + } + if ((action>>8) == '0' || (action>>8 == 'o')) { + PanMenuEnter('o'); + } + break; case C_REDRAW: + if (anchors_da.cnt) + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); /* DO_REDRAW */ if ( state == 0 ) break; - if ( rotateAlignState != 2 ) - DrawLine( &tempD, base, orig, 0, wDrawColorBlack ); - DrawSelectedTracksD( &mainD, wDrawColorWhite ); + if ( rotateAlignState != 2 ) { + DIST_T width = mainD.scale*0.5; + DrawLine( &tempD, base, orig, 0, wDrawColorBlue ); + if (drawnAngle) { + DrawLine( &tempD, orig_base, orig, (wDrawWidth)width, wDrawColorBlue ); + ANGLE_T a = DifferenceBetweenAngles(FindAngle(orig, orig_base),FindAngle(orig, base)); + + DIST_T dist = FindDistance(orig,base); + if (dist>(60.0/75.0)*mainD.scale) dist = (60.0/75.0)*mainD.scale; + + if (direction_set) { + if (clockwise) { + if (a<0) a = a + 360; + DrawArc( &tempD, orig, dist/2, FindAngle(orig,orig_base), a, FALSE, 0, wDrawColorBlue); + } else { + if (a>0) a = a - 360; + DrawArc( &tempD, orig, dist/2, FindAngle(orig,base), fabs(a), FALSE, 0, wDrawColorBlue); + } + DIST_T d; + d = mainD.scale*0.25; + ANGLE_T arrow_a = NormalizeAngle(FindAngle(orig,orig_base)+a/2); + coOrd arr1,arr2,arr3; + Translate(&arr2,orig,arrow_a,dist/2); + if (clockwise) arrow_a +=90; + else arrow_a -=90; + Translate(&arr1,arr2,arrow_a+135,d/2); + Translate(&arr3,arr2,arrow_a-135,d/2); + DrawLine( &tempD, arr1, arr2, 0, wDrawColorBlue ); + DrawLine( &tempD, arr2, arr3, 0, wDrawColorBlue ); + } + } + + } DrawMovedTracks(); break; @@ -1524,12 +2215,9 @@ static void QuickMove( void* pos) { return; wDrawDelayUpdate( mainD.d, TRUE ); GetMovedTracks(FALSE); - DrawSelectedTracksD( &mainD, wDrawColorWhite ); UndoStart( _("Move Tracks"), "Move Tracks" ); - MoveTracks( quickMove==MOVE_QUICK, TRUE, FALSE, move_pos, zero, 0.0 ); + MoveTracks( TRUE, TRUE, FALSE, move_pos, zero, 0.0, TRUE ); wDrawDelayUpdate( mainD.d, FALSE ); - MainRedraw(); - MapRedraw(); } static void QuickRotate( void* pangle ) @@ -1539,18 +2227,16 @@ static void QuickRotate( void* pangle ) return; wDrawDelayUpdate( mainD.d, TRUE ); GetMovedTracks(FALSE); - DrawSelectedTracksD( &mainD, wDrawColorWhite ); + //DrawSelectedTracksD( &mainD, wDrawColorWhite ); UndoStart( _("Rotate Tracks"), "Rotate Tracks" ); - MoveTracks( quickMove==MOVE_QUICK, FALSE, TRUE, zero, cmdMenuPos, angle ); + MoveTracks( TRUE, FALSE, TRUE, zero, cmdMenuPos, (double)angle/1000, TRUE); wDrawDelayUpdate( mainD.d, FALSE ); - MainRedraw(); - MapRedraw(); } static wMenu_p moveDescM; static wMenuToggle_p moveDescMI; -static track_p moveDescTrk; + static void ChangeDescFlag( wBool_t set, void * mode ) { wDrawDelayUpdate( mainD.d, TRUE ); @@ -1565,113 +2251,228 @@ static void ChangeDescFlag( wBool_t set, void * mode ) wDrawDelayUpdate( mainD.d, FALSE ); } -STATUS_T CmdMoveDescription( - wAction_t action, - coOrd pos ) -{ - static track_p trk; - static EPINX_T ep; - track_p trk1; - EPINX_T ep1; - DIST_T d, dd; - static int mode; - - switch (action) { - case C_START: - if ( labelWhen < 2 || mainD.scale > labelScale || - (labelEnable&(LABELENABLE_TRKDESC|LABELENABLE_LENGTHS|LABELENABLE_ENDPT_ELEV))==0 ) { - ErrorMessage( MSG_DESC_NOT_VISIBLE ); - return C_TERMINATE; - } - InfoMessage( _("Select and drag a description") ); - break; - case C_DOWN: - if ( labelWhen < 2 || mainD.scale > labelScale ) - return C_TERMINATE; - trk = NULL; - dd = 10000; - trk1 = NULL; +track_p FindTrackDescription(coOrd pos, EPINX_T * ep_o, int * mode_o, BOOL_T show_hidden, BOOL_T * hidden_o) { + track_p trk = NULL; + DIST_T d, dd = 10000; + track_p trk1 = NULL; + EPINX_T ep1=-1, ep=-1; + BOOL_T hidden_t, hidden; + coOrd dpos = pos; + coOrd cpos; + int mode = -1; while ( TrackIterate( &trk1 ) ) { if ( !GetLayerVisible(GetTrkLayer(trk1)) ) continue; if ( (!GetTrkVisible(trk1)) && drawTunnel==0 ) continue; - for ( ep1=0; ep1