summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/CMakeLists.txt5
-rw-r--r--app/bin/CMakeLists.txt110
-rw-r--r--app/bin/acclkeys.h12
-rw-r--r--app/bin/appdefaults.c25
-rw-r--r--app/bin/archive.c454
-rw-r--r--app/bin/archive.h15
-rw-r--r--app/bin/bdf2xtp.c9
-rw-r--r--app/bin/bitmaps/SVG/star.svg124
-rw-r--r--app/bin/bitmaps/XCF/bluedot.xcfbin0 -> 2124 bytes
-rw-r--r--app/bin/bitmaps/XCF/greendot.xcfbin0 -> 2024 bytes
-rw-r--r--app/bin/bitmaps/XCF/greydot.xcfbin0 -> 2022 bytes
-rw-r--r--app/bin/bitmaps/XCF/reddot.xcfbin0 -> 2124 bytes
-rw-r--r--app/bin/bitmaps/XCF/yellowdot.xcfbin0 -> 1854 bytes
-rw-r--r--app/bin/bitmaps/arrow0.xbm14
-rw-r--r--app/bin/bitmaps/arrow0_ctl.xbm9
-rw-r--r--app/bin/bitmaps/arrow0_shift.xbm9
-rw-r--r--app/bin/bitmaps/arrow3.xbm2
-rw-r--r--app/bin/bitmaps/arrow3_ctl.xbm9
-rw-r--r--app/bin/bitmaps/arrow3_shift.xbm9
-rw-r--r--app/bin/bitmaps/arrowr3.xbm9
-rw-r--r--app/bin/bitmaps/arrowr3_ctl.xbm9
-rw-r--r--app/bin/bitmaps/arrowr3_shift.xbm9
-rw-r--r--app/bin/bitmaps/arrows.xbm2
-rw-r--r--app/bin/bitmaps/background.xpm155
-rw-r--r--app/bin/bitmaps/bluedot.xpm26
-rw-r--r--app/bin/bitmaps/bma0.xbm2
-rw-r--r--app/bin/bitmaps/bma135.xbm2
-rw-r--r--app/bin/bitmaps/bma45.xbm2
-rw-r--r--app/bin/bitmaps/bma90.xbm2
-rw-r--r--app/bin/bitmaps/bmendpt.xbm2
-rw-r--r--app/bin/bitmaps/bridge.xpm22
-rw-r--r--app/bin/bitmaps/clip.xbm6
-rw-r--r--app/bin/bitmaps/convertfr.xpm23
-rw-r--r--app/bin/bitmaps/convertto.xpm23
-rw-r--r--app/bin/bitmaps/cornu.xpm23
-rw-r--r--app/bin/bitmaps/cross0.xbm2
-rw-r--r--app/bin/bitmaps/delete.xpm39
-rw-r--r--app/bin/bitmaps/document-export.xpm90
-rw-r--r--app/bin/bitmaps/document-exportdxf.xpm84
-rw-r--r--app/bin/bitmaps/document-import.xpm92
-rw-r--r--app/bin/bitmaps/document-importmod.xpm71
-rw-r--r--app/bin/bitmaps/dpolyline.xpm23
-rw-r--r--app/bin/bitmaps/export.xpm21
-rw-r--r--app/bin/bitmaps/flash.xbm2
-rw-r--r--app/bin/bitmaps/greendot.xpm23
-rw-r--r--app/bin/bitmaps/greenstar.xpm69
-rw-r--r--app/bin/bitmaps/greydot.xpm25
-rw-r--r--app/bin/bitmaps/greystar.xpm69
-rw-r--r--app/bin/bitmaps/import.xpm21
-rw-r--r--app/bin/bitmaps/joinline.xpm22
-rw-r--r--app/bin/bitmaps/link.xbm6
-rw-r--r--app/bin/bitmaps/magnet.xpm22
-rw-r--r--app/bin/bitmaps/magnifier.xpm89
-rw-r--r--app/bin/bitmaps/note.xbm8
-rw-r--r--app/bin/bitmaps/pan.xpm2
-rw-r--r--app/bin/bitmaps/parallel-line.xpm22
-rw-r--r--app/bin/bitmaps/parallel.xpm15
-rw-r--r--app/bin/bitmaps/reddot.xpm26
-rw-r--r--app/bin/bitmaps/redstar.xpm67
-rw-r--r--app/bin/bitmaps/sticky-note-chain.xpm84
-rw-r--r--app/bin/bitmaps/sticky-note-clip.xpm99
-rw-r--r--app/bin/bitmaps/sticky-note-text.xpm86
-rw-r--r--app/bin/bitmaps/tunnel.xpm19
-rw-r--r--app/bin/bitmaps/yellowdot.xpm27
-rw-r--r--app/bin/bitmaps/yellowstar.xpm67
-rwxr-xr-xapp/bin/cJSON.c2932
-rwxr-xr-xapp/bin/cJSON.h285
-rw-r--r--app/bin/cbezier.c233
-rw-r--r--app/bin/cbezier.h7
-rw-r--r--app/bin/cblock.c184
-rw-r--r--app/bin/ccontrol.c42
-rw-r--r--app/bin/ccornu.c2515
-rw-r--r--app/bin/ccornu.h11
-rw-r--r--app/bin/ccurve.c637
-rw-r--r--app/bin/ccurve.h8
-rw-r--r--app/bin/cdraw.c1814
-rw-r--r--app/bin/celev.c364
-rw-r--r--app/bin/cgroup.c495
-rw-r--r--app/bin/chndldto.c14
-rw-r--r--app/bin/chotbar.c119
-rw-r--r--app/bin/cjoin.c610
-rw-r--r--app/bin/cmisc.c114
-rw-r--r--app/bin/cmodify.c490
-rw-r--r--app/bin/cnote.c430
-rw-r--r--app/bin/common.h22
-rw-r--r--app/bin/compound.c285
-rw-r--r--app/bin/compound.h24
-rw-r--r--app/bin/cparalle.c370
-rw-r--r--app/bin/cprint.c516
-rw-r--r--app/bin/cprofile.c2314
-rw-r--r--app/bin/cpull.c263
-rw-r--r--app/bin/cruler.c22
-rw-r--r--app/bin/cselect.c2238
-rw-r--r--app/bin/cselect.h12
-rw-r--r--app/bin/csensor.c42
-rw-r--r--app/bin/csignal.c47
-rw-r--r--app/bin/csnap.c32
-rw-r--r--app/bin/csplit.c89
-rw-r--r--app/bin/cstraigh.c77
-rw-r--r--app/bin/cstruct.c421
-rw-r--r--app/bin/cswitchmotor.c108
-rw-r--r--app/bin/ctext.c71
-rw-r--r--app/bin/ctodesgn.c1515
-rw-r--r--app/bin/ctrain.c139
-rw-r--r--app/bin/ctrain.h20
-rw-r--r--app/bin/cturnout.c1186
-rw-r--r--app/bin/cturntbl.c115
-rw-r--r--app/bin/custom.c51
-rw-r--r--app/bin/custom.h14
-rw-r--r--app/bin/dbench.c2
-rw-r--r--app/bin/dbitmap.c14
-rw-r--r--app/bin/dcar.c625
-rw-r--r--app/bin/dcmpnd.c33
-rw-r--r--app/bin/dcontmgm.c5
-rw-r--r--app/bin/dcustmgm.c73
-rw-r--r--app/bin/dease.c2
-rw-r--r--app/bin/directory.c162
-rw-r--r--app/bin/directory.h6
-rw-r--r--app/bin/dlayer.c143
-rw-r--r--app/bin/doption.c90
-rw-r--r--app/bin/dpricels.c2
-rw-r--r--app/bin/dprmfile.c757
-rw-r--r--app/bin/draw.c1612
-rw-r--r--app/bin/draw.h262
-rw-r--r--app/bin/drawgeom.c2347
-rw-r--r--app/bin/drawgeom.h65
-rw-r--r--app/bin/dxfoutput.c16
-rw-r--r--app/bin/elev.c42
-rw-r--r--app/bin/file2uri.c83
-rw-r--r--app/bin/file2uri.h27
-rw-r--r--app/bin/fileio.c963
-rw-r--r--app/bin/fileio.h68
-rw-r--r--app/bin/filenoteui.c330
-rw-r--r--app/bin/helphelper.c1
-rw-r--r--app/bin/include/dirent.h1254
-rw-r--r--app/bin/include/paramfile.h26
-rw-r--r--app/bin/include/paramfilelist.h32
-rw-r--r--app/bin/include/partcatalog.h70
-rw-r--r--app/bin/include/stringxtc.h8
-rw-r--r--app/bin/include/utf8convert.h24
-rw-r--r--app/bin/layout.c364
-rw-r--r--app/bin/layout.h20
-rw-r--r--app/bin/linknoteui.c260
-rw-r--r--app/bin/macro.c501
-rw-r--r--app/bin/manifest.c176
-rw-r--r--app/bin/manifest.h6
-rw-r--r--app/bin/misc.c2972
-rw-r--r--app/bin/misc.h87
-rw-r--r--app/bin/misc2.c16
-rw-r--r--app/bin/misc2.h14
-rw-r--r--app/bin/note.h110
-rw-r--r--app/bin/param.c213
-rw-r--r--app/bin/param.h2
-rw-r--r--app/bin/paramfile.c393
-rw-r--r--app/bin/paramfilelist.c496
-rw-r--r--app/bin/paramfilesearch_ui.c426
-rw-r--r--app/bin/partcatalog.c846
-rw-r--r--app/bin/paths.c39
-rw-r--r--app/bin/paths.h2
-rw-r--r--app/bin/shortentext.c92
-rw-r--r--app/bin/shortentext.h28
-rw-r--r--app/bin/smalldlg.c17
-rw-r--r--app/bin/stringxtc.c106
-rw-r--r--app/bin/tbezier.c389
-rw-r--r--app/bin/tbezier.h6
-rw-r--r--app/bin/tcornu.c377
-rw-r--r--app/bin/tcornu.h6
-rw-r--r--app/bin/tcurve.c231
-rw-r--r--app/bin/tease.c232
-rw-r--r--app/bin/textnoteui.c243
-rw-r--r--app/bin/tocornu.src21
-rw-r--r--app/bin/tocornu3way.src33
-rw-r--r--app/bin/tocornuwye.src24
-rw-r--r--app/bin/track.c900
-rw-r--r--app/bin/track.h161
-rw-r--r--app/bin/trackx.h2
-rw-r--r--app/bin/trknote.c720
-rw-r--r--app/bin/trkseg.c558
-rw-r--r--app/bin/tstraigh.c108
-rw-r--r--app/bin/unittest/CMakeLists.txt36
-rw-r--r--app/bin/unittest/catalogtest.c124
-rw-r--r--app/bin/unittest/defaultstest.c8
-rw-r--r--app/bin/unittest/pathstest.c5
-rw-r--r--app/bin/unittest/shortentest.c152
-rw-r--r--app/bin/unittest/testfiles/HO-Peco-Code83.xtp236
-rw-r--r--app/bin/unittest/testfiles/atl83ho.xtp561
-rw-r--r--app/bin/unittest/testfiles/atlasn.xtp (renamed from app/lib/params/atlasn.xtp)30
-rw-r--r--app/bin/utf8convert.c96
-rw-r--r--app/bin/utility.c171
-rw-r--r--app/bin/utility.h4
-rw-r--r--app/bin/validator.c87
-rw-r--r--app/bin/validator.h29
-rw-r--r--app/cornu/bezctx_xtrkcad.c13
-rw-r--r--app/cornu/bezctx_xtrkcad.h2
-rw-r--r--app/doc/CMakeLists.txt11
-rw-r--r--app/doc/addm.but312
-rw-r--r--app/doc/appendix.but26
-rw-r--r--app/doc/changem.but679
-rw-r--r--app/doc/drawm.but436
-rw-r--r--app/doc/editm.but58
-rw-r--r--app/doc/filem.but184
-rw-r--r--app/doc/helpm.but16
-rw-r--r--app/doc/hotbar.but38
-rw-r--r--app/doc/intro.but.in192
-rw-r--r--app/doc/managem.but27
-rw-r--r--app/doc/navigation.but156
-rw-r--r--app/doc/optionm.but67
-rw-r--r--app/doc/png.d/bcornu.pngbin0 -> 4346 bytes
-rw-r--r--app/doc/png.d/bfile.pngbin0 -> 681 bytes
-rw-r--r--app/doc/png.d/bjoin.pngbin277 -> 4433 bytes
-rw-r--r--app/doc/png.d/bjoinline.pngbin0 -> 4329 bytes
-rw-r--r--app/doc/png.d/blayer.pngbin1620 -> 70247 bytes
-rw-r--r--app/doc/png.d/blink.pngbin0 -> 626 bytes
-rw-r--r--app/doc/png.d/bnote.pngbin250 -> 600 bytes
-rw-r--r--app/doc/png.d/bparalle.pngbin239 -> 0 bytes
-rw-r--r--app/doc/png.d/bparallel.pngbin0 -> 4402 bytes
-rw-r--r--app/doc/png.d/bparalleline.pngbin0 -> 4357 bytes
-rw-r--r--app/doc/png.d/cmdopt.pngbin19624 -> 7407 bytes
-rw-r--r--app/doc/png.d/convertfrom.pngbin0 -> 4169 bytes
-rw-r--r--app/doc/png.d/convertto.pngbin0 -> 4169 bytes
-rw-r--r--app/doc/png.d/cornuendanchor.pngbin0 -> 5312 bytes
-rw-r--r--app/doc/png.d/dcprofile.pngbin8234 -> 11508 bytes
-rw-r--r--app/doc/png.d/displayopt.pngbin68298 -> 86476 bytes
-rw-r--r--app/doc/png.d/dprmfile.pngbin24735 -> 13308 bytes
-rw-r--r--app/doc/png.d/greendot.pngbin0 -> 301 bytes
-rw-r--r--app/doc/png.d/greenstar.pngbin0 -> 415 bytes
-rw-r--r--app/doc/png.d/greydot.pngbin0 -> 262 bytes
-rw-r--r--app/doc/png.d/greystar.pngbin0 -> 431 bytes
-rw-r--r--app/doc/png.d/iconfile.pngbin0 -> 165 bytes
-rw-r--r--app/doc/png.d/iconlink.PNGbin0 -> 230 bytes
-rw-r--r--app/doc/png.d/iconnote.pngbin479 -> 211 bytes
-rw-r--r--app/doc/png.d/layout.pngbin13213 -> 72958 bytes
-rw-r--r--app/doc/png.d/madd.pngbin7895 -> 13693 bytes
-rw-r--r--app/doc/png.d/main.pngbin36744 -> 397486 bytes
-rw-r--r--app/doc/png.d/maintagged.pngbin0 -> 400969 bytes
-rw-r--r--app/doc/png.d/mmovedraw.pngbin1037 -> 0 bytes
-rw-r--r--app/doc/png.d/mnote.pngbin0 -> 1392 bytes
-rw-r--r--app/doc/png.d/notefile.pngbin0 -> 6830 bytes
-rw-r--r--app/doc/png.d/notelink.pngbin0 -> 6780 bytes
-rw-r--r--app/doc/png.d/notetext.pngbin0 -> 6928 bytes
-rw-r--r--app/doc/png.d/paramsearch.pngbin0 -> 14516 bytes
-rw-r--r--app/doc/png.d/print.pngbin14306 -> 46869 bytes
-rw-r--r--app/doc/png.d/printmargin.pngbin0 -> 10613 bytes
-rw-r--r--app/doc/png.d/reddot.pngbin0 -> 301 bytes
-rw-r--r--app/doc/png.d/redstar.pngbin0 -> 364 bytes
-rw-r--r--app/doc/png.d/satusbarparallel.pngbin1617 -> 0 bytes
-rw-r--r--app/doc/png.d/statusbarparallel.pngbin0 -> 12964 bytes
-rw-r--r--app/doc/png.d/yellowdot.pngbin0 -> 326 bytes
-rw-r--r--app/doc/png.d/yellowstar.pngbin0 -> 414 bytes
-rw-r--r--app/doc/statusbar.but13
-rw-r--r--app/doc/upgrade.but74
-rw-r--r--app/doc/view_winm.but25
-rw-r--r--app/dynstring/dynstring.c17
-rw-r--r--app/dynstring/dynstring.h89
-rw-r--r--app/help/CMakeLists.txt5
-rw-r--r--app/help/cJSON.c2932
-rw-r--r--app/help/cJSON.h285
-rw-r--r--app/help/genhelp.c286
-rw-r--r--app/help/genhelp.in728
-rw-r--r--app/help/genhelp.json681
-rw-r--r--app/help/messages.in244
-rw-r--r--app/help/xtrkcad.info1123
-rw-r--r--app/help/xtrkcad.tip65
-rw-r--r--app/i18n/CMakeLists.txt12
-rw-r--r--app/i18n/de_DE.po29324
-rw-r--r--app/i18n/fi.po28654
-rw-r--r--app/i18n/fr_FR.po16142
-rw-r--r--app/i18n/pt_BR.po26391
-rw-r--r--app/i18n/stripmsg.c23
-rw-r--r--app/lib/CHANGELOG.md360
-rw-r--r--app/lib/CMakeLists.txt6
-rw-r--r--app/lib/Readme.md45
-rw-r--r--app/lib/demos/dmadjend.xtr622
-rw-r--r--app/lib/demos/dmbench.xtr8
-rw-r--r--app/lib/demos/dmcancel.xtr52
-rw-r--r--app/lib/demos/dmcircle.xtr9
-rw-r--r--app/lib/demos/dmconn1.xtr336
-rw-r--r--app/lib/demos/dmconn2.xtr236
-rw-r--r--app/lib/demos/dmcrvtrk.xtr32
-rw-r--r--app/lib/demos/dmctlpnl.xtr1082
-rw-r--r--app/lib/demos/dmdelund.xtr10
-rw-r--r--app/lib/demos/dmdialog.xtr13
-rw-r--r--app/lib/demos/dmdimlin.xtr138
-rw-r--r--app/lib/demos/dmease.xtr162
-rw-r--r--app/lib/demos/dmelev.xtr239
-rw-r--r--app/lib/demos/dmexcept.xtr52
-rw-r--r--app/lib/demos/dmextend.xtr49
-rw-r--r--app/lib/demos/dmflip.xtr3
-rw-r--r--app/lib/demos/dmgroup.xtr158
-rw-r--r--app/lib/demos/dmhelix.xtr33
-rw-r--r--app/lib/demos/dmhndld.xtr66
-rw-r--r--app/lib/demos/dmintro.xtr24
-rw-r--r--app/lib/demos/dmjcir.xtr34
-rw-r--r--app/lib/demos/dmjnabut.xtr16
-rw-r--r--app/lib/demos/dmjncs.xtr44
-rw-r--r--app/lib/demos/dmjnmove.xtr27
-rw-r--r--app/lib/demos/dmjnss.xtr225
-rw-r--r--app/lib/demos/dmjntt.xtr34
-rw-r--r--app/lib/demos/dmlines.xtr132
-rw-r--r--app/lib/demos/dmlines2.xtr149
-rw-r--r--app/lib/demos/dmmouse.xtr232
-rw-r--r--app/lib/demos/dmmovabt.xtr3
-rw-r--r--app/lib/demos/dmnotes.xtr7
-rw-r--r--app/lib/demos/dmparall.xtr41
-rw-r--r--app/lib/demos/dmplymod.xtr88
-rw-r--r--app/lib/demos/dmprof.xtr164
-rw-r--r--app/lib/demos/dmrescal.xtr129
-rw-r--r--app/lib/demos/dmrotate.xtr913
-rw-r--r--app/lib/demos/dmruler.xtr3
-rw-r--r--app/lib/demos/dmselect.xtr468
-rw-r--r--app/lib/demos/dmsplit.xtr42
-rw-r--r--app/lib/demos/dmstrtrk.xtr6
-rw-r--r--app/lib/demos/dmtbledg.xtr59
-rw-r--r--app/lib/demos/dmtosel.xtr99
-rw-r--r--app/lib/demos/dmtotrim.xtr28
-rw-r--r--app/lib/demos/dmtoyard.xtr159
-rw-r--r--app/lib/demos/dmtrkwid.xtr134
-rw-r--r--app/lib/demos/dmtrntab.xtr4
-rw-r--r--app/lib/examples/psr.xtc14
-rw-r--r--app/lib/params/Any-AtlasControllers.xtp571
-rw-r--r--app/lib/params/Any-CTC_panel.xtp24
-rw-r--r--app/lib/params/BachmannEZ-N.xtp2
-rw-r--r--app/lib/params/CMakeLists.txt11
-rw-r--r--app/lib/params/FastTrack-HO.xtp4
-rw-r--r--app/lib/params/FastTrack_n.xtp2
-rw-r--r--app/lib/params/G-MicroEngineeringTrack.xtp142
-rw-r--r--app/lib/params/G-NQD-AMAX Plastic.xtp4
-rw-r--r--app/lib/params/G-Peco G45 Track.xtp46
-rw-r--r--app/lib/params/G-aristo.xtp2
-rw-r--r--app/lib/params/Gn15-nmra.xtp2
-rw-r--r--app/lib/params/H0_ncb-Roads.xtp1098
-rw-r--r--app/lib/params/HO-CentralValley Bridges.xtp407
-rw-r--r--app/lib/params/HO-DapolHOOO.xtp8
-rw-r--r--app/lib/params/HO-EndoRailwayTrackSystem.xtp228
-rw-r--r--app/lib/params/HO-HornbyHO.xtp271
-rw-r--r--app/lib/params/HO-Marklin C-Track.xtp (renamed from app/lib/params/mrklnhoc.xtp)1064
-rw-r--r--app/lib/params/HO-Marklin K-track.xtp (renamed from app/lib/params/mrklnhok.xtp)928
-rw-r--r--app/lib/params/HO-Marklin M-Track.xtp (renamed from app/lib/params/mrklnhom.xtp)1978
-rw-r--r--app/lib/params/HO-MetcalfeHOOO.xtp4
-rw-r--r--app/lib/params/HO-MicroEngineering-Bridges.xtp736
-rw-r--r--app/lib/params/HO-MicroEngineering.xtp2
-rw-r--r--app/lib/params/HO-Peco-Code100Streamline.xtp130
-rw-r--r--app/lib/params/HO-Peco-Code75Finescale.xtp101
-rw-r--r--app/lib/params/HO-RatioHOOO.xtp6
-rw-r--r--app/lib/params/HO-Roco HO Code 83.xtp469
-rw-r--r--app/lib/params/HO-Slot-Car-AFX-Track.xtp46
-rw-r--r--app/lib/params/HO-Slot-Cars.xtp5
-rw-r--r--app/lib/params/HO-Walthers Cornerstone Engineered Bridge System.xtp624
-rw-r--r--app/lib/params/HO-Weinert-Code75.xtp42
-rw-r--r--app/lib/params/HO-WillsHOOO.xtp8
-rw-r--r--app/lib/params/HO-atl100ho.xtp72
-rw-r--r--app/lib/params/HO-cmr-ho.xtp2
-rw-r--r--app/lib/params/HO_toolkit-Roads.xtp2
-rw-r--r--app/lib/params/HOn3-MicroEngineering-Bridges.xtp377
-rw-r--r--app/lib/params/HOn3-MicroEngineering.xtp50
-rw-r--r--app/lib/params/HOn30_Minitrains.xtp2
-rw-r--r--app/lib/params/Hornby Dublo 2 Rail.xtp2
-rw-r--r--app/lib/params/Hornby Dublo 3 Rail with Turntable.xtp4
-rw-r--r--app/lib/params/Hornby Dublo Signals.xtp2
-rw-r--r--app/lib/params/Hornby Dublo Wood Buildings.xtp2
-rw-r--r--app/lib/params/HornbyOO.xtp221
-rw-r--r--app/lib/params/LifeLike-N.xtp66
-rw-r--r--app/lib/params/Lionel-O.xtp6
-rw-r--r--app/lib/params/Lionel27.xtp6
-rw-r--r--app/lib/params/N-AtlasTrueTrack.xtp26
-rw-r--r--app/lib/params/N-Bonus Generic Industrial Structures.xtp3
-rw-r--r--app/lib/params/N-CentralValley Bridges.xtp123
-rw-r--r--app/lib/params/N-Kato Track and Structures.xtp (renamed from app/lib/params/N-kato.xtp)3445
-rw-r--r--app/lib/params/N-Kato-Unitram.xtp7
-rw-r--r--app/lib/params/N-Katocn.xtp2
-rw-r--r--app/lib/params/N-LifeLike Power-Loc.xtp2
-rw-r--r--app/lib/params/N-ME Structures.xtp3
-rw-r--r--app/lib/params/N-MicroEngineering-Bridges.xtp318
-rw-r--r--app/lib/params/N-NULINE.xtp2
-rw-r--r--app/lib/params/N-PecoCode55Finescale.xtp50
-rw-r--r--app/lib/params/N-PecoCode80Streamline.xtp50
-rw-r--r--app/lib/params/N-Rix-Pikestuff.xtp2
-rw-r--r--app/lib/params/N-Shinohara70.xtp4
-rw-r--r--app/lib/params/N-Tomix Track.xtp (renamed from app/lib/params/tomix-n.xtp)3394
-rw-r--r--app/lib/params/N-atlasn55.xtp27
-rw-r--r--app/lib/params/N-atlasn80.xtp845
-rw-r--r--app/lib/params/N-cmr.xtp2
-rw-r--r--app/lib/params/N-kato-n-gl-trk.xtp567
-rw-r--r--app/lib/params/N-kato-turntable.xtp16
-rw-r--r--app/lib/params/N-me.xtp2
-rw-r--r--app/lib/params/Newqida.xtp43
-rw-r--r--app/lib/params/Nn3-FastTrack.xtp2
-rw-r--r--app/lib/params/O-Atlas2Rail.xtp296
-rw-r--r--app/lib/params/O-Atlas2RailObsolete.xtp120
-rw-r--r--app/lib/params/O-Atlas3Rail Roadbed.xtp340
-rw-r--r--app/lib/params/O-Atlas3Rrail.xtp617
-rw-r--r--app/lib/params/O-AtlasIndustrial3Rail.xtp151
-rw-r--r--app/lib/params/O-Bassett-Lowke (discontinued).xtp6
-rw-r--r--app/lib/params/O-ETS TramTrack.xtp2
-rw-r--r--app/lib/params/O-Lehnhardt Tramrails.xtp2
-rw-r--r--app/lib/params/O-atlaso3rail.xtp6
-rw-r--r--app/lib/params/On30-FastTrack.xtp2
-rw-r--r--app/lib/params/On30-MicroEngineering.xtp50
-rw-r--r--app/lib/params/Proto-AmSlotCar.xtp2
-rw-r--r--app/lib/params/RemcoMightyCasey.xtp42
-rw-r--r--app/lib/params/S-Lionel AF Fastrack.xtp306
-rw-r--r--app/lib/params/S_ACG_18.824in Radius Track.xtp2
-rw-r--r--app/lib/params/S_ACG_20.000 Track.xtp2
-rw-r--r--app/lib/params/TT-Kuehn.xtp20
-rw-r--r--app/lib/params/TT-TilligAdvBeddingTrack.xtp9
-rw-r--r--app/lib/params/TT-Trak Modules.xtp3
-rw-r--r--app/lib/params/TilligAdvTT.xtp9
-rw-r--r--app/lib/params/TilligH0EliteCode83.xtp2
-rw-r--r--app/lib/params/TilligH0e.xtp2
-rw-r--r--app/lib/params/TilligH0m.xtp2
-rw-r--r--app/lib/params/USA-G.xtp2
-rw-r--r--app/lib/params/Z-Fasttrack.xtp4
-rw-r--r--app/lib/params/Z-Rokuhan.xtp21
-rw-r--r--app/lib/params/Z-T-Trak.xtp9
-rw-r--r--app/lib/params/arnold.xtp5
-rw-r--r--app/lib/params/atl83ho.xtp2
-rw-r--r--app/lib/params/atlaso2rail.xtp3
-rw-r--r--app/lib/params/br.xtp2
-rw-r--r--app/lib/params/dpm-ho.xtp2
-rw-r--r--app/lib/params/eu.xtp2
-rw-r--r--app/lib/params/ho-amb.xtp4
-rwxr-xr-xapp/lib/params/ho-ncb-roads.xtp2
-rw-r--r--app/lib/params/hon3cars.xtp9
-rw-r--r--app/lib/params/hubner1.xtp6
-rw-r--r--app/lib/params/kato-ho.xtp4
-rw-r--r--app/lib/params/kato-n-DblTrk.xtp369
-rw-r--r--app/lib/params/kato-n.xtp1639
-rw-r--r--app/lib/params/lgb.xtp2
-rw-r--r--app/lib/params/me-ho.xtp47
-rw-r--r--app/lib/params/minitrix.xtp2
-rw-r--r--app/lib/params/mrkhomde.xtp2
-rw-r--r--app/lib/params/mrkln1.xtp2
-rw-r--r--app/lib/params/mrklnhoc-de.xtp4
-rw-r--r--app/lib/params/mrklnz.xtp4
-rw-r--r--app/lib/params/nmra-0-lapped.xtp76
-rw-r--r--app/lib/params/nmra-ho.xtp2
-rw-r--r--app/lib/params/nmra-ho3.xtp2
-rw-r--r--app/lib/params/nmra-n.xtp4
-rw-r--r--app/lib/params/nmra-o.xtp2
-rw-r--r--app/lib/params/nmra-s.xtp2
-rw-r--r--app/lib/params/nmra-tt.to2
-rw-r--r--app/lib/params/nmra-tt.xtp2
-rw-r--r--app/lib/params/nmra-z.xtp2
-rw-r--r--app/lib/params/pecohom.xtp2
-rw-r--r--app/lib/params/pecohon30.xtp2
-rw-r--r--app/lib/params/proto-ng.xtp29
-rw-r--r--app/lib/params/protoam.xtp2
-rw-r--r--app/lib/params/protosteam.xtp2
-rw-r--r--app/lib/params/rocho100.xtp5
-rw-r--r--app/lib/params/rocho83.xtp293
-rw-r--r--app/lib/params/supero.xtp2
-rw-r--r--app/lib/params/toolkit-n.xtp2
-rw-r--r--app/lib/params/walth-n.xtp2686
-rw-r--r--app/lib/params/wlthho10.xtp2
-rw-r--r--app/lib/params/wlthho83.xtp4
-rw-r--r--app/lib/xtrkcad.xtq18
-rw-r--r--app/tools/HACKING4
-rw-r--r--app/wlib/gtklib/CMakeLists.txt48
-rw-r--r--app/wlib/gtklib/browserhelp.c59
-rw-r--r--app/wlib/gtklib/button.c44
-rw-r--r--app/wlib/gtklib/color.c11
-rw-r--r--app/wlib/gtklib/control.c59
-rw-r--r--app/wlib/gtklib/droplist.c75
-rw-r--r--app/wlib/gtklib/filesel.c238
-rw-r--r--app/wlib/gtklib/font.c17
-rw-r--r--app/wlib/gtklib/gtkdraw-cairo.c995
-rw-r--r--app/wlib/gtklib/gtkint.h24
-rw-r--r--app/wlib/gtklib/help.c16
-rw-r--r--app/wlib/gtklib/ixhelp.c10
-rw-r--r--app/wlib/gtklib/list.c5
-rw-r--r--app/wlib/gtklib/liststore.c2
-rw-r--r--app/wlib/gtklib/menu.c8
-rw-r--r--app/wlib/gtklib/notice.c18
-rw-r--r--app/wlib/gtklib/opendocument.c117
-rw-r--r--app/wlib/gtklib/osxhelp.c67
-rw-r--r--app/wlib/gtklib/print.c233
-rw-r--r--app/wlib/gtklib/single.c82
-rw-r--r--app/wlib/gtklib/splash.c12
-rw-r--r--app/wlib/gtklib/statusbar.c6
-rw-r--r--app/wlib/gtklib/text.c24
-rw-r--r--app/wlib/gtklib/timer.c3
-rw-r--r--app/wlib/gtklib/util.c88
-rw-r--r--app/wlib/gtklib/window.c204
-rw-r--r--app/wlib/gtklib/wpref.c10
-rw-r--r--app/wlib/include/mswlib.h2
-rw-r--r--app/wlib/include/wlib.h103
-rw-r--r--app/wlib/mswlib/CMakeLists.txt19
-rw-r--r--app/wlib/mswlib/backgnd.c220
-rw-r--r--app/wlib/mswlib/mswbitmap.c46
-rw-r--r--app/wlib/mswlib/mswbutt.c21
-rw-r--r--app/wlib/mswlib/mswchksm.c125
-rw-r--r--app/wlib/mswlib/mswdraw.c833
-rw-r--r--app/wlib/mswlib/mswedit.c210
-rw-r--r--app/wlib/mswlib/mswint.h23
-rw-r--r--app/wlib/mswlib/mswlist.c2
-rw-r--r--app/wlib/mswlib/mswmenu.c8
-rw-r--r--app/wlib/mswlib/mswmisc.c266
-rw-r--r--app/wlib/mswlib/mswmsg.c9
-rw-r--r--app/wlib/mswlib/mswpref.c1
-rw-r--r--app/wlib/mswlib/mswprint.c46
-rw-r--r--app/wlib/mswlib/mswsplash.c8
-rw-r--r--app/wlib/mswlib/mswtext.c63
-rw-r--r--app/wlib/mswlib/simple-gettext.c3
-rw-r--r--app/wlib/mswlib/unittest/CMakeLists.txt11
-rw-r--r--app/wlib/mswlib/unittest/utf8test.c65
-rw-r--r--app/wlib/mswlib/utf8conv.c210
506 files changed, 126824 insertions, 65858 deletions
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 */
@@ -227,6 +230,14 @@ InitializeRegionCode(void)
}
/**
+ * 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 <errno.h>
+#include <fcntl.h>
+
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <zip.h>
+
+#ifdef WINDOWS
+ #include "include/dirent.h"
+ #include <direct.h>
+ #include <io.h>
+ #include <process.h>
+ #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 <dirent.h>
+ #include <unistd.h>
+#endif
+
+#include <wlib.h>
+#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 <zip.h>
+#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 <math.h>
#ifndef _MSDOS
#include <unistd.h>
+#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 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="64"
+ height="64"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ version="1.0"
+ inkscape:export-filename="C:\Users\mf\Desktop\star.png"
+ inkscape:export-xdpi="22.5"
+ inkscape:export-ydpi="22.5"
+ sodipodi:docbase="C:\Users\mf\Documents\XTrackCAD\src\work\app\bin\bitmaps\SVG"
+ sodipodi:docname="star.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3159">
+ <stop
+ style="stop-color:#808080;stop-opacity:1;"
+ offset="0"
+ id="stop3161" />
+ <stop
+ id="stop3167"
+ offset="1"
+ style="stop-color:#404040;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3153">
+ <stop
+ id="stop3155"
+ offset="0"
+ style="stop-color:#ffff00;stop-opacity:1;" />
+ <stop
+ id="stop3157"
+ offset="1"
+ style="stop-color:#ffff00;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3136">
+ <stop
+ style="stop-color:#ffff00;stop-opacity:1;"
+ offset="0"
+ id="stop3138" />
+ <stop
+ style="stop-color:#ffff00;stop-opacity:0;"
+ offset="1"
+ id="stop3140" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3159"
+ id="radialGradient3165"
+ cx="37.931442"
+ cy="34.408134"
+ fx="37.931442"
+ fy="34.408134"
+ r="35.324765"
+ gradientTransform="matrix(1,0,0,0.956027,0,1.7894602)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.8"
+ inkscape:cx="61.305799"
+ inkscape:cy="40.157191"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="64px"
+ height="64px"
+ inkscape:window-width="765"
+ inkscape:window-height="575"
+ inkscape:window-x="785"
+ inkscape:window-y="236" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ sodipodi:type="star"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.27731241;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1.0;fill:url(#radialGradient3165)"
+ id="path2160"
+ sodipodi:sides="5"
+ sodipodi:cx="43.214287"
+ sodipodi:cy="44"
+ sodipodi:r1="35.801678"
+ sodipodi:r2="14.088029"
+ sodipodi:arg1="-2.8166875"
+ sodipodi:arg2="-2.1460669"
+ inkscape:flatsided="false"
+ inkscape:rounded="0"
+ inkscape:randomized="0"
+ d="M 9.2857168,32.571428 L 35.549528,32.179508 L 43.599,8.2003894 L 52.087702,33.057648 L 77.380623,33.303196 L 56.363118,49.057747 L 63.94553,73.188622 L 42.467296,58.068211 L 21.860564,72.736365 L 29.60379,47.636886 L 9.2857168,32.571428 z "
+ transform="matrix(0.793397,0,0,0.7725297,-2.475811,0.6853635)" />
+ </g>
+</svg>
diff --git a/app/bin/bitmaps/XCF/bluedot.xcf b/app/bin/bitmaps/XCF/bluedot.xcf
new file mode 100644
index 0000000..30d323e
--- /dev/null
+++ b/app/bin/bitmaps/XCF/bluedot.xcf
Binary files differ
diff --git a/app/bin/bitmaps/XCF/greendot.xcf b/app/bin/bitmaps/XCF/greendot.xcf
new file mode 100644
index 0000000..f59311a
--- /dev/null
+++ b/app/bin/bitmaps/XCF/greendot.xcf
Binary files differ
diff --git a/app/bin/bitmaps/XCF/greydot.xcf b/app/bin/bitmaps/XCF/greydot.xcf
new file mode 100644
index 0000000..7e795a5
--- /dev/null
+++ b/app/bin/bitmaps/XCF/greydot.xcf
Binary files differ
diff --git a/app/bin/bitmaps/XCF/reddot.xcf b/app/bin/bitmaps/XCF/reddot.xcf
new file mode 100644
index 0000000..449581f
--- /dev/null
+++ b/app/bin/bitmaps/XCF/reddot.xcf
Binary files differ
diff --git a/app/bin/bitmaps/XCF/yellowdot.xcf b/app/bin/bitmaps/XCF/yellowdot.xcf
new file mode 100644
index 0000000..9395645
--- /dev/null
+++ b/app/bin/bitmaps/XCF/yellowdot.xcf
Binary files 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<F. ",
+" ............ "};
diff --git a/app/bin/bitmaps/document-exportdxf.xpm b/app/bin/bitmaps/document-exportdxf.xpm
new file mode 100644
index 0000000..fc4071b
--- /dev/null
+++ b/app/bin/bitmaps/document-exportdxf.xpm
@@ -0,0 +1,84 @@
+/* XPM */
+static char * export_dxf_xpm[] = {
+"16 16 65 1",
+" c None",
+". c #406C98",
+"+ c #DDF0FB",
+"@ c #D4E9F7",
+"# c #11CC22",
+"$ c #CEE4F4",
+"% c #CCE2F3",
+"& c #CCE1F2",
+"* c #A7C2DC",
+"= c #D6EBF7",
+"- c #C5DFEF",
+"; c #BCD6EA",
+"> 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;<a;qxxx",
+"xxq<;;&x=2pppqxx",
+"xxq===$o+;>#xxxx",
+"xxq=aid=$=,1>txx",
+"xxq=ilaf->44>txx",
+"x5qiijlsg-31=0xx",
+"5zzzzzzkjh1,#rxx",
+"x5Xuuhlsf1111exx",
+"xxw<uzpf211;:exx",
+"xx9;pys1<<;$+9xx",
+"xx0@&@=<;;=%#9xx",
+"xx8;<;;===$##7xx",
+"xx8*<<==+@++#7xx",
+"xx.677776667w xx"
+};
diff --git a/app/bin/bitmaps/dpolyline.xpm b/app/bin/bitmaps/dpolyline.xpm
new file mode 100644
index 0000000..7f01bda
--- /dev/null
+++ b/app/bin/bitmaps/dpolyline.xpm
@@ -0,0 +1,23 @@
+/* XPM */
+static char * dpolyline_xpm[] = {
+"16 16 3 1",
+"X c None",
+" c #FFFF00000000",
+". c #000000000000",
+"XXXXXXXXXXXXXXXX",
+"XXXXXXX .... XXX",
+"XXXXXXXXXX..XXXX",
+"XXXXXXXXX.XXXXXX",
+"XXXXXXX..XXXXXXX",
+"XXXXXX.XXXXXXXXX",
+"XXXX..XXXXXXXXXX",
+"XXX ...XXXXXXXXX",
+"XXXXXXX......XXX",
+" XXXXXXXXXXXX.. ",
+"X.XXXXXXXXXXXX.X",
+"X.XXXXXXXXXX..XX",
+"XX.XXXXXXXX.XXXX",
+"XXX.XXXXXX.XXXXX",
+"XXX.XXXX..XXXXXX",
+"XXXX .. XXXXXXXX"};
+
diff --git a/app/bin/bitmaps/export.xpm b/app/bin/bitmaps/export.xpm
deleted file mode 100644
index f6bc7d3..0000000
--- a/app/bin/bitmaps/export.xpm
+++ /dev/null
@@ -1,21 +0,0 @@
-/* XPM */
-static char * export_xpm[] = {
-"16 16 2 1",
-" c None",
-". c #000000000000",
-" .........",
-" . .",
-" . . .",
-" . . .",
-"...... . .",
-" .. .",
-" .. .",
-"...... . .",
-" . . .. .",
-" . .. . ..",
-" . .. ",
-" ",
-" . . ... .",
-" . . .",
-" . . . . .",
-" "};
diff --git a/app/bin/bitmaps/flash.xbm b/app/bin/bitmaps/flash.xbm
index 677978d..d135b2f 100644
--- a/app/bin/bitmaps/flash.xbm
+++ b/app/bin/bitmaps/flash.xbm
@@ -1,6 +1,6 @@
#define flash_width 24
#define flash_height 24
-static char flash_bits[] = {
+static unsigned char flash_bits[] = {
0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x08, 0x04, 0x02,
0x10, 0x04, 0x01, 0x20, 0x84, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00,
0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf5, 0x1f, 0x00, 0x00, 0x00,
diff --git a/app/bin/bitmaps/greendot.xpm b/app/bin/bitmaps/greendot.xpm
new file mode 100644
index 0000000..8c44035
--- /dev/null
+++ b/app/bin/bitmaps/greendot.xpm
@@ -0,0 +1,23 @@
+/* XPM */
+static char * greendot[] = {
+"16 16 4 1",
+" c None",
+". c #000000",
+"+ c #4E9A06",
+"@ c #59A51A",
+" ",
+" ",
+" .... ",
+" ..++++.. ",
+" .+@@@++++. ",
+" .@@@@@+++. ",
+" .+@@@@@++++. ",
+" .+@@@@@++++. ",
+" .++@@@+++++. ",
+" .++++++++++. ",
+" .++++++++. ",
+" .++++++++. ",
+" ..++++.. ",
+" .... ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/greenstar.xpm b/app/bin/bitmaps/greenstar.xpm
new file mode 100644
index 0000000..b83a4b9
--- /dev/null
+++ b/app/bin/bitmaps/greenstar.xpm
@@ -0,0 +1,69 @@
+/* XPM */
+static char * greenstar[] = {
+"16 16 50 1",
+" c None",
+". c #264706",
+"+ c #274906",
+"@ c #346408",
+"# c #386C09",
+"$ c #478A0D",
+"% c #46880C",
+"& c #224007",
+"* c #131D0A",
+"= c #234207",
+"- c #274B06",
+"; c #2D5306",
+"> 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<mno')!%h ",
+" pqirdstu2,vwxp ",
+" yzzzzzzzzzzzzy ",
+" ",
+" "};
diff --git a/app/bin/bitmaps/sticky-note-clip.xpm b/app/bin/bitmaps/sticky-note-clip.xpm
new file mode 100644
index 0000000..c74c64d
--- /dev/null
+++ b/app/bin/bitmaps/sticky-note-clip.xpm
@@ -0,0 +1,99 @@
+/* XPM */
+static char * sticky_note_clip_bits[] = {
+"16 16 80 1",
+" c None",
+". c #CCB301",
+"+ c #CAB101",
+"@ c #FBEF9C",
+"# c #F9EB8F",
+"$ c #F8EA8D",
+"% c #F8E98A",
+"& c #F7E992",
+"* c #EDE1A3",
+"= c #555753",
+"- c #DFCF67",
+"; c #D5C44D",
+"> 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 <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+
+#ifdef ENABLE_LOCALES
+#include <locale.h>
+#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 <stddef.h>
+
+/* 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;i<segs.cnt;i++) {
+ trkSeg_t t = DYNARR_N(trkSeg_t, segs, i);
+ if (t.type == SEG_CRVTRK || t.type == SEG_CRVLIN) {
+ dd += fabs((t.u.c.radius+(t.u.c.radius>0?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 <stdint.h>
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;i<extra_points.cnt;i++) {
+ posk[(end[0]?3:1)+i] = DYNARR_N(coOrd,extra_points,i);
+ type[(end[0]?3:1)+i] = SPIRO_G4;
+ }
+
+ posk[(end[0]?3:1)+extra_points.cnt] = pos[1];
+ coOrd pos1 = pos[1];
+
+ if (end[1]) {
+ type[(end[0]?3:1)+extra_points.cnt] = SPIRO_LEFT;
+ type[(end[0]?3:1)+extra_points.cnt+1] = SPIRO_G2;
+ type[(end[0]?3:1)+extra_points.cnt+2] = SPIRO_END_OPEN_CONTOUR;
+ if (cp->radius[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<Da.mid_points.cnt;i++) {
+ createMidPoint(&Da.midSegs, DYNARR_N(coOrd,Da.mid_points,i),selectMidPoint == i,TRUE, TRUE );
+ }
+ if (Da.radius[0] >=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<Da.mid_points.cnt;i++) {
+ d = FindDistance(DYNARR_N(coOrd,Da.mid_points,i),pos);
+ if (IsClose(d)) {
+ CreateCornuAnchor(DYNARR_N(coOrd,Da.mid_points,i),FALSE);
+ return C_CONTINUE;
+ }
+ }
+ for (int i=0;i<2;i++) {
+ if (Da.endHandle[i].end_valid == FALSE) continue;
+ d = FindDistance(Da.endHandle[i].end_center,pos);
+ if (IsClose(d)) {
+ CreateCornuAnchor(Da.endHandle[i].end_center, FALSE);
+ return C_CONTINUE;
+ }
+ }
+ for (int i=0;i<2;i++) {
+ if (Da.endHandle[i].end_valid == FALSE) continue;
+ d = FindDistance(Da.endHandle[i].end_curve,pos);
+ if (IsClose(d)) {
+ CreateCornuAnchor(Da.endHandle[i].end_curve, FALSE);
+ return C_CONTINUE;
+ }
+ }
+ coOrd temp_pos = pos;
+ if (IsClose(DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,NULL))) {
+ CreateCornuAnchor(temp_pos, TRUE);
+ }
+ }
+ return C_CONTINUE;
case C_DOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if (Da.state != PICK_POINT) return C_CONTINUE;
- dd = 10000.0;
- Da.selectPoint = -1;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ Da.selectEndHandle = -1;
+ Da.prevSelected = -1;
+ if (infoSubst) {
+ InfoSubstituteControls( NULL, NULL );
+ infoSubst = FALSE;
+ }
for (int i=0;i<2;i++) {
d = FindDistance(Da.pos[i],pos);
- if (d < dd) {
- dd = d;
- Da.selectPoint = i;
+ if (IsClose(d)) {
+ Da.selectEndPoint = i;
+ CreateCornuAnchor(Da.pos[i],FALSE);
+ break;
}
}
- if (!IsClose(dd) ) Da.selectPoint = -1;
- if (Da.selectPoint == -1) {
+ if (Da.selectEndPoint == -1) {
+ for (int i=0;i<Da.mid_points.cnt;i++) {
+ d = FindDistance(DYNARR_N(coOrd,Da.mid_points,i),pos);
+ if (IsClose(d)) {
+ Da.selectMidPoint = i;
+ Da.selectEndPoint = -1;
+ CreateCornuAnchor(DYNARR_N(coOrd,Da.mid_points,i),FALSE);
+ break;
+ }
+ }
+ if (Da.selectMidPoint == -1 ) {
+ for (int i=0;i<2;i++) {
+ if (Da.endHandle[i].end_valid == FALSE) continue;
+ d = FindDistance(Da.endHandle[i].end_center,pos);
+ if (IsClose(d)) {
+ Da.selectEndHandle = i*2;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ CreateCornuAnchor(Da.endHandle[i].end_center,i);
+ break;
+ }
+ }
+ if (Da.selectEndHandle == -1) {
+ for (int i=0;i<2;i++) {
+ if (Da.endHandle[i].end_valid == FALSE) continue;
+ d = FindDistance(Da.endHandle[i].end_curve,pos);
+ if (IsClose(d)) {
+ Da.selectEndHandle = 1+i*2;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ CreateCornuAnchor(Da.endHandle[i].end_curve,i);
+ break;
+ }
+ }
+ }
+ }
+ } else { //We picked an end point
+ if (!Da.trk[Da.selectEndPoint] && ((MyGetKeyState() & WKEY_SHIFT) != 0) && Da.selectTrack) { //With Shift no track -> 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<Da.mid_points.cnt;i++) {
+ temp_pos = DYNARR_N(coOrd ,Da.mid_points,i);
+ DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&nIndex);
+ if (((pIndex<=index) && (nIndex>=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<minLength) {
- InfoMessage(_("Too close to other end of selected Track"));
- return C_CONTINUE;
+ if (!inside) {
+ if (Da.ep[sel]>=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<minLength) {
+ InfoMessage(_("Too close to other end of selected Track"));
+ 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
+ }
+ }
+ } 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;i<Da.mid_points.cnt;i++) {
+ DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd,Da.mid_points,i+1);
+ }
+ Da.mid_points.cnt--;
+ }
+ Da.prevSelected = -1;
+ CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
+ cornuParm_t cp;
+ 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;
+ }
+ return C_CONTINUE;
+
case C_OK: //C_OK is not called by Modify.
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( Da.state == PICK_POINT ) {
Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
if (CornuTotalWindingArc(Da.pos,Da.crvSegs_da)>4*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<Da.mid_points.cnt;i++) {
+ sub_pos[1] = DYNARR_N(coOrd,Da.mid_points,i);
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point))== NULL) return C_TERMINATE;
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]) {
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ DrawNewTrack(trk1);
+ if (first_trk == NULL) first_trk = trk1;
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ trk2 = trk1;
+ end_point[0] = FALSE;
+ sub_pos[0] = DYNARR_N(coOrd,Da.mid_points,i);
}
-
- CopyAttributes( Da.trk[0], t );
+ sub_pos[1] = Da.pos[1];
+ end_point[1] = TRUE;
+ if (Da.radius[1] == -1) end_point[1] = FALSE;
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point)) == NULL) return C_TERMINATE;
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]){
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ if (first_trk == NULL) first_trk = trk1;
+ //t = NewCornuTrack( Da.pos, Da.center, Da.angle, Da.radius,(trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt);
for (int i=0;i<2;i++) {
- UndoModify(Da.trk[i]);
- MoveEndPt(&Da.trk[i],&Da.ep[i],Da.pos[i],0);
- if ((GetTrkType(Da.trk[i])==T_BEZIER) || (GetTrkType(Da.trk[i])==T_CORNU)) { //Bezier split position not precise, so readjust Cornu
- GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i]);
+ if (Da.trk[i]) {
+ UndoModify(Da.trk[i]);
+ MoveEndPt(&Da.trk[i],&Da.ep[i],Da.pos[i],0);
+ //End position not precise, so readjust Cornu
+ GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i],FALSE);
ANGLE_T endAngle = NormalizeAngle(GetTrkEndAngle(Da.trk[i],Da.ep[i])+180);
- SetCornuEndPt(t,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
+ SetCornuEndPt(i==0?first_trk:trk1,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
+ if (Da.ep[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<Da.tracks.cnt;i++) {
+ DrawTrack(DYNARR_N(track_p,Da.tracks,i),&mainD,wDrawColorWhite); //Wipe out real tracks, draw replacement
+ }
return AdjustCornuCurve(C_START, pos, InfoMessage);
+ case wActionMove:
+ return AdjustCornuCurve(wActionMove, pos, InfoMessage);
+ break;
+
case C_DOWN:
if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up
return AdjustCornuCurve(C_DOWN, pos, InfoMessage);
+ case C_LCLICK:
+ if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up
+ AdjustCornuCurve(C_DOWN, pos, InfoMessage);
+ return AdjustCornuCurve(C_UP, pos, InfoMessage);
case C_MOVE:
if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up and down
@@ -895,10 +1935,19 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG
return AdjustCornuCurve(C_UP, pos, InfoMessage); //Run Adjust
case C_TEXT:
- if ((action>>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<Da.mid_points.cnt;i++) {
+ sub_pos[1] = DYNARR_N(coOrd,Da.mid_points,i);
+ if ((trk1 = CreateCornuFromPoints(sub_pos, end_point))== 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]));
+ UndoUndo();
+ Da.state = NONE;
+ return C_TERMINATE;
+ }
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]) {
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ DrawNewTrack(trk1);
+ if (first_trk == NULL) first_trk = trk1;
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ trk2 = trk1;
+ end_point[0] = FALSE;
+ sub_pos[0] = DYNARR_N(coOrd,Da.mid_points,i);
+ }
+ sub_pos[1] = Da.pos[1];
+ end_point[1] = TRUE;
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point)) == 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,
@@ -954,15 +2039,26 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG
Da.angle[0],Da.angle[1],
FormatDistance(Da.radius[0]),FormatDistance(Da.radius[1]));
UndoUndo();
- MainRedraw();
- MapRedraw();
- //DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
+ Da.state = NONE;
return C_TERMINATE;
}
+ DrawNewTrack(trk1);
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]) {
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ if (first_trk == NULL) first_trk = trk1;
- CopyAttributes( trk, t );
+ Da.state = NONE; //Must do before Delete
- DeleteTrack(trk, TRUE);
+ for (int i=0;i<Da.tracks.cnt;i++) {
+ DeleteTrack(DYNARR_N(track_p,Da.tracks,i), TRUE);
+ }
if (Da.trk[0]) UndoModify(Da.trk[0]);
if (Da.trk[1]) UndoModify(Da.trk[1]);
@@ -970,13 +2066,12 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG
for (int i=0;i<2;i++) { //Attach new track
if (Da.trk[i] && Da.ep[i] != -1) { //Like the old track
if (MoveEndPt(&Da.trk[i],&Da.ep[i],Da.pos[i],0)) {
- if (GetTrkType(Da.trk[i])==T_BEZIER) { //Bezier split position not precise, so readjust Cornu
- GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i]);
- ANGLE_T endAngle = NormalizeAngle(GetTrkEndAngle(Da.trk[i],Da.ep[i])+180);
- SetCornuEndPt(t,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
- }
+ //Bezier split position not precise, so readjust Cornu
+ GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i],FALSE);
+ ANGLE_T endAngle = NormalizeAngle(GetTrkEndAngle(Da.trk[i],Da.ep[i])+180);
+ SetCornuEndPt(i==0?first_trk:trk1,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
if (Da.ep[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;i<segs.cnt;i++) {
+ trkSeg_t t = DYNARR_N(trkSeg_t, segs, i);
+ if (t.type == SEG_CRVTRK || t.type == SEG_CRVLIN) {
+ dd += fabs((t.u.c.radius+(t.u.c.radius>0?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; i<xx->cornuData.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<Da.mid_points.cnt;i++) {
+ sub_pos[1] = DYNARR_N(coOrd,Da.mid_points,i);
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point))== NULL) continue;
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]) {
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ DrawNewTrack(trk1);
+ if (first_trk == NULL) first_trk = trk1;
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ trk2 = trk1;
+ end_point[0] = FALSE;
+ sub_pos[0] = DYNARR_N(coOrd,Da.mid_points,i);
+ }
+ sub_pos[1] = Da.pos[1];
+ end_point[1] = TRUE;
+ if (Da.radius[1] == -1) end_point[1] = FALSE;
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point)) == NULL) continue;
+ created++;
+ DrawNewTrack(trk1);
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]){
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ if (first_trk == NULL) first_trk = trk1;
+
+ for (int i=0;i<2;i++) {
+ if (Da.ep[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; i<Da.tracks.cnt;i++) {
+ DeleteTrack(DYNARR_N(track_p,Da.tracks,i),FALSE);
+ deleted++;
+ }
+
+ UndoEnd(); //Stop accumulating
+ NoticeMessage(_("Tracks Counts: %d converted %d unconvertible %d created %d deleted"),_("OK"),NULL,converted,not_convertable,created,deleted);
+
+ return C_TERMINATE;
+
+ case C_REDRAW:
+ if (trk) {
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
+ }
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ return C_TERMINATE;
+
+ case C_OK:
+ return C_TERMINATE;
+
+ case C_CONFIRM:
+ return C_CONTINUE;
+
+ default:
+ return C_CONTINUE;
+ }
+}
+static STATUS_T CmdConvertFrom(
+ wAction_t action,
+ coOrd pos )
+{
+ static track_p trk;
+ track_p trk1,trk2;
+ switch (action) {
+
+ case wActionMove:
+ if ((trk = OnTrack(&pos,FALSE,TRUE)) == NULL) return C_CONTINUE;
+ if ((!(GetTrkType(trk) == T_CORNU)) ||
+ (!(GetTrkType(trk) == T_BEZIER)))
+ trk = NULL;
+ return C_CONTINUE;
+
+ case C_LCLICK:
+ if ((trk = OnTrack(&pos,FALSE,TRUE))!=NULL) {
+ SetTrkBits(trk,TB_SELECTED);
+ selectedTrackCount = 1;
+ trk = NULL;
+ } else {
+ wBeep();
+ InfoMessage( _("Not on a Track") );
+ trk = NULL;
+ return C_CONTINUE;
+ }
+ /* no break */
+ case C_START:
+ if (selectedTrackCount==0) {
+ InfoMessage( _("Select a Cornu or Bezier Track To Convert to Fixed") );
+ return C_CONTINUE;
+ }
+ else if (selectedTrackCount>1) {
+ 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<Da.tracks.cnt;i++) {
+ DeleteTrack(DYNARR_N(track_p,Da.tracks,i),FALSE);
+ deleted++;
+ }
+ UndoEnd();
+ NoticeMessage(_("Tracks Counts: %d converted %d unconvertible %d deleted"),_("OK"),NULL,converted,not_convertable,deleted);
+ return C_TERMINATE;
+
+ case C_REDRAW:
+ if (trk) {
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
+ }
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ return C_TERMINATE;
+
+ case C_OK:
+ return C_TERMINATE;
+
+ case C_CONFIRM:
+ return C_CONTINUE;
+
+ default:
+ return C_CONTINUE;
+ }
+}
+
+#include "bitmaps/convertto.xpm"
+#include "bitmaps/convertfr.xpm"
EXPORT void InitCmdCornu( wMenu_p menu )
{
-
+ ButtonGroupBegin( _("Convert"), "cmdConvertSetCmd", _("Convert") );
+ AddMenuButton( menu, CmdConvertTo, "cmdConvertTo", _("Convert To Cornu"), wIconCreatePixMap(convertto_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP3|IC_WANT_MOVE,ACCL_CONVERTTO, NULL );
+ AddMenuButton( menu, CmdConvertFrom, "cmdConvertFrom", _("Convert From Cornu"), wIconCreatePixMap(convertfr_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP3|IC_WANT_MOVE,ACCL_CONVERTFR, NULL );
+ cornuHotBarCmdInx = AddMenuButton(menu, cmdCornuCreate, "cmdCornuCreate", "", NULL, LEVEL0_50, IC_STICKY|IC_POPUP3|IC_WANT_MOVE, 0, NULL);
+ ButtonGroupEnd();
+ ParamCreateControls( &cornuModPG, cornuModDlgUpdate) ;
}
diff --git a/app/bin/ccornu.h b/app/bin/ccornu.h
index b279cb4..2bd1f49 100644
--- a/app/bin/ccornu.h
+++ b/app/bin/ccornu.h
@@ -11,13 +11,24 @@
typedef void (*cornuMessageProc)( char *, ... );
+#define cornuCmdNone (0)
+#define cornuJoinTrack (1)
+#define cornuCmdCreateTrack (2)
+#define cornuCmdHotBar (3)
+
#endif /* APP_BIN_CCORNU_H_ */
STATUS_T CmdCornu( wAction_t action, coOrd pos );
+BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p, BOOL_T spots);
DIST_T CornuMinRadius(coOrd pos[4],dynArr_t segs);
DIST_T CornuMaxRateofChangeofCurvature(coOrd pos[4],dynArr_t segs,DIST_T * last_c);
DIST_T CornuLength(coOrd pos[4],dynArr_t segs);
+DIST_T CornuOffsetLength(dynArr_t segs, double offset);
DIST_T CornuTotalWindingArc(coOrd pos[4],dynArr_t segs);
STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG);
+
+void InitCmdCornu( wMenu_p menu );
+
+void AddHotBarCornu( void );
diff --git a/app/bin/ccurve.c b/app/bin/ccurve.c
index 58bb5c1..e119610 100644
--- a/app/bin/ccurve.c
+++ b/app/bin/ccurve.c
@@ -39,57 +39,102 @@
#include "utility.h"
#include "wlib.h"
#include "cbezier.h"
+#include "ccornu.h"
+#include "layout.h"
/*
* STATE INFO
*/
+typedef enum createState_e {NOCURVE,FIRSTEND_DEF,SECONDEND_DEF,CENTER_DEF} createState_e;
+
static struct {
STATE_T state;
+ createState_e create_state;
coOrd pos0;
coOrd pos1;
curveData_t curveData;
track_p trk;
EPINX_T ep;
BOOL_T down;
+ BOOL_T lock0;
+ coOrd middle;
+ coOrd end0;
+ coOrd end1;
} Da;
static long curveMode;
+static dynArr_t anchors_da;
+#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N)
+#define array_anchor(N) DYNARR_N(trkSeg_t,*anchor_array,N)
+
-EXPORT void DrawArrowHeads(
+EXPORT int DrawArrowHeads(
trkSeg_p sp,
coOrd pos,
ANGLE_T angle,
BOOL_T bidirectional,
wDrawColor color )
{
- coOrd p0, p1;
- DIST_T d, w;
- int inx;
- d = mainD.scale*0.25;
- w = mainD.scale/mainD.dpi*2;
- for ( inx=0; inx<5; inx++ ) {
- sp[inx].type = SEG_STRLIN;
- sp[inx].width = w;
- sp[inx].color = color;
- }
- Translate( &p0, pos, angle, d );
- Translate( &p1, pos, angle+180, bidirectional?d:(d/2.0) );
- sp[0].u.l.pos[0] = p0;
- sp[0].u.l.pos[1] = p1;
- sp[1].u.l.pos[0] = p0;
- Translate( &sp[1].u.l.pos[1], p0, angle+135, d/2.0 );
- sp[2].u.l.pos[0] = p0;
- Translate( &sp[2].u.l.pos[1], p0, angle-135, d/2.0 );
- if (bidirectional) {
- sp[3].u.l.pos[0] = p1;
- Translate( &sp[3].u.l.pos[1], p1, angle-45, d/2.0 );
- sp[4].u.l.pos[0] = p1;
- Translate( &sp[4].u.l.pos[1], p1, angle+45, d/2.0 );
- }
+ coOrd p0, p1;
+ DIST_T d, w;
+ int inx;
+ d = mainD.scale*0.25;
+ w = mainD.scale/mainD.dpi*2;
+ for ( inx=0; inx<5; inx++ ) {
+ sp[inx].type = SEG_STRLIN;
+ sp[inx].width = w;
+ sp[inx].color = color;
+ }
+ Translate( &p0, pos, angle, d );
+ Translate( &p1, pos, angle+180, bidirectional?d:(d/2.0) );
+ sp[0].u.l.pos[0] = p0;
+ sp[0].u.l.pos[1] = p1;
+ sp[1].u.l.pos[0] = p0;
+ Translate( &sp[1].u.l.pos[1], p0, angle+135, d/2.0 );
+ sp[2].u.l.pos[0] = p0;
+ Translate( &sp[2].u.l.pos[1], p0, angle-135, d/2.0 );
+ if (bidirectional) {
+ sp[3].u.l.pos[0] = p1;
+ Translate( &sp[3].u.l.pos[1], p1, angle-45, d/2.0 );
+ sp[4].u.l.pos[0] = p1;
+ Translate( &sp[4].u.l.pos[1], p1, angle+45, d/2.0 );
+ } else {
+ sp[3].u.l.pos[0] = p1;
+ sp[3].u.l.pos[1] = p1;
+ sp[4].u.l.pos[0] = p1;
+ sp[4].u.l.pos[1] = p1;
+ }
+ return 5;
}
+EXPORT int DrawArrowHeadsArray(
+ dynArr_t *anchor_array,
+ coOrd pos,
+ ANGLE_T angle,
+ BOOL_T bidirectional,
+ wDrawColor color )
+{
+ int i = (*anchor_array).cnt;
+ DYNARR_SET(trkSeg_t,*anchor_array,i+5)
+ return DrawArrowHeads(&DYNARR_N(trkSeg_t,*anchor_array,i),pos,angle,bidirectional,color);
+
+}
+
+static void CreateEndAnchor(coOrd p, dynArr_t * anchor_array, wBool_t lock) {
+ DIST_T d = tempD.scale*0.15;
+
+ DYNARR_APPEND(trkSeg_t,*anchor_array,1);
+ int i = (*anchor_array).cnt-1;
+ array_anchor(i).type = lock?SEG_FILCRCL:SEG_CRVLIN;
+ array_anchor(i).color = wDrawColorBlue;
+ array_anchor(i).u.c.center = p;
+ array_anchor(i).u.c.radius = d/2;
+ array_anchor(i).u.c.a0 = 0.0;
+ array_anchor(i).u.c.a1 = 360.0;
+ array_anchor(i).width = 0;
+}
@@ -100,6 +145,7 @@ EXPORT STATUS_T CreateCurve(
wDrawColor color,
DIST_T width,
long mode,
+ dynArr_t * anchor_array,
curveMessageProc message )
{
track_p t;
@@ -110,23 +156,28 @@ EXPORT STATUS_T CreateCurve(
switch ( action ) {
case C_START:
- DYNARR_SET( trkSeg_t, tempSegs_da, 8 );
+ DYNARR_RESET(trkSeg_t,*anchor_array);
+ DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
+ Da.create_state = NOCURVE;
+ tempSegs_da.cnt = 0;
Da.down = FALSE; //Not got a valid start yet
+ Da.pos0 = zero;
+ Da.pos1 = zero;
switch ( curveMode ) {
case crvCmdFromEP1:
if (track)
- message(_("Drag from End-Point in direction of curve - Shift locks to track open end-point") );
+ message(_("Drag from endpoint in direction of curve - lock to track open endpoint") );
else
- message (_("Drag from End-Point in direction of curve") );
+ message (_("Drag from endpoint in direction of curve") );
break;
case crvCmdFromTangent:
if (track)
- message(_("Drag from End-Point to Center - Shift locks to track open end-point") );
+ message(_("Drag from endpoint to center - lock to track open endpoint") );
else
- message(_("Drag from End-Point to Center") );
+ message(_("Drag from endpoint to center") );
break;
case crvCmdFromCenter:
- message(_("Drag from Center to End-Point") );
+ message(_("Drag from center to endpoint") );
break;
case crvCmdFromChord:
message(_("Drag from one to other end of chord") );
@@ -134,6 +185,7 @@ EXPORT STATUS_T CreateCurve(
}
return C_CONTINUE;
case C_DOWN:
+ DYNARR_RESET(trkSeg_t, *anchor_array);
for ( inx=0; inx<8; inx++ ) {
tempSegs(inx).color = wDrawColorBlack;
tempSegs(inx).width = 0;
@@ -141,150 +193,212 @@ EXPORT STATUS_T CreateCurve(
tempSegs_da.cnt = 0;
p = pos;
BOOL_T found = FALSE;
- Da.trk = NULL;
- if ((mode == crvCmdFromEP1 || mode == crvCmdFromTangent) && track && (MyGetKeyState() & WKEY_SHIFT) != 0) {
- if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) {
- EPINX_T ep = PickUnconnectedEndPointSilent(p, t);
- if (ep != -1) {
- Da.trk = t;
- Da.ep = ep;
- pos = GetTrkEndPos(t, ep);
- found = TRUE;
- } else {
- Da.pos0=pos;
- message(_("No unconnected end-point on track - Try again or release Shift and click"));
- return C_CONTINUE;
- }
- } else {
- Da.pos0=pos;
- message(_("Not on a track - Try again or release Shift and click"));
- return C_CONTINUE;
+ Da.trk = NULL;
+ if (track) {
+ if ((mode == crvCmdFromEP1 || mode == crvCmdFromTangent || (mode == crvCmdFromChord)) &&
+ ((MyGetKeyState() & WKEY_ALT) == 0 ) == magneticSnap) {
+ if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) {
+ EPINX_T ep = PickUnconnectedEndPointSilent(p, t);
+ if (ep != -1) {
+ if (GetTrkScale(t) != (char)GetLayoutCurScale()) {
+ wBeep();
+ InfoMessage(_("Track is different gauge"));
+ return C_CONTINUE;
+ }
+ Da.trk = t;
+ Da.ep = ep;
+ pos = GetTrkEndPos(t, ep);
+ found = TRUE;
+ }
+ }
}
- Da.down = TRUE;
- }
+ } else {
+ if ((t = OnTrack(&p, FALSE, FALSE)) != NULL) {
+ if (!IsTrack(t)) {
+ pos = p;
+ found = TRUE;
+ }
+ }
+ }
Da.down = TRUE;
if (!found) SnapPos( &pos );
- pos0 = pos;
- Da.pos0 = pos;
+ Da.lock0 = found;
+
+ if (Da.create_state == NOCURVE)
+ Da.pos0 = pos;
+ else
+ Da.pos1 = pos;
+
+ tempSegs_da.cnt = 1;
switch (mode) {
case crvCmdFromEP1:
tempSegs(0).type = (track?SEG_STRTRK:SEG_STRLIN);
tempSegs(0).color = color;
tempSegs(0).width = width;
- if (Da.trk) message(_("End Locked: Drag out curve start"));
+ Da.create_state = FIRSTEND_DEF;
+ Da.end0 = pos;
+ CreateEndAnchor(pos,anchor_array,found);
+ if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) message(_("End locked: Drag out curve start"));
+ else if (Da.trk) message(_("End Position locked: Drag out curve start with Shift"));
else message(_("Drag along curve start") );
break;
case crvCmdFromTangent:
+ Da.create_state = FIRSTEND_DEF;
+ tempSegs(0).type = SEG_STRLIN;
+ tempSegs(0).color = color;
+ Da.create_state = CENTER_DEF;
+ CreateEndAnchor(pos,anchor_array,found);
+ if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) message(_("End locked: Drag out curve center"));
+ else if (Da.trk) message(_("End Position locked: Drag out curve start with Shift"));
+ else message(_("Drag out curve center") );
+ break;
case crvCmdFromCenter:
tempSegs(0).type = SEG_STRLIN;
- tempSegs(1).type = SEG_CRVLIN;
- tempSegs(1).u.c.radius = mainD.scale*0.05;
- tempSegs(1).u.c.a0 = 0;
- tempSegs(1).u.c.a1 = 360;
- tempSegs(2).type = SEG_STRLIN;
- if (Da.trk && mode==crvCmdFromTangent) message(_("End Locked: Drag out to center"));
- else
- message( mode==crvCmdFromTangent?_("Drag from End-Point to Center"):_("Drag from Center to End-Point") );
+ tempSegs(0).color = color;
+ Da.create_state = CENTER_DEF;
+ CreateEndAnchor(pos,anchor_array,FALSE);
+ message(_("Drag out from center to endpoint"));
break;
case crvCmdFromChord:
tempSegs(0).type = (track?SEG_STRTRK:SEG_STRLIN);
tempSegs(0).color = color;
tempSegs(0).width = width;
- message( _("Drag to other end of chord") );
+ CreateEndAnchor(pos,anchor_array,FALSE);
+ Da.create_state = FIRSTEND_DEF;
+ if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT))
+ message( _("End locked: Drag to other end of chord") );
+ else if (Da.trk) message(_("End Position locked: Drag out curve start with Shift"));
+ else
+ message( _("Drag to other end of chord") );
break;
}
- tempSegs(0).u.l.pos[0] = pos;
+ tempSegs(0).u.l.pos[0] = tempSegs(0).u.l.pos[1] = pos;
return C_CONTINUE;
case C_MOVE:
+ DYNARR_RESET(trkSeg_t,*anchor_array);
+ DYNARR_APPEND(trkSeg_t,*anchor_array,1);
if (!Da.down) return C_CONTINUE;
- if (Da.trk) {
+ if (Da.trk && !(MyGetKeyState() & WKEY_SHIFT)) { //Shift inhibits direction lock
angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk, Da.ep));
- angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1);
- if (mode ==crvCmdFromEP1) {
+ 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)) );
- 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)<minLength) {
+ ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(FindDistance(Da.pos0,Da.pos1)) );
+ return C_TERMINATE;
+ }
}
switch (mode) {
case crvCmdFromEP1:
- DrawArrowHeads( &tempSegs(1), pos, FindAngle(pos,pos0)+90, TRUE, drawColorRed );
- tempSegs_da.cnt = 6;
- break;
- case crvCmdFromChord:
- tempSegs(1).color = drawColorRed;
case crvCmdFromTangent:
case crvCmdFromCenter:
- tempSegs(2).color = drawColorRed;
- tempSegs(3).color = drawColorRed;
- tempSegs(4).color = drawColorRed;
- tempSegs(5).color = drawColorRed;
- tempSegs(6).color = drawColorRed;
- break;
+ case crvCmdFromChord:
+ for (int i=0;i<(*anchor_array).cnt;i++) {
+ DYNARR_N(trkSeg_t,*anchor_array,i).color = drawColorRed;
+ }
+ break;
}
message( _("Drag on Red arrows to adjust curve") );
return C_CONTINUE;
@@ -296,6 +410,7 @@ EXPORT STATUS_T CreateCurve(
}
+
static STATUS_T CmdCurve( wAction_t action, coOrd pos )
{
track_p t;
@@ -310,38 +425,71 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos )
Da.state = -1;
Da.pos0 = pos;
tempSegs_da.cnt = 0;
+ segCnt = 0;
STATUS_T rcode;
- return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage );
-
- case C_TEXT:
- if ( Da.state == 0 )
- return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage );
- else
- return C_CONTINUE;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage );
case C_DOWN:
- if ( Da.state == -1 ) {
- //SnapPos( &pos );
- Da.pos0 = pos;
+ if (Da.state == -1) {
+ BOOL_T found = FALSE;
+ if (curveMode != crvCmdFromCenter ) {
+ if (((MyGetKeyState() & WKEY_ALT)==0) == magneticSnap) {
+ if ((t = OnTrack(&pos,FALSE,TRUE))!=NULL) {
+ EPINX_T ep = PickUnconnectedEndPointSilent(pos, t);
+ if (ep != -1) {
+ if (GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) {
+ wBeep();
+ InfoMessage(_("Track is different gauge"));
+ return C_CONTINUE;
+ }
+ pos = GetTrkEndPos(t, ep);
+ found = TRUE;
+ }
+ }
+ }
+ }
+ if (!found) SnapPos( &pos );
+ Da.pos0 = Da.pos1 = pos;
Da.state = 0;
- rcode = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage );
+ rcode = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage );
+ segCnt = tempSegs_da.cnt ;
if (!Da.down) Da.state = -1;
return rcode;
//Da.pos0 = pos;
- } else {
- tempSegs_da.cnt = segCnt;
- return C_CONTINUE;
}
+ //This is where the user could adjust - if we allow that?
+ tempSegs_da.cnt = segCnt;
+ return C_CONTINUE;
+
+
+ case wActionMove:
+ if ((Da.state<0) && (curveMode != crvCmdFromCenter)) {
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (((MyGetKeyState() & WKEY_ALT)==0) == magneticSnap) {
+ if ((t=OnTrack(&pos,FALSE,TRUE))!= NULL) {
+ if (GetTrkGauge(t) == GetScaleTrackGauge(GetLayoutCurScale())) {
+ EPINX_T ep = PickUnconnectedEndPointSilent(pos, t);
+ if (ep != -1) {
+ pos = GetTrkEndPos(t, ep);
+ CreateEndAnchor(pos,&anchors_da,FALSE);
+ }
+ }
+ }
+ }
+ }
+ return C_CONTINUE;
case C_MOVE:
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 ) {
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))<minLength) {
+ ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) );
+ return C_TERMINATE;
+ }
Da.state = 1;
- CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage );
- DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, &anchors_da, InfoMessage );
+ tempSegs_da.cnt = 1;
mainD.funcs->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))<minLength) {
+ ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(fabs(minLength-d)) );
+ return C_TERMINATE;
+ }
+ PlotCurve( curveMode, Da.pos0, Da.pos1, Da.middle, &Da.curveData, TRUE );
+ }
+ mainD.funcs->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 <math.h>
#include <stdint.h>
#include <string.h>
+#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;i<segsArr->cnt;i++) {
+ trkSeg_p sp = &DYNARR_N(trkSeg_t,*segsArr,i);
+ if (sp->type == SEG_BEZLIN || sp->type == SEG_BEZTRK ) {
+ for (int j=0;j<sp->bezSegs.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;i<segsArr->cnt;i++) {
+ trkSeg_p sp = &DYNARR_N(trkSeg_t,*segsArr,i);
+ if (sp->type == SEG_BEZLIN || sp->type == SEG_BEZTRK ) {
+ for (int l=0;l<sp->bezSegs.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; k<slices;k++) {
+ if (spb->u.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; k<slices;k++) {
+ if (sp->u.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;i<segPtr->u.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;i<segPtr->u.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;i<segPtr->u.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;i<segPtr->u.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<drawModCmdContext.max_inx))) {
+ wMenuPushEnable( drawModRound,TRUE);
+ wMenuPushEnable( drawModVertex, TRUE);
+ wMenuPushEnable( drawModSmooth, TRUE);
+ }
+ wMenuPushEnable( drawModFill, (!drawModCmdContext.open) && (!drawModCmdContext.filled));
+ wMenuPushEnable( drawModEmpty, (!drawModCmdContext.open) && (drawModCmdContext.filled));
+ wMenuPushEnable( drawModClose, drawModCmdContext.open);
+ wMenuPushEnable( drawModOpen, !drawModCmdContext.open);
+ }
+ wMenuPushEnable( drawModOrigin,drawModCmdContext.rotate_state);
+ wMenuPushEnable( drawModLast,drawModCmdContext.rotate_state && (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;i<xx->segs[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; i<xx->segs[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;j<number;j++) {
+ DYNARR_APPEND(coOrd,params->nodes,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;i<xx->segs[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; inx2<dsp->cnt; 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; segInx<segCnt; segInx++ ) {
if ( refCount(segInx) == inx ) {
@@ -608,19 +609,25 @@ EXPORT void DoUngroup( void )
static drawCmd_t groupD = {
- NULL, &tempSegDrawFuncs, DC_GROUP, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix };
+ NULL, &tempSegDrawFuncs, DC_SEGTRACK, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix };
static long groupSegCnt;
static long groupReplace;
+static double groupOriginX;
+static double groupOriginY;
char * groupReplaceLabels[] = { N_("Replace with new group?"), NULL };
static wWin_p groupW;
static paramIntegerRange_t r0_999999 = { 0, 999999 };
+static paramFloatRange_t r_1000_1000 = { -1000.0, 1000.0, 80 };
static paramData_t groupPLs[] = {
/*0*/ { PD_STRING, groupManuf, "manuf", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)350, N_("Manufacturer"), 0, 0, sizeof(groupManuf)},
/*1*/ { PD_STRING, groupDesc, "desc", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)230, N_("Description"), 0, 0, sizeof(groupDesc)},
/*2*/ { PD_STRING, groupPartno, "partno", PDO_NOPREF|PDO_DLGHORZ|PDO_DLGIGNORELABELWIDTH|PDO_STRINGLIMITLENGTH, (void*)100, N_("#"), 0, 0, sizeof(groupPartno)},
/*3*/ { PD_LONG, &groupSegCnt, "segcnt", PDO_NOPREF, &r0_999999, N_("# Segments"), BO_READONLY },
-/*4*/ { PD_TOGGLE, &groupReplace, "replace", 0, groupReplaceLabels, "", BC_HORZ|BC_NOBORDER } };
+#define I_GROUP_ORIGIN_OFFSET 4 /* Need to change if add above */
+/*4*/ { PD_FLOAT, &groupOriginX, "orig", PDO_DIM, &r_1000_1000, N_("Offset X,Y:")},
+/*5*/ { PD_FLOAT, &groupOriginY, "origy",PDO_DIM | PDO_DLGHORZ, &r_1000_1000, ""},
+/*6*/ { PD_TOGGLE, &groupReplace, "replace", 0, groupReplaceLabels, "", BC_HORZ|BC_NOBORDER } };
static paramGroup_t groupPG = { "group", 0, groupPLs, sizeof groupPLs/sizeof groupPLs[0] };
@@ -652,18 +659,14 @@ static dynArr_t pathElem_da;
static int pathElemStart;
-static BOOL_T CheckTurnoutEndPoint(
- trkSeg_p segs,
- coOrd pos,
- int end )
-{
- coOrd pos1;
- DIST_T d;
- pos1 = GetSegEndPt( segs, end, FALSE, NULL );
- d = FindDistance( pos, pos1 );
- return ( d < connectDistance );
-}
-
+/*
+ * Find sub-path that connects the 2 EPs for the given track
+ *
+ * \param trk IN Track
+ * \param ep1, ep2 IN EndPt index
+ * \param BOOL_T *flip OUT whether path is flipped
+ * \return sub-path that connects the 2 EPs
+ */
static char * FindPathBtwEP(
track_p trk,
EPINX_T ep1,
@@ -671,12 +674,11 @@ static char * FindPathBtwEP(
BOOL_T * flip )
{
struct extraData * xx = GetTrkExtraData( trk );
- char * cp, *cp0;
- int epN;
- coOrd pos1, pos2;
- int segInx;
- EPINX_T segEP;
+ char * cp;
+ coOrd trkPos[2];
+
+ LOG( log_group, 3, (" FindPathBtwEP: T%d .%d .%d = ", trk?GetTrkIndex(trk):-1, ep1, ep2 ));
if ( GetTrkType(trk) != T_TURNOUT ) {
if ( ep1+ep2 != 1 )
AbortProg( "findPathBtwEP" );
@@ -685,40 +687,63 @@ static char * FindPathBtwEP(
cp = CreateSegPathList(trk); // Make path
LOG( log_group, 2, ( " Group: Cornu path:%s \n", cp ) )
} else cp = "\1\0\0"; //One segment (but could be a Bezier)
+ LOG( log_group, 3, (" Flip:%s Path= Seg=%d-\n", *flip?"T":"F", *cp ) );
return cp;
}
cp = (char *)xx->paths;
- 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; inx<groupTrk_da.cnt; inx++ ) {
@@ -793,7 +818,7 @@ if (log_shortPath<=0||logTable(log_shortPath).level<4) LOG( log_group, 2, ( "
}
}
if ( ep1<0 || ep2<0 ) {
-LOG( log_group, 2, ( " Remove: ep not found\n" ) )
+LOG( log_group, 4, ( " Remove: ep not found\n" ) )
pathElem_da.cnt = pathElemStart;
return 0;
}
@@ -801,7 +826,7 @@ LOG( log_group, 2, ( " Remove: ep not found\n" ) )
pp = &path(inx);
if ( ( ep1 < 0 || ( pp->ep1 == 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( "<NULL>\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; inx<segInMap_da.cnt; inx++ ) {
+ LogPrintf( "%d: %s X%d - ", inx+1, segInMap(inx).track?"Track":"Other", segInMap(inx).inx );
+ LogSeg( GetSegFromSegMap( inx ) );
+ }
+}
if ( groupTrk_da.cnt>0 ) {
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; inx<tempEndPts_da.cnt; inx++ ) {
+ endPtP = &tempEndPts(inx);
+ LogPrintf( " [ %0.3f %0.3f ] A:%0.3f, T:%d.%d\n",
+ endPtP->pos.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; inx<tempEndPts_da.cnt; inx++ ) {
+ endPtP = &tempEndPts(inx);
+ LogPrintf( " [ %0.3f %0.3f ] A:%0.3f, T:%d.%d\n",
+ endPtP->pos.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<groupTrk_da.cnt; inx++ ) {
trk = groupTrk(inx).trk;
@@ -1162,13 +1314,37 @@ static void GroupOk( void * junk )
trk1 = GetTrkEndTrk(trk,ep);
if ( trk1 == NULL || !GetTrkSelected(trk1) ) {
/* boundary EP */
+ LOG( log_group, 3, ("FindShortPath: T%d.%d\n", GetTrkIndex(trk), ep ) );
rc = FindShortestPath( trk, ep, FALSE, GroupShortestPathFunc, NULL );
}
}
}
-
+if ( log_group >= 1 && logTable(log_group).level >= 3 ) {
+ LogPrintf( "Shortest path:\n Group Tracks\n" );
+ for ( int inx=0; inx<groupTrk_da.cnt; inx++ ) {
+ groupTrk_p gtp = &groupTrk(inx);
+ LogPrintf( " %d: T%d S%d-%d\n", inx, GetTrkIndex( gtp->trk ), gtp->segStart+1, gtp->segEnd+1 );
+ }
+ LogPrintf( " Path Elem\n" );
+ for ( int inx=0; inx<pathElem_da.cnt; inx++ ) {
+ ppp = &pathElem(inx);
+ LogPrintf( " %d: GTx: %d, EP: %d %d, F:%s, P:",
+ inx, ppp->groupInx, 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; inx<path_da.cnt; inx++ ) {
+ path_p pp = &path(inx);
+ LogPrintf( " %d: PE: %d-%d, EP: %d-%d, Conf: %d, InGrp: %s, Done: %s\n",
+ inx, pp->pathElemStart, 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; pinx<path_da.cnt; pinx++ ) {
pp = &path(pinx);
- LogPrintf( "P%2d:%d.%d ", pinx, pp->ep1, 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; inx<path_da.cnt; inx++ ) {
- pp = &path(inx);
- for ( inx2=pp->pathElem_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; inx3<groupP->segCnt; 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; inx<groupTrk_da.cnt; inx++ ) {
- groupP = &groupTrk(inx);
- LogPrintf( "%2d", GetTrkIndex(groupP->trk) );
- for ( inx2=1; inx2<groupP->segCnt; inx2++ ) LogPrintf( "--" );
- }
- LogPrintf( "\n " );
- for ( inx=0; inx<groupTrk_da.cnt; inx++ ) {
- groupP = &groupTrk(inx);
- for ( inx2=0; inx2<groupP->segCnt; inx2++ )
- LogPrintf( "%2d", inx2+1 );
- }
- LogPrintf( "\n" );
- for ( inx=0; inx<path_da.cnt; inx++ ) {
- LogPrintf( "%2d ", inx );
- for ( inx2=0; inx2<trackSegs_da.cnt; inx2++ )
- LogPrintf( "%2d", segMap(inx,inx2) );
- LogPrintf("\n");
- }
-}
-#endif
/*
- * Create Conflict Map
+ * 5: Create Conflict Map
*/
DYNARR_SET( int, conflictMap_da, path_da.cnt*path_da.cnt );
memset( conflictMap_da.ptr, 0, conflictMap_da.max * sizeof conflictMap(0,0) );
@@ -1353,42 +1476,18 @@ if ( log_group >= 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<groupCnt; pinx++ ) {
LogPrintf( "G%d:", pinx );
for ( ginx=0; groupMap(pinx,ginx) >= 0; ginx++ )
- LogPrintf( " %d", groupMap(pinx,ginx) );
+ LogPrintf( " %d: %d", ginx, groupMap(pinx,ginx) );
LogPrintf( "\n" );
}
}
-#ifdef SEGMAP
- for ( inx=0; inx<path_da.cnt; inx++ ) {
- for ( inx2=0; inx2<tempSegs_da.cnt; inx2++ ) {
- groupInx = 0;
- memset( &SegTotal(0), 0, tempSegs_da.cnt * sizeof SegAcc(0) );
- while (1) {
- memcpy( &SegAcc(0), &SegTotal(0), tempSegs_da.cnt * sizeof SegAcc(0) );
- collision = FALSE;
- for ( inx=0; inx<path_da.cnt; inx++ ) {
- pp = path(0);
- if ( pp->groupInx < 0 ) continue;
- for ( inx2=0; inx2<tempSegs_da.cnt; inx2++ ) {
- if ( !segMap(inx,inx2) ) continue;
- if ( SegAcc(inx2) ) {
- collision = TRUE;
- break;
- }
- SegAcc(inx2) = TRUE;
- }
- }
- if ( collision )
- }
-#endif
-
/*
- * Count number of times each segment is used as flipped
+ * 6: Count number of times each segment is used as flipped
*/
DYNARR_SET( int, conflictMap_da, trackSegs_da.cnt );
memset( &segFlip(0), 0, trackSegs_da.cnt * sizeof segFlip(0) );
@@ -1414,15 +1513,17 @@ if ( log_group >= 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<trackSegs_da.cnt; pinx++ ) {
if ( segFlip(pinx) < 0 ) {
-LOG( log_group, 1, ( "Flipping Segment %d\n", pinx+1 ) );
SegProc( SEGPROC_FLIP, &trackSegs(pinx), NULL );
+LOG( log_group, 3, ( " %d", pinx ) );
}
}
+LOG( log_group, 3, ( "\n" ) );
/*
- * Output Path lists
+ * 7: Output Path lists
*/
for ( pinx=0; pinx<groupCnt; pinx++ ) {
sprintf( message, "P%d", pinx );
@@ -1431,8 +1532,10 @@ LOG( log_group, 1, ( "Flipping Segment %d\n", pinx+1 ) );
memcpy( &pathPtr(inx), message, pathPtr_da.cnt-inx );
for ( ginx=0; groupMap(pinx,ginx) >= 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; i<segInMap_da.cnt;i++) {
+ DYNARR_APPEND(trkSeg_t,outputSegs_da,10);
+ trkSeg_p from_p = GetSegFromSegMap(i);
+ trkSeg_p to_p = &DYNARR_LAST(trkSeg_t, outputSegs_da);
+ memcpy((void *)to_p,(void *)from_p,sizeof( trkSeg_t));
}
- GetSegBounds( zero, 0, trackSegs_da.cnt, &trackSegs(0), &orig, &size );
+ CloneFilledDraw( outputSegs_da.cnt, outputSegs_da.ptr, FALSE );
+
+ GetSegBounds( zero, 0, outputSegs_da.cnt, &outputSegs(0), &orig, &size );
orig.x = - tempEndPts(0).pos.x;
orig.y = - tempEndPts(0).pos.y;
- MoveSegs( trackSegs_da.cnt, &trackSegs(0), orig );
+ MoveSegs( outputSegs_da.cnt, &outputSegs(0), orig );
for ( ep=0; ep<tempEndPts_da.cnt; ep++ ) {
tempEndPts(ep).pos.x += orig.x;
tempEndPts(ep).pos.y += orig.y;
}
/*
- * Final: create new definition
+ * 9: Final: create new definition
+ */
+
+ CheckPaths( outputSegs_da.cnt, &outputSegs(0), path );
+
+ to = CreateNewTurnout( curScaleName, groupTitle, outputSegs_da.cnt, &outputSegs(0), pathLen, path, tempEndPts_da.cnt, &tempEndPts(0), NULL, TRUE );
+
+ /*
+ * 10: Write defn to xtrkcad.cus
*/
- CheckPaths( trackSegs_da.cnt, &trackSegs(0), path );
- to = CreateNewTurnout( curScaleName, groupTitle, trackSegs_da.cnt, &trackSegs(0), pathLen, path, tempEndPts_da.cnt, &tempEndPts(0), TRUE );
-#ifdef LATER
- if ( xx )
- to->customInfo = 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; ep<tempEndPts_da.cnt; ep++ ) {
@@ -1544,18 +1654,15 @@ groupSimpleTurnout:
} else {
CloneFilledDraw( tempSegs_da.cnt, &tempSegs(0), TRUE );
GetSegBounds( zero, 0, tempSegs_da.cnt, &tempSegs(0), &orig, &size );
- orig.x = - orig.x;
- orig.y = - orig.y;
+
+ orig.x = - orig.x-groupOriginX; //Include orig offset
+ orig.y = - orig.y-groupOriginY;
MoveSegs( tempSegs_da.cnt, &tempSegs(0), orig );
to = CreateNewStructure( curScaleName, groupTitle, tempSegs_da.cnt, &tempSegs(0), TRUE );
f = OpenCustom("a");
if (f && to) {
oldLocale = SaveLocale("C");
rc &= fprintf( f, "STRUCTURE %s \"%s\"\n", curScaleName, PutTitle(groupTitle) )>0;
-#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"