summaryrefslogtreecommitdiff
path: root/app/bin
diff options
context:
space:
mode:
authorJΓΆrg Frings-FΓΌrst <debian@jff-webhosting.net>2020-08-24 21:26:53 +0200
committerJΓΆrg Frings-FΓΌrst <debian@jff-webhosting.net>2020-08-24 21:26:53 +0200
commitdf247efec654e512242e4f4f1b0212034f9e01fe (patch)
tree25c02e16957f3aa613af30c140fd8e8a3d52fda6 /app/bin
parentd0b6a8a4ec298024f14f704f9e40a6f9d324ccf3 (diff)
parenta5ade52caa489cf0a713e0f02b764000d203140e (diff)
Merge branch 'release/debian/1%5.2.0Beta2.1-1' into masterdebian/1%5.2.0Beta2.1-1
Diffstat (limited to 'app/bin')
-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.xtp697
-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
191 files changed, 36965 insertions, 9289 deletions
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"
#include "track.h"
EXPORT DIST_T curBarScale = -1;
@@ -57,7 +58,7 @@ typedef struct {
DIST_T labelW;
coOrd size;
coOrd orig;
- BOOL_T isTrack;
+ BOOL_T isFixed;
void * context;
hotBarProc_t proc;
DIST_T barScale;
@@ -72,12 +73,15 @@ static int hotBarCurrEnds[2] = { -1, -1 };
#define hotBarCurrEnd (hotBarCurrEnds[programMode])
static DIST_T hotBarWidth = 0.0;
-static void HotBarHighlight( int inx )
+static void HotBarHighlight( int inx, DIST_T fixed_x )
{
wPos_t x0;
- if ( inx >= hotBarCurrStart && inx < hotBarCurrEnd ) {
- x0 = (wPos_t)((hotBarMap(inx).x-hotBarMap((int)hotBarCurrStart).x)*hotBarD.dpi);
- wDrawFilledRectangle( hotBarD.d, x0, 0, (wPos_t)(hotBarMap(inx).w*hotBarD.dpi-2), hotBarHeight, wDrawColorBlack, wDrawOptTemp );
+ if ( inx == 0 && hotBarMap_da.cnt>0 && hotBarMap(0).isFixed) {
+ x0 = (wPos_t)0;
+ wDrawFilledRectangle( hotBarD.d, x0, 0, (wPos_t)(hotBarMap(0).w*hotBarD.dpi-2), hotBarHeight, wDrawColorBlack, wDrawOptTransparent );
+ } else if ( inx >= hotBarCurrStart && inx < hotBarCurrEnd ) {
+ x0 = (wPos_t)((hotBarMap(inx).x-hotBarMap((int)hotBarCurrStart).x + (inx>0?fixed_x:0))*hotBarD.dpi);
+ wDrawFilledRectangle( hotBarD.d, x0, 0, (wPos_t)(hotBarMap(inx).w*hotBarD.dpi-2), hotBarHeight, wDrawColorBlack, wDrawOptTransparent );
}
}
@@ -105,11 +109,38 @@ static void RedrawHotBar( wDraw_p dd, void * data, wPos_t w, wPos_t h )
if ( hotBarLabels && !hotBarFp )
hotBarFp = wStandardFont( F_HELV, FALSE, FALSE );
wPos_t textSize = wMessageGetHeight(0L);
+ DIST_T fixed_x = 0.0;
+ if (hotBarCurrStart>0 && hotBarMap_da.cnt>0 && hotBarMap(0).isFixed) { //Do fixed element first - Cornu
+ tbm = &hotBarMap(0);
+ barScale = tbm->barScale;
+ x = 0.0;
+ orig.y = hh/2.0*barScale - tbm->size.y/2.0 - tbm->orig.y;
+ if ( hotBarLabels ) {
+ orig.y += textSize/hotBarD.dpi*barScale;
+ if ( tbm->labelW > tbm->objectW ) {
+ fixed_x = tbm->labelW;
+ x += (tbm->labelW-tbm->objectW)/2;
+ } else fixed_x = tbm->objectW;
+ } else fixed_x = tbm->objectW;
+ x *= barScale;
+ orig.x = x;
+ hotBarD.scale = barScale;
+ hotBarD.size.x = barWidth*barScale;
+ hotBarD.size.y = barHeight*barScale;
+ tbm->proc( HB_DRAW, tbm->context, &hotBarD, &orig );
+ if ( hotBarLabels ) {
+ hotBarD.scale = 1.0;
+ orig.x = 0.0;
+ orig.y = 2.0/hotBarD.dpi; //Draw Label under icon
+ DrawString( &hotBarD, orig, 0.0, tbm->proc( HB_BARTITLE, tbm->context, NULL, NULL ), hotBarFp, hotBarFs, drawColorBlack );
+ }
+
+ }
for ( inx=hotBarCurrStart; inx < hotBarMap_da.cnt; inx++ ) {
tbm = &hotBarMap(inx);
barScale = tbm->barScale;
- x = tbm->x - hotBarMap(hotBarCurrStart).x;
- if ( x + tbm->w > barWidth ) {
+ x = tbm->x - hotBarMap(hotBarCurrStart).x + fixed_x; //Add space for fixed at start
+ if ( x + tbm->w + fixed_x > barWidth ) {
break;
}
orig.y = hh/2.0*barScale - tbm->size.y/2.0 - tbm->orig.y;
@@ -120,6 +151,7 @@ static void RedrawHotBar( wDraw_p dd, void * data, wPos_t w, wPos_t h )
}
}
x *= barScale;
+ x -= tbm->orig.x;
orig.x = x;
hotBarD.scale = barScale;
hotBarD.size.x = barWidth*barScale;
@@ -127,14 +159,15 @@ static void RedrawHotBar( wDraw_p dd, void * data, wPos_t w, wPos_t h )
tbm->proc( HB_DRAW, tbm->context, &hotBarD, &orig );
if ( hotBarLabels ) {
hotBarD.scale = 1.0;
- orig.x = tbm->x - hotBarMap(hotBarCurrStart).x;
+ orig.x = tbm->x - hotBarMap(hotBarCurrStart).x + fixed_x;
orig.y = 2.0/hotBarD.dpi; //Draw Label under icon
DrawString( &hotBarD, orig, 0.0, tbm->proc( HB_BARTITLE, tbm->context, NULL, NULL ), hotBarFp, hotBarFs, drawColorBlack );
}
}
hotBarCurrEnd = inx;
- if (hotBarCurrSelect >= hotBarCurrStart && hotBarCurrSelect < hotBarCurrEnd )
- HotBarHighlight( hotBarCurrSelect );
+ if ((hotBarCurrSelect==0 && hotBarMap_da.cnt>0 && hotBarMap(0).isFixed) ||
+ ((hotBarCurrSelect >= hotBarCurrStart) && (hotBarCurrSelect < hotBarCurrEnd)) )
+ HotBarHighlight( hotBarCurrSelect, fixed_x );
/* else
hotBarCurrSelect = -1;*/
wControlActive( (wControl_p)hotBarRightB, hotBarCurrEnd < hotBarMap_da.cnt );
@@ -223,17 +256,33 @@ static void SelectHotBar( wDraw_p d, void * context, wAction_t action, wPos_t w,
wMenuPopupShow( hotbarPopupM );
return;
}
- x = w/hotBarD.dpi + hotBarMap(hotBarCurrStart).x;
- for ( inx=hotBarCurrStart; inx<hotBarCurrEnd; inx++ ) {
- if ((x >= hotBarMap(inx).x) && //leave spaces between buttons
- (x <= hotBarMap(inx).x + hotBarMap(inx).w )) {
- break;
+ inx = -1;
+ x = hotBarMap(0).x;
+ DIST_T fixed_x = 0.0;
+ if (hotBarCurrStart>0 && hotBarMap_da.cnt>0 && hotBarMap(0).isFixed) {
+ fixed_x = hotBarMap(0).w;
+ x = w/hotBarD.dpi + hotBarMap(0).x;
+ if ( (x>= hotBarMap(0).x) &&
+ (x <=hotBarMap(0).w )) inx = 0; //Match on fixed
+ }
+ if (inx<0){ //NoMatch
+ x = w/hotBarD.dpi + hotBarMap(hotBarCurrStart).x;
+ for ( inx=hotBarCurrStart; inx<hotBarCurrEnd; inx++ ) {
+ if ((x >= hotBarMap(inx).x + fixed_x) && //leave spaces between buttons
+ (x <= hotBarMap(inx).x + hotBarMap(inx).w + fixed_x )) {
+ break;
+ }
}
}
+
if (inx >= hotBarCurrEnd)
return;
tbm = &hotBarMap(inx);
- px = (wPos_t)((tbm->x-hotBarMap(hotBarCurrStart).x)*hotBarD.dpi);
+ if (inx==0) {
+ px = (wPos_t)((tbm->x-hotBarMap(0).x)*hotBarD.dpi);
+ } else {
+ px = (wPos_t)(((tbm->x-hotBarMap(hotBarCurrStart).x)+fixed_x)*hotBarD.dpi);
+ }
px += (wPos_t)(tbm->w*hotBarD.dpi/2);
titleP = tbm->proc( HB_LISTTITLE, tbm->context, NULL, NULL );
px -= wLabelWidth( titleP ) / 2;
@@ -243,12 +292,14 @@ static void SelectHotBar( wDraw_p d, void * context, wAction_t action, wPos_t w,
pos.x = mainD.size.x+mainD.orig.x;
pos.y = mainD.size.y+mainD.orig.y;
if ( hotBarCurrSelect >= 0 ) {
- HotBarHighlight( hotBarCurrSelect );
+ //HotBarHighlight( hotBarCurrSelect );
hotBarCurrSelect = -1;
+ RedrawHotBar(hotBarD.d, NULL, 0, 0 );
}
+
tbm->proc( HB_SELECT, tbm->context, NULL, NULL );
hotBarCurrSelect = inx;
- HotBarHighlight( hotBarCurrSelect );
+ HotBarHighlight( hotBarCurrSelect, fixed_x );
if (recordF) {
fprintf( recordF, "HOTBARSELECT %s\n", tbm->proc( HB_FULLTITLE, tbm->context, NULL, NULL ) );
}
@@ -296,8 +347,9 @@ static void SelectHotBar( wDraw_p d, void * context, wAction_t action, wPos_t w,
EXPORT void HotBarCancel( void )
{
if ( hotBarCurrSelect >= 0 )
- HotBarHighlight( hotBarCurrSelect );
+ //HotBarHighlight( hotBarCurrSelect );
hotBarCurrSelect = -1;
+ RedrawHotBar(hotBarD.d, NULL, 0, 0 );
}
@@ -306,18 +358,23 @@ static BOOL_T HotBarSelectPlayback( char * line )
int inx;
hotBarMap_t * tbm;
while (*line && isspace((unsigned char)*line) ) line++;
+ DIST_T fixed_x = 0;
for ( inx=0; inx<hotBarMap_da.cnt; inx++ ) {
tbm = &hotBarMap(inx);
+ if (inx == 0 && hotBarMap_da.cnt>0 && hotBarMap(0).isFixed) {
+ fixed_x = hotBarMap(0).w;
+ }
if ( strcmp( tbm->proc( HB_FULLTITLE, tbm->context, NULL, NULL ), line) == 0) {
if ( hotBarCurrSelect >= 0 ) {
- HotBarHighlight( hotBarCurrSelect );
+ //HotBarHighlight( hotBarCurrSelect );
+ RedrawHotBar(hotBarD.d, NULL, 0, 0 );
}
hotBarCurrSelect = inx;
if ( hotBarCurrSelect < hotBarCurrStart || hotBarCurrSelect > hotBarCurrEnd ) {
hotBarCurrStart = hotBarCurrSelect;
RedrawHotBar( hotBarD.d, NULL, 0, 0 );
}
- HotBarHighlight( hotBarCurrSelect );
+ HotBarHighlight( hotBarCurrSelect, fixed_x );
hotBarMap(inx).proc( HB_SELECT, hotBarMap(inx).context, NULL, NULL );
FakeDownMouseState();
return TRUE;
@@ -347,6 +404,7 @@ EXPORT void AddHotBarElement(
coOrd size,
coOrd orig,
BOOL_T isTrack,
+ BOOL_T isFixed,
DIST_T barScale,
void * context,
hotBarProc_t proc_p )
@@ -360,10 +418,13 @@ EXPORT void AddHotBarElement(
}
if (barScale <= 0) {
- if (isTrack)
+ if (!isTrack)
+ barScale = size.y/((double)hotBarDrawHeight/hotBarD.dpi);
+ else if (isTrack) {
barScale = (trackGauge>0.1)?trackGauge*24:10;
- else
- barScale = size.y/((double)hotBarDrawHeight/hotBarD.dpi-0.07);
+ if (size.y >= size.x)
+ barScale = size.y/((double)hotBarDrawHeight/hotBarD.dpi);
+ }
}
DYNARR_APPEND( hotBarMap_t, hotBarMap_da, 10 );
tbm = &hotBarMap(hotBarMap_da.cnt-1);
@@ -376,6 +437,7 @@ EXPORT void AddHotBarElement(
tbm->orig = orig;
tbm->proc = proc_p;
tbm->barScale = barScale;
+ tbm->isFixed = isFixed;
tbm->w = tbm->objectW = size.x/barScale + 5.0/hotBarD.dpi;
tbm->labelW = 0;
tbm->x = hotBarWidth;
@@ -409,6 +471,8 @@ static void ChangeHotBar( long changes )
DYNARR_RESET( hotBarMap_t, hotBarMap_da );
curContentsLabel[0] = '\0';
if ( programMode == MODE_DESIGN ) {
+ if (showFlexTrack)
+ AddHotBarCornu();
AddHotBarTurnouts();
AddHotBarStructures();
} else {
@@ -446,6 +510,13 @@ EXPORT void LayoutHotBar( void * redraw )
wWinGetSize( mainW, &winWidth, &winHeight );
hotBarHeight = hotBarDrawHeight;
+ double scaleicon;
+ wPrefGetFloat(PREFSECTION, LARGEICON, &scaleicon, 1.0);
+ if (scaleicon<1.0) scaleicon=1.0;
+ if (scaleicon>2.0) scaleicon=2.0;
+ if (scaleicon>1.0) {
+ hotBarHeight = hotBarHeight*scaleicon;
+ }
if ( hotBarLabels) {
hotBarHeight += wMessageGetHeight(0L);
}
diff --git a/app/bin/cjoin.c b/app/bin/cjoin.c
index 8cfa3d4..71f4dae 100644
--- a/app/bin/cjoin.c
+++ b/app/bin/cjoin.c
@@ -1,5 +1,5 @@
/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cjoin.c,v 1.4 2008-03-06 19:35:05 m_fischer Exp $
+ * $Header: /home/dave/Source/xtrkcad_5_1_2a/app/bin/RCS/cjoin.c,v 1.3 2019/07/24 15:11:51 dave Exp $
*
* JOINS
*
@@ -39,7 +39,7 @@
#include "cselect.h"
#include "fileio.h"
-
+static BOOL_T debug = 0;
static int log_join = 0;
typedef struct {
curveType_e type;
@@ -53,25 +53,18 @@ typedef struct {
static struct {
STATE_T state;
int joinMoveState;
+ BOOL_T cornuMode;
struct {
TRKTYP_T realType;
track_p trk;
coOrd pos;
EPINX_T ep;
trackParams_t params;
-#ifdef LATER
- curveType_e type;
- ANGLE_T angle;
- coOrd lineOrig;
- coOrd lineEnd;
- coOrd arcP;
- DIST_T arcR;
- ANGLE_T arcA0, arcA1;
-#endif
} inp[2];
joinRes_t jRes;
coOrd inp_pos[2];
easementData_t jointD[2];
+ dynArr_t anchors;
} Dj;
@@ -169,7 +162,8 @@ LOG( log_join, 2, (" = CURVE @ Pc=[%0.3f %0.3f] R=%0.3f A0=%0.3f A1=%0.3f Fli
d = D2R(res->arcA1);
if (d < 0.0)
d = 2*M_PI + d;
- InfoMessage( _("Curved Track: Radius=%s Length=%s"),
+ if (!debug)
+ InfoMessage( _("Curved Track: Radius=%s Length=%s"),
FormatDistance(res->arcR), FormatDistance(res->arcR*d) );
return TRUE;
@@ -213,7 +207,7 @@ LOG( log_join, 3, (" p1=[%0.3f %0.3f] aa=%0.3f a=%0.3f\n",
/* Straight: */
PointOnCircle( &pt, pos0, r0, a1);
LOG( log_join, 2, (" = STRAIGHT [%0.3f %0.3f] [%0.3f %0.3f]\n", pt.x, pt.y, pos1.x, pos1.y ) )
- InfoMessage( _("Straight Track: Length=%s Angle=%0.3f"),
+ if (!debug) InfoMessage( _("Straight Track: Length=%s Angle=%0.3f"),
FormatDistance(FindDistance( pt, pos1 )), PutAngle(FindAngle( pt, pos1 )) );
res->type = curveTypeStraight;
res->pos[0]=pt;
@@ -255,7 +249,7 @@ LOG( log_join, 3, (" A0=%0.3f A1=%0.3f R=%0.3f\n", res->arcA0, res->arcA1,
d = D2R(res->arcA1);
if (d < 0.0)
d = 2*M_PI + d;
- InfoMessage( _("Curved Track: Radius=%s Length=%s Angle=%0.3f"),
+ if (!debug) InfoMessage( _("Curved Track: Radius=%s Length=%s Angle=%0.3f"),
FormatDistance(res->arcR), FormatDistance(res->arcR*d), PutAngle(res->arcA1) );
res->type = curveTypeCurve;
}
@@ -302,11 +296,11 @@ static STATUS_T AdjustJoint(
switch ( Dj.inp[0].params.type ) {
case curveTypeCurve:
if (adjust) {
- a0 = FindAngle( Dj.inp[0].params.arcP, Dj.jRes.pos[0] ) +
- ((Dj.jointD[0].Scurve==TRUE || Dj.jointD[0].flip==FALSE)?0:+180);
+ a0 = FindAngle( Dj.inp[0].params.arcP, Dj.jRes.pos[0] );
Translate( &pc, Dj.inp[0].params.arcP, a0, Dj.jointD[0].x );
-LOG( log_join, 2, (" Move P0 X%0.3f A%0.3f P1 X%0.3f A%0.3f)\n",
- Dj.jointD[0].x, a0, Dj.jointD[1].x, a1 ) )
+LOG( log_join, 2, (" Move P0 X%0.3f A%0.3f P1 X%0.3f A%0.3f SC%d FL%d\n",
+ Dj.jointD[0].x, a0, Dj.jointD[1].x, a1,
+ Dj.jointD[0].Scurve, Dj.jointD[0].flip ) )
} else {
pc = Dj.inp[0].params.arcP;
}
@@ -368,7 +362,8 @@ LOG( log_join, 2, (" Move P0 X%0.3f A%0.3f P1 X%0.3f A%0.3f\n",
}
d -= l;
if ( d <= minLength ) {
- InfoMessage( _("Connecting track is too short by %0.3f"), PutDim(fabs(minLength-d)) );
+ if (!debug)
+ InfoMessage( _("Connecting track is too short by %0.3f"), PutDim(fabs(minLength-d)) );
return FALSE;
}
@@ -415,7 +410,6 @@ static STATUS_T DoMoveToJoin( coOrd pos )
_("Click on an unselected End-Point"):
_("Click on a selected End-Point") );
Dj.inp[0].pos = pos;
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
return C_CONTINUE;
}
if ( GetTrkSelected(Dj.inp[0].trk) == GetTrkSelected(Dj.inp[1].trk) ) {
@@ -423,7 +417,6 @@ static STATUS_T DoMoveToJoin( coOrd pos )
? _("unselected") : _("selected") );
return C_CONTINUE;
}
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
if (GetTrkSelected(Dj.inp[0].trk))
MoveToJoin( Dj.inp[0].trk, Dj.inp[0].params.ep, Dj.inp[1].trk, Dj.inp[1].params.ep );
else
@@ -432,6 +425,372 @@ static STATUS_T DoMoveToJoin( coOrd pos )
return C_TERMINATE;
}
+typedef enum {NO_LINE,FIRST_END,HAVE_LINE,HAVE_SECOND_LINE} LineState_t;
+
+static struct {
+ LineState_t line_state;
+ int joinMoveState;
+ track_p curr_line;
+ struct {
+ TRKTYP_T realType;
+ track_p line;
+ coOrd pos;
+ coOrd end;
+ int cnt;
+ } inp[2];
+ joinRes_t jRes;
+ coOrd inp_pos[2];
+ dynArr_t anchors_da;
+ trackParams_t params;
+ dynArr_t newLine;
+ } Dl;
+
+#define anchors(N) DYNARR_N(trkSeg_t,Dl.anchors_da,N)
+
+void AddAnchorEnd(coOrd p) {
+ DIST_T d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,Dl.anchors_da,1);
+ trkSeg_p a = &DYNARR_LAST(trkSeg_t,Dl.anchors_da);
+ a->type = SEG_CRVLIN;
+ a->width = 0;
+ a->u.c.a0 = 0.0;
+ a->u.c.a1 = 360.0;
+ a->u.c.center = p;
+ a->u.c.radius = d/2;
+ a->color = wDrawColorPowderedBlue;
+}
+
+
+static STATUS_T CmdJoinLine(
+ wAction_t action,
+ coOrd pos )
+/*
+ * Join 2 lines.
+ */
+{
+
+ switch (action&0xFF) {
+ case C_START:
+ InfoMessage( _("Left click - Select first draw object end") );
+ Dl.line_state = NO_LINE;
+ Dl.joinMoveState = 0;
+ tempSegs_da.cnt = 0;
+ DYNARR_RESET(trkSeg_t,Dl.newLine);
+ Dl.curr_line = NULL;
+ return C_CONTINUE;
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,Dl.anchors_da);
+ Dl.curr_line = NULL;
+ coOrd pos1= pos;
+ Dl.curr_line = OnTrack( &pos1, FALSE, FALSE );
+ if (!Dl.curr_line) return C_CONTINUE;
+ if (IsTrack(Dl.curr_line)) {
+ Dl.curr_line = NULL;
+ return C_CONTINUE;
+ }
+ if (!QueryTrack(Dl.curr_line,Q_GET_NODES)) {
+ Dl.curr_line = NULL;
+ return C_CONTINUE;
+ }
+ if (!GetTrackParams(PARAMS_NODES,Dl.curr_line,pos,&Dl.params)) {
+ Dl.curr_line = NULL;
+ return C_CONTINUE;
+ }
+ if ( (Dl.line_state != NO_LINE) &&
+ (Dl.inp[0].line == Dl.curr_line) &&
+ (IsClose(FindDistance(Dl.inp[0].pos,Dl.params.lineOrig)) ) ) {
+ Dl.curr_line = NULL;
+ } else {
+ AddAnchorEnd(Dl.params.lineOrig);
+ }
+ break;
+ case C_DOWN:
+ DYNARR_RESET(trkSeg_t,Dl.anchors_da);
+ Dl.curr_line = NULL;
+ if (Dl.line_state == NO_LINE) {
+ Dl.curr_line = OnTrack( &pos, FALSE, FALSE);
+ if (!Dl.curr_line || IsTrack(Dl.curr_line)) {
+ InfoMessage( _("Not a line - Try again") );
+ return C_CONTINUE;
+ }
+ if (!QueryTrack(Dl.curr_line,Q_GET_NODES)) return C_CONTINUE;
+ if (!GetTrackParams(PARAMS_NODES,Dl.curr_line,pos,&Dl.params)) return C_CONTINUE;
+ Dl.line_state = HAVE_LINE;
+ Dl.inp[0].line = Dl.curr_line;
+ Dl.inp[0].pos = Dl.params.lineOrig;
+ Dl.inp[0].end = Dl.params.lineEnd;
+ DYNARR_SET(trkSeg_t,Dl.newLine,1);
+
+ DYNARR_LAST(trkSeg_t,Dl.newLine).type = SEG_POLY;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).color = wDrawColorBlack;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).width = 0;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.polyType = POLYLINE;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts = MyMalloc(sizeof(pts_t)*Dl.params.nodes.cnt);
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.cnt = Dl.params.nodes.cnt;
+ //Copy in reverse as we want this point to be last
+ for (int i=0;i<Dl.params.nodes.cnt;i++) {
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[i].pt = DYNARR_N(coOrd,Dl.params.nodes,Dl.params.nodes.cnt-1-i);
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[i].pt_type = wPolyLineStraight;
+ }
+ InfoMessage( _("Left click - Select second object end") );
+ } else {
+ Dl.curr_line = OnTrack( &pos, FALSE, FALSE );
+ if (!Dl.curr_line || IsTrack(Dl.curr_line)) {
+ InfoMessage( _("Not a line - Try again") );
+ return C_CONTINUE;
+ }
+ if (!QueryTrack(Dl.curr_line,Q_GET_NODES)) return C_CONTINUE;
+ if (!GetTrackParams(PARAMS_NODES,Dl.curr_line,pos,&Dl.params)) return C_CONTINUE;
+ if (Dl.curr_line == Dl.inp[0].line) {
+ if ((Dl.params.lineOrig.x == Dl.inp[0].pos.x) &&
+ (Dl.params.lineOrig.y == Dl.inp[0].pos.y)) {
+ InfoMessage( _("Same draw object and same endpoint - Try again") );
+ return C_CONTINUE;
+ }
+ }
+ Dl.line_state = HAVE_SECOND_LINE;
+ Dl.inp[1].line = Dl.curr_line;
+ Dl.inp[1].pos = Dl.params.lineOrig;
+ Dl.inp[1].end = Dl.params.lineEnd;
+ int old_cnt = DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.cnt;
+ BOOL_T join_near = FALSE;
+ if (Dl.inp[1].line == Dl.inp[0].line) {
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts = MyRealloc(DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts,sizeof(pts_t)*(old_cnt+1));
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[old_cnt] = DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[0]; // Joined up Polygon
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.cnt += 1;
+ } else {
+ if (IsClose(FindDistance(Dl.inp[0].pos,Dl.inp[1].pos)))
+ join_near = TRUE;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts = MyRealloc(DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts,sizeof(pts_t)*(old_cnt+Dl.params.nodes.cnt-join_near));
+ //Copy forwards as this point is first
+ for (int i=join_near;i<Dl.params.nodes.cnt;i++) {
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[i-join_near+old_cnt].pt = DYNARR_N(coOrd,Dl.params.nodes,i);
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[i-join_near+old_cnt].pt_type = wPolyLineStraight;
+ }
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.cnt += Dl.params.nodes.cnt-join_near;
+ }
+ }
+ UndrawNewTrack(Dl.curr_line);
+ Dl.curr_line = NULL;
+ break;
+ case C_MOVE:
+ break;
+ case C_UP:
+ if (Dl.line_state != HAVE_SECOND_LINE) return C_CONTINUE;
+ Dl.line_state = NO_LINE;
+ UndoStart(_("Create PolyLine"), "newPolyLine");
+ track_p newTrack = MakePolyLineFromSegs( zero, 0.0, &Dl.newLine );
+ DeleteTrack(Dl.inp[0].line,FALSE);
+ if (Dl.inp[0].line != Dl.inp[1].line)
+ DeleteTrack(Dl.inp[1].line,FALSE);
+ UndoEnd();
+ DrawNewTrack(newTrack);
+ CleanSegs(&Dl.newLine);
+ Dl.curr_line = NULL;
+ return C_TERMINATE;
+ break;
+ case C_CANCEL:
+ CleanSegs(&Dl.newLine);
+ Dl.line_state = NO_LINE;
+ Dl.curr_line = NULL;
+ break;
+ case C_REDRAW:
+ if (Dl.line_state != NO_LINE) DrawSegs(&tempD,zero,0.0,((trkSeg_t*)Dl.newLine.ptr), Dl.newLine.cnt, trackGauge, wDrawColorPreviewSelected);
+ if (Dl.curr_line) DrawTrack(Dl.curr_line,&tempD,wDrawColorPreviewSelected);
+ if (Dl.anchors_da.cnt>0)
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), Dl.anchors_da.cnt, trackGauge, wDrawColorPreviewSelected );
+ break;
+ case C_TEXT:
+ case C_OK:
+ default:;
+
+ }
+
+
+ return C_CONTINUE;
+
+}
+
+void AnchorTempLine(coOrd p0, coOrd p1) {
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ p->type = SEG_STRLIN;
+ p->color = wDrawColorBlue;
+ p->width = 0.0;
+ p->u.l.pos[0] = p0;
+ p->u.l.pos[1] = p1;
+}
+
+void AnchorTempCircle(coOrd center,DIST_T radius, ANGLE_T a0, ANGLE_T a1) {
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ p->type = SEG_CRVLIN;
+ p->color = wDrawColorBlue;
+ p->width = 0.0;
+ p->u.c.a0 =a0;
+ p->u.c.a1 = a1;
+ p->u.c.radius = radius;
+ p->u.c.center = center;
+}
+
+void AnchorPoint(coOrd center) {
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ p->type = SEG_CRVLIN;
+ p->color = wDrawColorAqua;
+ p->width = 0.0;
+ p->u.c.a0 =0.0;
+ p->u.c.a1 = 360.0;
+ p->u.c.radius = mainD.scale/4;
+ p->u.c.center = center;
+}
+
+static DIST_T desired_radius = 0.0;
+
+static paramFloatRange_t r_0_10000 = { 0.0, 100000.0 };
+static paramData_t joinPLs[] = {
+#define joinRadPD (joinPLs[0])
+#define joinRadI 0
+ { PD_FLOAT, &desired_radius, "radius", PDO_DIM, &r_0_10000, N_("Desired Radius") }
+};
+static paramGroup_t joinPG = { "join-fixed", 0, joinPLs, sizeof joinPLs/sizeof joinPLs[0] };
+
+
+
+BOOL_T AdjustPosToRadius(coOrd *pos, DIST_T desired_radius, ANGLE_T an0, ANGLE_T an1) {
+ coOrd point1,point2;
+ switch ( Dj.inp[1].params.type ) {
+ case curveTypeCurve:
+ if (Dj.inp[0].params.type == curveTypeStraight) {
+ coOrd newP, newP1;
+ //Offset curve by desired_radius
+ DIST_T newR1;
+ newR1 = Dj.inp[1].params.arcR + desired_radius*((fabs(an1-Dj.inp[1].params.arcA0)<1.0)?1:-1);
+ if (newR1<=0.0) {
+ if (debug) InfoMessage("Zero Radius C1");
+ return FALSE;
+ }
+ //Offset line by desired_radius
+ Translate(&newP,Dj.inp[0].params.lineEnd,an0,desired_radius);
+ Translate(&newP1,Dj.inp[0].params.lineOrig,an0,desired_radius);
+ if (debug)
+ AnchorTempLine(newP,newP1);
+ //Intersect - this is the joining curve center
+ if (debug)
+ AnchorTempCircle(Dj.inp[1].params.arcP,newR1,Dj.inp[1].params.arcA0,Dj.inp[1].params.arcA1);
+ if (!FindArcAndLineIntersections(&point1,&point2,Dj.inp[1].params.arcP,newR1,newP,newP1))
+ return FALSE;
+ } else if (Dj.inp[0].params.type == curveTypeCurve) {
+ //Offset curve by desired_radius
+ DIST_T newR0;
+ newR0 = Dj.inp[0].params.arcR + desired_radius*((fabs(an0-Dj.inp[0].params.arcA0)<1.0)?1:-1);
+ if (newR0<=0.0) {
+ if (debug) InfoMessage("Zero Radius C0");
+ return FALSE;
+ }
+ //Offset curve by desired_radius
+ if (debug)
+ AnchorTempCircle(Dj.inp[0].params.arcP,newR0,Dj.inp[0].params.arcA0,Dj.inp[0].params.arcA1);
+ DIST_T newR1;
+ newR1 = Dj.inp[1].params.arcR + desired_radius*((fabs(an1-Dj.inp[1].params.arcA0)<1.0)?1:-1);
+ if (newR1<=0.0) {
+ if (debug) InfoMessage("Zero Radius C1");
+ return FALSE;
+ }
+ //Intersect - this is the joining curve center
+ if (debug)
+ AnchorTempCircle(Dj.inp[1].params.arcP,newR1,Dj.inp[1].params.arcA0,Dj.inp[1].params.arcA1);
+ if (!FindArcIntersections(&point1,&point2,Dj.inp[0].params.arcP,newR0,Dj.inp[1].params.arcP,newR1))
+ return FALSE;
+ }
+ if (debug) {
+ AnchorPoint(point1);
+ AnchorPoint(point2);
+ }
+ break;
+ case curveTypeStraight:
+ if (Dj.inp[0].params.type == curveTypeStraight) {
+ coOrd newI,newP0,newP01, newP1, newP11;
+ //Offset line1 by desired_radius
+ Translate(&newP0,Dj.inp[0].params.lineEnd,an0,desired_radius);
+ Translate(&newP01,Dj.inp[0].params.lineOrig,an0,desired_radius);
+ if (debug)
+ AnchorTempLine(newP0,newP01);
+ //Offset line2 by desired_radius
+ Translate(&newP1,Dj.inp[1].params.lineEnd,an1,desired_radius);
+ Translate(&newP11,Dj.inp[1].params.lineOrig,an1,desired_radius);
+ if (debug)
+ AnchorTempLine(newP1,newP11);
+ if (!FindIntersection(&newI,newP0,Dj.inp[0].params.angle,newP1,Dj.inp[1].params.angle))
+ return FALSE;
+ point1 = point2 = newI;
+ } else if (Dj.inp[0].params.type == curveTypeCurve) {
+ coOrd newP, newP1;
+ //Offset curve by desired_radius
+ DIST_T newR0;
+ newR0 = Dj.inp[0].params.arcR + desired_radius*((fabs(an0-Dj.inp[0].params.arcA0)<1.0)?1:-1);
+ if (newR0<=0.0) {
+ if (debug) InfoMessage("Zero Radius C0");
+ return FALSE;
+ }
+ if (debug)
+ AnchorTempCircle(Dj.inp[0].params.arcP,newR0,Dj.inp[0].params.arcA0,Dj.inp[0].params.arcA1);
+ //Offset line by desired_radius
+ Translate(&newP,Dj.inp[1].params.lineEnd,an1,desired_radius);
+ Translate(&newP1,Dj.inp[1].params.lineOrig,an1,desired_radius);
+ if (debug)
+ AnchorTempLine(newP,newP1);
+ //Intersect - this is the joining curve center
+ if (!FindArcAndLineIntersections(&point1,&point2,Dj.inp[0].params.arcP,newR0,newP,newP1))
+ return FALSE;
+ }
+ if (debug) {
+ AnchorPoint(point1);
+ AnchorPoint(point2);
+ }
+ break;
+ default:
+ return FALSE;
+ }
+ if (FindDistance(*pos,point1)<=FindDistance(*pos,point2)) {
+ if (Dj.inp[1].params.type == curveTypeCurve) {
+ ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,point1);
+ Translate(pos,Dj.inp[1].params.arcP,a,Dj.inp[1].params.arcR);
+ } else {
+ Translate(pos,point1,NormalizeAngle(an1+180),desired_radius);
+ }
+ } else {
+ if (Dj.inp[1].params.type == curveTypeCurve) {
+ ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,point2);
+ Translate(pos,Dj.inp[1].params.arcP,a,Dj.inp[1].params.arcR);
+ } else
+ Translate(pos,point2,NormalizeAngle(an1+180),desired_radius);
+ }
+
+ return TRUE;
+
+}
+
+void AddAnchorJoin(coOrd pos, ANGLE_T angle) {
+ DIST_T d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p a = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ a->type = SEG_CRVLIN;
+ a->width = 0;
+ a->u.c.a0 = 0.0;
+ a->u.c.a1 = 360.0;
+ a->u.c.center = pos;
+ a->u.c.radius = d/2;
+ a->color = wDrawColorBlue;
+ DYNARR_SET(trkSeg_t,Dj.anchors,Dj.anchors.cnt+5);
+ DrawArrowHeads(&DYNARR_N(trkSeg_t,Dj.anchors,Dj.anchors.cnt-5),pos,angle,FALSE,wDrawColorBlue);
+
+}
+
+static BOOL_T infoSubst = FALSE;
+static track_p anchor_trk;
+static coOrd anchor_pos;
+static ANGLE_T anchor_angle = 0.0;
static STATUS_T CmdJoin(
wAction_t action,
@@ -451,26 +810,63 @@ static STATUS_T CmdJoin(
ANGLE_T a, a1;
DIST_T eR[2];
BOOL_T ok;
+ wControl_p controls[2];
+ char * labels[1];
switch (action&0xFF) {
case C_START:
+ if (joinPLs[0].control==NULL) {
+ ParamCreateControls(&joinPG, NULL);
+ }
if (selectedTrackCount==0)
InfoMessage( _("Left click - join with track") );
else
InfoMessage( _("Left click - join with track, Shift Left click - move to join") );
+ DYNARR_RESET(trkSeg_t,Dj.anchors);
Dj.state = 0;
Dj.joinMoveState = 0;
+ Dj.cornuMode = FALSE;
/*ParamGroupRecord( &easementPG );*/
- if (easementVal < 0)
+ infoSubst = FALSE;
+ anchor_trk = NULL;
+ if (easementVal < 0.0)
return CmdCornu(action, pos);
return C_CONTINUE;
+
+ case wActionMove:
+ anchor_trk = NULL;
+ DYNARR_RESET(rkSeg_t,Dj.anchors);
+ if ((easementVal < 0) && Dj.joinMoveState == 0 )
+ return CmdCornu(action, pos);
+ if ( Dj.state >= 2) return C_CONTINUE;
+ if ( (trk = OnTrack( &pos, FALSE, TRUE )) == NULL)
+ return C_CONTINUE;
+ if (!CheckTrackLayer( trk ) )
+ return C_CONTINUE;
+ if ((Dj.state > 0) && (trk == Dj.inp[0].trk))
+ return C_CONTINUE;
+ trackParams_t moveParams;
+ if (!GetTrackParams( PARAMS_1ST_JOIN, trk, pos, &moveParams ))
+ return C_CONTINUE;
+ ep = PickUnconnectedEndPointSilent(pos,trk);
+ if (ep <0) return C_CONTINUE;
+ if (IsClose(FindDistance(GetTrkEndPos(trk,ep),pos)))
+ anchor_angle = GetTrkEndAngle(trk,ep);
+ else
+ anchor_angle = FindAngle(pos,GetTrkEndPos(trk,ep));
+ anchor_trk = trk;
+ anchor_pos = pos;
+ AddAnchorJoin(pos,anchor_angle);
+ break;
case C_DOWN:
- if ( (Dj.state == 0 && (MyGetKeyState() & WKEY_SHIFT) != 0) || Dj.joinMoveState != 0 )
+ if ( !Dj.cornuMode && ((Dj.state == 0 && (MyGetKeyState() & WKEY_SHIFT) != 0) || Dj.joinMoveState != 0) )
return DoMoveToJoin( pos );
- if (easementVal < 0.0)
+ if (easementVal < 0.0 && Dj.joinMoveState == 0) {
+ Dj.cornuMode = TRUE;
return CmdCornu(action, pos);
+ }
DYNARR_SET( trkSeg_t, tempSegs_da, 3 );
tempSegs(0).color = drawColorBlack;
@@ -495,10 +891,18 @@ LOG( log_join, 1, ("JOIN: 1st track %d @[%0.3f %0.3f]\n",
Dj.inp[0].realType = GetTrkType(Dj.inp[0].trk);
InfoMessage( _("Select 2nd track") );
Dj.state = 1;
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
+ wPrefGetFloat("misc", "desired_radius", &desired_radius, desired_radius);
+ controls[0] = joinRadPD.control;
+ controls[1] = NULL;
+ labels[0] = N_("Desired Radius");
+ InfoSubstituteControls(controls, labels);
+ infoSubst = TRUE;
+ joinRadPD.option |= PDO_NORECORD;
+ ParamLoadControls(&joinPG);
+ ParamGroupRecord(&joinPG);
return C_CONTINUE;
} else {
- if ( (Dj.inp[1].trk = OnTrack( &pos, TRUE, TRUE )) == NULL)
+ if ( (Dj.inp[1].trk = OnTrack( &pos, FALSE, TRUE )) == NULL)
return C_CONTINUE;
if (!CheckTrackLayer( Dj.inp[1].trk ) )
return C_CONTINUE;
@@ -509,6 +913,10 @@ LOG( log_join, 1, ("JOIN: 1st track %d @[%0.3f %0.3f]\n",
ErrorMessage( MSG_JOIN_SAME );
return C_CONTINUE;
}
+ if (infoSubst)
+ InfoSubstituteControls(NULL, NULL);
+ infoSubst = FALSE;
+
Dj.inp[1].realType = GetTrkType(Dj.inp[1].trk);
if ( IsCurveCircle( Dj.inp[0].trk ) )
Dj.inp[0].params.ep = PickArcEndPt( Dj.inp[0].params.arcP, Dj.inp[0].pos, pos );
@@ -519,21 +927,30 @@ LOG( log_join, 1, (" 2nd track %d, @[%0.3f %0.3f] EP0=%d EP1=%d\n",
GetTrkIndex(Dj.inp[1].trk), Dj.inp[1].pos.x, Dj.inp[1].pos.y,
Dj.inp[0].params.ep, Dj.inp[1].params.ep ) )
LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
- if ( GetTrkEndTrk(Dj.inp[0].trk,Dj.inp[0].params.ep) != NULL) {
- ErrorMessage( MSG_TRK_ALREADY_CONN, _("First") );
- return C_CONTINUE;
+ BOOL_T only_merge = FALSE;
+ if ( (Dj.inp[0].params.ep >=0) &&
+ (GetTrkEndTrk(Dj.inp[0].trk,Dj.inp[0].params.ep) != NULL)) {
+ if (GetTrkEndTrk(Dj.inp[0].trk,Dj.inp[0].params.ep) != Dj.inp[1].trk) {
+ only_merge = TRUE;
+ ErrorMessage( MSG_TRK_ALREADY_CONN, _("First") );
+ return C_CONTINUE;
+ }
}
- if ( Dj.inp[1].params.ep >= 0 &&
- GetTrkEndTrk(Dj.inp[1].trk,Dj.inp[1].params.ep) != NULL) {
- ErrorMessage( MSG_TRK_ALREADY_CONN, _("Second") );
- return C_CONTINUE;
+ if ( (Dj.inp[1].params.ep >= 0) &&
+ (GetTrkEndTrk(Dj.inp[1].trk,Dj.inp[1].params.ep) != NULL)) {
+ if (GetTrkEndTrk(Dj.inp[1].trk,Dj.inp[1].params.ep) != Dj.inp[0].trk) {
+ only_merge = TRUE;
+ ErrorMessage( MSG_TRK_ALREADY_CONN, _("Second") );
+ return C_CONTINUE;
+ }
}
-
rc = C_CONTINUE;
if ( MergeTracks( Dj.inp[0].trk, Dj.inp[0].params.ep,
- Dj.inp[1].trk, Dj.inp[1].params.ep ) )
+ Dj.inp[1].trk, Dj.inp[1].params.ep ) ) {
+ rc = C_TERMINATE;
+ } else if (only_merge) {
rc = C_TERMINATE;
- else if ( Dj.inp[0].params.ep >= 0 && Dj.inp[1].params.ep >= 0 ) {
+ } else if ( Dj.inp[0].params.ep >= 0 && Dj.inp[1].params.ep >= 0 ) {
if ( Dj.inp[0].params.type == curveTypeStraight &&
Dj.inp[1].params.type == curveTypeStraight &&
ExtendStraightToJoin( Dj.inp[0].trk, Dj.inp[0].params.ep,
@@ -544,7 +961,6 @@ LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
rc = C_TERMINATE;
}
if ( rc == C_TERMINATE ) {
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
return rc;
}
if ( QueryTrack( Dj.inp[0].trk, Q_CANNOT_BE_ON_END ) ||
@@ -553,30 +969,103 @@ LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
return C_CONTINUE;
}
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
Dj.state = 2;
Dj.jRes.flip = FALSE;
}
tempSegs_da.cnt = 0;
+ /* no break */
case C_MOVE:
- if (easementVal < 0)
+ if (easementVal < 0 && Dj.cornuMode)
return CmdCornu(action, pos);
LOG( log_join, 3, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
if (Dj.state != 2)
return C_CONTINUE;
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, drawColorBlack );
+ DYNARR_RESET(trkSeg_t,Dj.anchors);
+
+
+ //Fix Pos onto the line of the second track
+ if (Dj.inp[1].params.type == curveTypeStraight) {
+ ANGLE_T a = NormalizeAngle(FindAngle(Dj.inp[1].params.lineOrig,pos)-Dj.inp[1].params.angle);
+ DIST_T d = FindDistance(Dj.inp[1].params.lineOrig,pos);
+ Translate(&pos,Dj.inp[1].params.lineOrig,Dj.inp[1].params.angle,d*cos(D2R(a)));
+ } else {
+ ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,pos);
+ Translate(&pos,Dj.inp[1].params.arcP,a,Dj.inp[1].params.arcR);
+ }
+
+ if ((desired_radius != 0.0) &&
+ ((Dj.inp[0].params.type == curveTypeStraight) || (Dj.inp[0].params.type == curveTypeCurve)) &&
+ ((Dj.inp[1].params.type == curveTypeStraight) || (Dj.inp[1].params.type == curveTypeCurve)) &&
+ Dj.jRes.type==curveTypeCurve
+ ) {
+ ANGLE_T na0=0.0,na1=0.0;
+ coOrd end0, end1;
+ ANGLE_T a0,a1;
+ end0 = GetTrkEndPos(Dj.inp[0].trk,Dj.inp[0].params.ep);
+ end1 = GetTrkEndPos(Dj.inp[1].trk,Dj.inp[1].params.ep);
+ if (Dj.inp[0].params.type == curveTypeStraight) {
+ a0 = DifferenceBetweenAngles(Dj.inp[0].params.angle,FindAngle(Dj.jRes.pos[0], pos));
+ na0 = NormalizeAngle( Dj.inp[0].params.angle +
+ ((a0>0.0)?90.0:-90.0));
+ } else {
+ na0 = Dj.inp[0].params.arcA0;
+ if (FindDistance(Dj.inp[0].params.arcP,pos)<Dj.inp[0].params.arcR)
+ na0 = NormalizeAngle(na0+180.0);
+ }
+ //Now Second Line offset
+ if (Dj.inp[1].params.type == curveTypeStraight) {
+ a1 = DifferenceBetweenAngles(Dj.inp[1].params.angle,FindAngle(pos, Dj.jRes.pos[0]));
+ na1 = NormalizeAngle( Dj.inp[1].params.angle +
+ ((a1>0.0)?90.0:-90.0));
+ } else {
+ na1 = Dj.inp[1].params.arcA0;
+ if (FindDistance(Dj.inp[1].params.arcP,Dj.jRes.pos[0])<Dj.inp[1].params.arcR)
+ na1 = NormalizeAngle(na1+180.0);
+ }
+ coOrd pos1 = pos;
+ if (AdjustPosToRadius(&pos1,desired_radius+(Dj.jointD[0].x), na0, na1)) {
+ if (Dj.inp[1].params.type == curveTypeStraight) {
+ FindPos( &off, &beyond, pos1, Dj.inp[1].params.lineOrig, Dj.inp[1].params.angle,
+ FindDistance(Dj.inp[1].params.lineOrig,Dj.inp[1].params.lineEnd) );
+ } else if (Dj.inp[1].params.type == curveTypeCurve) {
+ ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,pos1);
+ if ((a>Dj.inp[1].params.arcA0+Dj.inp[1].params.arcA1) || (a< Dj.inp[1].params.arcA0)) {
+ beyond = 1.0;
+ }
+ }
+ //Suppress result unless on track and close to user position (when on track)
+ if (beyond>-0.01 && IsClose(FindDistance(pos,pos1))) {
+ pos = pos1;
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ p->type= SEG_CRVLIN;
+ p->width = 0;
+ p->color = wDrawColorBlue;
+ p->u.c.center = pos;
+ p->u.c.a1= 360.0;
+ p->u.c.a0 = 0.0;
+ p->u.c.radius = tempD.scale*0.25/2;
+ }
+ }
+
+ }
+
+
tempSegs_da.cnt = 0;
tempSegs(0).color = drawColorBlack;
ok = FALSE;
/* Populate (Dj.inp[1]) */
+
if ( QueryTrack(Dj.inp[1].trk,Q_REFRESH_JOIN_PARAMS_ON_MOVE) ) {
if ( !GetTrackParams( PARAMS_2ND_JOIN, Dj.inp[1].trk, pos, &Dj.inp[1].params ) )
return C_CONTINUE;
}
+
+
beyond = 1.0;
switch ( Dj.inp[1].params.type ) {
case curveTypeCurve:
@@ -798,16 +1287,14 @@ errorReturn:
default:
AbortProg( "Bad track type %d", Dj.jRes.type );
}
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, drawColorBlack );
if (!ok)
Dj.jRes.type = curveTypeNone;
return C_CONTINUE;
case C_UP:
-
if (Dj.state == 0) {
- if (easementVal<0)
- return CmdCornu(action, pos);
+ if (easementVal<0 && Dj.cornuMode)
+ return CmdCornu(action, pos);
else
return C_CONTINUE;
}
@@ -815,12 +1302,10 @@ errorReturn:
InfoMessage( _("Select 2nd track") );
return C_CONTINUE;
}
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, drawColorBlack );
tempSegs(0).color = drawColorBlack;
tempSegs_da.cnt = 0;
if (Dj.jRes.type == curveTypeNone) {
Dj.state = 1;
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
InfoMessage( _("Select 2nd track") );
return C_CONTINUE;
}
@@ -845,7 +1330,10 @@ errorReturn:
UndrawNewTrack( Dj.inp[1].trk );
ep = Dj.jRes.flip?1:0;
Dj.state = 0;
+ DYNARR_RESET(trkSeg_t,Dj.anchors);
rc = C_TERMINATE;
+ if (easementVal == 0.0)
+ wPrefSetFloat("misc", "desired_radius", desired_radius);
if ( (!JoinTracks( Dj.inp[0].trk, Dj.inp[0].params.ep, Dj.inp_pos[0],
trk, ep, Dj.jRes.pos[0], &Dj.jointD[0] ) ) ||
(!JoinTracks( Dj.inp[1].trk, Dj.inp[1].params.ep, Dj.inp_pos[1],
@@ -856,24 +1344,34 @@ errorReturn:
DrawNewTrack( Dj.inp[0].trk );
DrawNewTrack( Dj.inp[1].trk );
DrawNewTrack( trk );
+ if (infoSubst)
+ InfoSubstituteControls(NULL, NULL);
+ infoSubst = FALSE;
return rc;
case C_CANCEL:
- case C_REDRAW:
-
+ if (infoSubst)
+ InfoSubstituteControls(NULL, NULL);
+ infoSubst = FALSE;
+ break;
+ case C_REDRAW:
if ( Dj.joinMoveState == 1 || Dj.state == 1 ) {
DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
- } else if (easementVal<0 )
- return CmdCornu(action,pos);
-
+ } else if (easementVal<0 && Dj.joinMoveState == 0)
+ return CmdCornu(action,pos);
+ if (Dj.anchors.cnt)
+ DrawSegs(&tempD, zero, 0.0, &(((trkSeg_t *)Dj.anchors.ptr)[0]), Dj.anchors.cnt,trackGauge,wDrawColorBlack);
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
break;
case C_TEXT:
case C_OK:
- if (easementVal<0 )
- return CmdCornu(action,pos);
+ if (easementVal<0 && Dj.cornuMode)
+ return CmdCornu(action,pos);
+ if (infoSubst)
+ InfoSubstituteControls(NULL, NULL);
+ infoSubst = FALSE;
}
@@ -889,10 +1387,14 @@ errorReturn:
*/
#include "bitmaps/join.xpm"
+#include "bitmaps/joinline.xpm"
void InitCmdJoin( wMenu_p menu )
{
- joinCmdInx = AddMenuButton( menu, CmdJoin, "cmdJoin", _("Join"), wIconCreatePixMap(join_xpm), LEVEL0_50, IC_STICKY|IC_POPUP, ACCL_JOIN, NULL );
+ ButtonGroupBegin( _("Join"), "cmdJoinSetCmd", _("Join") );
+ joinCmdInx = AddMenuButton( menu, CmdJoin, "cmdJoinTrack", _("Join Track"), wIconCreatePixMap(join_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_JOIN, NULL );
+ AddMenuButton( menu, CmdJoinLine, "cmdJoinLine", _("Join Lines"), wIconCreatePixMap(joinline_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_JOIN, NULL );
+ ButtonGroupEnd();
log_join = LogFindIndex( "join" );
}
diff --git a/app/bin/cmisc.c b/app/bin/cmisc.c
index a353530..b41ae42 100644
--- a/app/bin/cmisc.c
+++ b/app/bin/cmisc.c
@@ -23,6 +23,7 @@
#include <stdint.h>
#include "common.h"
+#include "utility.h"
#include "cundo.h"
#include "i18n.h"
#include "messages.h"
@@ -32,6 +33,10 @@
EXPORT wIndex_t describeCmdInx;
EXPORT BOOL_T inDescribeCmd;
+extern wIndex_t selectCmdInx;
+extern wIndex_t joinCmdInx;
+extern wIndex_t modifyCmdInx;
+
static track_p descTrk;
static descData_p descData;
static descUpdate_t descUpdateFunc;
@@ -43,13 +48,16 @@ static BOOL_T descNeedDrawHilite;
static wPos_t describeW_posy;
static wPos_t describeCmdButtonEnd;
+static wMenu_p descPopupM;
+
static unsigned int editableLayerList[NUM_LAYERS]; /**< list of non-frozen layers */
static int * layerValue; /**pointer to current Layer (int *) */
static paramFloatRange_t rdata = { 0, 0, 100, PDO_NORANGECHECK_HIGH|PDO_NORANGECHECK_LOW };
static paramIntegerRange_t idata = { 0, 0, 100, PDO_NORANGECHECK_HIGH|PDO_NORANGECHECK_LOW };
static paramTextData_t tdata = { 300, 150 };
-static char * pivotLabels[] = { N_("First"), N_("Middle"), N_("Second"), NULL };
+static char * pivotLabels[] = { N_("First"), N_("Middle"), N_("End"), NULL };
+static char * boxLabels[] = { "", NULL };
static paramData_t describePLs[] = {
#define I_FLOAT_0 (0)
{ PD_FLOAT, NULL, "F1", 0, &rdata },
@@ -114,13 +122,15 @@ static paramData_t describePLs[] = {
#define I_LAYER_N I_LAYER_0+1
#define I_COLOR_0 I_LAYER_N
- { PD_COLORLIST, NULL, "C1", 0, NULL, N_("Color") },
+ { PD_COLORLIST, NULL, "C1", PDO_NOPREF, NULL, N_("Color"), BC_HORZ|BC_NOBORDER },
#define I_COLOR_N I_COLOR_0+1
#define I_LIST_0 I_COLOR_N
{ PD_DROPLIST, NULL, "L1", 0, (void*)150, NULL, 0 },
{ PD_DROPLIST, NULL, "L2", 0, (void*)150, NULL, 0 },
-#define I_LIST_N I_LIST_0+2
+ { PD_DROPLIST, NULL, "L3", 0, (void*)150, NULL, 0 },
+ { PD_DROPLIST, NULL, "L4", 0, (void*)150, NULL, 0 },
+#define I_LIST_N I_LIST_0+4
#define I_EDITLIST_0 I_LIST_N
{ PD_DROPLIST, NULL, "LE1", 0, (void*)150, NULL, BL_EDITABLE },
@@ -131,8 +141,15 @@ static paramData_t describePLs[] = {
#define I_TEXT_N I_TEXT_0+1
#define I_PIVOT_0 I_TEXT_N
- { PD_RADIO, NULL, "P1", 0, pivotLabels, N_("Pivot"), BC_HORZ|BC_NOBORDER, 0 }
+ { PD_RADIO, NULL, "P1", 0, pivotLabels, N_("Pivot"), BC_HORZ|BC_NOBORDER, 0 },
#define I_PIVOT_N I_PIVOT_0+1
+
+#define I_TOGGLE_0 I_PIVOT_N
+ { PD_TOGGLE, NULL, "boxed1", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER },
+ { PD_TOGGLE, NULL, "boxed2", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER },
+ { PD_TOGGLE, NULL, "boxed3", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER },
+ { PD_TOGGLE, NULL, "boxed4", PDO_NOPREF|PDO_DLGHORZ, boxLabels, N_("Boxed"), BC_HORZ|BC_NOBORDER },
+#define I_TOGGLE_N I_TOGGLE_0+4
};
static paramGroup_t describePG = { "describe", 0, describePLs, sizeof describePLs/sizeof describePLs[0] };
@@ -149,7 +166,7 @@ CreateEditableLayersList()
int i = 0;
int j = 0;
- while (i <= NUM_LAYERS) {
+ while (i < NUM_LAYERS) {
if (!GetLayerFrozen(i)) {
editableLayerList[j++] = i;
}
@@ -179,7 +196,7 @@ SearchEditableLayerList(unsigned int layer)
return (-1);
}
-static void DrawDescHilite(void)
+static void DrawDescHilite(BOOL_T selected)
{
wPos_t x, y, w, h;
@@ -194,7 +211,7 @@ static void DrawDescHilite(void)
w = (wPos_t)((descSize.x/mainD.scale)*mainD.dpi+0.5);
h = (wPos_t)((descSize.y/mainD.scale)*mainD.dpi+0.5);
mainD.CoOrd2Pix(&mainD,descOrig,&x,&y);
- wDrawFilledRectangle(mainD.d, x, y, w, h, descColor, wDrawOptTemp);
+ wDrawFilledRectangle(tempD.d, x, y, w, h, selected?descColor:wDrawColorBlue, wDrawOptTemp|wDrawOptTransparent);
}
@@ -221,10 +238,6 @@ static void DescribeUpdate(
return;
}
- if ((ddp->mode&DESC_NOREDRAW) == 0) {
- DrawDescHilite();
- }
-
if (!descUndoStarted) {
UndoStart(_("Change Track"), "Change Track");
descUndoStarted = TRUE;
@@ -252,7 +265,6 @@ static void DescribeUpdate(
descOrig.y -= descBorder;
descSize.x -= descOrig.x-descBorder;
descSize.y -= descOrig.y-descBorder;
- DrawDescHilite();
}
for (inx = 0; inx < sizeof describePLs/sizeof describePLs[0]; inx++) {
@@ -288,9 +300,6 @@ static void DescOk(void * junk)
{
wHide(describePG.win);
- if (descTrk) {
- DrawDescHilite();
- }
if (layerValue && *layerValue>=0) {
SetTrkLayer(descTrk, editableLayerList[*layerValue]); //int found that is really in the parm controls.
}
@@ -304,7 +313,7 @@ static void DescOk(void * junk)
}
descNeedDrawHilite = FALSE;
- Reset();
+ Reset(); // DescOk
}
@@ -326,10 +335,22 @@ static struct {
/*STRING*/ { PD_STRING,0, I_STRING_0, I_STRING_N },
/*TEXT*/ { PD_TEXT, PDO_DLGNOLABELALIGN, I_TEXT_0, I_TEXT_N },
/*LIST*/ { PD_DROPLIST, PDO_LISTINDEX, I_LIST_0, I_LIST_N },
- /*EDITABLELIST*/{ PD_DROPLIST, 0, I_EDITLIST_0, I_EDITLIST_N }
+ /*EDITABLELIST*/{ PD_DROPLIST, 0, I_EDITLIST_0, I_EDITLIST_N },
+ /*BOXED*/ { PD_TOGGLE, 0, I_TOGGLE_0, I_TOGGLE_N },
};
-static wControl_p AllocateButt(descData_p ddp, void * valueP, char * label,
+/**
+ * An unused param element is selected from the list of pre-defined param elements and initialized
+ * for an element specific param.
+ *
+ * \param ddp Element specific param
+ * \param valueP the value pointer used by the element
+ * \param label the label assigned by the element
+ * \param sep ?
+ * \return the selected widget
+ */
+
+static wControl_p AssignParamToDescribeDialog(descData_p ddp, void * valueP, char * label,
wPos_t sep)
{
int inx;
@@ -364,7 +385,7 @@ static wControl_p AllocateButt(descData_p ddp, void * valueP, char * label,
}
}
- AbortProg("allocateButt: can't find %d", ddp->type);
+ AbortProg("AssignParamToDescribeDialog: can't find %d", ddp->type);
return NULL;
}
@@ -465,13 +486,13 @@ void DoDescribe(char * title, track_p trk, descData_p data, descUpdate_t update)
label = _(ddp->label);
ddp->posy = describeW_posy;
- ddp->control0 = AllocateButt(ddp, ddp->valueP, label,
+ ddp->control0 = AssignParamToDescribeDialog(ddp, ddp->valueP, label,
(ddp->type == DESC_POS?3:3));
wControlActive(ddp->control0, ((ddp->mode|ro_mode)&DESC_RO)==0);
switch (ddp->type) {
case DESC_POS:
- ddp->control1 = AllocateButt(ddp,
+ ddp->control1 = AssignParamToDescribeDialog(ddp,
&((coOrd*)(ddp->valueP))->y,
NULL,
0);
@@ -523,9 +544,10 @@ EXPORT void DescribeCancel(void)
{
if (describePG.win && wWinIsVisible(describePG.win)) {
if (descTrk) {
- descUpdateFunc(descTrk, -1, descData, TRUE);
- descTrk = NULL;
- DrawDescHilite();
+ if (!IsTrackDeleted(descTrk))
+ descUpdateFunc(descTrk, -1, descData, TRUE);
+ descTrk = NULL;
+
}
wHide(describePG.win);
@@ -540,21 +562,27 @@ EXPORT void DescribeCancel(void)
}
-static STATUS_T CmdDescribe(wAction_t action, coOrd pos)
+EXPORT STATUS_T CmdDescribe(wAction_t action, coOrd pos)
{
- track_p trk;
+ static track_p trk;
char msg[STR_SIZE];
switch (action) {
case C_START:
InfoMessage(_("Select track to describe"));
+ wSetCursor(mainD.d,wCursorQuestion);
descUndoStarted = FALSE;
+ trk = NULL;
return C_CONTINUE;
+ case wActionMove:
+ trk = OnTrack(&pos, FALSE, FALSE);
+ return C_CONTINUE;
+
+
case C_DOWN:
if ((trk = OnTrack(&pos, FALSE, FALSE)) != NULL) {
if (describePG.win && wWinIsVisible(describePG.win) && descTrk) {
- DrawDescHilite();
descUpdateFunc(descTrk, -1, descData, TRUE);
descTrk = NULL;
}
@@ -572,10 +600,10 @@ static STATUS_T CmdDescribe(wAction_t action, coOrd pos)
descSize.x -= descOrig.x-descBorder;
descSize.y -= descOrig.y-descBorder;
descNeedDrawHilite = TRUE;
- DrawDescHilite();
DescribeTrack(trk, msg, 255);
inDescribeCmd = FALSE;
InfoMessage(msg);
+ trk = NULL;
} else {
InfoMessage("");
}
@@ -583,17 +611,31 @@ static STATUS_T CmdDescribe(wAction_t action, coOrd pos)
return C_CONTINUE;
case C_REDRAW:
+
if (describePG.win && wWinIsVisible(describePG.win) && descTrk) {
- DrawDescHilite();
+ DrawDescHilite(TRUE);
+ if (descTrk && QueryTrack(descTrk, Q_IS_DRAW)) {
+ DrawOriginAnchor(descTrk);
+ }
+ } else if (trk){
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
}
+
break;
case C_CANCEL:
DescribeCancel();
+ wSetCursor(mainD.d,defaultCursor);
return C_CONTINUE;
+
+ case C_CMDMENU:
+ menuPos = pos;
+ if (!trk) wMenuPopupShow(descPopupM);
+ return C_CONTINUE;
}
+
return C_CONTINUE;
}
@@ -601,11 +643,23 @@ static STATUS_T CmdDescribe(wAction_t action, coOrd pos)
#include "bitmaps/describe.xpm"
+extern wIndex_t selectCmdInx;
+extern wIndex_t modifyCmdInx;
+extern wIndex_t panCmdInx;
+
void InitCmdDescribe(wMenu_p menu)
{
describeCmdInx = AddMenuButton(menu, CmdDescribe, "cmdDescribe",
_("Properties"), wIconCreatePixMap(describe_xpm),
- LEVEL0, IC_CANCEL|IC_POPUP, ACCL_DESCRIBE, NULL);
+ LEVEL0, IC_CANCEL|IC_POPUP|IC_WANT_MOVE|IC_CMDMENU, ACCL_DESCRIBE, NULL);
RegisterChangeNotification(DescChange);
ParamRegister(&describePG);
}
+void InitCmdDescribe2(wMenu_p menu)
+{
+ descPopupM = MenuRegister( "Describe Context Menu" );
+ wMenuPushCreate(descPopupM, "cmdSelectMode", GetBalloonHelpStr("cmdSelectMode"), 0, DoCommandB, (void*) (intptr_t) selectCmdInx);
+ wMenuPushCreate(descPopupM, "cmdModifyMode", GetBalloonHelpStr("cmdModifyMode"), 0, DoCommandB, (void*) (intptr_t) modifyCmdInx);
+ wMenuPushCreate(descPopupM, "cmdPanMode", GetBalloonHelpStr("cmdPanMode"), 0, DoCommandB, (void*) (intptr_t) panCmdInx);
+
+}
diff --git a/app/bin/cmodify.c b/app/bin/cmodify.c
index 11f4c06..8f82012 100644
--- a/app/bin/cmodify.c
+++ b/app/bin/cmodify.c
@@ -34,6 +34,9 @@
#include "param.h"
#include "track.h"
#include "utility.h"
+#include "drawgeom.h"
+#include "common.h"
+#include "layout.h"
static struct {
track_p Trk;
@@ -47,10 +50,65 @@ static struct {
BOOL_T first;
} Dex;
+static wMenu_p modPopupM;
+
+extern wIndex_t selectCmdInx;
+extern wIndex_t joinCmdInx;
+extern wIndex_t describeCmdInx;
+
+static dynArr_t anchors_da;
+#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N)
static int log_modify;
static BOOL_T modifyBezierMode;
static BOOL_T modifyCornuMode;
+static BOOL_T modifyDrawMode;
+static BOOL_T modifyRulerMode;
+static BOOL_T modifyExtendMode;
+
+
+static void CreateEndAnchor(coOrd p, wBool_t lock) {
+ DIST_T d = tempD.scale*0.15;
+
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN;
+ anchors(i).color = wDrawColorBlue;
+ anchors(i).u.c.center = p;
+ anchors(i).u.c.radius = d/2;
+ anchors(i).u.c.a0 = 0.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).width = 0;
+}
+
+static void CreateCornuAnchor(coOrd p, wBool_t lock) {
+ DIST_T d = tempD.scale*0.15;
+
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN;
+ anchors(i).color = wDrawColorBlue;
+ anchors(i).u.c.center = p;
+ anchors(i).u.c.radius = d/2;
+ anchors(i).u.c.a0 = 0.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).width = 0;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_CRVLIN;
+ anchors(i).color = wDrawColorBlue;
+ anchors(i).u.c.center = p;
+ anchors(i).u.c.radius = d;
+ anchors(i).u.c.a0 = 0.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).width = 0;
+}
+
+
+static void CreateRadiusAnchor(coOrd p, ANGLE_T a, BOOL_T bi) {
+ DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5);
+ DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),p,a,bi,wDrawColorBlue);
+}
/*
* Call cbezier.c CmdBezModify to alter Bezier Track and Lines.
@@ -66,6 +124,7 @@ static STATUS_T ModifyBezier(wAction_t action, coOrd pos) {
case C_UP:
case C_OK:
case C_TEXT:
+ case wActionMove:
trackGauge = (IsTrack(Dex.Trk)?GetTrkGauge(Dex.Trk):0.0);
rc = CmdBezModify(Dex.Trk, action, pos, trackGauge);
break;
@@ -89,12 +148,14 @@ static STATUS_T ModifyCornu(wAction_t action, coOrd pos) {
STATUS_T rc = C_CONTINUE;
if (Dex.Trk == NULL) return C_ERROR; //No track picked yet!
switch (action&0xFF) {
+ case C_LCLICK:
case C_START:
case C_DOWN:
case C_MOVE:
case C_UP:
case C_OK:
case C_TEXT:
+ case wActionMove:
trackGauge = (IsTrack(Dex.Trk)?GetTrkGauge(Dex.Trk):0.0);
rc = CmdCornuModify(Dex.Trk, action, pos, trackGauge);
break;
@@ -110,7 +171,61 @@ static STATUS_T ModifyCornu(wAction_t action, coOrd pos) {
return rc;
}
-static STATUS_T CmdModify(
+/*
+ * Picking a DRAW will allow point modifications until terminated with "Enter"
+ */
+static STATUS_T ModifyDraw(wAction_t action, coOrd pos) {
+ STATUS_T rc = C_CONTINUE;
+ if (Dex.Trk == NULL) return C_ERROR; //No item picked yet!
+ switch (action&0xFF) {
+ case C_START:
+ case C_DOWN:
+ case C_MOVE:
+ case C_UP:
+ rc = ModifyTrack( Dex.Trk, action, pos );
+ break;
+ case wActionMove:
+ rc = ModifyTrack( Dex.Trk, action, pos );
+ break;
+ case C_TEXT:
+ //Delete or '0' - continues
+ if ((action>>8 !=32) && (action >>8 !=13))
+ return ModifyTrack( Dex.Trk, action, pos );
+ //Enter/Space does not
+ if ((action>>8 !=32) && (action>>8 != 13)) return C_CONTINUE;
+ /*no break*/
+ case C_OK:
+ UndoStart( _("Modify Track"), "Modify( T%d[%d] )", GetTrkIndex(Dex.Trk), Dex.params.ep );
+ UndoModify( Dex.Trk );
+ rc = ModifyTrack( Dex.Trk, C_TEXT | (13<<8), pos );
+ if (rc != C_CONTINUE) modifyDrawMode = FALSE;
+ UndoEnd();
+ break;
+ case C_CANCEL:
+ case C_FINISH:
+ case C_CONFIRM:
+ case C_TERMINATE:
+ rc = ModifyTrack( Dex.Trk, action, pos );
+ Dex.Trk = NULL;
+ modifyDrawMode = FALSE;
+ tempSegs_da.cnt = 0;
+ rc = C_CONTINUE;
+ break;
+ case C_REDRAW:
+ rc = ModifyTrack( Dex.Trk, action, pos );
+ break;
+ case C_CMDMENU:
+ menuPos = pos;
+ rc = ModifyTrack( Dex.Trk, action, pos );
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+
+STATUS_T CmdModify(
wAction_t action,
coOrd pos )
/*
@@ -128,7 +243,7 @@ static STATUS_T CmdModify(
EPINX_T inx;
curveType_e curveType;
static BOOL_T changeTrackMode;
- static BOOL_T modifyRulerMode;
+
STATUS_T rc;
static DIST_T trackGauge;
@@ -143,7 +258,8 @@ static STATUS_T CmdModify(
switch (action&0xFF) {
case C_START:
- InfoMessage( _("Select track to modify") );
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ InfoMessage( _("Select a track to modify, Left-Click change length, Right-Click to add flextrack") );
Dex.Trk = NULL;
tempSegs_da.cnt = 0;
/*ChangeParameter( &easementPD );*/
@@ -151,21 +267,28 @@ static STATUS_T CmdModify(
changeTrackMode = modifyRulerMode = FALSE;
modifyBezierMode = FALSE;
modifyCornuMode = FALSE;
+ modifyDrawMode = FALSE;
+ modifyExtendMode = FALSE;
return C_CONTINUE;
case C_DOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if (modifyBezierMode)
return ModifyBezier(C_DOWN, pos);
if (modifyCornuMode)
return ModifyCornu(C_DOWN, pos);
+ if (modifyDrawMode)
+ return ModifyDraw(C_DOWN, pos);
+ /*no break*/
+ case C_LDOUBLE:
DYNARR_SET( trkSeg_t, tempSegs_da, 2 );
tempSegs(0).color = wDrawColorBlack;
tempSegs(0).width = 0;
tempSegs(1).color = wDrawColorBlack;
tempSegs(1).width = 0;
tempSegs_da.cnt = 0;
- SnapPos( &pos );
Dex.Trk = OnTrack( &pos, TRUE, FALSE );
+ //Dex.Trk = trk;
if (Dex.Trk == NULL) {
if ( ModifyRuler( C_DOWN, pos ) == C_CONTINUE )
modifyRulerMode = TRUE;
@@ -173,6 +296,7 @@ static STATUS_T CmdModify(
}
if (!CheckTrackLayer( Dex.Trk ) ) {
Dex.Trk = NULL;
+
return C_CONTINUE;
}
trackGauge = (IsTrack(Dex.Trk)?GetTrkGauge(Dex.Trk):0.0);
@@ -185,21 +309,38 @@ static STATUS_T CmdModify(
}
return C_CONTINUE; //That's it
}
- if (QueryTrack( Dex.Trk, Q_IS_CORNU )) { //Bezier
+ if (QueryTrack( Dex.Trk, Q_IS_CORNU )) { //Cornu
modifyCornuMode = TRUE;
if (ModifyCornu(C_START, pos) != C_CONTINUE) { //Call Start with track
- modifyCornuMode = FALSE; //Function rejected Bezier
+ modifyCornuMode = FALSE; //Function rejected Cornu
Dex.Trk =NULL;
tempSegs_da.cnt = 0;
+
}
return C_CONTINUE; //That's it
}
- if ( (MyGetKeyState()&WKEY_SHIFT) &&
+ if (QueryTrack( Dex.Trk, Q_IS_DRAW )) {
+ modifyDrawMode = TRUE;
+ if (ModifyDraw(C_START, pos) != C_CONTINUE) {
+ modifyDrawMode = FALSE;
+ Dex.Trk = NULL;
+ tempSegs_da.cnt = 0;
+ }
+ return C_CONTINUE;
+ }
+
+ if ((action&0xFF) == C_LDOUBLE) return C_ERROR;
+
+ if ((MyGetKeyState()&WKEY_CTRL)) goto extendTrack;
+
+
+
+ if ( (MyGetKeyState()&WKEY_SHIFT) && //Free to change radius
QueryTrack( Dex.Trk, Q_CAN_MODIFYRADIUS )&&
- (inx=PickUnconnectedEndPoint(pos,Dex.Trk)) >= 0 ) {
+ ((inx=PickUnconnectedEndPoint(pos,Dex.Trk)) >= 0 )) {
trk = Dex.Trk;
- while ( (trk1=GetTrkEndTrk(trk,1-inx)) &&
+ while ( (trk1=GetTrkEndTrk(trk,1-inx)) && //Means next track to mine even if can be end...
QueryTrack(trk1, Q_CANNOT_BE_ON_END) ) {
inx = GetEndPtConnectedToMe( trk1, trk );
trk = trk1;
@@ -208,7 +349,8 @@ static STATUS_T CmdModify(
UndoStart( _("Change Track"), "Change( T%d[%d] )", GetTrkIndex(Dex.Trk), Dex.params.ep );
inx = GetEndPtConnectedToMe( trk1, trk );
Dex.Trk = NULL;
- DeleteTrack(trk, TRUE);
+ UndrawNewTrack( trk );
+ DeleteTrack(trk, TRUE); //Get rid of original track
if ( !GetTrkEndTrk( trk1, inx ) ) {
Dex.Trk = trk1;
Dex.pos00 = GetTrkEndPos( Dex.Trk, inx );
@@ -218,16 +360,70 @@ static STATUS_T CmdModify(
}
ErrorMessage( MSG_CANNOT_CHANGE );
}
+ ModifyTrack(Dex.Trk, C_START, pos); //Basically trim via Modify...
rc = ModifyTrack( Dex.Trk, C_DOWN, pos );
if ( rc != C_CONTINUE ) {
Dex.Trk = NULL;
rc = C_CONTINUE;
}
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- MainRedraw();
- MapRedraw();
return rc;
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (modifyCornuMode) return ModifyCornu(wActionMove,pos);
+ if (modifyDrawMode) return ModifyDraw(wActionMove,pos);
+ if (modifyBezierMode) return ModifyBezier(wActionMove, pos);
+ track_p t;
+ if (((t=OnTrack(&pos,FALSE,TRUE))!= NULL) && CheckTrackLayerSilent( t )) {
+ EPINX_T ep = PickUnconnectedEndPointSilent(pos, t);
+ if (QueryTrack( t, Q_IS_CORNU )) {
+ CreateCornuAnchor(pos,FALSE);
+ } else if ( QueryTrack( t, Q_CAN_MODIFY_CONTROL_POINTS )) {
+ CreateRadiusAnchor(pos,NormalizeAngle(GetAngleAtPoint(t,pos,NULL,NULL)+90.0),TRUE);
+ CreateEndAnchor(pos,FALSE);
+ } else if (QueryTrack(t,Q_CAN_ADD_ENDPOINTS)){ //Turntable
+ trackParams_t tp;
+ if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE;
+ ANGLE_T a = tp.angle;
+ Translate(&pos,tp.ttcenter,a,tp.ttradius);
+ CreateRadiusAnchor(pos,a,FALSE);
+ } else if (QueryTrack(t,Q_CAN_EXTEND)) {
+ if (ep != -1) {
+ if (MyGetKeyState()&WKEY_CTRL) {
+ pos = GetTrkEndPos(t,ep);
+ CreateEndAnchor(pos,FALSE);
+ CreateRadiusAnchor(pos,GetTrkEndAngle(t,ep),FALSE);
+ CreateRadiusAnchor(pos,GetTrkEndAngle(t,ep)+90,TRUE);
+ } else {
+ CreateEndAnchor(pos,FALSE);
+ if ((MyGetKeyState()&WKEY_SHIFT) && //Shift Down
+ QueryTrack( t, Q_CAN_MODIFYRADIUS ) && // Straight or Curve
+ ((inx=PickUnconnectedEndPointSilent(pos,t)) >= 0 )) { //Which has an open end
+ if (GetTrkEndTrk(t,1-inx)) // Has to have a track on other end
+ CreateRadiusAnchor(pos,NormalizeAngle(GetAngleAtPoint(t,pos,NULL,NULL)+90.0),TRUE);
+ }
+ CreateRadiusAnchor(pos,GetAngleAtPoint(t,pos,NULL,NULL),TRUE);
+ }
+ }
+ } else if (ep>=0){ //Turnout
+ pos = GetTrkEndPos(t, ep);
+ CreateEndAnchor(pos,TRUE);
+ if ( (MyGetKeyState()&WKEY_CTRL)) {
+ CreateRadiusAnchor(pos,NormalizeAngle(GetTrkEndAngle(t,ep)),FALSE);
+ CreateRadiusAnchor(pos,GetTrkEndAngle(t,ep)+90,TRUE);
+ CreateEndAnchor(pos,TRUE);
+ } else {
+ CreateRadiusAnchor(pos,NormalizeAngle(GetTrkEndAngle(t,ep)),FALSE);
+ CreateEndAnchor(pos,TRUE);
+ }
+ }
+ } else if (((t=OnTrack(&pos,FALSE,FALSE))!= NULL)
+ && (!(GetLayerFrozen(GetTrkLayer(t)) && GetLayerModule(GetTrkLayer(t))))
+ && (QueryTrack(t, Q_IS_DRAW ) && !QueryTrack(t, Q_IS_TEXT)) ) {
+ CreateEndAnchor(pos,FALSE);
+ }
+ return C_CONTINUE;
+
case C_MOVE:
if ( modifyRulerMode )
return ModifyRuler( C_MOVE, pos );
@@ -237,21 +433,22 @@ static STATUS_T CmdModify(
return ModifyBezier(C_MOVE, pos);
if ( modifyCornuMode )
return ModifyCornu(C_MOVE, pos);
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ if ( modifyDrawMode)
+ return ModifyDraw(C_MOVE, pos);
+ if (modifyExtendMode && (MyGetKeyState()&WKEY_CTRL))
+ goto extendTrackMove;
tempSegs_da.cnt = 0;
+
SnapPos( &pos );
rc = ModifyTrack( Dex.Trk, C_MOVE, pos );
if ( rc != C_CONTINUE ) {
rc = C_CONTINUE;
Dex.Trk = NULL;
}
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- MainRedraw();
- MapRedraw();
return rc;
-
case C_UP:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if (Dex.Trk == NULL)
return C_CONTINUE;
if ( modifyRulerMode )
@@ -260,58 +457,71 @@ static STATUS_T CmdModify(
return ModifyBezier( C_UP, pos);
if (modifyCornuMode)
return ModifyCornu(C_UP, pos);
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ if (modifyDrawMode)
+ return ModifyDraw(C_UP, pos);
+ if ((MyGetKeyState()&WKEY_CTRL)) goto extendTrackUp;
+
tempSegs_da.cnt = 0;
+
SnapPos( &pos );
UndoStart( _("Modify Track"), "Modify( T%d[%d] )", GetTrkIndex(Dex.Trk), Dex.params.ep );
UndoModify( Dex.Trk );
rc = ModifyTrack( Dex.Trk, C_UP, pos );
UndoEnd();
- //changeTrackMode = FALSE;
Dex.Trk = NULL;
- MainRedraw();
- MapRedraw();
return rc;
- case C_RDOWN:
+ case C_RDOWN: //This is same as context menu....
+extendTrack:
+ DYNARR_RESET(trkSeg_t,anchors_da);
changeTrackMode = TRUE;
+ modifyExtendMode = TRUE;
modifyRulerMode = FALSE;
modifyBezierMode = FALSE;
modifyCornuMode = FALSE;
- Dex.Trk = OnTrack( &pos, TRUE, TRUE );
- if (Dex.Trk) {
- if (!CheckTrackLayer( Dex.Trk ) ) {
- Dex.Trk = NULL;
- return C_CONTINUE;
- }
- trackGauge = GetTrkGauge( Dex.Trk );
- Dex.pos00 = pos;
-CHANGE_TRACK:
- if (GetTrackParams( PARAMS_EXTEND, Dex.Trk, Dex.pos00, &Dex.params)) {
- if (Dex.params.ep == -1) {
+ modifyDrawMode = FALSE;
+ Dex.first = FALSE;
+ if (((action&0xFF) == C_RDOWN) || ((action&0xFF)== C_DOWN)) {
+ Dex.Trk = OnTrack( &pos, TRUE, TRUE );
+ if (Dex.Trk) {
+ if (!CheckTrackLayer( Dex.Trk ) ) {
Dex.Trk = NULL;
return C_CONTINUE;
- break;
}
- if (Dex.params.ep == 0) {
- Dex.params.arcR = -Dex.params.arcR;
+ trackGauge = GetTrkGauge( Dex.Trk );
+ Dex.pos00 = pos;
+ CHANGE_TRACK:
+ if (GetTrackParams( PARAMS_EXTEND, Dex.Trk, Dex.pos00, &Dex.params)) {
+ if (Dex.params.ep == -1) {
+ Dex.Trk = NULL;
+ return C_CONTINUE;
+ break;
+ }
+ if (Dex.params.ep == 0) {
+ Dex.params.arcR = -Dex.params.arcR;
+ }
+ Dex.pos00 = GetTrkEndPos(Dex.Trk,Dex.params.ep);
+ Dex.angle = GetTrkEndAngle( Dex.Trk,Dex.params.ep);
+ Translate( &Dex.pos00x, Dex.pos00, Dex.angle, 10.0 );
+ LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n",
+ Dex.params.ep, Dex.pos00.x, Dex.pos00.y, Dex.angle ) )
+ InfoMessage( _("Drag to add flex track") );
+ } else {
+ return C_ERROR;
}
- Dex.pos00 = GetTrkEndPos(Dex.Trk,Dex.params.ep);
- Dex.angle = GetTrkEndAngle( Dex.Trk,Dex.params.ep);
- Translate( &Dex.pos00x, Dex.pos00, Dex.angle, 10.0 );
-LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n",
- Dex.params.ep, Dex.pos00.x, Dex.pos00.y, Dex.angle ) )
- InfoMessage( _("Drag to create new track segment") );
} else {
+ InfoMessage ( _("No track to extend"));
return C_ERROR;
}
+ Dex.first = TRUE;
+ } else if (!Dex.Trk) {
+ InfoMessage ( _("No track selected"));
+ return C_ERROR;
}
- Dex.first = TRUE;
- MainRedraw();
- MapRedraw();
/* no break */
case C_RMOVE:
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+extendTrackMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
tempSegs_da.cnt = 0;
Dex.valid = FALSE;
if (Dex.Trk == NULL) return C_CONTINUE;
@@ -320,7 +530,8 @@ LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n",
return C_CONTINUE;
Dex.first = FALSE;
Dex.pos01 = Dex.pos00;
- if (Dex.params.type == curveTypeCornu) { //Restrict Cornu drag out to match end
+
+ if (Dex.params.type == curveTypeCornu) { //Always Restrict Cornu drag out to match end
ANGLE_T angle2 = NormalizeAngle(FindAngle(pos, Dex.pos00)-Dex.angle);
if (angle2 > 90.0 && angle2 < 270.0) {
if (Dex.params.cornuRadius[Dex.params.ep] == 0) {
@@ -346,11 +557,6 @@ LOG( log_modify, 1, ("extend endPt[%d] = [%0.3f %0.3f] A%0.3f\n",
ErrorMessage( MSG_TRK_TOO_SHORT, "First ", PutDim(fabs(minLength-d)) );
return C_CONTINUE;
}
- a0 = Dex.angle + (Dex.jointD.negate?-90.0:+90.0);
- Translate( &Dex.pos01, Dex.pos00, a0, Dex.jointD.x );
- Translate( &Dex.curveData.pos1, Dex.curveData.pos1,
- a0, Dex.jointD.x );
-LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) )
} else {
Dex.jointD.d1 = 0.0;
}
@@ -376,44 +582,55 @@ LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) )
return C_CONTINUE;
} else if ( curveType == curveTypeCurve ) {
Dex.r1 = Dex.curveData.curveRadius;
- if ( easeR > 0.0 && Dex.r1 < easeR ) {
- ErrorMessage( MSG_RADIUS_LSS_EASE_MIN,
- FormatDistance( Dex.r1 ), FormatDistance( easeR ) );
- return C_CONTINUE;
- }
- if ( Dex.r1*2.0*M_PI*Dex.curveData.a1/360.0 > mapD.size.x+mapD.size.y ) {
- ErrorMessage( MSG_CURVE_TOO_LARGE );
- return C_CONTINUE;
- }
- if ( NormalizeAngle( FindAngle( Dex.pos00, pos ) - Dex.angle ) > 180.0 )
- Dex.r1 = -Dex.r1;
if ( QueryTrack( Dex.Trk, Q_IGNORE_EASEMENT_ON_EXTEND ) ) {
- /* Ignore easements when extending turnouts */
+ /* Ignore easements when extending turnouts or turntables */
Dex.jointD.x =
Dex.jointD.r0 = Dex.jointD.r1 =
Dex.jointD.l0 = Dex.jointD.l1 =
Dex.jointD.d0 = Dex.jointD.d1 = 0.0;
Dex.jointD.flip = Dex.jointD.negate = Dex.jointD.Scurve = FALSE;
- } else {
- if (ComputeJoint( Dex.params.arcR, Dex.r1, &Dex.jointD ) == E_ERROR)
- return C_CONTINUE;
- d = Dex.params.len - Dex.jointD.d0;
- if (d <= minLength) {
- ErrorMessage( MSG_TRK_TOO_SHORT, "First ", PutDim(fabs(minLength-d)) );
- return C_CONTINUE;
+ d = Dex.curveData.curveRadius * Dex.curveData.a1 * 2.0*M_PI/360.0;
+ } else { /* Easement code */
+ if (easementVal<0.0) { //Cornu Join - need to estimate a "good" easement length
+ d = Dex.curveData.curveRadius * Dex.curveData.a1 * 2.0*M_PI/360.0;
+ Dex.jointD.d0 = Dex.jointD.d1 =0.75*72*12/GetTrkScale(Dex.Trk); //Easement 1.5 cars long to start
+ if (Dex.jointD.d0>(GetTrkLength(Dex.Trk,0,1)/2))
+ Dex.jointD.d0 = GetTrkLength(Dex.Trk,0,1)/2;
+ if (Dex.jointD.d1>d/2)
+ Dex.jointD.d1 = d/2;
+ Dex.jointD.negate = DifferenceBetweenAngles(Dex.angle,FindAngle(Dex.pos00,pos))<0.0;
+ Dex.jointD.x = 2*trackGauge; //Signal an easement present to JoinTracks
+ } else {
+ if ( easeR > 0.0 && Dex.r1 < easeR ) {
+ ErrorMessage( MSG_RADIUS_LSS_EASE_MIN,
+ FormatDistance( Dex.r1 ), FormatDistance( easeR ) );
+ return C_CONTINUE;
+ }
+ if ( Dex.r1*2.0*M_PI*Dex.curveData.a1/360.0 > mapD.size.x+mapD.size.y ) {
+ ErrorMessage( MSG_CURVE_TOO_LARGE );
+ return C_CONTINUE;
+ }
+ if ( NormalizeAngle( FindAngle( Dex.pos00, pos ) - Dex.angle ) > 180.0 )
+ Dex.r1 = - Dex.r1;
+ if (ComputeJoint( Dex.params.arcR, Dex.r1, &Dex.jointD ) == E_ERROR)
+ return C_CONTINUE;
+ d = Dex.params.len - Dex.jointD.d0;
+ if (d <= minLength) {
+ ErrorMessage( MSG_TRK_TOO_SHORT, "First ", PutDim(fabs(minLength-d)) );
+ return C_CONTINUE;
+ }
}
+ d -= Dex.jointD.d1;
+ a0 = Dex.angle + (Dex.jointD.negate?-90.0:+90.0);
+ Translate( &Dex.pos01, Dex.pos00, a0, Dex.jointD.x );
+ Translate( &Dex.curveData.curvePos, Dex.curveData.curvePos,
+ a0, Dex.jointD.x );
+LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) )
}
- d = Dex.curveData.curveRadius * Dex.curveData.a1 * 2.0*M_PI/360.0;
- d -= Dex.jointD.d1;
if (d <= minLength) {
ErrorMessage( MSG_TRK_TOO_SHORT, "Extending ", PutDim(fabs(minLength-d)) );
return C_CONTINUE;
}
- a0 = Dex.angle + (Dex.jointD.negate?-90.0:+90.0);
- Translate( &Dex.pos01, Dex.pos00, a0, Dex.jointD.x );
- Translate( &Dex.curveData.curvePos, Dex.curveData.curvePos,
- a0, Dex.jointD.x );
-LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) )
tempSegs(0).type = SEG_CRVTRK;
tempSegs(0).width = 0;
tempSegs(0).u.c.center = Dex.curveData.curvePos;
@@ -421,9 +638,9 @@ LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) )
tempSegs(0).u.c.a0 = Dex.curveData.a0;
tempSegs(0).u.c.a1 = Dex.curveData.a1;
tempSegs_da.cnt = 1;
- d = D2R(Dex.curveData.a1);
- if (d < 0.0)
- d = 2*M_PI + d;
+ double da = D2R(Dex.curveData.a1);
+ if (da < 0.0)
+ da = 2*M_PI + da;
a = NormalizeAngle( Dex.angle - FindAngle( Dex.pos00, Dex.curveData.curvePos ) );
if ( a < 180.0 )
a = NormalizeAngle( Dex.curveData.a0-90 );
@@ -433,17 +650,15 @@ LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) )
if (action != C_RDOWN)
InfoMessage( _("Curve Track: Radius=%s Length=%s Angle=%0.3f"),
FormatDistance( Dex.curveData.curveRadius ),
- FormatDistance( Dex.curveData.curveRadius * d),
+ FormatDistance( Dex.curveData.curveRadius * da),
Dex.curveData.a1 );
}
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
case C_RUP:
+extendTrackUp:
changeTrackMode = FALSE;
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ modifyExtendMode = FALSE;
tempSegs_da.cnt = 0;
if (Dex.Trk == NULL) return C_CONTINUE;
if (!Dex.valid)
@@ -453,22 +668,24 @@ LOG( log_modify, 2, ("A=%0.3f X=%0.3f\n", a0, Dex.jointD.x ) )
curveType = Dex.curveData.type;
if ( curveType == curveTypeStraight ) {
- if ( Dex.params.type == curveTypeStraight && Dex.params.len > 0 ) {
- //UndrawNewTrack( Dex.Trk );
- UndoModify( Dex.Trk );
- AdjustStraightEndPt( Dex.Trk, Dex.params.ep, Dex.curveData.pos1 );
- UndoEnd();
- DrawNewTrack(Dex.Trk );
- MainRedraw();
- MapRedraw();
- return C_TERMINATE;
+ if (QueryTrack(Dex.Trk,Q_CAN_EXTEND)) //Check it isn't a turnout end....
+ if ( Dex.params.type == curveTypeStraight &&
+ FindDistance(Dex.pos01, Dex.curveData.pos1) > 0 ) {
+ UndoModify( Dex.Trk );
+ AdjustStraightEndPt( Dex.Trk, Dex.params.ep, Dex.curveData.pos1 );
+ UndoEnd();
+ DrawNewTrack(Dex.Trk );
+ return C_TERMINATE;
}
+ if (FindDistance(Dex.pos01, Dex.curveData.pos1) == 0) return C_ERROR;
+LOG( log_modify, 1, ("L = %0.3f, P0 = %0.3f, P1 = %0.3f\n",
+ Dex.params.len, Dex.pos01, Dex.curveData.pos1 ) )
trk = NewStraightTrack( Dex.pos01, Dex.curveData.pos1 );
inx = 0;
} else if ( curveType == curveTypeCurve ) {
-LOG( log_modify, 1, ("A0 = %0.3f, A1 = %0.3f\n",
- Dex.curveData.a0, Dex.curveData.a1 ) )
+LOG( log_modify, 1, ("R = %0.3f, A0 = %0.3f, A1 = %0.3f\n",
+ Dex.curveData.curveRadius, Dex.curveData.a0, Dex.curveData.a1 ) )
trk = NewCurvedTrack( Dex.curveData.curvePos, Dex.curveData.curveRadius,
Dex.curveData.a0, Dex.curveData.a1, 0 );
inx = PickUnconnectedEndPoint( Dex.pos01, trk );
@@ -478,39 +695,86 @@ LOG( log_modify, 1, ("A0 = %0.3f, A1 = %0.3f\n",
} else {
return C_ERROR;
}
- //UndrawNewTrack( Dex.Trk );
CopyAttributes( Dex.Trk, trk );
- JoinTracks( Dex.Trk, Dex.params.ep, Dex.pos00, trk, inx, Dex.pos01, &Dex.jointD );
+ if (Dex.jointD.d1 == 0) {
+ DrawEndPt( &mainD, Dex.Trk, Dex.params.ep, wDrawColorWhite );
+ ConnectTracks(Dex.Trk, Dex.params.ep, trk, inx);
+ DrawEndPt( &mainD, Dex.Trk, Dex.params.ep, wDrawColorBlack );
+ } else {
+ UndrawNewTrack( Dex.Trk );
+ JoinTracks( Dex.Trk, Dex.params.ep, Dex.pos00, trk, inx, Dex.pos01, &Dex.jointD );
+ DrawNewTrack( Dex.Trk );
+ }
UndoEnd();
+ tempSegs_da.cnt = 0;
DrawNewTrack( trk );
- DrawNewTrack( Dex.Trk );
- Dex.Trk = NULL;
- MainRedraw();
- MapRedraw();
return C_TERMINATE;
case C_REDRAW:
if (modifyBezierMode) return ModifyBezier(C_REDRAW, pos);
if (modifyCornuMode) return ModifyCornu(C_REDRAW, pos);
- if ( (!changeTrackMode) && Dex.Trk && !QueryTrack( Dex.Trk, Q_MODIFY_REDRAW_DONT_UNDRAW_TRACK ) )
- UndrawNewTrack( Dex.Trk );
+ if (modifyDrawMode) return ModifyDraw(C_REDRAW, pos);
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ if (anchors_da.cnt)
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+
return C_CONTINUE;
case C_TEXT:
+ if ((action>>8) == 'c') {
+ panCenter = pos;
+ LOG( log_pan, 2, ( "PanCenter:Mod-%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)0);
+ return C_CONTINUE;
+ }
+ if ((action>>8) == 'e') {
+ DoZoomExtents(0);
+ }
+ if ((action>>8) == '0' || (action>>8 == 'o')) {
+ PanMenuEnter('o');
+ }
if ( !Dex.Trk )
return C_CONTINUE;
if (modifyBezierMode)
return ModifyBezier(action, pos);
if (modifyCornuMode)
return ModifyCornu(action, pos);
+ if (modifyDrawMode)
+ return ModifyDraw(action, pos);
+ return ModifyTrack( Dex.Trk, action, pos );
+
+ case C_CMDMENU:
+ if ( !Dex.Trk ) {
+ menuPos = pos;
+ wMenuPopupShow(modPopupM);
+ return C_CONTINUE;
+ }
+ if (modifyBezierMode)
+ return ModifyBezier(action, pos);
+ if (modifyCornuMode)
+ return ModifyCornu(action, pos);
+ if (modifyDrawMode)
+ return ModifyDraw(action, pos);
return ModifyTrack( Dex.Trk, action, pos );
+ case C_LCLICK:
+ if ( modifyDrawMode) {
+ rc = ModifyDraw(C_DOWN, pos);
+ if (rc == C_CONTINUE)
+ return ModifyDraw(C_UP, pos);
+ }
+ if (modifyCornuMode)
+ return ModifyCornu(action, pos);
+ /*no break*/
default:
if (modifyBezierMode) return ModifyBezier(action, pos);
if (modifyCornuMode) return ModifyCornu(action, pos);
+ if (modifyDrawMode) return ModifyDraw(action, pos);
+ if (Dex.Trk)
+ return ModifyTrack( Dex.Trk, action, pos );
return C_CONTINUE;
}
+ return C_CONTINUE;
}
@@ -521,9 +785,21 @@ LOG( log_modify, 1, ("A0 = %0.3f, A1 = %0.3f\n",
*/
#include "bitmaps/extend.xpm"
+extern wIndex_t panCmdInx;
+extern wIndex_t selectCmdInx;
+extern wIndex_t describeCmdInx;
+
void InitCmdModify( wMenu_p menu )
{
- modifyCmdInx = AddMenuButton( menu, CmdModify, "cmdModify", _("Modify"), wIconCreatePixMap(extend_xpm), LEVEL0_50, IC_STICKY|IC_POPUP, ACCL_MODIFY, NULL );
+ modifyCmdInx = AddMenuButton( menu, CmdModify, "cmdModify", _("Modify"), wIconCreatePixMap(extend_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE|IC_CMDMENU, ACCL_MODIFY, NULL );
log_modify = LogFindIndex( "modify" );
+ modPopupM = MenuRegister( "Modify Context Menu" );
+ wMenuPushCreate(modPopupM, "cmdSelectMode", GetBalloonHelpStr("cmdSelectMode"), 0, DoCommandB, (void*) (intptr_t) selectCmdInx);
+ wMenuPushCreate(modPopupM, "cmdDescribeMode", GetBalloonHelpStr("cmdDescribeMode"), 0, DoCommandB, (void*) (intptr_t) describeCmdInx);
+ wMenuPushCreate(modPopupM, "cmdPanMode", GetBalloonHelpStr("cmdPanMode"), 0, DoCommandB, (void*) (intptr_t) panCmdInx);
+ wMenuSeparatorCreate(modPopupM);
+ wMenuPushCreate(modPopupM, "", _("Zoom In"), 0,(wMenuCallBack_p) DoZoomUp, (void*) 1);
+ wMenuPushCreate(modPopupM, "", _("Zoom Out"), 0, (wMenuCallBack_p) DoZoomDown, (void*) 1);
+ wMenuPushCreate(modPopupM, "", _("Pan center - 'c'"), 0, (wMenuCallBack_p) PanHere, (void*) 3);
}
diff --git a/app/bin/cnote.c b/app/bin/cnote.c
index 3cbd28d..0a015f1 100644
--- a/app/bin/cnote.c
+++ b/app/bin/cnote.c
@@ -1,5 +1,5 @@
/** \file cnote.c
- * NOTE
+ * Main layout note
*/
/* XTrkCad - Model Railroad CAD
@@ -21,26 +21,13 @@
*/
#include <string.h>
-#include "cundo.h"
#include "custom.h"
+#include "dynstring.h"
#include "fileio.h"
#include "i18n.h"
+#include "misc.h"
#include "param.h"
-#include "track.h"
-#include "utility.h"
-
-static TRKTYP_T T_NOTE = -1;
-
-static wDrawBitMap_p note_bm;
-struct extraData {
- coOrd pos;
- char * text;
-};
-
-extern BOOL_T inDescribeCmd;
-
-#define NOTEHIDE "CNOTE HIDE"
-#define NOTEDONE "CNOTE DONE"
+#include "include/utf8convert.h"
static char * mainText = NULL;
static wWin_p noteW;
@@ -54,18 +41,6 @@ static paramData_t notePLs[] = {
static paramGroup_t notePG = { "note", 0, notePLs, sizeof notePLs/sizeof notePLs[0] };
-static track_p NewNote(wIndex_t index, coOrd p, long size)
-{
- track_p t;
- struct extraData * xx;
- t = NewTrack(index, T_NOTE, 0, sizeof *xx);
- xx = GetTrkExtraData(t);
- xx->pos = p;
- xx->text = (char*)MyMalloc((int)size + 2);
- SetBoundingBox(t, p, p);
- return t;
-}
-
void ClearNote(void)
{
if (mainText) {
@@ -82,12 +57,6 @@ static void NoteOk(void * junk)
len = wTextGetSize(noteT);
mainText = (char*)MyMalloc(len+2);
wTextGetText(noteT, mainText, len);
-
- if (mainText[len-1] != '\n') {
- mainText[len++] = '\n';
- }
-
- mainText[len] = '\0';
}
wHide(noteW);
@@ -98,7 +67,7 @@ void DoNote(void)
{
if (noteW == NULL) {
noteW = ParamCreateDialog(&notePG, MakeWindowTitle(_("Note")), _("Ok"), NoteOk,
- NULL, FALSE, NULL, F_RESIZE, NULL);
+ wHide, FALSE, NULL, F_NOTTRANSIENT|F_RESIZE, NULL);
}
wTextClear(noteT);
@@ -109,365 +78,66 @@ void DoNote(void)
}
-
-/*****************************************************************************
- * NOTE OBJECT
- */
-
-static void DrawNote(track_p t, drawCmd_p d, wDrawColor color)
-{
- struct extraData *xx = GetTrkExtraData(t);
- coOrd p[4];
-
- if (d->scale >= 16) {
- return;
- }
-
- if ((d->funcs->options & wDrawOptTemp) == 0) {
- DrawBitMap(d, xx->pos, note_bm, color);
- } else {
- DIST_T dist;
- dist = 0.1*d->scale;
- p[0].x = p[1].x = xx->pos.x-dist;
- p[2].x = p[3].x = xx->pos.x+dist;
- p[1].y = p[2].y = xx->pos.y-dist;
- p[3].y = p[0].y = xx->pos.y+dist;
- DrawLine(d, p[0], p[1], 0, color);
- DrawLine(d, p[1], p[2], 0, color);
- DrawLine(d, p[2], p[3], 0, color);
- DrawLine(d, p[3], p[0], 0, color);
- }
-}
-
-static DIST_T DistanceNote(track_p t, coOrd * p)
-{
- struct extraData *xx = GetTrkExtraData(t);
- DIST_T d;
- d = FindDistance(*p, xx->pos);
-
- if (d < 1.0) {
- return d;
- }
-
- return 100000.0;
-}
-
-
-static struct {
- coOrd pos;
- unsigned int layer;
-} noteData;
-typedef enum { OR, LY, TX } noteDesc_e;
-static descData_t noteDesc[] = {
- /*OR*/ { DESC_POS, N_("Position"), &noteData.pos },
- /*LY*/ { DESC_LAYER, N_("Layer"), &noteData.layer },
- /*TX*/ { DESC_TEXT, NULL, NULL },
- { DESC_NULL }
-};
-
-static void UpdateNote(track_p trk, int inx, descData_p descUpd,
- BOOL_T needUndoStart)
-{
- struct extraData *xx = GetTrkExtraData(trk);
-
- switch (inx) {
- case OR:
- xx->pos = noteData.pos;
- SetBoundingBox(trk, xx->pos, xx->pos);
- MainRedraw();
- break;
-
- case LY:
- SetTrkLayer(trk, noteData.layer);
- MainRedraw();
- break;
-
- case -1:
- if (wTextGetModified((wText_p)noteDesc[TX].control0)) {
- int len;
-
- if (needUndoStart) {
- UndoStart(_("Change Track"), "Change Track");
- }
-
- UndoModify(trk);
- MyFree(xx->text);
- len = wTextGetSize((wText_p)noteDesc[TX].control0);
- xx->text = (char*)MyMalloc(len+2);
- wTextGetText((wText_p)noteDesc[TX].control0, xx->text, len);
-
- if (xx->text[len-1] != '\n') {
- xx->text[len++] = '\n';
- }
-
- xx->text[len] = '\0';
- }
- MainRedraw();
- break;
-
- default:
- break;
- }
-}
-
-
-static void DescribeNote(track_p trk, char * str, CSIZE_T len)
-{
- struct extraData * xx = GetTrkExtraData(trk);
- strcpy(str, _("Note: "));
- len -= strlen(_("Note: "));
- str += strlen(_("Note: "));
- strncpy(str, xx->text, len);
-
- for (; *str; str++) {
- if (*str=='\n') {
- *str = ' ';
- }
- }
-
- noteData.pos = xx->pos;
- noteDesc[TX].valueP = xx->text;
- noteDesc[OR].mode = 0;
- noteDesc[TX].mode = 0;
- noteDesc[LY].mode = DESC_NOREDRAW;
- DoDescribe(_("Note"), trk, noteDesc, UpdateNote);
-}
-
-static void DeleteNote(track_p t)
-{
- struct extraData *xx = GetTrkExtraData(t);
-
- if (xx->text) {
- MyFree(xx->text);
- }
-}
-
-static BOOL_T WriteNote(track_p t, FILE * f)
+BOOL_T WriteMainNote(FILE* f)
{
- struct extraData *xx = GetTrkExtraData(t);
- int len;
- BOOL_T addNL = FALSE;
BOOL_T rc = TRUE;
- len = strlen(xx->text);
-
- if (xx->text[len-1] != '\n') {
- len++;
- addNL = TRUE;
+ char *noteText = mainText;
+
+ if (noteText && *noteText) {
+#ifdef WINDOWS
+ char *out = NULL;
+ if (RequiresConvToUTF8(mainText)) {
+ unsigned cnt = strlen(mainText) * 2 + 1;
+ out = MyMalloc(cnt);
+ wSystemToUTF8(mainText, out, cnt);
+ noteText = out;
+ }
+#endif // WINDOWS
+
+
+ char * sText = ConvertToEscapedText( noteText );
+ rc &= fprintf(f, "NOTE MAIN 0 0 0 0 0 \"%s\"\n", sText )>0;
+ MyFree( sText );
+
+#ifdef WINDOWS
+ if (out) {
+ MyFree(out);
+ }
+#endif // WINDOWS
}
-
- rc &= fprintf(f, "NOTE %d %d 0 0 %0.6f %0.6f 0 %d\n", GetTrkIndex(t),
- GetTrkLayer(t),
- xx->pos.x, xx->pos.y, len)>0;
- rc &= fprintf(f, "%s%s", xx->text, addNL?"\n":"")>0;
- rc &= fprintf(f, " END\n")>0;
return rc;
}
+/**
+ * Read the layout main note
+ *
+ * \param line complete NOTE statement
+ */
-static void ReadNote(char * line)
+BOOL_T ReadMainNote(char *line)
{
- coOrd pos;
- DIST_T elev;
- CSIZE_T size;
- char * cp;
- struct extraData *xx;
- wIndex_t index;
- wIndex_t layer;
- int lineCount;
-
- if (strncmp(line, "NOTE MAIN", 9) == 0) {
- if (!GetArgs(line+9, paramVersion<3?"d":"0000d", &size)) {
- return;
- }
+ long size;
+ char * sNote = NULL;
- if (mainText) {
- MyFree(mainText);
- }
-
- mainText = (char*)MyMalloc(size+2);
- cp = mainText;
- } else {
- track_p t;
-
- if (!GetArgs(line+5, paramVersion<3?"XXpYd":paramVersion<9?"dL00pYd":"dL00pfd",
- &index, &layer, &pos, &elev, &size)) {
- return;
- }
-
- t = NewNote(index, pos, size+2);
- SetTrkLayer(t, layer);
- xx = GetTrkExtraData(t);
- cp = xx->text;
- }
-
- lineCount = 0;
-
- while (1) {
- int len;
- line = GetNextLine();
-
- if (strncmp(line, " END", 7) == 0) {
- break;
- }
-
- len = strlen(line);
-
- if (size > 0 && size < len) {
- InputError("NOTE text overflow", TRUE);
- size = -1;
- }
-
- if (size > 0) {
- if (lineCount != 0) {
- strcat(cp, "\n");
- cp++;
- size--;
- }
-
- strcpy(cp, line);
- cp += len;
- size -= len;
- }
-
- lineCount++;
- }
-
- if (cp[-1] != '\n') {
- *cp++ = '\n';
+ if (!GetArgs(line + 9,
+ paramVersion < 3 ? "l" :
+ paramVersion < 12 ? "0000l":
+ "0000lq", &size, &sNote)) {
+ return FALSE;
}
- *cp = '\0';
-}
-
-
-static void MoveNote(track_p trk, coOrd orig)
-{
- struct extraData * xx = GetTrkExtraData(trk);
- xx->pos.x += orig.x;
- xx->pos.y += orig.y;
- SetBoundingBox(trk, xx->pos, xx->pos);
-}
-
-
-static void RotateNote(track_p trk, coOrd orig, ANGLE_T angle)
-{
- struct extraData * xx = GetTrkExtraData(trk);
- Rotate(&xx->pos, orig, angle);
- SetBoundingBox(trk, xx->pos, xx->pos);
-}
-
-static void RescaleNote(track_p trk, FLOAT_T ratio)
-{
- struct extraData * xx = GetTrkExtraData(trk);
- xx->pos.x *= ratio;
- xx->pos.y *= ratio;
-}
-
-
-static trackCmd_t noteCmds = {
- "NOTE",
- DrawNote,
- DistanceNote,
- DescribeNote,
- DeleteNote,
- WriteNote,
- ReadNote,
- MoveNote,
- RotateNote,
- RescaleNote,
- NULL, /* audit */
- NULL, /* getAngle */
- NULL, /* split */
- NULL, /* traverse */
- NULL, /* enumerate */
- NULL /* redraw */
-};
-
-
-BOOL_T WriteMainNote(FILE* f)
-{
- BOOL_T rc = TRUE;
-
- if (mainText && *mainText) {
- rc &= fprintf(f, "NOTE MAIN 0 0 0 0 %lu\n", strlen(mainText))>0;
- rc &= fprintf(f, "%s", mainText)>0;
- rc &= fprintf(f, " END\n")>0;
+ if (mainText) {
+ MyFree(mainText);
}
- return rc;
+ if ( paramVersion < 12 )
+ mainText = ReadMultilineText();
+ else
+ mainText = sNote;
+ return TRUE;
}
-/*****************************************************************************
- * NOTE COMMAND
- */
-
-
-
-static STATUS_T CmdNote(wAction_t action, coOrd pos)
-{
- static coOrd oldPos;
- track_p trk;
- struct extraData * xx;
- const char* tmpPtrText;
- static int state_on = FALSE;
-
- switch (action) {
- case C_START:
- InfoMessage(_("Place a note on the layout"));
- return C_CONTINUE;
-
- case C_DOWN:
- state_on = TRUE;
- oldPos = pos;
- MainRedraw();
- return C_CONTINUE;
-
- case C_MOVE:
- oldPos = pos;
- MainRedraw();
- return C_CONTINUE;
- break;
-
- case C_UP:
- UndoStart(_("New Note"), "New Note");
- state_on = FALSE;
- MainRedraw();
- trk = NewNote(-1, pos, 2);
- DrawNewTrack(trk);
- xx = GetTrkExtraData(trk);
- tmpPtrText = _("Replace this text with your note");
- xx->text = (char*)MyMalloc(strlen(tmpPtrText) + 1);
- strcpy(xx->text, tmpPtrText);
- inDescribeCmd = TRUE;
- DescribeNote(trk, message, sizeof message);
- inDescribeCmd = FALSE;
- return C_CONTINUE;
-
- case C_REDRAW:
- if (state_on) DrawBitMap(&tempD, oldPos, note_bm, normalColor);
- return C_CONTINUE;
-
- case C_CANCEL:
- DescribeCancel();
- return C_CONTINUE;
- }
-
- return C_INFO;
-}
-
-
-#include "bitmaps/note.xbm"
-#include "bitmaps/cnote.xpm"
-
-void InitCmdNote(wMenu_p menu)
+void InitCmdNote()
{
ParamRegister(&notePG);
- AddMenuButton(menu, CmdNote, "cmdNote", _("Note"), wIconCreatePixMap(cnote_xpm),
- LEVEL0_50, IC_POPUP2, ACCL_NOTE, NULL);
-}
-
-void InitTrkNote(void)
-{
- note_bm = wDrawBitMapCreate(mainD.d, note_width, note_width, 8, 8, note_bits);
- T_NOTE = InitObject(&noteCmds);
}
diff --git a/app/bin/common.h b/app/bin/common.h
index 255e8d7..2db961f 100644
--- a/app/bin/common.h
+++ b/app/bin/common.h
@@ -24,6 +24,7 @@
#define COMMON_H
#include <stdlib.h>
+#include <stdint.h>
#ifndef TRUE
#define TRUE (1)
@@ -46,6 +47,11 @@ typedef struct {
POS_T x,y;
} coOrd;
+typedef struct {
+ coOrd pt;
+ int pt_type;
+} pts_t;
+
typedef int INT_T;
typedef int BOOL_T;
@@ -61,6 +67,11 @@ typedef int TRKINX_T;
typedef long DEBUGF_T;
typedef int REGION_T;
+enum paramFileState { PARAMFILE_UNLOADED = 0, PARAMFILE_NOTUSABLE, PARAMFILE_COMPATIBLE, PARAMFILE_FIT, PARAMFILE_MAXSTATE };
+
+#define SCALE_ANY (-2)
+#define SCALE_DEMO (-1)
+
typedef struct {
int cnt;
int max;
@@ -108,6 +119,17 @@ typedef struct {
} \
(DA).max = 0; \
(DA).cnt = 0; }
+#define DYNARR_REMOVE(T,DA,I) \
+ { \
+ { if ((DA).cnt-1 > I) { \
+ for (int i=I;i<(DA).cnt-1;i++) { \
+ (((T*)(DA).ptr)[i])= (((T*)(DA).ptr)[i+1]); \
+ } \
+ } \
+ } \
+ if ((DA.cnt)>=I) (DA).cnt--; \
+ }
+
#ifdef WINDOWS
#define M_PI 3.14159
diff --git a/app/bin/compound.c b/app/bin/compound.c
index d1a16f5..627d2ef 100644
--- a/app/bin/compound.c
+++ b/app/bin/compound.c
@@ -38,6 +38,7 @@
#include "track.h"
#include "utility.h"
#include "messages.h"
+#include "include/paramfile.h"
/*****************************************************************************
*
@@ -45,6 +46,25 @@
*
*/
+//Convert the internal path segment into the external one - which is based on the index count of only the track segments
+
+char ConvertPathSegToExternal(char signed pp, int segCnt,trkSeg_p segs) {
+
+ char signed new_pp;
+ int old_inx;
+ EPINX_T old_EP;
+ GetSegInxEP(pp,&old_inx,&old_EP);
+ int j = old_inx;
+ for (int i=0;i<old_inx;i++) {
+ if ( !IsSegTrack(&segs[i]) ) {
+ j--;
+ }
+ }
+ SetSegInxEP(&new_pp,j,old_EP);
+ return new_pp;
+
+}
+
BOOL_T WriteCompoundPathsEndPtsSegs(
FILE * f,
PATHPTR_T paths,
@@ -55,11 +75,12 @@ BOOL_T WriteCompoundPathsEndPtsSegs(
{
int i;
PATHPTR_T pp;
+
BOOL_T rc = TRUE;
for ( pp=paths; *pp; pp+=2 ) {
rc &= fprintf( f, "\tP \"%s\"", pp )>0;
- for ( pp+=strlen((char *)pp)+1; pp[0]!=0||pp[1]!=0; pp++ )
- rc &= fprintf( f, " %d", *pp )>0;
+ for ( pp+=strlen((char *)pp)+1; pp[0]!=0 || pp[1]!=0; pp++ )
+ rc &= fprintf( f, " %d", ConvertPathSegToExternal(pp[0],segCnt,segs) )>0;
rc &= fprintf( f, "\n" )>0;
}
for ( i=0; i<endPtCnt; i++ )
@@ -315,7 +336,7 @@ void DrawCompoundDescription(
return;
if ((labelEnable&LABELENABLE_TRKDESC)==0)
return;
- if ( (d->options&DC_GROUP) )
+ if ( (d->options&DC_SIMPLE) )
return;
if ( xx->special == TOpier ) {
desc = xx->u.pier.name;
@@ -340,18 +361,25 @@ void DrawCompoundDescription(
DIST_T CompoundDescriptionDistance(
coOrd pos,
- track_p trk )
+ track_p trk,
+ coOrd * dpos,
+ BOOL_T show_hidden,
+ BOOL_T * hidden)
{
struct extraData *xx = GetTrkExtraData(trk);
coOrd p1;
if (GetTrkType(trk) != T_TURNOUT && GetTrkType(trk) != T_STRUCTURE)
return 100000;
- if ( (GetTrkBits( trk ) & TB_HIDEDESC) != 0 )
+ if ( ((GetTrkBits( trk ) & TB_HIDEDESC) != 0 ) && !show_hidden)
return 100000;
p1 = xx->descriptionOrig;
+ coOrd offset = xx->descriptionOff;
+ if ( (GetTrkBits( trk ) & TB_HIDEDESC) != 0 ) offset = zero;
Rotate( &p1, zero, xx->angle );
- p1.x += xx->orig.x + xx->descriptionOff.x;
- p1.y += xx->orig.y + xx->descriptionOff.y;
+ p1.x += xx->orig.x + offset.x;
+ p1.y += xx->orig.y + offset.y;
+ if (hidden) *hidden = (GetTrkBits( trk ) & TB_HIDEDESC);
+ *dpos = p1;
return FindDistance( p1, pos );
}
@@ -370,6 +398,7 @@ STATUS_T CompoundDescriptionMove(
case C_DOWN:
editMode = TRUE;
REORIGIN( p0, xx->descriptionOrig, xx->angle, xx->orig )
+ DrawCompoundDescription( trk, &mainD, wDrawColorWhite );
case C_MOVE:
case C_UP:
@@ -383,13 +412,15 @@ STATUS_T CompoundDescriptionMove(
if (action == C_UP) {
editMode = FALSE;
}
- MainRedraw();
- MapRedraw();
+ if ( action == C_UP ) {
+ DrawCompoundDescription( trk, &mainD, color );
+ }
return action==C_UP?C_TERMINATE:C_CONTINUE;
break;
case C_REDRAW:
if (editMode) {
- DrawLine( &tempD, p0, p1, 0, wDrawColorBlack );
+ DrawCompoundDescription( trk, &tempD, wDrawColorBlue );
+ DrawLine( &tempD, p0, p1, 0, wDrawColorBlue );
}
}
@@ -405,6 +436,18 @@ STATUS_T CompoundDescriptionMove(
*
*/
+EXPORT void SetSegInxEP(
+ signed char * segChar,
+ int segInx,
+ EPINX_T segEP )
+{
+ if (segEP == 1) {
+ * segChar = -(segInx+1);
+ } else {
+ * segChar = (segInx+1);
+ }
+
+}
EXPORT void GetSegInxEP(
signed char segChar,
@@ -482,6 +525,7 @@ static struct {
FLOAT_T elev[4];
coOrd orig;
ANGLE_T angle;
+ descPivot_t pivot;
char manuf[STR_SIZE];
char name[STR_SIZE];
char partno[STR_SIZE];
@@ -490,9 +534,10 @@ static struct {
long pathCnt;
FLOAT_T grade;
DIST_T length;
+ drawLineType_e linetype;
unsigned int layerNumber;
} compoundData;
-typedef enum { E0, A0, C0, R0, Z0, E1, A1, C1, R1, Z1, E2, A2, C2, R2, Z2, E3, A3, C3, R3, Z3, GR, OR, AN, MN, NM, PN, EC, SC, LY } compoundDesc_e;
+typedef enum { E0, A0, C0, R0, Z0, E1, A1, C1, R1, Z1, E2, A2, C2, R2, Z2, E3, A3, C3, R3, Z3, GR, OR, AN, PV, MN, NM, PN, LT, SC, LY } compoundDesc_e;
static descData_t compoundDesc[] = {
/*E0*/ { DESC_POS, N_("End Pt 1: X,Y"), &compoundData.endPt[0] },
/*A0*/ { DESC_ANGLE, N_("Angle"), &compoundData.endAngle[0] },
@@ -517,10 +562,11 @@ static descData_t compoundDesc[] = {
/*GR*/ { DESC_FLOAT, N_("Grade"), &compoundData.grade },
/*OR*/ { DESC_POS, N_("Origin: X,Y"), &compoundData.orig },
/*AN*/ { DESC_ANGLE, N_("Angle"), &compoundData.angle },
+/*PV*/ { DESC_PIVOT, N_("Pivot"), &compoundData.pivot },
/*MN*/ { DESC_STRING, N_("Manufacturer"), &compoundData.manuf, sizeof(compoundData.manuf)},
/*NM*/ { DESC_STRING, N_("Name"), &compoundData.name, sizeof(compoundData.name) },
/*PN*/ { DESC_STRING, N_("Part No"), &compoundData.partno, sizeof(compoundData.partno)},
-/*EC*/ { DESC_LONG, N_("# End Pts"), &compoundData.epCnt },
+/*LT*/ { DESC_LIST, N_("LineType"), &compoundData.linetype },
/*SC*/ { DESC_LONG, N_("# Segments"), &compoundData.segCnt },
/*LY*/ { DESC_LAYER, N_("Layer"), &compoundData.layerNumber },
{ DESC_NULL } };
@@ -539,7 +585,11 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee
BOOL_T titleChanged, flipped, ungrouped, split;
char * newTitle;
- if ( inx == -1 ) {
+ switch ( inx ) {
+ case -1:
+ case MN:
+ case NM:
+ case PN:
titleChanged = FALSE;
ParseCompoundTitle( xtitle(xx), &mP, &mL, &nP, &nL, &pP, &pL );
if (mP == NULL) mP = "";
@@ -616,7 +666,7 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee
GetBoundingBox( trk, &hi, &lo );
if ( labelScale >= mainD.scale &&
!OFF_MAIND( lo, hi ) ) {
- DrawCompoundDescription( trk, &tempD, GetTrkColor(trk,&tempD) );
+ DrawCompoundDescription( trk, &mainD, wDrawColorWhite );
}
/*sprintf( message, "%s\t%s\t%s", manufS, nameS, partnoS );*/
if (xx->title) MyFree(xx->title);
@@ -626,12 +676,13 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee
xx->split = split;
if ( labelScale >= mainD.scale &&
!OFF_MAIND( lo, hi ) ) {
- DrawCompoundDescription( trk, &tempD, GetTrkColor(trk,&tempD) );
+ DrawCompoundDescription( trk, &mainD, GetTrkColor(trk,&tempD) );
}
return;
}
UndrawNewTrack( trk );
+ coOrd orig;
switch ( inx ) {
case OR:
pos.x = compoundData.orig.x - xx->orig.x;
@@ -643,17 +694,31 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee
case A1:
case A2:
case A3:
- if (inx==E3) ep=3;
- else if (inx==E2) ep=2;
- else if (inx==E1) ep=1;
+ if (inx==A3) ep=3;
+ else if (inx==A2) ep=2;
+ else if (inx==A1) ep=1;
else ep=0;
- RotateTrack( trk, xx->orig, NormalizeAngle( compoundData.endAngle[ep]-xx->angle ) );
+ RotateTrack( trk, GetTrkEndPos(trk,ep), NormalizeAngle( compoundData.endAngle[ep]-GetTrkEndAngle(trk,ep) ) );
ComputeCompoundBoundingBox( trk );
- compoundData.angle = xx->angle;
- compoundDesc[AN].mode |= DESC_CHANGE;
break;
case AN:
- RotateTrack( trk, xx->orig, NormalizeAngle( compoundData.angle-xx->angle ) );
+ orig = xx->orig;
+ GetBoundingBox(trk,&hi,&lo);
+ switch (compoundData.pivot) {
+ case DESC_PIVOT_MID:
+ orig.x = (hi.x-lo.x)/2+lo.x;
+ orig.y = (hi.y-lo.y)/2+lo.y;
+ break;
+ case DESC_PIVOT_SECOND:
+ orig.x = (hi.x-lo.x)/2+lo.x;
+ orig.y = (hi.y-lo.y)/2+lo.y;
+ orig.x = (orig.x - xx->orig.x)*2+xx->orig.x;
+ orig.y = (orig.y - xx->orig.y)*2+xx->orig.y;
+ break;
+ default:
+ break;
+ }
+ RotateTrack( trk, orig, NormalizeAngle( compoundData.angle-xx->angle ) );
ComputeCompoundBoundingBox( trk );
break;
case E0:
@@ -680,7 +745,7 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee
break;
for (int i=0;i<compoundData.epCnt;i++) {
if (i==ep) continue;
- ComputeElev( trk, i, FALSE, &compoundData.elev[i], NULL );
+ ComputeElev( trk, i, FALSE, &compoundData.elev[i], NULL, TRUE );
}
if ( compoundData.length > minLength )
compoundData.grade = fabs( (compoundData.elev[0]-compoundData.elev[1])/compoundData.length )*100.0;
@@ -719,6 +784,13 @@ static void UpdateCompound( track_p trk, int inx, descData_p descUpd, BOOL_T nee
compoundDesc[i*(E1-E0)+C0].mode |= DESC_CHANGE;
}
}
+ compoundData.orig = xx->orig;
+ compoundDesc[OR].mode |= DESC_CHANGE;
+ compoundData.angle = xx->angle;
+ compoundDesc[AN].mode |= DESC_CHANGE;
+ break;
+ case LT:
+ xx->lineType = compoundData.linetype;
break;
default:
break;
@@ -839,9 +911,10 @@ void DescribeCompound(
compoundDesc[MN].mode =
compoundDesc[NM].mode =
compoundDesc[PN].mode = 0 /*DESC_NOREDRAW*/;
- compoundDesc[EC].mode =
compoundDesc[SC].mode = DESC_RO;
compoundDesc[LY].mode = DESC_NOREDRAW;
+ compoundDesc[PV].mode = 0;
+ compoundData.pivot = DESC_PIVOT_FIRST;
if (compoundData.epCnt >0) {
for (int i=0;(i<compoundData.epCnt)&&(i<MAX_DESCRIBE_ENDS);i++) {
compoundDesc[A0+(E1-E0)*i].mode = (int)mode;
@@ -859,18 +932,37 @@ void DescribeCompound(
compoundDesc[C0+(E1-E0)*i].mode = DESC_IGNORE;
compoundDesc[R0+(E1-E0)*i].mode = DESC_IGNORE;
}
- ComputeElev( trk, i, FALSE, &compoundData.elev[i], NULL );
+ ComputeElev( trk, i, FALSE, &compoundData.elev[i], NULL, FALSE );
compoundDesc[Z0+(E1-E0)*i].mode = (EndPtIsDefinedElev(trk,i)?0:DESC_RO)|DESC_NOREDRAW;
}
compoundDesc[GR].mode = DESC_RO;
}
+ if ( compoundData.epCnt == 2 )
+ compoundData.length = GetTrkLength( trk, 0, 1 );
if ( compoundData.length > minLength && compoundData.epCnt > 1)
compoundData.grade = fabs( (compoundData.elev[0]-compoundData.elev[1])/compoundData.length )*100.0;
else
compoundData.grade = 0.0;
+ if (GetTrkEndPtCnt(trk) == 0) {
+ compoundDesc[LT].mode = 0;
+ } else
+ compoundDesc[LT].mode = DESC_IGNORE;
+
DoDescribe(trackType, trk, compoundDesc, UpdateCompound);
+ if ( compoundDesc[LT].control0!=NULL) {
+ wListClear( (wList_p)compoundDesc[LT].control0 );
+ wListAddValue( (wList_p)compoundDesc[LT].control0, _("Solid"), NULL, (void*)0 );
+ wListAddValue( (wList_p)compoundDesc[LT].control0, _("Dash"), NULL, (void*)1 );
+ wListAddValue( (wList_p)compoundDesc[LT].control0, _("Dot"), NULL, (void*)2 );
+ wListAddValue( (wList_p)compoundDesc[LT].control0, _("DashDot"), NULL, (void*)3 );
+ wListAddValue( (wList_p)compoundDesc[LT].control0, _("DashDotDot"), NULL, (void*)4 );
+ wListAddValue( (wList_p)compoundDesc[LT].control0, _("CenterDot"), NULL, (void*)5 );
+ wListAddValue( (wList_p)compoundDesc[LT].control0, _("PhantomDot"), NULL, (void*)6 );
+ wListSetIndex( (wList_p)compoundDesc[LT].control0, compoundData.linetype );
+ }
+
}
@@ -880,6 +972,7 @@ void DeleteCompound(
struct extraData *xx = GetTrkExtraData(t);
FreeFilledDraw( xx->segCnt, xx->segs );
MyFree( xx->segs );
+ xx->segs = NULL;
}
@@ -891,6 +984,7 @@ BOOL_T WriteCompound(
EPINX_T ep, epCnt;
long options;
long position = 0;
+ drawLineType_e lineType = 0;
PATHPTR_T path;
BOOL_T rc = TRUE;
@@ -918,10 +1012,11 @@ BOOL_T WriteCompound(
position++;
}
}
- rc &= fprintf(f, "%s %d %d %ld %ld 0 %s %d %0.6f %0.6f 0 %0.6f \"%s\"\n",
+ lineType = xx->lineType;
+ rc &= fprintf(f, "%s %d %d %ld %ld %d %s %d %0.6f %0.6f 0 %0.6f \"%s\"\n",
GetTrkTypeName(t),
- GetTrkIndex(t), GetTrkLayer(t), options, position,
- GetTrkScaleName(t), GetTrkVisible(t),
+ GetTrkIndex(t), GetTrkLayer(t), options, position, lineType,
+ GetTrkScaleName(t), GetTrkVisible(t)|(GetTrkNoTies(t)?1<<2:0)|(GetTrkBridge(t)?1<<3:0),
xx->orig.x, xx->orig.y, xx->angle,
PutTitle(xtitle(xx)) )>0;
for (ep=0; ep<epCnt; ep++ )
@@ -933,6 +1028,8 @@ BOOL_T WriteCompound(
break;
case TOpier:
rc &= fprintf( f, "\tX %s %0.6f \"%s\"\n", PIER, xx->u.pier.height, xx->u.pier.name )>0;
+ break;
+
default:
;
}
@@ -950,6 +1047,34 @@ BOOL_T WriteCompound(
*
*/
+EXPORT void SetCompoundLineType( track_p trk, int width ) {
+ struct extraData * xx = GetTrkExtraData(trk);
+ switch(width) {
+ case 0:
+ xx->lineType = DRAWLINESOLID;
+ break;
+ case 1:
+ xx->lineType = DRAWLINEDASH;
+ break;
+ case 2:
+ xx->lineType = DRAWLINEDOT;
+ break;
+ case 3:
+ xx->lineType = DRAWLINEDASHDOT;
+ break;
+ case 4:
+ xx->lineType = DRAWLINEDASHDOTDOT;
+ break;
+ case 5:
+ xx->lineType = DRAWLINECENTER;
+ break;
+ case 6:
+ xx->lineType = DRAWLINEPHANTOM;
+ break;
+ }
+}
+
+
EXPORT track_p NewCompound(
TRKTYP_T trkType,
@@ -959,6 +1084,7 @@ EXPORT track_p NewCompound(
char * title,
EPINX_T epCnt,
trkEndPt_t * epp,
+ DIST_T * radii,
int pathLen,
char * paths,
wIndex_t segCnt,
@@ -994,13 +1120,23 @@ EXPORT track_p NewCompound(
FixUpBezierSegs(xx->segs,xx->segCnt);
ComputeCompoundBoundingBox( trk );
SetDescriptionOrig( trk );
- for ( ep=0; ep<epCnt; ep++ )
+// if (radii) {
+// xx->special = TOcurved;
+// xx->u.curved.radii.max = 0;
+// xx->u.curved.radii.cnt = 0;
+// DYNARR_SET(DIST_T,xx->u.curved.radii,epCnt);
+// }
+ for ( ep=0; ep<epCnt; ep++ ) {
SetTrkEndPoint( trk, ep, epp[ep].pos, epp[ep].angle );
+// if (radii) {
+// DYNARR_N(DIST_T,xx->u.curved.radii,ep) = radii[ep];
+// }
+ }
return trk;
}
-void ReadCompound(
+BOOL_T ReadCompound(
char * line,
TRKTYP_T trkType )
{
@@ -1017,26 +1153,28 @@ void ReadCompound(
char *cp;
long options = 0;
long position = 0;
+ long lineType = 0;
PATHPTR_T path=NULL;
if (paramVersion<3) {
if ( !GetArgs( line, "dXsdpfq",
&index, &layer, scale, &visible, &orig, &angle, &title ) )
- return;
+ return FALSE;
} else if (paramVersion <= 5 && trkType == T_STRUCTURE) {
if ( !GetArgs( line, "dL00sdpfq",
&index, &layer, scale, &visible, &orig, &angle, &title ) )
- return;
+ return FALSE;
} else {
- if ( !GetArgs( line, paramVersion<9?"dLll0sdpYfq":"dLll0sdpffq",
- &index, &layer, &options, &position, scale, &visible, &orig, &elev, &angle, &title ) )
- return;
+ if ( !GetArgs( line, paramVersion<9?"dLlldsdpYfq":"dLlldsdpffq",
+ &index, &layer, &options, &position, &lineType, scale, &visible, &orig, &elev, &angle, &title ) )
+ return FALSE;
}
if (paramVersion >=3 && paramVersion <= 5 && trkType == T_STRUCTURE)
strcpy( scale, curScaleName );
DYNARR_RESET( trkEndPt_t, tempEndPts_da );
pathCnt = 0;
- ReadSegs();
+ if ( !ReadSegs() )
+ return FALSE;
path = pathPtr;
if ( tempEndPts_da.cnt > 0 && pathCnt <= 1 ) {
pathCnt = 10;
@@ -1051,9 +1189,17 @@ void ReadCompound(
UpdateTitleMark( title, LookupScale(scale) );
}
}
- trk = NewCompound( trkType, index, orig, angle, title, 0, NULL, pathCnt, (char *)path, tempSegs_da.cnt, &tempSegs(0) );
+ trk = NewCompound( trkType, index, orig, angle, title, 0, NULL, NULL, pathCnt, (char *)path, tempSegs_da.cnt, &tempSegs(0) );
SetEndPts( trk, 0 );
- SetTrkVisible(trk, visible);
+ if ( paramVersion < 3 ) {
+ SetTrkVisible(trk, visible!=0);
+ SetTrkNoTies(trk, FALSE);
+ SetTrkBridge(trk, FALSE);
+ } else {
+ SetTrkVisible(trk, visible&2);
+ SetTrkNoTies(trk, visible&4);
+ SetTrkBridge(trk, visible&8);
+ }
SetTrkScale(trk, LookupScale( scale ));
SetTrkLayer(trk, layer);
SetTrkWidth(trk, (int)(options&3));
@@ -1062,68 +1208,27 @@ void ReadCompound(
xx->flipped = (int)((options&0x10)!=0);
xx->ungrouped = (int)((options&0x20)!=0);
xx->split = (int)((options&0x40)!=0);
+ xx->lineType = lineType;
xx->descriptionOff = descriptionOff;
if ( ( options & 0x80 ) != 0 )
SetTrkBits( trk, TB_HIDEDESC );
-#ifdef LATER
- trk = NewTrack( index, trkType, 0, sizeof (*xx) + 1 );
- SetEndPts( trk, 0 );
- xx = GetTrkExtraData(trk);
- SetTrkVisible(trk, visible);
- SetTrkScale(trk, LookupScale( scale ));
- SetTrkLayer(trk, layer);
- SetTrkWidth(trk, (int)(options&3));
- xx->orig = orig;
- xx->angle = angle;
- xx->customInfo = NULL;
- xx->handlaid = (int)((options>>3)&0x01);
- xx->flipped = (int)((options>>4)&0x01);
- xx->segCnt = tempSegs_da.cnt;
- xx->segs = MyMalloc( (tempSegs_da.cnt)*sizeof xx->segs[0] );
- if (paramVersion<6 && strlen( title ) > 2) {
- cp = strchr( title, '\t' );
- if (cp != NULL) {
- cp = strchr( cp, '\t' );
- }
- if (cp == NULL) {
- UpdateTitleMark(title, GetTrkScale(trk));
- }
- }
- xx->title = title;
- if ( GetTrkEndPtCnt(trk) > 0 && pathCnt <= 1 ) {
- xx->pathLen = 10;
- xx->paths = xx->pathCurr = (PATHPTR_T)Malloc( xx->pathLen );
- memcpy( xx->paths, "Normal\01\0\0", xx->pathLen );
- } else {
- xx->pathLen = pathCnt;
- if (pathCnt > 0) {
- xx->paths = xx->pathCurr = (PATHPTR_T)Malloc( pathCnt );
- memcpy( xpaths(xx), pathPtr, pathCnt );
- } else {
- xx->paths = xx->pathCurr = NULL;
- }
- }
- xx->segCnt = tempSegs_da.cnt;
- memcpy( xx->segs, tempSegs_da.ptr, tempSegs_da.cnt * sizeof *xx->segs );
-
- ComputeCompoundBoundingBox( trk );
- SetDescriptionOrig( trk );
- xx->descriptionOff = descriptionOff;
-#endif
if (tempSpecial[0] != '\0') {
if (strncmp( tempSpecial, ADJUSTABLE, strlen(ADJUSTABLE) ) == 0) {
xx->special = TOadjustable;
- GetArgs( tempSpecial+strlen(ADJUSTABLE), "ff",
- &xx->u.adjustable.minD, &xx->u.adjustable.maxD );
+ if ( !GetArgs( tempSpecial+strlen(ADJUSTABLE), "ff",
+ &xx->u.adjustable.minD, &xx->u.adjustable.maxD ) )
+ return FALSE;
} else if (strncmp( tempSpecial, PIER, strlen(PIER) ) == 0) {
xx->special = TOpier;
- GetArgs( tempSpecial+strlen(PIER), "fq",
- &xx->u.pier.height, &xx->u.pier.name );
+ if ( !GetArgs( tempSpecial+strlen(PIER), "fq",
+ &xx->u.pier.height, &xx->u.pier.name ) )
+ return FALSE;
} else {
InputError("Unknown special case", TRUE);
+ return FALSE;
}
}
if (pathCnt > 0) {
@@ -1138,7 +1243,7 @@ void ReadCompound(
}
}
xx->pathCurr = path;
-
+ return TRUE;
}
void MoveCompound(
@@ -1217,12 +1322,12 @@ void FlipCompound(
mP && strcmp( mP, mfg ) == 0 && nP && pP ) {
if ( strcmp( nP, descL ) == 0 && strcmp( pP, partL ) == 0 ) {
sprintf( message, "%s\t%s\t%s", mfg, descR, partR );
- xx->title = strdup( message );
+ xx->title = MyStrdup( message );
return;
}
if ( strcmp( nP, descR ) == 0 && strcmp( pP, partR ) == 0 ) {
sprintf( message, "%s\t%s\t%s", mfg, descL, partL );
- xx->title = strdup( message );
+ xx->title = MyStrdup( message );
return;
}
}
diff --git a/app/bin/compound.h b/app/bin/compound.h
index 4845f78..b4c63ca 100644
--- a/app/bin/compound.h
+++ b/app/bin/compound.h
@@ -26,7 +26,7 @@
#include "common.h"
#include "track.h"
-typedef enum { TOnormal, TOadjustable, TOpierInfo, TOpier, TOcarDesc, TOlast } TOspecial_e;
+typedef enum { TOnormal, TOadjustable, TOpierInfo, TOpier, TOcarDesc, TOlast, TOcurved } TOspecial_e;
typedef struct {
char * name;
@@ -44,6 +44,9 @@ typedef union {
FLOAT_T height;
char * name;
} pier;
+ struct {
+ dynArr_t radii;
+ } curved;
} turnoutInfo_u;
typedef struct turnoutInfo_t{
@@ -91,6 +94,8 @@ struct extraData {
PATHPTR_T pathCurr;
wIndex_t segCnt;
trkSeg_t * segs;
+ DIST_T * radii;
+ drawLineType_e lineType;
};
#endif
@@ -111,6 +116,7 @@ extern turnoutInfo_t * curStructure;
#define ADJUSTABLE "adjustable"
#define PIER "pier"
+#define CURVED "curvedends"
/* compound.c */
#define FIND_TURNOUT (1<<11)
@@ -129,14 +135,15 @@ void DrawCompoundDescription( track_p, drawCmd_p, wDrawColor );
DIST_T DistanceCompound( track_p, coOrd * );
void DescribeCompound( track_p, char *, CSIZE_T );
void DeleteCompound( track_p );
-track_p NewCompound( TRKTYP_T, TRKINX_T, coOrd, ANGLE_T, char *, EPINX_T, trkEndPt_t *, int, char *, wIndex_t, trkSeg_p );
+track_p NewCompound( TRKTYP_T, TRKINX_T, coOrd, ANGLE_T, char *, EPINX_T, trkEndPt_t *, DIST_T *, int, char *, wIndex_t, trkSeg_p );
BOOL_T WriteCompound( track_p, FILE * );
-void ReadCompound( char *, TRKTYP_T );
+BOOL_T ReadCompound( char *, TRKTYP_T );
void MoveCompound( track_p, coOrd );
void RotateCompound( track_p, coOrd, ANGLE_T );
void RescaleCompound( track_p, FLOAT_T );
void FlipCompound( track_p, coOrd, ANGLE_T );
BOOL_T EnumerateCompound( track_p );
+void SetCompoundLineType( track_p trk, int width );
/* cgroup.c */
void UngroupCompound( track_p );
@@ -147,27 +154,34 @@ void DoGroup( void );
void UpdateTitleMark( char *, SCALEINX_T );
void DoUpdateTitles( void );
BOOL_T RefreshCompound( track_p, BOOL_T );
+wIndex_t FindListItemByContext( wList_p, void *);
+
/* cturnout.c */
EPINX_T TurnoutPickEndPt( coOrd p, track_p );
+BOOL_T SplitTurnoutCheck(track_p,coOrd,EPINX_T ep,track_p *,EPINX_T *,EPINX_T *,BOOL_T check, coOrd *, ANGLE_T *);
void GetSegInxEP( signed char, int *, EPINX_T * );
+void SetSegInxEP( signed char *, int, EPINX_T) ;
wIndex_t CheckPaths( wIndex_t, trkSeg_p, PATHPTR_T );
-turnoutInfo_t * CreateNewTurnout( char *, char *, wIndex_t, trkSeg_p, wIndex_t, PATHPTR_T, EPINX_T, trkEndPt_t *, wBool_t );
+turnoutInfo_t * CreateNewTurnout( char *, char *, wIndex_t, trkSeg_p, wIndex_t, PATHPTR_T, EPINX_T, trkEndPt_t *, DIST_T *, wBool_t );
+void DeleteTurnoutParams(int fileInx);
turnoutInfo_t * TurnoutAdd( long, SCALEINX_T, wList_p, coOrd *, EPINX_T );
STATUS_T CmdTurnoutAction( wAction_t, coOrd );
BOOL_T ConnectAdjustableTracks( track_p trk1, EPINX_T ep1, track_p trk2, EPINX_T ep2 );
track_p NewHandLaidTurnout( coOrd, ANGLE_T, coOrd, ANGLE_T, coOrd, ANGLE_T, ANGLE_T );
void NextTurnoutPosition( track_p trk );
-
+enum paramFileState GetTrackCompatibility(int paramFileIndex, SCALEINX_T scaleIndex);
/* ctodesgn.c */
void EditCustomTurnout( turnoutInfo_t *, turnoutInfo_t * );
long ComputeTurnoutRoadbedSide( trkSeg_p, int, int, ANGLE_T, DIST_T );
/* cstruct.c */
turnoutInfo_t * CreateNewStructure( char *, char *, wIndex_t, trkSeg_p, BOOL_T );
+enum paramFileState GetStructureCompatibility(int paramFileIndex, SCALEINX_T scaleIndex);
turnoutInfo_t * StructAdd( long, SCALEINX_T, wList_p, coOrd * );
STATUS_T CmdStructureAction( wAction_t, coOrd );
BOOL_T StructLoadCarDescList( wList_p );
+void DeleteStructures(int fileIndex);
/* cstrdsgn.c */
void EditCustomStructure( turnoutInfo_t * );
diff --git a/app/bin/cparalle.c b/app/bin/cparalle.c
index 8e70408..27276b1 100644
--- a/app/bin/cparalle.c
+++ b/app/bin/cparalle.c
@@ -30,162 +30,274 @@
#include "param.h"
#include "track.h"
#include "utility.h"
+#include "layout.h"
static struct {
track_p Trk;
coOrd orig;
+ track_p anchor_Trk;
} Dpa;
static DIST_T parSeparation = 1.0;
+static double parSepFactor = 0.0;
+static long parType = 0;
-static paramFloatRange_t r_0o1_100 = { 0.1, 100.0, 100 };
+enum PAR_TYPE_E { PAR_TRACK, PAR_LINE };
+
+static paramFloatRange_t r_0o1_100 = { 0.0, 100.0, 100 };
+static paramFloatRange_t r_0_10 = { 0.0, 10.0 };
static paramData_t parSepPLs[] = {
#define parSepPD (parSepPLs[0])
- { PD_FLOAT, &parSeparation, "separation", PDO_DIM|PDO_NOPREF|PDO_NOPREF, &r_0o1_100, N_("Separation") } };
+#define parSepI 0
+ { PD_FLOAT, &parSeparation, "separation", PDO_DIM, &r_0o1_100, N_("Separation") },
+#define parFactorPD (parSepPLs[1])
+#define parFactorI 1
+ { PD_FLOAT, &parSepFactor, "factor", 0, &r_0_10, N_("Radius Factor") }
+};
static paramGroup_t parSepPG = { "parallel", 0, parSepPLs, sizeof parSepPLs/sizeof parSepPLs[0] };
-static STATUS_T CmdParallel( wAction_t action, coOrd pos )
+static STATUS_T CmdParallel(wAction_t action, coOrd pos)
{
- DIST_T d;
- track_p t=NULL;
- coOrd p;
- static coOrd p0, p1;
- ANGLE_T a;
- track_p t0, t1;
- EPINX_T ep0=-1, ep1=-1;
- wControl_p controls[2];
- char * labels[1];
-
- switch (action) {
-
- case C_START:
- if (parSepPD.control==NULL) {
- ParamCreateControls( &parSepPG, NULL );
- }
- sprintf( message, "parallel-separation-%s", curScaleName );
- parSeparation = ceil(13.0*12.0/curScaleRatio);
- wPrefGetFloat( "misc", message, &parSeparation, parSeparation );
- ParamLoadControls( &parSepPG );
- ParamGroupRecord( &parSepPG );
- controls[0] = parSepPD.control;
- controls[1] = NULL;
- labels[0] = N_("Separation");
- InfoSubstituteControls( controls, labels );
- /*InfoMessage( "Select track" );*/
- return C_CONTINUE;
-
- case C_DOWN:
- if ( parSeparation <= 0.0 ) {
- ErrorMessage( MSG_PARALLEL_SEP_GTR_0 );
- return C_ERROR;
- }
- controls[0] = parSepPD.control;
- controls[1] = NULL;
- labels[0] = N_("Separation");
- InfoSubstituteControls( controls, labels );
- ParamLoadData( &parSepPG );
- Dpa.orig = pos;
- Dpa.Trk = OnTrack( &Dpa.orig, TRUE, TRUE );
- if (!Dpa.Trk) {
- return C_CONTINUE;
- }
- if ( !QueryTrack( Dpa.Trk, Q_CAN_PARALLEL ) ) {
- Dpa.Trk = NULL;
- InfoMessage(_(" Track doesn't support parallel"));
- return C_CONTINUE;
- }
- /* in case query has changed things (eg joint) */
- /*
- * this seems to cause problems so I commented it out
- * until further investigation shows the necessity
- */
- //Dpa.Trk = OnTrack( &Dpa.orig, TRUE, TRUE );
- tempSegs_da.cnt = 0;
-
- case C_MOVE:
-
- if (Dpa.Trk == NULL) return C_CONTINUE;
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- if ( !MakeParallelTrack( Dpa.Trk, pos, parSeparation, NULL, &p0, &p1 ) ) {
- Dpa.Trk = NULL;
- return C_CONTINUE;
- }
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- return C_CONTINUE;
-
- case C_UP:
- if (Dpa.Trk == NULL) return C_CONTINUE;
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- p = p0;
- if ((t0=OnTrack( &p, FALSE, TRUE )) != NULL) {
- ep0 = PickEndPoint( p, t0 );
- if ( GetTrkEndTrk(t0,ep0) != NULL ) {
- t0 = NULL;
- } else {
- p = GetTrkEndPos( t0, ep0 );
- d = FindDistance( p, p0 );
- if ( d > connectDistance )
+ DIST_T d;
+ track_p t=NULL;
+ coOrd p;
+ static coOrd p0, p1;
+ ANGLE_T a;
+ track_p t0, t1;
+ EPINX_T ep0=-1, ep1=-1;
+ wControl_p controls[4];
+ char * labels[3];
+ static DIST_T parRFactor;
+
+ parType = (long)commandContext;
+
+ switch (action&0xFF) {
+
+ case C_START:
+ if (parSepPLs[0].control==NULL) {
+ ParamCreateControls(&parSepPG, NULL);
+ }
+ if (parType == PAR_TRACK) {
+ sprintf(message, "parallel-separation-%s", curScaleName);
+ parSeparation = ceil(13.0*12.0/curScaleRatio);
+ } else {
+ sprintf(message, "parallel-line-separation-%s", curScaleName);
+ parSeparation = 5.0*12.0/curScaleRatio;
+ }
+ wPrefGetFloat("misc", message, &parSeparation, parSeparation);
+ ParamLoadControls(&parSepPG);
+ ParamGroupRecord(&parSepPG);
+ parSepPD.option |= PDO_NORECORD;
+ parFactorPD.option |= PDO_NORECORD;
+ controls[0] = parSepPD.control;
+ if (parType == PAR_TRACK)
+ controls[1] = parFactorPD.control;
+ else
+ controls[1] = NULL;
+ controls[2] = NULL;
+ labels[0] = N_("Separation");
+ labels[1] = N_("Radius Factor");
+ InfoSubstituteControls(controls, labels);
+ parSepPD.option &= ~PDO_NORECORD;
+ parFactorPD.option &= ~PDO_NORECORD;
+ Dpa.anchor_Trk = NULL;
+ tempSegs_da.cnt = 0;
+ return C_CONTINUE;
+
+ case wActionMove:
+ tempSegs_da.cnt = 0;
+ Dpa.anchor_Trk = NULL;
+ if (parType == PAR_TRACK)
+ Dpa.anchor_Trk = OnTrack(&pos, FALSE, TRUE);
+ else
+ Dpa.anchor_Trk = OnTrack(&pos, FALSE, FALSE);
+
+ if (!Dpa.anchor_Trk) {
+ return C_CONTINUE;
+ }
+ if (Dpa.anchor_Trk && !CheckTrackLayerSilent(Dpa.anchor_Trk)) {
+ Dpa.anchor_Trk = NULL;
+ return C_CONTINUE;
+ }
+ if (!QueryTrack(Dpa.anchor_Trk, Q_CAN_PARALLEL)) {
+ Dpa.anchor_Trk = NULL;
+ return C_CONTINUE;
+ }
+ break;
+ case C_DOWN:
+ Dpa.anchor_Trk = NULL;
+ tempSegs_da.cnt = 0;
+ if (parSeparation < 0.0) {
+ ErrorMessage(MSG_PARALLEL_SEP_GTR_0);
+ return C_ERROR;
+ }
+
+ controls[0] = parSepPD.control;
+ controls[1] = parFactorPD.control;
+ controls[2] = NULL;
+ labels[0] = N_("Separation");
+ labels[1] = N_("Radius factor");
+ InfoSubstituteControls(controls, labels);
+ ParamLoadData(&parSepPG);
+ Dpa.orig = pos;
+ if (parType == PAR_TRACK)
+ Dpa.Trk = OnTrack(&pos, FALSE, TRUE);
+ else
+ Dpa.Trk = OnTrack(&pos, FALSE, FALSE); //Also lines for line
+ if (!Dpa.Trk) {
+ return C_CONTINUE;
+ }
+ if (!QueryTrack(Dpa.Trk, Q_CAN_PARALLEL)) {
+ Dpa.Trk = NULL;
+ InfoMessage(_(" Track/Line doesn't support parallel"));
+ wBeep();
+ return C_CONTINUE;
+ }
+
+ parRFactor = (2864.0*(double)parSepFactor)/curScaleRatio;
+
+ if ((parType == PAR_TRACK) && (parSeparation == 0.0)) {
+ DIST_T orig_gauge = GetTrkGauge(Dpa.Trk);
+ DIST_T new_gauge = GetScaleTrackGauge(GetLayoutCurScale());
+ if (orig_gauge == new_gauge) {
+ ErrorMessage(MSG_PARALLEL_SEP_GTR_0);
+ return C_ERROR;
+ }
+ parSeparation = fabs(orig_gauge/2-new_gauge/2);
+ parRFactor = 0.0;
+ } else if (parType != PAR_TRACK)
+ parRFactor = 0.0;
+ /* in case query has changed things (eg joint) */
+ /*
+ * this seems to cause problems so I commented it out
+ * until further investigation shows the necessity
+ */
+ //Dpa.Trk = OnTrack( &Dpa.orig, TRUE, TRUE );
+ tempSegs_da.cnt = 0;
+ /* no break */
+
+ case C_MOVE:
+ if (Dpa.Trk == NULL) {
+ return C_CONTINUE;
+ }
+ tempSegs_da.cnt = 0;
+ if (!MakeParallelTrack(Dpa.Trk, pos, parSeparation, parRFactor, NULL, &p0, &p1,
+ parType == PAR_TRACK)) {
+ Dpa.Trk = NULL;
+ return C_CONTINUE;
+ }
+ return C_CONTINUE;
+
+ case C_UP:
+ Dpa.anchor_Trk = NULL;
+ if (Dpa.Trk == NULL) {
+ return C_CONTINUE;
+ }
+ t0=t1=NULL;
+ if (parType == PAR_TRACK) {
+ p = p0;
+ tempSegs_da.cnt = 0;
+ if ((t0=OnTrack(&p, FALSE, TRUE)) != NULL) {
+ ep0 = PickEndPoint(p, t0);
+ if (GetTrkEndTrk(t0,ep0) != NULL) {
t0 = NULL;
+ } else {
+ p = GetTrkEndPos(t0, ep0);
+ d = FindDistance(p, p0);
+ if (d > connectDistance) {
+ t0 = NULL;
+ }
+ }
}
- }
- p = p1;
- if ((t1=OnTrack( &p, FALSE, TRUE )) != NULL) {
- ep1 = PickEndPoint( p, t1 );
- if ( GetTrkEndTrk(t1,ep1) != NULL ) {
- t1 = NULL;
- } else {
- p = GetTrkEndPos( t1, ep1 );
- d = FindDistance( p, p1 );
- if ( d > connectDistance )
+ p = p1;
+ if ((t1=OnTrack(&p, FALSE, TRUE)) != NULL) {
+ ep1 = PickEndPoint(p, t1);
+ if (GetTrkEndTrk(t1,ep1) != NULL) {
t1 = NULL;
+ } else {
+ p = GetTrkEndPos(t1, ep1);
+ d = FindDistance(p, p1);
+ if (d > connectDistance) {
+ t1 = NULL;
+ }
+ }
}
- }
- UndoStart( _("Create Parallel Track"), "newParallel" );
- if ( !MakeParallelTrack( Dpa.Trk, pos, parSeparation, &t, NULL, NULL ) ) {
- return C_TERMINATE;
- }
- CopyAttributes( Dpa.Trk, t );
- if ( t0 ) {
- a = NormalizeAngle( GetTrkEndAngle( t0, ep0 ) - GetTrkEndAngle( t, 0 ) + (180.0+connectAngle/2.0) );
- if (a < connectAngle) {
- DrawEndPt( &mainD, t0, ep0, wDrawColorWhite );
- ConnectTracks( t0, ep0, t, 0 );
- DrawEndPt( &mainD, t0, ep0, wDrawColorBlack );
+ }
+ UndoStart(_("Create Parallel Track"), "newParallel");
+ if (!MakeParallelTrack(Dpa.Trk, pos, parSeparation, parRFactor, &t, NULL, NULL,
+ parType == PAR_TRACK)) {
+ tempSegs_da.cnt = 0;
+ return C_TERMINATE;
+ }
+ if (parType == PAR_TRACK) {
+ if (GetTrkGauge(Dpa.Trk)> parSeparation) {
+ SetTrkNoTies(t, TRUE);
+ }
+ //CopyAttributes( Dpa.Trk, t ); Don't force scale or track width or Layer
+ SetTrkBits(t,(GetTrkBits(t)&TB_HIDEDESC) | (GetTrkBits(Dpa.Trk)&~TB_HIDEDESC));
+
+ if (t0) {
+ a = NormalizeAngle(GetTrkEndAngle(t0, ep0) - GetTrkEndAngle(t,
+ 0) + (180.0+connectAngle/2.0));
+ if (a < connectAngle) {
+ DrawEndPt(&mainD, t0, ep0, wDrawColorWhite);
+ ConnectTracks(t0, ep0, t, 0);
+ DrawEndPt(&mainD, t0, ep0, wDrawColorBlack);
+ }
}
- }
- if ( t1 ) {
- a = NormalizeAngle( GetTrkEndAngle( t1, ep1 ) - GetTrkEndAngle( t, 1 ) + (180.0+connectAngle/2.0) );
- if (a < connectAngle) {
- DrawEndPt( &mainD, t1, ep1, wDrawColorWhite );
- ConnectTracks( t1, ep1, t, 1 );
- DrawEndPt( &mainD, t1, ep1, wDrawColorBlack );
+ if (t1) {
+ a = NormalizeAngle(GetTrkEndAngle(t1, ep1) - GetTrkEndAngle(t,
+ 1) + (180.0+connectAngle/2.0));
+ if (a < connectAngle) {
+ DrawEndPt(&mainD, t1, ep1, wDrawColorWhite);
+ ConnectTracks(t1, ep1, t, 1);
+ DrawEndPt(&mainD, t1, ep1, wDrawColorBlack);
+ }
}
- }
- DrawNewTrack( t );
- UndoEnd();
- InfoSubstituteControls( NULL, NULL );
- sprintf( message, "parallel-separation-%s", curScaleName );
- wPrefSetFloat( "misc", message, parSeparation );
- return C_TERMINATE;
-
- case C_REDRAW:
- return C_CONTINUE;
-
- case C_CANCEL:
- InfoSubstituteControls( NULL, NULL );
- return C_TERMINATE;
-
- }
- return C_CONTINUE;
+ }
+ DrawNewTrack(t);
+ UndoEnd();
+ InfoSubstituteControls(NULL, NULL);
+ if (parType == PAR_TRACK)
+ sprintf(message, "parallel-separation-%s", curScaleName);
+ else
+ sprintf(message, "parallel-line-separation-%s", curScaleName);
+ wPrefSetFloat("misc", message, parSeparation);
+ tempSegs_da.cnt = 0;
+ return C_TERMINATE;
+
+ case C_REDRAW:
+ if (Dpa.anchor_Trk) {
+ DrawTrack(Dpa.anchor_Trk,&tempD,
+ wDrawColorPreviewSelected); //Special color means THICK3 as well
+ }
+ if (tempSegs_da.cnt>0) {
+ DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge,
+ wDrawColorBlack );
+ }
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ Dpa.anchor_Trk = NULL;
+ tempSegs_da.cnt = 0;
+ InfoSubstituteControls(NULL, NULL);
+ return C_TERMINATE;
+
+ }
+ return C_CONTINUE;
}
#include "bitmaps/parallel.xpm"
+#include "bitmaps/parallel-line.xpm"
EXPORT void InitCmdParallel( wMenu_p menu )
{
- AddMenuButton( menu, CmdParallel, "cmdParallel", _("Parallel"), wIconCreatePixMap(parallel_xpm), LEVEL0_50, IC_STICKY|IC_POPUP, ACCL_PARALLEL, NULL );
+ ButtonGroupBegin( _("Parallel"), "cmdParallelSetCmd", _("Parallel") );
+ AddMenuButton( menu, CmdParallel, "cmdParallelTrack", _("Parallel Track"), wIconCreatePixMap(parallel_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_PARALLEL, (void*)0 );
+ AddMenuButton( menu, CmdParallel, "cmdParallelLine", _("Parallel Line"), wIconCreatePixMap(parallel_line_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_PARALLEL, (void*)1 );
+ ButtonGroupEnd();
ParamRegister( &parSepPG );
}
diff --git a/app/bin/cprint.c b/app/bin/cprint.c
index 88a9151..066e649 100644
--- a/app/bin/cprint.c
+++ b/app/bin/cprint.c
@@ -25,8 +25,10 @@
#include <string.h>
#include <ctype.h>
#include <math.h>
+#include <stdbool.h>
#include "custom.h"
+#include "dynstring.h"
#include "fileio.h"
#include "i18n.h"
#include "layout.h"
@@ -69,6 +71,7 @@ struct {
static long printGaudy = 1;
static long printRegistrationMarks = 1;
+static long printPageNumbers = 1;
static long printPhysSize = FALSE;
static long printFormat = PORTRAIT;
static long printOrder = 0;
@@ -85,7 +88,8 @@ static long iPrintScale = 16;
static coOrd maxPageSize;
static coOrd realPageSize;
-static wWin_p printWin;
+static wWin_p printWin = NULL;
+static wWin_p printMarginWin = NULL;
static wMenu_p printGridPopupM;
@@ -98,16 +102,21 @@ static void DoResetGrid( void );
static void DoPrintSetup( void );
static void PrintClear( void );
static void PrintMaxPageSize( void );
+static void SelectAllPages(void);
+static void DoPrintMargin(void);
+static bool PrintPageNumber( wPos_t x, wPos_t y, DIST_T width, DIST_T height );
+static bool PrintNextPageNumbers(int x, int y, DIST_T pageW, DIST_T pageH);
static char * printFormatLabels[] = { N_("Portrait"), N_("Landscape"), NULL };
static char * printOrderLabels[] = { N_("Normal"), N_("Reverse"), NULL };
static char * printGaudyLabels[] = { N_("Engineering Data"), NULL };
-static char * printRegistrationMarksLabels[] = { N_("Print Registration Marks"), NULL };
+static char * printRegistrationMarksLabels[] = { N_("Registration Marks (in 1:1 scale only)"), NULL };
+static char * printPageNumberLabels[] = { N_("Page Numbers"), NULL };
static char * printPhysSizeLabels[] = { N_("Ignore Page Margins"), NULL };
-static char * printGridLabels[] = { N_("Print Snap Grid"), NULL };
-static char * printRulerLabels[] = { N_("Print Rulers"), NULL };
-static char * printRoadbedLabels[] = { N_("Print Roadbed Outline"), NULL };
-static char * printCenterLineLabels[] = { N_("Print Centerline below Scale 1:1"), NULL };
+static char * printGridLabels[] = { N_("Snap Grid"), NULL };
+static char * printRulerLabels[] = { N_("Rulers"), NULL };
+static char * printRoadbedLabels[] = { N_("Roadbed Outline"), NULL };
+static char * printCenterLineLabels[] = { N_("Centerline below Scale 1:1"), NULL };
static paramIntegerRange_t rminScale_999 = { 1, 999, 0, PDO_NORANGECHECK_HIGH };
static paramFloatRange_t r0_ = { 0, 0, 0, PDO_NORANGECHECK_HIGH };
static paramFloatRange_t r1_ = { 1, 0, 0, PDO_NORANGECHECK_HIGH };
@@ -122,34 +131,41 @@ static paramData_t printPLs[] = {
/*4*/ { PD_BUTTON, (void*)PrintSnapShot, "snapshot", PDO_DLGHORZ, NULL, N_("Snap Shot") },
/*5*/ { PD_RADIO, &printFormat, "format", 0, printFormatLabels, N_("Page Format"), BC_HORZ|BC_NOBORDER, (void*)1 },
/*6*/ { PD_RADIO, &printOrder, "order", PDO_DLGBOXEND, printOrderLabels, N_("Print Order"), BC_HORZ|BC_NOBORDER },
-
-/*7*/ { PD_TOGGLE, &printGaudy, "style", PDO_DLGNOLABELALIGN, printGaudyLabels, NULL, BC_HORZ|BC_NOBORDER, (void*)1 },
-/*8*/ { PD_TOGGLE, &printPhysSize, "physsize", PDO_DLGNOLABELALIGN, printPhysSizeLabels, NULL, BC_HORZ|BC_NOBORDER, (void*)1 },
+/*7*/ { PD_MESSAGE, N_("Print "), NULL, PDO_DLGRESETMARGIN| PDO_DLGNOLABELALIGN, (void*)0 },
+/*8*/ { PD_TOGGLE, &printGaudy, "style", PDO_DLGNOLABELALIGN, printGaudyLabels, NULL, BC_HORZ|BC_NOBORDER, (void*)1 },
#define I_REGMARKS (9)
/*9*/ { PD_TOGGLE, &printRegistrationMarks, "registrationMarks", PDO_DLGNOLABELALIGN, printRegistrationMarksLabels, NULL, BC_HORZ|BC_NOBORDER },
-#define I_GRID (10)
-/*10*/ { PD_TOGGLE, &printGrid, "grid", PDO_DLGNOLABELALIGN, printGridLabels, NULL, BC_HORZ|BC_NOBORDER },
-#define I_RULER (11)
-/*11*/ { PD_TOGGLE, &printRuler, "ruler", PDO_DLGNOLABELALIGN, printRulerLabels, NULL, BC_HORZ|BC_NOBORDER },
-#define I_CENTERLINE (12)
-/*12*/ { PD_TOGGLE, &printCenterLine, "centerLine", PDO_DLGNOLABELALIGN, printCenterLineLabels, NULL, BC_HORZ|BC_NOBORDER },
-#define I_ROADBED (13)
-/*13*/{ PD_TOGGLE, &printRoadbed, "roadbed", PDO_DLGNOLABELALIGN, printRoadbedLabels, NULL, BC_HORZ|BC_NOBORDER },
-#define I_ROADBEDWIDTH (14)
-/*14*/{ PD_FLOAT, &printRoadbedWidth, "roadbedWidth", PDO_DIM|PDO_DLGBOXEND, &r0_, N_("Width") },
-/*15*/{ PD_FLOAT, &newPrintGrid.orig.x, "origx", PDO_DIM|PDO_DLGRESETMARGIN, &r_10_99999, N_("Origin: X"), 0, (void*)2 },
-/*16*/ { PD_FLOAT, &newPrintGrid.orig.y, "origy", PDO_DIM, &r_10_99999, N_("Y"), 0, (void*)2 },
-/*17*/ { PD_BUTTON, (void*)DoResetGrid, "reset", PDO_DLGHORZ, NULL, N_("Reset") },
-/*18*/ { PD_FLOAT, &newPrintGrid.angle, "origa", PDO_ANGLE|PDO_DLGBOXEND, &r0_360, N_("Angle"), 0, (void*)2 },
-/*19*/ { PD_BUTTON, (void*)DoPrintSetup, "setup", PDO_DLGCMDBUTTON, NULL, N_("Setup") },
-/*20*/ { PD_BUTTON, (void*)PrintClear, "clear", 0, NULL, N_("Clear") },
-#define I_PAGECNT (21)
-/*21*/ { PD_MESSAGE, N_("0 pages"), NULL, 0, (void*)80 },
-/*22*/ { PD_MESSAGE, N_("selected"), NULL, 0, (void*)80 }
+#define I_PAGENUMBERS (10)
+/*10*/ { PD_TOGGLE, &printPageNumbers, "pageNumbers", PDO_DLGNOLABELALIGN, printPageNumberLabels, NULL, BC_HORZ | BC_NOBORDER },
+#define I_GRID (11)
+/*11*/ { PD_TOGGLE, &printGrid, "grid", PDO_DLGNOLABELALIGN, printGridLabels, NULL, BC_HORZ|BC_NOBORDER },
+#define I_RULER (12)
+/*12*/ { PD_TOGGLE, &printRuler, "ruler", PDO_DLGNOLABELALIGN, printRulerLabels, NULL, BC_HORZ|BC_NOBORDER },
+#define I_CENTERLINE (13)
+/*13*/ { PD_TOGGLE, &printCenterLine, "centerLine", PDO_DLGNOLABELALIGN, printCenterLineLabels, NULL, BC_HORZ|BC_NOBORDER },
+#define I_ROADBED (14)
+/*14*/{ PD_TOGGLE, &printRoadbed, "roadbed", PDO_DLGNOLABELALIGN, printRoadbedLabels, NULL, BC_HORZ|BC_NOBORDER },
+#define I_ROADBEDWIDTH (15)
+/*15*/{ PD_FLOAT, &printRoadbedWidth, "roadbedWidth", PDO_DIM , &r0_, N_(" Width") },
+/*16*/ { PD_TOGGLE, &printPhysSize, "physsize", PDO_DLGNOLABELALIGN, printPhysSizeLabels, NULL, BC_HORZ | BC_NOBORDER, (void*)1 },
+/*17*/ { PD_BUTTON, (void*)DoPrintMargin, "margin", PDO_DLGHORZ|PDO_DLGBOXEND, NULL, N_("Margins") },
+/*18*/{ PD_FLOAT, &newPrintGrid.orig.x, "origx", PDO_DIM|PDO_DLGRESETMARGIN, &r_10_99999, N_("Origin: X"), 0, (void*)2 },
+/*19*/ { PD_FLOAT, &newPrintGrid.orig.y, "origy", PDO_DIM, &r_10_99999, N_("Y"), 0, (void*)2 },
+/*20*/ { PD_BUTTON, (void*)DoResetGrid, "reset", PDO_DLGHORZ, NULL, N_("Reset") },
+/*21*/ { PD_FLOAT, &newPrintGrid.angle, "origa", PDO_ANGLE|PDO_DLGBOXEND, &r0_360, N_("Angle"), 0, (void*)2 },
+/*22*/ { PD_BUTTON, (void*)DoPrintSetup, "setup", PDO_DLGCMDBUTTON, NULL, N_("Setup") },
+/*23*/ { PD_BUTTON, (void*)SelectAllPages, "selall", 0, NULL, N_("Select All") },
+/*24*/ { PD_BUTTON, (void*)PrintClear, "clear", 0, NULL, N_("Clear") },
+#define I_PAGECNT (25)
+/*25*/ { PD_MESSAGE, N_("0 pages"), NULL, 0, (void*)80 },
+/*26*/ { PD_MESSAGE, N_("selected"), NULL, 0, (void*)80 }
};
static paramGroup_t printPG = { "print", PGO_PREFMISCGROUP, printPLs, sizeof printPLs/sizeof printPLs[0] };
+static struct {
+ double top, right, bottom, left;
+} printMargin = { 0.0, 0.0, 0.0, 0.0 };
/*****************************************************************************
*
@@ -157,6 +173,23 @@ static paramGroup_t printPG = { "print", PGO_PREFMISCGROUP, printPLs, sizeof pri
*
*/
+/**
+ * Update the dialog with the current number of selected pages.
+ *
+ */
+
+static void
+UpdatePageCount()
+{
+ DynString msg;
+ DynStringMalloc(&msg, 0);
+
+ DynStringPrintf(&msg, (pageCount == 1?_("%d page"):_("%d pages")), pageCount);
+ ParamLoadMessage(&printPG, I_PAGECNT, DynStringToCStr(&msg));
+ ParamDialogOkActive(&printPG, pageCount != 0);
+
+ DynStringFree(&msg);
+}
static void ChangeDim( void )
{
@@ -208,9 +241,7 @@ static void ChangeDim( void )
bm.orig = currPrintGrid.orig;
bm.size = currPrintGrid.size;
bm.angle = currPrintGrid.angle;
- sprintf( message, _("%d pages"), pageCount );
- ParamLoadMessage( &printPG, I_PAGECNT, message );
- ParamDialogOkActive( &printPG, pageCount!=0 );
+ UpdatePageCount();
}
@@ -237,7 +268,7 @@ LOG1( log_print, ( "MarkPage( %d, %d )\n", x, y) )
Rotate( &p[2], currPrintGrid.orig, currPrintGrid.angle );
Rotate( &p[3], currPrintGrid.orig, currPrintGrid.angle );
LOG( log_print, 2, ( "MP(%d,%d) [%0.3f %0.3f] x [%0.3f %0.3f]\n", x, y, p[0].x, p[0].y, p[2].x, p[2].y ) )
- DrawHilightPolygon( &mainD, p, 4 );
+ DrawHilightPolygon( &tempD, p, 4 );
}
@@ -256,10 +287,7 @@ static void SelectPage( coOrd pos )
selected = BITMAP( bm, x, y );
pageCount += (selected?-1:1);
BITMAP( bm, x, y ) = !selected;
- MarkPage( x, y );
- sprintf( message, _("%d pages"), pageCount );
- ParamLoadMessage( &printPG, I_PAGECNT, message );
- ParamDialogOkActive( &printPG, pageCount!=0 );
+ UpdatePageCount();
}
@@ -351,11 +379,11 @@ static void PrintGaudyBox(
DrawLine( &page_d, p00, p10, 0, wDrawColorBlack );
p00.y = p10.y = 0.5;
DrawLine( &page_d, p00, p10, 0, wDrawColorBlack );
- p00.y = 0.5;
- p01.y = 1.0;
+ //p00.y = 0.5;
+ //p01.y = 1.0;
p00.x = 0.05; p00.y = 0.5+0.05;
fp = wStandardFont( F_TIMES, TRUE, TRUE );
- DrawString( &page_d, p00, 0.0, sProdName, fp, 30.0, wDrawColorBlack );
+ DrawString( &page_d, p00, 0.0, sProdName, fp, 22.0, wDrawColorBlack );
p00.y = 0.5; p01.y = 1.0;
p00.x = p01.x = (157.0/72.0)+0.1;
@@ -365,17 +393,17 @@ static void PrintGaudyBox(
fp = wStandardFont( F_TIMES, FALSE, FALSE );
p00.x = pageW-((157.0/72.0)+0.05); p00.y = 0.5+0.25+0.05;
- DrawString( &page_d, p00, 0.0, dat, fp, 16.0, wDrawColorBlack );
+ DrawString( &page_d, p00, 0.0, dat, fp, 14.0, wDrawColorBlack );
p00.y = 0.5+0.05;
- DrawTextSize( &mainD, GetLayoutTitle(), fp, 16.0, FALSE, &textsize );
+ DrawTextSize( &mainD, GetLayoutTitle(), fp, 14.0, FALSE, &textsize );
p00.x = (pageW/2.0)-(textsize.x/2.0);
p00.y = 0.75+0.05;
- DrawString( &page_d, p00, 0.0, GetLayoutTitle(), fp, 16.0, wDrawColorBlack );
- DrawTextSize( &mainD, GetLayoutSubtitle(), fp, 16.0, FALSE, &textsize );
+ DrawString( &page_d, p00, 0.0, GetLayoutTitle(), fp, 14.0, wDrawColorBlack );
+ DrawTextSize( &mainD, GetLayoutSubtitle(), fp, 14.0, FALSE, &textsize );
p00.x = (pageW/2.0)-(textsize.x/2.0);
p00.y = 0.50+0.05;
- DrawString( &page_d, p00, 0.0, GetLayoutSubtitle(), fp, 16.0, wDrawColorBlack );
+ DrawString( &page_d, p00, 0.0, GetLayoutSubtitle(), fp, 12.0, wDrawColorBlack );
sprintf( dat, _("PrintScale 1:%ld Room %s x %s Model Scale %s File %s"),
(long)printScale,
@@ -383,7 +411,7 @@ static void PrintGaudyBox(
FormatDistance( roomSize.y ),
curScaleName, GetLayoutFilename() );
p00.x = 0.05; p00.y = 0.25+0.05;
- DrawString( &page_d, p00, 0.0, dat, fp, 16.0, wDrawColorBlack );
+ DrawString( &page_d, p00, 0.0, dat, fp, 14.0, wDrawColorBlack );
}
@@ -414,12 +442,7 @@ static void PrintPlainBox(
DrawLine( &page_d, p11, p01, 0, wDrawColorBlack );
DrawLine( &page_d, p01, p00, 0, wDrawColorBlack );
- fp = wStandardFont( F_HELV, FALSE, FALSE );
- sprintf( tmp, "[%d,%d]", x, y );
- p00.x = pageW/2.0 - 20.0/72.0;
- p00.y = pageH - 10.0/72.0;
- DrawString( &page_d, p00, 0.0, tmp, fp, 4.0, wDrawColorBlack );
-
+ fp = wStandardFont(F_HELV, FALSE, FALSE);
sprintf( tmp, "[%0.2f,%0.2f]", corners[0].x, corners[0].y );
p00.x = 4.0/72.0;
p00.y = 4.0/72.0;
@@ -482,7 +505,6 @@ static void PrintUpdate( int inx0 )
{
int inx;
- DrawPrintGrid();
ParamLoadData( &printPG );
if (newPrintGrid.size.x > maxPageSize.x+0.01 ||
@@ -504,17 +526,17 @@ static void PrintUpdate( int inx0 )
ParamLoadControl( &printPG, inx );
}
ChangeDim();
- DrawPrintGrid();
}
static void SetPageSize( BOOL_T doScale )
{
WDOUBLE_T temp, x, y;
- if (printPhysSize)
- wPrintGetPhysSize( &x, &y );
- else
- wPrintGetPageSize( &x, &y );
+ wPrintGetPageSize( &x, &y );
+ if (!printPhysSize) {
+ x -= (printMargin.left+printMargin.right);
+ y -= (printMargin.top+printMargin.bottom);
+ }
maxPageSize.x = x;
maxPageSize.y = y;
realPageSize = maxPageSize;
@@ -534,6 +556,22 @@ static void SetPageSize( BOOL_T doScale )
}
}
+/**
+ * Select all pages for printing.
+ *
+ */
+
+static void SelectAllPages(void)
+{
+ for (int y = bm.y0; y < bm.y1; y++) {
+ for (int x = bm.x0; x < bm.x1; x++) {
+ BITMAP(bm, x, y) = TRUE;
+ }
+ }
+ pageCount = (bm.x1 - bm.x0) * (bm.y1 - bm.y0);
+ UpdatePageCount();
+ TempRedraw(); // SelectAllPages
+}
static void PrintMaxPageSize( void )
/*
@@ -542,13 +580,12 @@ static void PrintMaxPageSize( void )
* (depending on paper size, scale and orientation)
*/
{
- DrawPrintGrid();
SetPageSize( TRUE );
currPrintGrid.size = maxPageSize;
newPrintGrid = currPrintGrid;
ParamLoadControls( &printPG );
ChangeDim();
- DrawPrintGrid();
+ TempRedraw(); // PrintMaxSize
wShow( printWin);
}
@@ -563,10 +600,152 @@ static void DoPrintScale( void )
PrintEnableControls();
}
+/*
+ * Printer Margins
+ */
+
+static void PrintMarginReset();
+
+static paramFloatRange_t r0_1 = { 0.0, 1.0, 50 };
+static paramData_t printMarginPLs[] = {
+#define I_PM_FIRST (0)
+ { PD_FLOAT, &printMargin.top, "marginT", PDO_DIM|PDO_NOPREF, &r0_1, NULL, 0, NULL },
+ { PD_FLOAT, &printMargin.right, "marginR", PDO_DIM|PDO_NOPREF, &r0_1, NULL, 0, NULL },
+ { PD_FLOAT, &printMargin.bottom, "marginB", PDO_DIM|PDO_NOPREF, &r0_1, NULL, 0, NULL },
+ { PD_FLOAT, &printMargin.left, "marginL", PDO_DIM|PDO_NOPREF, &r0_1, NULL, 0, NULL },
+#define I_PM_COUNT (4)
+#define I_PM_MESSAGE (4)
+ { PD_MESSAGE, NULL, NULL, 0, NULL },
+#define I_PM_RESET (5)
+ { PD_BUTTON, (void*) PrintMarginReset, "marginReset", PDO_DLGCMDBUTTON, NULL, N_("Reset") } };
+static paramGroup_t printMarginPG = { "printMargin", PGO_PREFMISCGROUP|PGO_NODEFAULTPROC, printMarginPLs, sizeof printMarginPLs/sizeof printMarginPLs[0] };
+
+static wLines_t aPmLines[] = {
+ { 1, 25, 11, 94, 11 },
+ { 1, 94, 11, 94, 111 },
+ { 1, 94, 111, 25, 111 },
+ { 1, 25, 111, 25, 11 }};
+static int pmxoff=14;
+static int pmyoff=5;
+
+static void PrintMarginLayout(
+ paramData_t * pd,
+ int index,
+ wPos_t colX,
+ wPos_t * w,
+ wPos_t * h )
+{
+ if ( index < I_PM_FIRST || index > (I_PM_MESSAGE) )
+ return;
+ if ( index == I_PM_MESSAGE ) {
+ *h = wControlGetPosY( printMarginPLs[I_PM_FIRST+2].control ) + wControlGetHeight( printMarginPLs[I_PM_FIRST+2].control );
+ return;
+ }
+ wPos_t x0, y0;
+ x0 = (aPmLines[index-I_PM_FIRST].x0+aPmLines[index-I_PM_FIRST].x1)/2;
+ y0 = (aPmLines[index-I_PM_FIRST].y0+aPmLines[index-I_PM_FIRST].y1)/2;
+ x0 -= pmxoff;
+ y0 -= pmyoff;
+// y0 += wControlGetPosY( printMarginPLs[0].control ) + wControlGetHeight( printMarginPLs[0].control );
+// x0 -= wControlGetWidth( printMarginPLs[index-I_PM_FIRST].control )/2;
+// y0 -= wControlGetHeight( printMarginPLs[index-I_PM_FIRST].control )/2;
+ *w = x0;
+ *h = y0;
+}
+
+
+static const char * sPrinterName = NULL;
+
+static BOOL_T SetMargins()
+{
+ double top, right, bottom, left;
+ wPrintGetMargins( &top, &right, &bottom, &left );
+ sprintf( message, "%s-marginT", sPrinterName );
+ wPrefGetFloat( "printer", message, &printMargin.top, top );
+ sprintf( message, "%s-marginR", sPrinterName );
+ wPrefGetFloat( "printer", message, &printMargin.right, right );
+ sprintf( message, "%s-marginB", sPrinterName );
+ wPrefGetFloat( "printer", message, &printMargin.bottom, bottom );
+ sprintf( message, "%s-marginL", sPrinterName );
+ wPrefGetFloat( "printer", message, &printMargin.left, left );
+ ParamLoadControls( &printMarginPG );
+ return
+ fabs( top - printMargin.top ) >= 0.001 ||
+ fabs( right - printMargin.right ) >= 0.001 ||
+ fabs( bottom - printMargin.bottom ) >= 0.001 ||
+ fabs( left - printMargin.left ) >= 0.001;
+}
+
+
+static void DoPrintMarginOk( void * context )
+{
+ wHide( printMarginWin );
+ sprintf( message, "%s-marginT", sPrinterName );
+ wPrefSetFloat( "printer", message, printMargin.top );
+ sprintf( message, "%s-marginR", sPrinterName );
+ wPrefSetFloat( "printer", message, printMargin.right );
+ sprintf( message, "%s-marginB", sPrinterName );
+ wPrefSetFloat( "printer", message, printMargin.bottom );
+ sprintf( message, "%s-marginL", sPrinterName );
+ wPrefSetFloat( "printer", message, printMargin.left );
+ SetPageSize( TRUE );
+ for ( int inx = 0; inx < sizeof printPLs/sizeof printPLs[0]; inx++ ) {
+ if ( printPLs[inx].context == (void*)2 )
+ ParamLoadControl( &printPG, inx );
+ }
+ DoPrintScale();
+}
+
+static void PrintMarginDlgUpdate( paramGroup_p pg, int index, void * context )
+{
+ wControlActive( printMarginPLs[I_PM_RESET].control, TRUE );
+}
+
+static void PrintMarginReset()
+{
+ wPrintGetMargins( &printMargin.top, &printMargin.right, &printMargin.bottom, &printMargin.left );
+ ParamLoadControls( &printMarginPG );
+ wControlActive( printMarginPLs[I_PM_RESET].control, FALSE );
+}
+
+static void DoPrintMargin( void )
+{
+ sPrinterName = wPrintGetName();
+ while ( *sPrinterName == '\0' ) {
+ int rc = NoticeMessage( MSG_NO_PRINTER_SELECTED, _("Ok"), _("Cancel") );
+ if ( rc <= 0 )
+ return;
+ DoPrintSetup();
+ }
+ if ( printMarginWin == NULL ) {
+ wPos_t x=10, y=10;
+ printMarginWin = ParamCreateDialog( &printMarginPG, MakeWindowTitle(_("Print Margins")), _("Ok"), DoPrintMarginOk, NULL, TRUE, PrintMarginLayout, F_BLOCK, PrintMarginDlgUpdate );
+ if ( printMarginWin == NULL )
+ return;
+ for ( int i=0; i<sizeof aPmLines / sizeof aPmLines[0]; i++ ) {
+ aPmLines[i].x0 += x;
+ aPmLines[i].x1 += x;
+ aPmLines[i].y0 += y;
+ aPmLines[i].y1 += y;
+ }
+ wLineCreate( printMarginWin, NULL, sizeof aPmLines / sizeof aPmLines[0], aPmLines );
+ }
+ wMessageSetValue( (wMessage_p)printMarginPLs[I_PM_MESSAGE].control, sPrinterName );
+ // Enable Reset button if we've changed anything
+ wControlActive( printMarginPLs[I_PM_RESET].control, SetMargins() );
+ wShow( printMarginWin );
+
+}
+
+/*
+ * Misc buttons
+ */
static void DoPrintSetup( void )
{
wPrintSetup( (wPrintSetupCallBack_p)DoPrintScale );
+ sPrinterName = wPrintGetName();
+ SetPageSize( TRUE );
}
@@ -582,11 +761,10 @@ static void PrintClear( void )
for (x=bm.x0; x<bm.x1; x++)
if (BITMAP(bm,x,y)) {
BITMAP(bm,x,y) = 0;
- MarkPage( x, y );
}
pageCount = 0;
- ParamLoadMessage( &printPG, I_PAGECNT, _("0 pages") );
- ParamDialogOkActive( &printPG, FALSE );
+ UpdatePageCount();
+ TempRedraw(); // PrintClear
}
@@ -604,7 +782,6 @@ static void PrintSnapShot( void )
POS_T t;
PrintClear();
- DrawPrintGrid();
SetPageSize( FALSE );
pageSize = realPageSize;
if (pageSize.x > pageSize.y) {
@@ -665,11 +842,10 @@ static void PrintSnapShot( void )
ChangeDim();
pageCount = 1;
BITMAP(bm,0,0) = TRUE;
- DrawPrintGrid();
- ParamLoadMessage( &printPG, I_PAGECNT, _("1 page") );
- ParamDialogOkActive( &printPG, TRUE );
+ UpdatePageCount();
PrintEnableControls();
wShow( printWin );
+ TempRedraw(); // PrintSnapShot
}
@@ -729,20 +905,167 @@ static void DrawRegistrationMarks( drawCmd_p d )
}
}
+/**
+ * Format the page coordinates. Also handle cases where the coordinates are
+ * out of range.
+ *
+ * \param x x position
+ * \param y y position
+ * \return TRUE
+ */
+
+static char *
+FormatPageNumber(int x, int y)
+{
+ DynString formatted;
+ char *result;
+
+ DynStringMalloc(&formatted, 16);
+ if (x > 0 && x <= bm.x1 && y > 0 && y <= bm.y1) {
+ DynStringPrintf(&formatted, "(%d/%d)", x, y);
+ } else {
+ DynStringCatCStr(&formatted, "(-/-)");
+ }
+
+ result = strdup(DynStringToCStr(&formatted));
+ DynStringFree(&formatted);
+
+ return (result);
+}
+
+/**
+ * Print the page number in the center of the page
+ *
+ * \param x page index x-direction
+ * \param y page index y-direction
+ * \param width page width
+ * \param height page height
+ * \return TRUE
+ */
+
+static bool
+PrintPageNumber(wPos_t x, wPos_t y, DIST_T width, DIST_T height)
+{
+ coOrd printPosition;
+ coOrd textSize;
+
+ char *positionText;
+ wFont_p fp = wStandardFont(F_HELV, TRUE, FALSE);
+ wFontSize_t fs = 64.0;
+
+ positionText = FormatPageNumber(x + 1, y + 1);
+
+ // even though we're printing into page_d, mainD must be used here
+ DrawTextSize(&mainD, positionText, fp, fs, TRUE, &textSize);
+
+ if (printFormat == PORTRAIT) {
+ printPosition.x = (width - textSize.x) / 2;
+ printPosition.y = (height - textSize.y) / 2;
+ } else {
+ printPosition.x = (height - textSize.x) / 2;
+ printPosition.y = (width - textSize.y) / 2;
+ }
+
+ page_d.funcs->options |= wDrawOutlineFont;
+ DrawString(&page_d, printPosition, 0.0, positionText, fp, fs,
+ wDrawColorGray(70));
+ page_d.funcs->options &= ~wDrawOutlineFont;
+
+ free(positionText);
+
+ return (TRUE);
+}
+
+/**
+ * Print the page number of an adjoining page at a specified position
+ *
+ * \param x page index x-direction
+ * \param y page index y-direction
+ * \param position page position
+ */
+
+void
+PrintNextPageNumberAt(int x, int y, coOrd position)
+{
+ char *pageNumber;
+ wFont_p fp = wStandardFont(F_HELV, FALSE, FALSE);
+ wFontSize_t fs = 8.0;
+
+ pageNumber = FormatPageNumber(x, y);
+ DrawString(&page_d, position, 0.0, pageNumber, fp, fs, wDrawColorBlack);
+ free(pageNumber);
+}
+
+/**
+ * Print the page numbers of all four adjoining pages (left, right, above, below)
+ *
+ * \param x page index of current page x
+ * \param y page index of current page y
+ * \param pageW width of page
+ * \param pageH height of page
+ *
+ * \return TRUE
+ */
+
+static bool
+PrintNextPageNumbers(int x, int y, DIST_T pageW, DIST_T pageH)
+{
+ coOrd p00;
+
+ // above
+ if (printFormat == PORTRAIT) {
+ p00.x = pageW / 2.0 - 20.0 / 72.0;
+ p00.y = pageH - 10.0 / 72.0;
+ } else {
+ p00.x = pageH / 2.0 - 20.0 / 72.0;
+ p00.y = pageW - 10.0 / 72.0;
+ }
+ PrintNextPageNumberAt(x + 1, y + 2, p00);
+
+ // below
+ if (printFormat == PORTRAIT) {
+ p00.y = 10.0 / 72.0;
+ } else {
+ p00.y = 10.0 / 72.0;
+ }
+ PrintNextPageNumberAt(x + 1, y, p00);
+
+ // right
+ if (printFormat == PORTRAIT) {
+ p00.y = pageH / 2 + 10.0 / 72.0;
+ p00.x = pageW - 20.0 / 72.0;
+ } else {
+ p00.y = pageW / 2 + 10.0 / 72.0;
+ p00.x = pageH - 20.0 / 72.0;
+ }
+ PrintNextPageNumberAt(x + 2, y + 1, p00);
+
+ // left
+ if (printFormat == PORTRAIT) {
+ p00.x = 10.0 / 72.0;
+ } else {
+ p00.x = 10.0 / 72.0;
+ }
+ PrintNextPageNumberAt(x, y + 1, p00);
+ return (TRUE);
+}
static BOOL_T PrintPage(
int x,
int y )
{
- coOrd orig, p[4], minP, maxP;
+ coOrd orig, p[4], psave[4], minP, maxP;
int i;
coOrd clipOrig, clipSize;
- wFont_p fp;
coOrd roomSize;
if (BITMAP(bm,x,y)) {
orig.x = currPrintGrid.orig.x + x*currPrintGrid.size.x;
orig.y = currPrintGrid.orig.y + y*currPrintGrid.size.y;
+ if (printPhysSize) {
+ orig.x += printMargin.left;
+ orig.y += printMargin.bottom;
+ }
Rotate( &orig, currPrintGrid.orig, currPrintGrid.angle );
p[0] = p[1] = p[2] = p[3] = orig;
p[1].x = p[2].x = orig.x + currPrintGrid.size.x;
@@ -774,6 +1097,9 @@ static BOOL_T PrintPage(
Translate( &print_d.orig, orig, currPrintGrid.angle+180.0, printScale );
print_d.size.y += printScale;
}
+ for (int i=0;i<4;i++) {
+ psave[i] = p[i];
+ }
if (printRotate) {
rotateCW = (printFormat != PORTRAIT);
if (rotateCW) {
@@ -798,7 +1124,7 @@ static BOOL_T PrintPage(
page_d.size.x = print_d.size.x/printScale;
page_d.size.y = print_d.size.y/printScale;
}
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
print_d.scale = printScale;
if (print_d.d == NULL)
AbortProg( "wPrintPageStart" );
@@ -814,8 +1140,7 @@ static BOOL_T PrintPage(
if (printRotate && rotateCW) {
print_d.size.x += printScale;
}
- } else if (printRegistrationMarks)
- PrintPlainBox( x, y, p );
+ }
if (printRotate) {
wPrintClip( (wPos_t)(clipOrig.y*print_d.dpi), (wPos_t)(clipOrig.x*print_d.dpi),
(wPos_t)(clipSize.y*print_d.dpi), (wPos_t)(clipSize.x*print_d.dpi) );
@@ -827,7 +1152,7 @@ static BOOL_T PrintPage(
p[1].x = p[2].x = roomSize.x;
p[0].y = p[1].y = 0.0;
p[2].y = p[3].y = roomSize.y;
- fp = wStandardFont( F_TIMES, FALSE, FALSE );
+
DrawRuler( &print_d, p[0], p[1], 0.0, TRUE, FALSE, wDrawColorBlack );
DrawRuler( &print_d, p[0], p[3], 0.0, TRUE, TRUE, wDrawColorBlack );
DrawRuler( &print_d, p[1], p[2], 0.0, FALSE, FALSE, wDrawColorBlack );
@@ -885,6 +1210,7 @@ static BOOL_T PrintPage(
DrawRuler( &print_d, p[0], p[1], minP.x, FALSE, TRUE, wDrawColorBlack );
}
}
+
if (printGrid)
DrawSnapGrid( &print_d, mapD.size, FALSE );
roadbedWidth = printRoadbed?printRoadbedWidth:0.0;
@@ -892,10 +1218,15 @@ static BOOL_T PrintPage(
DrawTracks( &print_d, print_d.scale, minP, maxP );
if (printRegistrationMarks && printScale == 1)
DrawRegistrationMarks( &print_d );
+ if (printRegistrationMarks)
+ PrintPlainBox( x, y, psave );
+
+ if (printPageNumbers) {
+ PrintPageNumber(x, y, page_d.size.x, page_d.size.y);
+ PrintNextPageNumbers(x, y, page_d.size.x, page_d.size.y);
+ }
if ( !wPrintPageEnd( print_d.d ) )
return FALSE;
- /*BITMAP(bm,x,y) = 0;*/
- MarkPage( x, y );
}
return TRUE;
}
@@ -920,9 +1251,9 @@ static void DoPrintPrint( void * junk )
wPrefGetInteger( "print", "nodecoration", &noDecoration, 0 );
print_d.CoOrd2Pix = page_d.CoOrd2Pix = mainD.CoOrd2Pix;
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
if (!wPrintDocStart(GetLayoutTitle(), pageCount, &copies )) {
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
return;
}
if (copies <= 0)
@@ -940,42 +1271,38 @@ static void DoPrintPrint( void * junk )
for (y=bm.y0; y<bm.y1; y++)
for (x=bm.x0; x<bm.x1; x++)
if (BITMAP(bm,x,y)) {
- if (copy < copies)
- MarkPage( x, y );
- else
+ if (copy >= copies)
BITMAP(bm,x,y) = 0;
}
}
quitPrinting:
wPrintDocEnd();
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
Reset(); /* undraws grid, resets pagecount, etc */
}
static void DoResetGrid( void )
{
- DrawPrintGrid();
currPrintGrid.orig = zero;
currPrintGrid.angle = 0.0;
ChangeDim();
newPrintGrid = currPrintGrid;
ParamLoadControls( &printPG );
- DrawPrintGrid();
+ TempRedraw(); // DoResetGrid
}
static void PrintGridRotate( void * pangle )
{
ANGLE_T angle = (ANGLE_T)(long)pangle;
- DrawPrintGrid();
currPrintGrid.orig = cmdMenuPos;
- currPrintGrid.angle += angle;
+ currPrintGrid.angle += angle/1000;
newPrintGrid = currPrintGrid;
ParamLoadControls( &printPG );
ChangeDim();
- DrawPrintGrid();
+ TempRedraw(); // PrintGridRotate
}
/*****************************************************************************
@@ -1008,6 +1335,7 @@ static void PrintDlgUpdate(
else if ( pg->paramPtr[inx].context == (void*)2 )
PrintUpdate( inx );
ParamControlActive( &printPG, I_RULER, currPrintGrid.angle == 0 );
+ TempRedraw(); // PrintDlgUpdate
}
static STATUS_T CmdPrint(
@@ -1038,6 +1366,8 @@ static STATUS_T CmdPrint(
print_d.scale = printScale;
printWin = ParamCreateDialog( &printPG, MakeWindowTitle(_("Print")), _("Print"), DoPrintPrint, (paramActionCancelProc)Reset, TRUE, NULL, 0, PrintDlgUpdate );
}
+ sPrinterName = wPrintGetName();
+ SetMargins();
wShow( printWin );
SetPageSize( TRUE );
if (currPrintGrid.size.x == 0.0) {
@@ -1050,17 +1380,15 @@ static STATUS_T CmdPrint(
currPrintGrid.size.y = maxPageSize.y;
newPrintGrid = currPrintGrid;
ParamLoadControls( &printPG );
- DrawPrintGrid();
pageCount = 0;
+ UpdatePageCount();
LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrintGrid.size.y ) )
PrintChange( CHANGE_MAP|CHANGE_UNITS );
- ParamGroupRecord( &printPG );
- ParamLoadMessage( &printPG, I_PAGECNT, "0 pages" );
- ParamDialogOkActive( &printPG, FALSE );
ChangeDim();
InfoMessage( _("Select pages to print, or drag to move print grid") );
downShift = FALSE;
ParamControlActive( &printPG, I_RULER, currPrintGrid.angle == 0 );
+ TempRedraw(); // CmdPrint C_START
return C_CONTINUE;
case C_DOWN:
@@ -1083,10 +1411,8 @@ LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrin
if (downShift) {
rc = GridAction( action, pos, &newPrintGrid.orig, &newPrintGrid.angle );
ParamLoadControls( &printPG );
- DrawPrintGrid();
currPrintGrid = newPrintGrid;
ChangeDim();
- DrawPrintGrid();
downShift = FALSE;
}
return C_CONTINUE;
@@ -1115,10 +1441,8 @@ LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrin
if (downShift) {
rc = GridAction( action, pos, &newPrintGrid.orig, &newPrintGrid.angle );
ParamLoadControls( &printPG );
- DrawPrintGrid();
currPrintGrid = newPrintGrid;
ChangeDim();
- DrawPrintGrid();
downShift = FALSE;
ParamControlActive( &printPG, I_RULER, currPrintGrid.angle == 0 );
}
@@ -1126,13 +1450,13 @@ LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrin
case C_REDRAW:
DrawPrintGrid();
+ rc = GridAction( action, pos, &newPrintGrid.orig, &newPrintGrid.angle );
return C_TERMINATE;
case C_CANCEL:
if (printWin == NULL)
return C_TERMINATE;
PrintClear();
- DrawPrintGrid();
wHide( printWin );
return C_TERMINATE;
@@ -1141,6 +1465,7 @@ LOG( log_print, 2, ( "Page size = %0.3f %0.3f\n", currPrintGrid.size.x, currPrin
return C_TERMINATE;
case C_CMDMENU:
+ menuPos = pos;
wMenuPopupShow( printGridPopupM );
return C_CONTINUE;
@@ -1157,7 +1482,8 @@ EXPORT wIndex_t InitCmdPrint( wMenu_p menu )
RegisterChangeNotification( PrintChange );
printGridPopupM = MenuRegister( "Print Grid Rotate" );
AddRotateMenu( printGridPopupM, PrintGridRotate );
- return InitCommand( menu, CmdPrint, N_("Print..."), NULL, LEVEL0, IC_LCLICK|IC_POPUP2|IC_CMDMENU, ACCL_PRINT );
+ ParamRegister( &printMarginPG );
+ return InitCommand( menu, CmdPrint, N_("Print..."), NULL, LEVEL0, IC_LCLICK|IC_POPUP3|IC_CMDMENU, ACCL_PRINT );
}
/*****************************************************************************
diff --git a/app/bin/cprofile.c b/app/bin/cprofile.c
index 49c3289..4f375ed 100644
--- a/app/bin/cprofile.c
+++ b/app/bin/cprofile.c
@@ -21,6 +21,7 @@
*/
#include <math.h>
+#include <stdbool.h>
#include "custom.h"
#include "cselect.h"
@@ -105,19 +106,21 @@ static BOOL_T printVert = TRUE;
static wMenu_p profilePopupM;
static track_p profilePopupTrk;
static EPINX_T profilePopupEp;
-static wMenuToggle_p profilePopupToggles[3];
+static wMenuToggle_p profilePopupToggles[3];
-static int log_profile = 0;
+static int log_profile = 0;
#define LABELH (labelH*fontSize/screenProfileFontSize)
+#define LABELW (labelW*fontSize/screenProfileFontSize)
#define PBB(FS) (2.0*(labelH*(FS)/screenProfileFontSize+3.0/mainD.dpi))
#define PBT (10.0/mainD.dpi)
-#define PBR (30.0/mainD.dpi)
-#define PBL (20.0/mainD.dpi)
+#define PBR(FS) (1.0*(labelW*(FS)/screenProfileFontSize+3.0/mainD.dpi))
+#define PBL(FS) (1.0*(labelW*(FS)/screenProfileFontSize+3.0/mainD.dpi))
static FLOAT_T labelH;
+static FLOAT_T labelW;
-track_p pathStartTrk;
+track_p pathStartTrk;
EPINX_T pathStartEp;
track_p pathEndTrk;
EPINX_T pathEndEp;
@@ -126,330 +129,467 @@ EPINX_T pathEndEp;
#define NOP
typedef struct {
- track_p trk;
- EPINX_T ep;
- DIST_T elev;
- DIST_T dist;
- BOOL_T defined; /* from prev PE to current */
- } profElem_t, *profElem_p;
-static dynArr_t profElem_da;
-#define profElem(N) DYNARR_N( profElem_t, profElem_da, N )
+ track_p trk;
+ EPINX_T ep;
+ DIST_T elev;
+ DIST_T dist;
+ BOOL_T defined; /* from prev PE to current */
+} profElem_t, *profElem_p;
+
+static dynArr_t profElem_da;
+static profElem_p copyOfprofElem;
+
+#define profElem(N) DYNARR_N( profElem_t, profElem_da, N )
typedef struct {
- DIST_T dist;
- char * name;
- } station_t, *station_p;
-static dynArr_t station_da;
+ DIST_T dist;
+ char * name;
+} station_t, *station_p;
+static dynArr_t station_da;
+
#define station(N) DYNARR_N( station_t, station_da, N )
+
struct {
- DIST_T totalD, minE;
- int minC, maxC, incrC;
- DIST_T scaleX, scaleY;
- } prof;
-static void DrawProfile( drawCmd_p D, wFontSize_t fontSize, BOOL_T printVert )
+ DIST_T totalD, minE;
+ int minC, maxC, incrC;
+ DIST_T scaleX, scaleY;
+} prof;
+
+
+/**
+ * Creates a copy of profile elements
+ */
+
+static void
+CreateCopyProfileElements()
{
- coOrd pl, pt, pb;
- int inx;
- DIST_T grade;
- wFont_p fp;
- static dynArr_t points_da;
-#define points(N) DYNARR_N( coOrd, points_da, N )
- wDrawWidth lw;
- station_p ps;
- coOrd textsize;
-
- lw = (wDrawWidth)(D->dpi*2.0/mainD.dpi);
- fp = wStandardFont( F_HELV, FALSE, FALSE );
- DYNARR_RESET( coOrd, points_da );
-
- pb.x = pt.x = 0;
- pb.y = prof.minE; pt.y = GetDim(prof.maxC);
- DrawLine( D, pb, pt, 0, snapGridColor );
- pb.x = pt.x = prof.totalD;
- DrawLine( D, pb, pt, 0, snapGridColor );
- pb.x = 0;
- pt.x = prof.totalD;
- for (inx=prof.minC; inx<=prof.maxC; inx+=prof.incrC) {
- pt.y = pb.y = GetDim(inx);
- DrawLine( D, pb, pt, 0, snapGridColor );
- pl.x = -(PBL-3.0/mainD.dpi)/prof.scaleX*D->scale;
- pl.y = pb.y-LABELH/2/prof.scaleY*D->scale;
- sprintf( message, "%d", inx );
- DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor );
- }
- if ( profElem_da.cnt <= 0 )
- return;
-
- for (inx=0; inx<profElem_da.cnt; inx++ ) {
- pt.y = profElem(inx).elev;
- pt.x = profElem(inx).dist;
- DYNARR_APPEND( coOrd, points_da, 10 );
- points(points_da.cnt-1) = pt;
- }
- pb.y = pt.y = prof.minE;
- if ( points_da.cnt > 1 ) {
- DYNARR_APPEND( coOrd, points_da, 10 );
- pt.x = prof.totalD;
- points(points_da.cnt-1) = pt;
- DYNARR_APPEND( coOrd, points_da, 10 );
- pb.x = 0;
- points(points_da.cnt-1) = pb;
- DrawFillPoly( D, points_da.cnt, &points(0), profileColorFill );
- DrawLine( D, pb, pt, lw, borderColor );
- }
+ if (copyOfprofElem) {
+ MyFree(copyOfprofElem);
+ }
+
+ copyOfprofElem = MyMalloc(profElem_da.cnt * sizeof(profElem_t));
+ if (!copyOfprofElem) {
+ AbortProg("Couldn't allocate memory for profile copy\n");
+ }
+ for (int i = 0; i < profElem_da.cnt; i++) {
+ copyOfprofElem[i] = profElem(i);
+ }
+}
- pt.y = prof.minE-(2*LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale;
- for (inx=0; inx<station_da.cnt; inx++ ) {
- ps = &station(inx);
- DrawTextSize( &mainD, ps->name, fp, fontSize, FALSE, &textsize );
- pt.x = ps->dist - textsize.x/2.0/prof.scaleX*D->scale;
- if (pt.x < -PBR)
- pt.x = -(PBR-3/mainD.dpi)/prof.scaleX*D->scale;
- else if (pt.x+textsize.x > prof.totalD)
- pt.x = prof.totalD-(textsize.x-3/mainD.dpi)/prof.scaleX*D->scale;
- DrawString( D, pt, 0.0, ps->name, fp, fontSize*D->scale, borderColor );
- }
+/**
+ * Destroys the copy of profile elements
+ */
- pb.x = 0.0; pb.y = prof.minE;
- pt = points(0);
- DrawLine( D, pb, pt, lw, borderColor );
- sprintf( message, "%0.1f", PutDim(profElem(0).elev) );
- if (printVert) {
- pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale;
- pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale;
- DrawString( D, pl, 270.0, message, fp, fontSize*D->scale, borderColor );
- } else {
- pl.x = pt.x+2.0/mainD.dpi/prof.scaleX*D->scale;
- pl.y = pt.y;
- if (profElem_da.cnt>1 && profElem(0).elev < profElem(1).elev )
- pl.y -= LABELH/prof.scaleY*D->scale;
- DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor );
- }
- pl = pt;
-
- for (inx=1; inx<profElem_da.cnt; inx++ ) {
- pt.y = profElem(inx).elev;
- pb.x = pt.x = profElem(inx).dist;
- pt = points(inx);
- pb.x = pt.x;
- DrawLine( D, pl, pt, lw, (profElem(inx).defined?profileColorDefinedProfile:profileColorUndefinedProfile) );
- DrawLine( D, pb, pt, lw, borderColor );
- if (profElem(inx).dist > 0.1) {
- grade = fabs(profElem(inx).elev-profElem(inx-1).elev)/
- (profElem(inx).dist-profElem(inx-1).dist);
- sprintf( message, "%0.1f%%", grade*100.0 );
- DrawTextSize( &mainD, message, fp, fontSize, FALSE, &textsize );
- pl.x = (points(inx).x+points(inx-1).x)/2.0;
- pl.y = (points(inx).y+points(inx-1).y)/2.0;
- if (printVert) {
- pl.x += (LABELH/2)/prof.scaleX*D->scale;
- pl.y += ((LABELH/2)*grade/prof.scaleX + 2.0/mainD.dpi/prof.scaleY)*D->scale;
- DrawString( D, pl, 270.0, message, fp, fontSize*D->scale, borderColor );
- } else {
- pl.x -= (textsize.x/2)/prof.scaleX*D->scale;
- pl.y += (textsize.x/2)*grade/prof.scaleX*D->scale;
- DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor );
- }
- }
- if (units==UNITS_ENGLISH) {
- if (prof.totalD > 240)
- sprintf( message, "%d'", ((int)floor(profElem(inx).dist)+6)/12 );
- else
- sprintf( message, "%d'%d\"", ((int)floor(profElem(inx).dist+0.5))/12, ((int)floor(profElem(inx).dist+0.5))%12 );
- } else {
- if (PutDim(prof.totalD) > 10000)
- sprintf( message, "%0.0fm", (PutDim(profElem(inx).dist)+50)/100.0 );
- else if (PutDim(prof.totalD) > 100)
- sprintf( message, "%0.1fm", (PutDim(profElem(inx).dist)+5)/100.0 );
- else
- sprintf( message, "%0.2fm", (PutDim(profElem(inx).dist)+0.5)/100.0 );
- }
- DrawTextSize( &mainD, message, fp, fontSize, FALSE, &textsize );
- pl.x = pb.x-(textsize.x/2)/prof.scaleX*D->scale;
- pl.y = prof.minE-(LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale;
- DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor );
- sprintf( message, "%0.1f", PutDim(profElem(inx).elev) );
- if (printVert) {
- pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale;
- pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale;
- DrawString( D, pl, 270.0, message, fp, fontSize*D->scale, borderColor );
- } else {
- pl.x = pt.x + 2.0/mainD.dpi/prof.scaleX*D->scale;
- pl.y = pt.y;
- if ( inx != profElem_da.cnt-1 && profElem(inx).elev < profElem(inx+1).elev )
- pl.y -= LABELH/prof.scaleY*D->scale;
- DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor );
+static void
+DestroyCopyOfProfileElements()
+{
+ if (copyOfprofElem) {
+ MyFree(copyOfprofElem);
+ copyOfprofElem = NULL;
+ }
+}
+
+
+/**
+ * Draw profile
+ *
+ * \param D The drawCmd_p to use.
+ * \param fontSize Size of the font.
+ * \param printVert print vertical.
+ */
+
+static void DrawProfile(drawCmd_p D, wFontSize_t fontSize, BOOL_T printVert)
+{
+ coOrd pl, pt, pb;
+ int inx;
+ DIST_T grade;
+ wFont_p fp;
+ static dynArr_t points_da;
+#define points(N) DYNARR_N( coOrd, points_da, N )
+ wDrawWidth lw;
+ station_p ps;
+ coOrd textsize;
+
+ lw = (wDrawWidth)(D->dpi*1.0/mainD.dpi);
+ fp = wStandardFont(F_HELV, FALSE, FALSE);
+ DYNARR_RESET(pts_t, points_da);
+
+ pb.x = pt.x = 0;
+ pb.y = prof.minE;
+ pt.y = GetDim(prof.maxC);
+ DrawLine(D, pb, pt, 0, snapGridColor);
+ pb.x = pt.x = prof.totalD;
+ DrawLine(D, pb, pt, 0, snapGridColor);
+ pb.x = 0;
+ pt.x = prof.totalD;
+
+ // Draw horizontal grid and y scale
+ for (inx=prof.minC; inx<=prof.maxC; inx+=prof.incrC) {
+ coOrd textsize;
+ // grid line
+ pt.y = pb.y = GetDim(inx);
+ DrawLine(D, pb, pt, 0, snapGridColor);
+ // scale
+ sprintf(message, "%d", inx);
+ DrawTextSize(&mainD, message, wStandardFont(F_HELV, FALSE, FALSE),
+ screenProfileFontSize, FALSE, &textsize);
+ pl.x = ((-3.0/mainD.dpi) - textsize.y*0.5 - textsize.x) / prof.scaleX*D->scale;
+ pl.y = pb.y-LABELH/2/prof.scaleY*D->scale;
+
+ DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor);
+ }
+
+ // show the measurement units
+ sprintf(message, "%s", units == UNITS_ENGLISH ? "in." : "cm");
+ DrawTextSize(&mainD, message, wStandardFont(F_HELV, FALSE, FALSE),
+ screenProfileFontSize, FALSE, &textsize);
+ pl.x = ((-3.0 / mainD.dpi) - textsize.y*0.5 - textsize.x) /
+ prof.scaleX*D->scale;
+ pl.y += LABELH * 1.5 / prof.scaleY*D->scale;
+ DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor);
+
+ if (profElem_da.cnt <= 0) {
+ return;
+ }
+
+ for (inx=0; inx<profElem_da.cnt; inx++) {
+ pt.y = profElem(inx).elev;
+ pt.x = profElem(inx).dist;
+ DYNARR_APPEND(pts_t, points_da, 10);
+ points(points_da.cnt-1) = pt;
+ }
+ pb.y = pt.y = prof.minE;
+ if (points_da.cnt > 1) {
+ DYNARR_APPEND(coOrd, points_da, 10);
+ pt.x = prof.totalD;
+ points(points_da.cnt-1) = pt;
+ DYNARR_APPEND(pts_t, points_da, 10);
+ pb.x = 0;
+ points(points_da.cnt-1) = pb;
+ DrawPoly(D, points_da.cnt, points_da.ptr, NULL, profileColorFill, 1, 1, 0);
+ }
+
+ pt.y = prof.minE-(2*LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale;
+ for (inx=0; inx<station_da.cnt; inx++) {
+ ps = &station(inx);
+ DrawTextSize(&mainD, ps->name, fp, fontSize, FALSE, &textsize);
+ pt.x = ps->dist - textsize.x/2.0/prof.scaleX*D->scale;
+ if (pt.x < -PBR(screenProfileFontSize)) {
+ pt.x = -(PBR(screenProfileFontSize)-3/mainD.dpi)/prof.scaleX*D->scale;
+ } else if (pt.x+textsize.x > prof.totalD) {
+ pt.x = prof.totalD-(textsize.x-3/mainD.dpi)/prof.scaleX*D->scale;
+ }
+ DrawString(D, pt, 0.0, ps->name, fp, fontSize*D->scale, borderColor);
+ }
+
+ pb.x = 0.0;
+ pb.y = prof.minE;
+
+ // mark the starting point for the profile
+ pt = points(0);
+ DrawLine(D, pb, pt, lw, snapGridColor);
+ DrawArc(D, pt, 0.05, 0, 360, TRUE, 2, wDrawColorGrey40);
+ if (units==UNITS_ENGLISH) {
+ sprintf(message, "%0.1f", PutDim(profElem(0).elev)+0.05);
+ } else {
+ sprintf(message, "%0.1f", PutDim(profElem(0).elev)+0.05);
+ }
+ if (printVert) {
+ pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale;
+ pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale + GetDim(prof.incrC) / 16;;
+ DrawString(D, pl, 270.0, message, fp, fontSize*D->scale, borderColor);
+ } else {
+ pl.x = pt.x+2.0/mainD.dpi/prof.scaleX*D->scale + GetDim(prof.incrC) / 16;;
+ pl.y = pt.y;
+ if (profElem_da.cnt>1 && profElem(0).elev < profElem(1).elev) {
+ pl.y -= LABELH/prof.scaleY*D->scale;
+ }
+ DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor);
+ }
+ pl = pt;
+
+ for (inx=1; inx<profElem_da.cnt; inx++) {
+ pt.y = profElem(inx).elev;
+ pb.x = pt.x = profElem(inx).dist;
+ pt = points(inx);
+
+ // draw line to x-axis for intermediate elevation points
+ if (inx != profElem_da.cnt - 1) {
+ unsigned long oldOptions = D->options;
+
+ D->options = D->options | DC_DOT;
+ DrawLine(D, pb, pt, lw, borderColor);
+ D->options = oldOptions;
}
- pl = pt;
- }
+
+ // draw grade line
+ DrawLine(D, pl, pt, lw*2, (profElem(inx).defined ? profileColorDefinedProfile :
+ profileColorUndefinedProfile));
+ // draw the markers
+ DrawArc(D, pt, 0.05, 0, 360, TRUE, 2, wDrawColorGrey40);
+
+ if (profElem(inx).dist > 0.1) {
+ grade = fabs(profElem(inx).elev-profElem(inx-1).elev)/
+ (profElem(inx).dist-profElem(inx-1).dist);
+ sprintf(message, "%0.1f%%", round(grade*1000.0)/10.0);
+ DrawTextSize(&mainD, message, fp, fontSize, FALSE, &textsize);
+ pl.x = (points(inx).x+points(inx-1).x)/2.0;
+ pl.y = (points(inx).y+points(inx-1).y)/2.0;
+ if (printVert) {
+ pl.x += (LABELH/2)/prof.scaleX*D->scale;
+ pl.y += ((LABELH/2)*grade/prof.scaleX + 2.0/mainD.dpi/prof.scaleY)*D->scale;
+ DrawString(D, pl, 270.0, message, fp, fontSize*D->scale, borderColor);
+ } else {
+ pl.x -= (textsize.x/2)/prof.scaleX*D->scale;
+ pl.y += (textsize.x/2)*grade/prof.scaleX*D->scale;
+ DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor);
+ }
+ }
+ if (units==UNITS_ENGLISH) {
+ if (prof.totalD > 240) {
+ sprintf(message, "%0.1f'", (round((profElem(inx).dist/12.0)*10.0)/10.0));
+ } else {
+ sprintf(message, "%d'%0.1f\"", (int)floor((profElem(inx).dist)/12.0),
+ round(fmod(profElem(inx).dist,12.0)*10.0)/10.0);
+ }
+ } else {
+ if (PutDim(prof.totalD) > 10000) {
+ sprintf(message, "%0.1fm", (round(PutDim(profElem(inx).dist)/10.0)/10.0));
+ } else if (PutDim(prof.totalD) > 100) {
+ sprintf(message, "%0.2fm", (round(PutDim(profElem(inx).dist))/100.0));
+ } else {
+ sprintf(message, "%0.1fcm", round(PutDim(profElem(inx).dist)+0.5));
+ }
+ }
+ DrawTextSize(&mainD, message, fp, fontSize, FALSE, &textsize);
+ pl.x = pb.x-(textsize.x/2)/prof.scaleX*D->scale;
+ pl.y = prof.minE-(LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale;
+ DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor);
+ sprintf(message, "%0.1f", round(PutDim(profElem(inx).elev)*100.0)/100.0);
+ if (printVert) {
+ pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale;
+ pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale+GetDim(prof.incrC) / 16;
+ DrawString(D, pl, 270.0, message, fp, fontSize*D->scale, borderColor);
+ } else {
+ pl.x = pt.x + 2.0/mainD.dpi/prof.scaleX*D->scale + GetDim(prof.incrC) / 16;
+ pl.y = pt.y;
+ if (inx != profElem_da.cnt-1 && profElem(inx).elev < profElem(inx+1).elev) {
+ pl.y -= LABELH/prof.scaleY*D->scale;
+ }
+ DrawString(D, pl, 0.0, message, fp, fontSize*D->scale, borderColor);
+ }
+ pl = pt;
+ }
}
-static void ProfilePix2CoOrd( drawCmd_p, wPos_t, wPos_t, coOrd * );
-static void ProfileCoOrd2Pix( drawCmd_p, coOrd, wPos_t*, wPos_t* );
+static void ProfilePix2CoOrd(drawCmd_p, wPos_t, wPos_t, coOrd *);
+static void ProfileCoOrd2Pix(drawCmd_p, coOrd, wPos_t*, wPos_t*);
static drawCmd_t screenProfileD = {
- NULL,
- &screenDrawFuncs,
- DC_NOCLIP,
- 1.0,
- 0.0,
- {0.0,0.0}, {0.0,0.0},
- ProfilePix2CoOrd, ProfileCoOrd2Pix };
+ NULL,
+ &screenDrawFuncs,
+ DC_NOCLIP,
+ 1.0,
+ 0.0,
+ {0.0,0.0}, {0.0,0.0},
+ ProfilePix2CoOrd, ProfileCoOrd2Pix
+};
static void ProfilePix2CoOrd(
- drawCmd_p d,
- wPos_t xx,
- wPos_t yy,
- coOrd * pos )
+ drawCmd_p d,
+ wPos_t xx,
+ wPos_t yy,
+ coOrd * pos)
{
- pos->x = (xx/d->dpi+d->orig.x)/prof.scaleX;
- pos->y = (yy/d->dpi+d->orig.y)/prof.scaleY+prof.minE;
+ pos->x = (xx/d->dpi+d->orig.x)/prof.scaleX;
+ pos->y = (yy/d->dpi+d->orig.y)/prof.scaleY+prof.minE;
}
+
static void ProfileCoOrd2Pix(
- drawCmd_p d,
- coOrd pos,
- wPos_t *xx,
- wPos_t *yy )
+ drawCmd_p d,
+ coOrd pos,
+ wPos_t *xx,
+ wPos_t *yy)
{
- wPos_t x, y;
- x = (wPos_t)((((pos.x*prof.scaleX)/d->scale-d->orig.x)*d->dpi+0.5));
- y = (wPos_t)(((((pos.y-prof.minE)*prof.scaleY)/d->scale-d->orig.y)*d->dpi+0.5));
- if ( d->angle == 0 ) {
- *xx = x;
- *yy = y;
- } else if ( d->angle == -90.0 ) {
- /* L->P */
- *xx = y;
- *yy = -x;
- } else {
- /* P->L */
- *xx = -y;
- *yy = x;
- }
+ wPos_t x, y;
+ x = (wPos_t)((((pos.x*prof.scaleX)/d->scale-d->orig.x)*d->dpi+0.5));
+ y = (wPos_t)(((((pos.y-prof.minE)*prof.scaleY)/d->scale-d->orig.y)*d->dpi+0.5));
+ if (d->angle == 0) {
+ *xx = x;
+ *yy = y;
+ } else if (d->angle == -90.0) {
+ /* L->P */
+ *xx = y;
+ *yy = -x;
+ } else {
+ /* P->L */
+ *xx = -y;
+ *yy = x;
+ }
}
+/**
+ * Redraw profile window
+ */
-static void RedrawProfileW( void )
+static void RedrawProfileW(void)
{
- wPos_t ww, hh;
- coOrd size;
- int inx, divC;
- DIST_T maxE, rngE;
- profElem_t *p;
- wFont_p fp;
- POS_T w;
- coOrd textsize;
-
- wDrawClear( screenProfileD.d );
- wDrawGetSize( screenProfileD.d, &ww, &hh );
- screenProfileD.size.x = (ww)/screenProfileD.dpi;
- screenProfileD.size.y = (hh)/screenProfileD.dpi;
- screenProfileD.orig.x = -PBL;
- screenProfileD.orig.y = -PBB(screenProfileFontSize);
-
- /* Calculate usable dimension of canvas */
- size = screenProfileD.size;
- size.x -= (PBL);
- size.y -= (PBB(screenProfileFontSize));
+ wPos_t ww, hh;
+ coOrd size;
+ int divC;
+ DIST_T maxE, rngE;
+ profElem_t *p;
+ wFont_p fp;
+ POS_T w;
+ coOrd textsize;
+ char *pTestString;
+
+ wDrawDelayUpdate(screenProfileD.d, TRUE);
+ wDrawClear(screenProfileD.d);
+
+ // get the size of the window area in pixels and convert to inches
+ wDrawGetSize(screenProfileD.d, &ww, &hh);
+ screenProfileD.size.x = (ww)/screenProfileD.dpi;
+ screenProfileD.size.y = (hh)/screenProfileD.dpi;
+
+ // calculate positions for labels???
+ fp = wStandardFont(F_HELV, FALSE, FALSE);
+ screenProfileD.orig.x = -PBL(screenProfileFontSize);
+ screenProfileD.orig.y = -PBB(screenProfileFontSize);
+
+ /* Calculate usable dimension of canvas in inches */
+ size = screenProfileD.size;
+ size.x -= (PBL(screenProfileFontSize));
+ size.y -= (PBB(screenProfileFontSize));
+
+ /* make sure there is enough space to show the rightmost coordinate value*/
+ if (units == UNITS_ENGLISH) {
+ if (prof.totalD > 240.0) {
+ pTestString = "9999'";
+ } else {
+ pTestString = "999'11\"";
+ }
+ } else {
+ if (PutDim(prof.totalD) > 10000.0) {
+ pTestString = "999m";
+ } else {
+ if (PutDim(prof.totalD) > 100.0) {
+ pTestString = "99.9m";
+ } else {
+ pTestString = "9.99m";
+ }
+ }
+ }
+ DrawTextSize(&mainD, pTestString, fp, screenProfileFontSize, FALSE, &textsize);
+ size.x -= textsize.x / 2;
+ size.y -= textsize.y * 1.5 ;
+
+
+ // now we have the size of the profile area
#ifdef WINDOWS
- if (printVert) {
- size.x -= PBR/4.0;
- size.y -= PBT;
- } else
+ if (printVert) {
+ size.x -= PBR(screenProfileFontSize)/4.0;
+ size.y -= PBT;
+ } else
#endif
- {
- size.x -= PBR;
- size.y -= PBT;
- }
- if ( size.x < 0.1 || size.y < 0.1 )
- return;
-
- /* Calculate range of data values */
- if (profElem_da.cnt<=0) {
- prof.totalD = 0.0;
- prof.minE = 0.0;
- maxE = 1.0;
- } else {
- maxE = prof.minE = profElem(0).elev;
- prof.totalD = profElem(profElem_da.cnt-1).dist;
- for (inx=1; inx<profElem_da.cnt; inx++ ) {
- p = &profElem(inx);
- if (p->elev<prof.minE)
- prof.minE = p->elev;
- if (p->elev>maxE)
- maxE = p->elev;
- }
- }
-
- /* Calculate number of grid lines */
- prof.minC = (int)floor(PutDim(prof.minE));
- prof.maxC = (int)ceil(PutDim(maxE));
- if ( prof.maxC-prof.minC <= 0 )
- prof.maxC = prof.minC+1;
- divC = (int)floor(size.y/labelH);
- if ( divC < 1 )
- divC = 1;
- prof.incrC = (prof.maxC-prof.minC+divC-1)/divC;
- if ( prof.incrC < 1 )
- prof.incrC = 1;
- prof.maxC = prof.minC + (prof.maxC-prof.minC+prof.incrC-1)/prof.incrC * prof.incrC;
-
- /* Reset bounds based on intergal values */
- prof.minE = GetDim(prof.minC);
- rngE = GetDim(prof.maxC) - prof.minE;
- if (rngE < 1.0)
- rngE = 1.0;
-
- /* Compute vert scale */
- prof.scaleY = size.y/rngE;
- sprintf( message, "%0.2f", maxE );
- fp = wStandardFont( F_HELV, FALSE, FALSE );
- DrawTextSize( &mainD, message, fp, screenProfileFontSize, FALSE, &textsize );
- w = textsize.x;
- w -= PBT;
- w += 4.0/screenProfileD.dpi;
- w -= (GetDim(prof.maxC)-maxE)*prof.scaleY;
- if (w > 0) {
- size.y -= w;
- prof.scaleY = size.y/rngE;
- }
-
- /* Compute horz scale */
- if (prof.totalD <= 0.1) {
- prof.totalD = size.x;
- }
- prof.scaleX = size.x/prof.totalD;
-
-#ifdef LATER
- D->size.x /= prof.scaleX;
- D->size.x -= D->orig.x;
- D->size.y /= prof.scaleY;
- D->size.y -= D->orig.y;
- D->size.y += prof.minE;
-#endif
-
- DrawProfile( &screenProfileD, screenProfileFontSize,
+ {
+ size.x -= PBR(screenProfileFontSize);
+ size.y -= PBT;
+ }
+
+ if (size.x < 0.1 || size.y < 0.1) {
+ wDrawDelayUpdate(screenProfileD.d, FALSE);
+ return;
+ }
+
+ /* Calculate range of data values */
+ if (profElem_da.cnt<=0) {
+ prof.totalD = 0.0;
+ prof.minE = 0.0;
+ maxE = 1.0;
+ } else {
+ maxE = prof.minE = profElem(0).elev;
+ prof.totalD = profElem(profElem_da.cnt-1).dist;
+ for (int inx=1; inx<profElem_da.cnt; inx++) {
+ p = &profElem(inx);
+ if (p->elev<prof.minE) {
+ prof.minE = p->elev;
+ }
+ if (p->elev>maxE) {
+ maxE = p->elev;
+ }
+ }
+ }
+
+ /* Calculate number of grid lines */
+ prof.minC = (int)floor(PutDim(prof.minE));
+ prof.maxC = (int)ceil(PutDim(maxE));
+ if (prof.maxC-prof.minC <= 0) {
+ prof.maxC = prof.minC+1;
+ }
+ divC = (int)floor(size.y/labelH);
+ if (divC < 1) {
+ divC = 1;
+ }
+ prof.incrC = (prof.maxC-prof.minC+divC-1)/divC;
+ if (prof.incrC < 1) {
+ prof.incrC = 1;
+ }
+ prof.maxC = prof.minC + (prof.maxC-prof.minC+prof.incrC-1)/prof.incrC *
+ prof.incrC;
+
+ /* Reset bounds based on intergal values */
+ prof.minE = GetDim(prof.minC);
+ rngE = GetDim(prof.maxC) - prof.minE;
+ if (rngE < 1.0) {
+ rngE = 1.0;
+ }
+
+ /* Compute vert scale */
+ prof.scaleY = size.y/rngE;
+ sprintf(message, "%0.2f", maxE);
+
+ DrawTextSize(&mainD, message, fp, screenProfileFontSize, FALSE, &textsize);
+ w = textsize.x;
+ w -= PBT;
+ w += 4.0/screenProfileD.dpi;
+ w -= (GetDim(prof.maxC)-maxE)*prof.scaleY;
+ if (w > 0) {
+ size.y -= w;
+ prof.scaleY = size.y/rngE;
+ }
+
+ /* Compute horz scale */
+ if (prof.totalD <= 0.1) {
+ prof.totalD = size.x;
+ }
+ prof.scaleX = size.x/prof.totalD;
+
+ DrawProfile(&screenProfileD, screenProfileFontSize,
#ifdef WINDOWS
- printVert
+ printVert
#else
- FALSE
+ FALSE
#endif
- );
+ );
+ wDrawDelayUpdate(screenProfileD.d, FALSE);
}
+
static drawCmd_t printProfileD = {
- NULL,
- &printDrawFuncs,
- DC_PRINT|DC_NOCLIP,
- 1.0,
- 0.0,
- {0.0,0.0}, {1.0,1.0},
- ProfilePix2CoOrd, ProfileCoOrd2Pix };
+ NULL,
+ &printDrawFuncs,
+ DC_PRINT | DC_NOCLIP,
+ 1.0,
+ 0.0,
+ {0.0,0.0}, {1.0,1.0},
+ ProfilePix2CoOrd, ProfileCoOrd2Pix
+};
/**
* This is the print function for the track height profile. The paper
@@ -457,94 +597,95 @@ static drawCmd_t printProfileD = {
* Eg. is the windows is wider than high, the printout will be in
* landscape.
* \todo Rework the layout of the printout
- * This function is (at least for me) hard to comprehend with all the
- * fiddling around with the ccordinates. Also the filled area is a
- * waste of toner or ink.
*
* \param junk IN
* \return
*/
-static void DoProfilePrint( void * junk )
+static void DoProfilePrint(void * junk)
{
- coOrd size, p[4];
- int copies;
- WDOUBLE_T w, h, screenRatio, printRatio, titleH;
- wFont_p fp;
- coOrd screenSize;
- coOrd textsize;
-
- if (!wPrintDocStart( _("Profile"), 1, &copies ))
- return;
- printProfileD.d = wPrintPageStart();
- if (printProfileD.d == NULL)
- return;
- printProfileD.dpi = wDrawGetDPI( printProfileD.d );
- wPrintGetPageSize( &w, &h );
- printProfileD.orig.x = -PBL;
- printProfileD.orig.y = -PBB(printProfileFontSize);
- printProfileD.angle = 0.0;
- screenRatio = screenProfileD.size.y/screenProfileD.size.x;
- screenSize.x = prof.totalD*prof.scaleX;
- screenSize.y = GetDim(prof.maxC-prof.minC)*prof.scaleY;
- screenRatio = screenSize.y/screenSize.x;
- printProfileD.size.x = w;
- printProfileD.size.y = h;
- sprintf( message, _("%s Profile: %s"), sProdName, GetLayoutTitle() );
- fp = wStandardFont( F_TIMES, FALSE, FALSE );
- DrawTextSize( &mainD, message, fp, 24, FALSE, &textsize );
- titleH = textsize.y + 6.0/mainD.dpi;
- if (screenRatio < 1.0 && w < h ) {
- /* Landscape -> Portrait */
- printProfileD.angle = -90.0;
- printProfileD.orig.x += h;
- size.x = h;
- size.y = w;
- } else if (screenRatio > 1.0 && w > h ) {
- /* Portrait -> Landscape */
- printProfileD.angle = 90.0;
- printProfileD.orig.y += w;
- size.x = h;
- size.y = w;
- } else {
- size.x = w;
- size.y = h;
- }
- size.y -= titleH+(printVert?PBT*2:PBT)+PBB(printProfileFontSize);
- size.x -= 4.0/mainD.dpi+PBL+(printVert?PBR/4.0:PBR);
- printRatio = size.y/size.x;
- if (printRatio < screenRatio) {
- printProfileD.scale = screenSize.y/size.y;
- size.x = screenSize.x/printProfileD.scale;
- } else {
- printProfileD.scale = screenSize.x/size.x;
- printProfileD.orig.y -= size.y;
- size.y = screenSize.y/printProfileD.scale;
- printProfileD.orig.y += size.y;
- }
+ coOrd size, p[4];
+ int copies;
+ WDOUBLE_T w, h, screenRatio, printRatio, titleH;
+ wFont_p fp;
+ coOrd screenSize;
+ coOrd textsize;
+
+ if (!wPrintDocStart(_("Profile"), 1, &copies)) {
+ return;
+ }
+ printProfileD.d = wPrintPageStart();
+ if (printProfileD.d == NULL) {
+ return;
+ }
+ printProfileD.dpi = wDrawGetDPI(printProfileD.d);
+ wPrintGetPageSize(&w, &h);
+ printProfileD.orig.x = -PBL(printProfileFontSize);
+ printProfileD.orig.y = -PBB(printProfileFontSize);
+ printProfileD.angle = 0.0;
+ screenRatio = screenProfileD.size.y/screenProfileD.size.x;
+ screenSize.x = prof.totalD*prof.scaleX;
+ screenSize.y = GetDim(prof.maxC-prof.minC)*prof.scaleY;
+ screenRatio = screenSize.y/screenSize.x;
+ printProfileD.size.x = w;
+ printProfileD.size.y = h;
+ sprintf(message, _("%s Profile: %s"), sProdName, GetLayoutTitle());
+ fp = wStandardFont(F_TIMES, FALSE, FALSE);
+ DrawTextSize(&mainD, message, fp, 24, FALSE, &textsize);
+ titleH = textsize.y + 6.0/mainD.dpi;
+ if (screenRatio < 1.0 && w < h) {
+ /* Landscape -> Portrait */
+ printProfileD.angle = -90.0;
+ printProfileD.orig.x += h;
+ size.x = h;
+ size.y = w;
+ } else if (screenRatio > 1.0 && w > h) {
+ /* Portrait -> Landscape */
+ printProfileD.angle = 90.0;
+ printProfileD.orig.y += w;
+ size.x = h;
+ size.y = w;
+ } else {
+ size.x = w;
+ size.y = h;
+ }
+ size.y -= titleH+(printVert?PBT*2:PBT)+PBB(printProfileFontSize);
+ size.x -= 4.0/mainD.dpi+PBL(printProfileFontSize)+(printVert?PBR(
+ printProfileFontSize)/4.0:PBR(printProfileFontSize));
+ printRatio = size.y/size.x;
+ if (printRatio < screenRatio) {
+ printProfileD.scale = screenSize.y/size.y;
+ size.x = screenSize.x/printProfileD.scale;
+ } else {
+ printProfileD.scale = screenSize.x/size.x;
+ printProfileD.orig.y -= size.y;
+ size.y = screenSize.y/printProfileD.scale;
+ printProfileD.orig.y += size.y;
+ }
#define PRINT_ABS2PAGEX(X) (((X)*printProfileD.scale)/prof.scaleX)
#define PRINT_ABS2PAGEY(Y) (((Y)*printProfileD.scale)/prof.scaleY+prof.minE)
- p[0].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT)+0.05);
- p[0].x = PRINT_ABS2PAGEX((size.x-textsize.x)/2.0);
- if ( p[0].x < 0 )
- p[0].x = 0;
- DrawString( &printProfileD, p[0], 0, message, fp, 24*printProfileD.scale, borderColor );
- p[0].x = p[3].x = PRINT_ABS2PAGEX((-PBL)+2.0/mainD.dpi);
- p[0].y = p[1].y = PRINT_ABS2PAGEY(-PBB(printProfileFontSize));
- p[1].x = p[2].x = PRINT_ABS2PAGEX(size.x+(printVert?PBR/4.0:PBR));
- p[2].y = p[3].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT));
- DrawLine( &printProfileD, p[0], p[1], 0, drawColorBlack );
- DrawLine( &printProfileD, p[1], p[2], 0, drawColorBlack );
- DrawLine( &printProfileD, p[2], p[3], 0, drawColorBlack );
- DrawLine( &printProfileD, p[3], p[0], 0, drawColorBlack );
-
- DrawProfile( &printProfileD, printProfileFontSize, printVert );
- wPrintPageEnd( printProfileD.d );
- wPrintDocEnd();
+ p[0].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT)+0.05);
+ p[0].x = PRINT_ABS2PAGEX((size.x-textsize.x)/2.0);
+ if (p[0].x < 0) {
+ p[0].x = 0;
+ }
+ DrawString(&printProfileD, p[0], 0, message, fp, 24*printProfileD.scale,
+ borderColor);
+ p[0].x = p[3].x = PRINT_ABS2PAGEX((-PBL(printProfileFontSize))+2.0/mainD.dpi);
+ p[0].y = p[1].y = PRINT_ABS2PAGEY(-PBB(printProfileFontSize));
+ p[1].x = p[2].x = PRINT_ABS2PAGEX(size.x+(printVert?PBR(
+ printProfileFontSize)/4.0:PBR(printProfileFontSize)));
+ p[2].y = p[3].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT));
+ DrawLine(&printProfileD, p[0], p[1], 0, drawColorBlack);
+ DrawLine(&printProfileD, p[1], p[2], 0, drawColorBlack);
+ DrawLine(&printProfileD, p[2], p[3], 0, drawColorBlack);
+ DrawLine(&printProfileD, p[3], p[0], 0, drawColorBlack);
+
+ DrawProfile(&printProfileD, printProfileFontSize, printVert);
+ wPrintPageEnd(printProfileD.d);
+ wPrintDocEnd();
}
-
-
/**************************************************************************
*
* Window Handlers
@@ -553,201 +694,218 @@ static void DoProfilePrint( void * junk )
static wWin_p profileW;
-
static BOOL_T profileUndo = FALSE;
-static void DoProfileDone( void * );
-static void DoProfileClear( void * );
-static void DoProfilePrint( void * );
-static void DoProfileChangeMode( void * );
-static void SelProfileW( wIndex_t, coOrd );
+static void DoProfileChange(void *junk);
+static void DoProfileReset(void *junk);
+static void DoProfileDone(void *);
+static void DoProfileClear(void *);
+static void DoProfilePrint(void *);
+static void DoProfileChangeMode(void *);
+static void SelProfileW(wIndex_t, coOrd);
+static void CloseProfileWindow(paramGroup_p pg, int event, void *data);
static paramDrawData_t profileDrawData = { 300, 150, (wDrawRedrawCallBack_p)RedrawProfileW, SelProfileW, &screenProfileD };
static paramData_t profilePLs[] = {
- { PD_DRAW, NULL, "canvas", PDO_DLGRESIZE, &profileDrawData },
+ { PD_DRAW, NULL, "canvas", PDO_DLGRESIZE, &profileDrawData },
#define I_PROFILEMSG (1)
- { PD_MESSAGE, NULL, NULL, PDO_DLGIGNOREX, (void*)300 },
- { PD_BUTTON, (void*)DoProfileClear, "clear", PDO_DLGCMDBUTTON, NULL, N_("Clear") },
- { PD_BUTTON, (void*)DoProfilePrint, "print", 0, NULL, N_("Print") } };
+ { PD_MESSAGE, NULL, NULL, PDO_DLGIGNOREX, (void*)300 },
+#define I_CHANGEBUTTON 2
+ { PD_BUTTON, (void*)DoProfileChange, "change", PDO_DLGCMDBUTTON, NULL, N_("Change") },
+#define I_RESETBUTTON 3
+ { PD_BUTTON, (void*)DoProfileReset, "reset", PDO_DLGCMDBUTTON, NULL, N_("Reset") },
+#define I_CLEARBUTTON 4
+ { PD_BUTTON, (void*)DoProfileClear, "clear", PDO_DLGCMDBUTTON, NULL, N_("Clear") },
+#define I_PRINTBUTTON 5
+ { PD_BUTTON, (void*)DoProfilePrint, "print", 0, NULL, N_("Print") }
+};
static paramGroup_t profilePG = { "profile", 0, profilePLs, sizeof profilePLs/sizeof profilePLs[0] };
+#define CHANGEBUTTON ((wButton_p)profilePLs[I_CHANGEBUTTON].control)
+#define RESETBUTTON ((wButton_p)profilePLs[I_RESETBUTTON].control)
+#define CLEARBUTTON ((wButton_p)profilePLs[I_CLEARBUTTON].control)
+#define PRINTBUTTON ((wButton_p)profilePLs[I_PRINTBUTTON].control)
-static void ProfileTempDraw( int inx, DIST_T elev )
+static void SelProfileW(
+ wIndex_t action,
+ coOrd pos)
{
- coOrd p0, p1;
-#ifdef LATER
- p0.x = profElem(inx).dist*prof.scaleX;
- p0.y = (elev-prof.minE)*prof.scaleY;
- screenProfileD.funcs = &tempDrawFuncs;
- if (inx > 0) {
- p1.x = profElem(inx-1).dist*prof.scaleX;
- p1.y = (profElem(inx-1).elev-prof.minE)*prof.scaleY;
- DrawLine( &screenProfileD, p0, p1, 2, borderColor );
- }
- if (inx < profElem_da.cnt-1) {
- p1.x = profElem(inx+1).dist*prof.scaleX;
- p1.y = (profElem(inx+1).elev-prof.minE)*prof.scaleY;
- DrawLine( &screenProfileD, p0, p1, 2, borderColor );
- }
- screenProfileD.funcs = &screenDrawFuncs;
-#endif
- p0.x = profElem(inx).dist;
- p0.y = elev;
- screenProfileD.funcs = &tempDrawFuncs;
- if (inx > 0) {
- p1.x = profElem(inx-1).dist;
- p1.y = profElem(inx-1).elev;
- DrawLine( &screenProfileD, p0, p1, 2, borderColor );
- }
- if (inx < profElem_da.cnt-1) {
- p1.x = profElem(inx+1).dist;
- p1.y = profElem(inx+1).elev;
- DrawLine( &screenProfileD, p0, p1, 2, borderColor );
- }
- screenProfileD.funcs = &screenDrawFuncs;
+ DIST_T dist;
+ static DIST_T oldElev;
+ static int inx;
+ DIST_T elev;
+
+ if (profElem_da.cnt <= 0) {
+ return;
+ }
+
+ dist = pos.x;
+ elev = pos.y;
+
+ switch (action&0xFF) {
+ case C_DOWN:
+ for (inx=0; inx<profElem_da.cnt; inx++) {
+ if (dist <= profElem(inx).dist) {
+ if (inx!=0 && profElem(inx).dist-dist > dist-profElem(inx-1).dist) {
+ inx--;
+ }
+ break;
+ }
+ }
+ if (inx >= profElem_da.cnt) {
+ inx = profElem_da.cnt-1;
+ }
+ sprintf(message, _("Elev = %0.1f"), round(PutDim(elev)*10.0)/10.0);
+ ParamLoadMessage(&profilePG, I_PROFILEMSG, message);
+ oldElev = elev;
+ RedrawProfileW();
+ break;
+ case C_MOVE:
+ if (inx < 0) {
+ break;
+ }
+ if (profElem_da.cnt == 1) {
+ sprintf(message, _("Elev = %0.1f"), round(PutDim(elev)*10.0)/10.0);
+ } else if (inx == 0) {
+ sprintf(message, _("Elev=%0.2f %0.1f%%"),
+ round(PutDim(elev)*100.0)/100.0,
+ round(fabs(((profElem(inx+1).elev-elev) / (profElem(inx+1).dist-profElem(
+ inx).dist)) * 1000.0))/10.0);
+ } else if (inx == profElem_da.cnt-1) {
+ sprintf(message, _("%0.1f%% Elev = %0.2f"),
+ round(fabs(((profElem(inx-1).elev-elev) / (profElem(inx).dist-profElem(
+ inx-1).dist)) * 1000.0))/10.0,
+ round(PutDim(elev)*100.0)/100.0);
+ } else {
+ sprintf(message, _("%0.1f%% Elev = %0.2f %0.1f%%"),
+ round(fabs(((profElem(inx-1).elev-elev) / (profElem(inx).dist-profElem(
+ inx-1).dist)) * 1000.0))/10.0,
+ round(PutDim(elev)*100.0)/100.0,
+ round(fabs((profElem(inx+1).elev-elev) / (profElem(inx+1).dist-profElem(
+ inx).dist)) * 1000.0)/10.0);
+ }
+ ParamLoadMessage(&profilePG, I_PROFILEMSG, message);
+ oldElev = elev;
+ profElem(inx).elev = oldElev;
+ RedrawProfileW();
+ wPause(500l);
+ break;
+ case C_UP:
+ if (profileUndo == FALSE) {
+ UndoStart(_("Profile Command"), "Profile - set elevation");
+ profileUndo = TRUE;
+ }
+ if (profElem(inx).trk) {
+ UpdateTrkEndElev(profElem(inx).trk, profElem(inx).ep, ELEV_DEF|ELEV_VISIBLE,
+ oldElev, NULL);
+ }
+ profElem(inx).elev = oldElev;
+ RedrawProfileW();
+ ParamLoadMessage(&profilePG, I_PROFILEMSG, _("Drag to change Elevation"));
+ inx = -1;
+ break;
+ default:
+ break;
+ }
}
-
-static void SelProfileW(
- wIndex_t action,
- coOrd pos )
+static void HilightProfileElevations(BOOL_T show)
{
- DIST_T dist;
- static DIST_T oldElev;
- static int inx;
- DIST_T elev;
-
- if (profElem_da.cnt <= 0)
- return;
+ /*if ( profElem_da.cnt <= 0 ) {*/
+ HilightElevations(show);
+ /*} else {
+ }*/
+}
- dist = pos.x;
- elev = pos.y;
+/**
+ *
+ *
+ * \param pg The page.
+ * \param event The event.
+ * \param [in,out] data If non-null, the data.
+ */
+void
+CloseProfileWindow(paramGroup_p pg, int event, void *data)
+{
+ Reset();
+ return;
+}
-#ifdef LATER
- if (recordF)
- RecordMouse( "PROFILEMOUSE", action, dist, elev );
-#endif
- switch (action&0xFF) {
- case C_DOWN:
- for (inx=0; inx<profElem_da.cnt; inx++) {
- if (dist <= profElem(inx).dist) {
- if (inx!=0 && profElem(inx).dist-dist > dist-profElem(inx-1).dist)
- inx--;
- break;
+/**
+ * Undo the changes made in the profile window to the layout.
+ */
+
+static void
+ResetChanges()
+{
+ if (copyOfprofElem) {
+ for (int i = 0; i < profElem_da.cnt; i++) {
+ profElem(i) = copyOfprofElem[i];
+ if (profElem(i).trk) {
+ UpdateTrkEndElev(profElem(i).trk, profElem(i).ep, ELEV_DEF | ELEV_VISIBLE,
+ copyOfprofElem[i].elev, NULL);
}
}
- if (inx >= profElem_da.cnt)
- inx = profElem_da.cnt-1;
- sprintf(message, _("Elev = %0.1f"), PutDim(elev) );
- ParamLoadMessage( &profilePG, I_PROFILEMSG, message );
- oldElev = elev;
- ProfileTempDraw( inx, elev );
- break;
- case C_MOVE:
- if ( inx < 0 )
- break;
- ProfileTempDraw( inx, oldElev );
- if (profElem_da.cnt == 1 ) {
- sprintf(message, _("Elev = %0.1f"), PutDim(elev) );
- } else if (inx == 0) {
- sprintf( message, _("Elev=%0.2f %0.1f%%"),
- PutDim(elev),
- fabs( profElem(inx+1).elev-elev ) / (profElem(inx+1).dist-profElem(inx).dist) * 100.0 );
- } else if (inx == profElem_da.cnt-1) {
- sprintf( message, _("%0.1f%% Elev = %0.2f"),
- fabs( profElem(inx-1).elev-elev ) / (profElem(inx).dist-profElem(inx-1).dist) * 100.0,
- PutDim(elev) );
- } else {
- sprintf( message, _("%0.1f%% Elev = %0.2f %0.1f%%"),
- fabs( profElem(inx-1).elev-elev ) / (profElem(inx).dist-profElem(inx-1).dist) * 100.0,
- PutDim(elev),
- fabs( profElem(inx+1).elev-elev ) / (profElem(inx+1).dist-profElem(inx).dist) * 100.0 );
- }
- ParamLoadMessage( &profilePG, I_PROFILEMSG, message );
- oldElev = elev;
- ProfileTempDraw( inx, oldElev );
- break;
- case C_UP:
- if (profileUndo == FALSE) {
- UndoStart( _("Profile Command"), "Profile - set elevation" );
- profileUndo = TRUE;
- }
- if (profElem(inx).trk) {
- UpdateTrkEndElev( profElem(inx).trk, profElem(inx).ep, ELEV_DEF|ELEV_VISIBLE, oldElev, NULL );
- }
- profElem(inx).elev = oldElev;
- RedrawProfileW();
- ParamLoadMessage( &profilePG, I_PROFILEMSG, _("Drag to change Elevation") );
- inx = -1;
- break;
- default:
- break;
}
}
+/**
+ * Executes the profile reset operation. All elevations are copied from the
+ * backup, the main drawing area and the profile window are updated
+ *
+ * \param [in,out] junk
+ */
-#ifdef LATER
-static BOOL_T ProfilePlayback( char * line )
+static void
+DoProfileReset(void *junk)
{
- int action;
- wPos_t x, y;
- coOrd pos;
-
- if ( !GetArgs( line, "dp", &action, &pos ) ) {
- return FALSE;
- } else {
- x = (wPos_t)(((pos.x*prof.scaleX)-screenProfileD.orig.x)*screenProfileD.dpi+0.5);
- y = (wPos_t)((((pos.y-prof.minE)*prof.scaleY)-screenProfileD.orig.y)*screenProfileD.dpi+0.5);
- PlaybackMouse( selProfileW, &screenProfileD, (wAction_t)action, x, y, drawColorBlack );
+ if (profileUndo == 0) {
+ profileUndo = TRUE;
+ UndoStart(_("Profile Command"), "Profile");
}
- return TRUE;
+ ResetChanges();
+ RedrawProfileW();
+ TempRedraw();
}
-#endif
-
+/**
+ * Confirm the changes made in the profile window
+ *
+ * \param [in,out] junk If non-null, the junk.
+ */
-static void HilightProfileElevations( BOOL_T show )
+static void
+DoProfileChange(void *junk)
{
- /*if ( profElem_da.cnt <= 0 ) {*/
- HilightElevations( show );
- /*} else {
- }*/
+ DestroyCopyOfProfileElements();
+ TempRedraw();
}
-static void DoProfileDone( void * junk )
+static void DoProfileDone(void * junk)
{
-#ifdef LATER
- HilightProfileElevations( FALSE );
- wHide( profileW );
- ClrAllTrkBits( TB_PROFILEPATH );
- MainRedraw();
- MapRedraw();
-#endif
- Reset();
+ Reset();
}
-static void DoProfileClear( void * junk )
+static void DoProfileClear(void * junk)
{
- profElem_da.cnt = 0;
- station_da.cnt = 0;
- if (ClrAllTrkBits( TB_PROFILEPATH )) {
- MainRedraw();
- MapRedraw();
- }
- pathStartTrk = pathEndTrk = NULL;
- RedrawProfileW();
+ ResetChanges();
+ profElem_da.cnt = 0;
+ station_da.cnt = 0;
+ ClrAllTrkBitsRedraw(TB_PROFILEPATH, TRUE);
+ pathStartTrk = pathEndTrk = NULL;
+ RedrawProfileW();
}
-static void DoProfileChangeMode( void * junk )
+static void DoProfileChangeMode(void * junk)
{
- if (profElem_da.cnt<=0) {
- InfoMessage( _("Select a Defined Elevation to start Profile") );
- } else {
- InfoMessage( _("Select a Defined Elevation to extend Profile") );
- }
+ if (profElem_da.cnt<=0) {
+ InfoMessage(_("Select a Defined Elevation to start Profile"));
+ } else {
+ InfoMessage(_("Select a Defined Elevation to extend Profile"));
+ }
}
/**************************************************************************
@@ -756,17 +914,17 @@ static void DoProfileChangeMode( void * junk )
*
**************************************************************************/
-static BOOL_T PathListEmpty( void )
+static BOOL_T PathListEmpty(void)
{
- return pathStartTrk == NULL;
+ return pathStartTrk == NULL;
}
-static BOOL_T PathListSingle( void )
+static BOOL_T PathListSingle(void)
{
- return pathStartTrk != NULL &&
- ( pathEndTrk == NULL ||
- ( GetTrkEndTrk(pathEndTrk,pathEndEp) == pathStartTrk &&
- GetTrkEndTrk(pathStartTrk,pathStartEp) == pathEndTrk ) );
+ return pathStartTrk != NULL &&
+ (pathEndTrk == NULL ||
+ (GetTrkEndTrk(pathEndTrk,pathEndEp) == pathStartTrk &&
+ GetTrkEndTrk(pathStartTrk,pathStartEp) == pathEndTrk));
}
@@ -774,102 +932,106 @@ static int profileShortestPathMatch;
static DIST_T profileShortestPathDist;
static int ProfileShortestPathFunc(
- SPTF_CMD cmd,
- track_p trk,
- EPINX_T ep,
- EPINX_T ep0,
- DIST_T dist,
- void * data )
+ SPTF_CMD cmd,
+ track_p trk,
+ EPINX_T ep,
+ EPINX_T ep0,
+ DIST_T dist,
+ void * data)
{
- track_p trkN;
- EPINX_T epN;
- int rc0=0;
- int pathMatch;
-
- switch (cmd) {
- case SPTC_TERMINATE:
- rc0 = 1;
- break;
-
- case SPTC_MATCH:
- if ( EndPtIsIgnoredElev(trk,ep) )
- break;
- if ( PathListSingle() ) {
- if ( trk == pathStartTrk && ep == pathStartEp ) {
- pathMatch = 2;
- } else if ( trk == pathEndTrk && ep == pathEndEp ) {
- pathMatch = 3;
- } else {
- break;
- }
- } else if ( ( trkN = GetTrkEndTrk(trk,ep) ) == NULL ) {
- break;
- } else {
- epN = GetEndPtConnectedToMe( trkN, trk );
- if ( trkN == pathStartTrk && epN == pathStartEp ) {
- pathMatch = 1;
- } else if ( trkN == pathEndTrk && epN == pathEndEp ) {
- pathMatch = 2;
- } else if ( trkN == pathStartTrk && trkN == pathEndTrk ) {
- pathMatch = 2;
- } else if ( trkN == pathStartTrk ) {
- pathMatch = 1;
- } else if ( trkN == pathEndTrk ) {
- pathMatch = 2;
- } else {
- break;
- }
- }
- if ( profileShortestPathMatch < 0 || profileShortestPathDist > dist ) {
-LOG( log_shortPath, 4, ( " Match=%d", pathMatch ) )
- profileShortestPathMatch = pathMatch;
- profileShortestPathDist = dist;
- }
- rc0 = 1;
- break;
-
- case SPTC_MATCHANY:
- rc0 = -1;
- break;
-
- case SPTC_IGNNXTTRK:
- if ( EndPtIsIgnoredElev(trk,ep) )
- rc0 = 1;
- else if ( (GetTrkBits(trk)&TB_PROFILEPATH)!=0 )
- rc0 = 1;
- else if ( (!EndPtIsDefinedElev(trk,ep)) && GetTrkEndTrk(trk,ep)==NULL )
- rc0 = 1;
- else
- rc0 = 0;
- break;
-
- case SPTC_ADD_TRK:
-if (log_shortPath<=0||logTable(log_shortPath).level<4) LOG( log_profile, 4, ( " ADD_TRK T%d:%d", GetTrkIndex(trk), ep ) )
- SetTrkBits( trk, TB_PROFILEPATH );
- DrawTrack( trk, &mainD, profilePathColor );
- rc0 = 0;
- break;
-
- case SPTC_VALID:
- rc0 = 1;
- break;
-
- default:
- break;
- }
- return rc0;
+ int rc0=0;
+ int pathMatch;
+
+ switch (cmd) {
+ track_p trkN;
+ case SPTC_TERMINATE:
+ rc0 = 1;
+ break;
+
+ case SPTC_MATCH:
+ if (EndPtIsIgnoredElev(trk,ep)) {
+ break;
+ }
+ if (PathListSingle()) {
+ if (trk == pathStartTrk && ep == pathStartEp) {
+ pathMatch = 2;
+ } else if (trk == pathEndTrk && ep == pathEndEp) {
+ pathMatch = 3;
+ } else {
+ break;
+ }
+ } else if ((trkN = GetTrkEndTrk(trk,ep)) == NULL) {
+ break;
+ } else {
+ EPINX_T epN;
+ epN = GetEndPtConnectedToMe(trkN, trk);
+ if (trkN == pathStartTrk && epN == pathStartEp) {
+ pathMatch = 1;
+ } else if (trkN == pathEndTrk && epN == pathEndEp) {
+ pathMatch = 2;
+ } else if (trkN == pathStartTrk && trkN == pathEndTrk) {
+ pathMatch = 2;
+ } else if (trkN == pathStartTrk) {
+ pathMatch = 1;
+ } else if (trkN == pathEndTrk) {
+ pathMatch = 2;
+ } else {
+ break;
+ }
+ }
+ if (profileShortestPathMatch < 0 || profileShortestPathDist > dist) {
+ LOG(log_shortPath, 4, (" Match=%d", pathMatch))
+ profileShortestPathMatch = pathMatch;
+ profileShortestPathDist = dist;
+ }
+ rc0 = 1;
+ break;
+
+ case SPTC_MATCHANY:
+ rc0 = -1;
+ break;
+
+ case SPTC_IGNNXTTRK:
+ if (EndPtIsIgnoredElev(trk,ep)) {
+ rc0 = 1;
+ } else if ((GetTrkBits(trk)&TB_PROFILEPATH)!=0) {
+ rc0 = 1;
+ } else if ((!EndPtIsDefinedElev(trk,ep)) && GetTrkEndTrk(trk,ep)==NULL) {
+ rc0 = 1;
+ } else {
+ rc0 = 0;
+ }
+ break;
+
+ case SPTC_ADD_TRK:
+ if (log_shortPath<=0||
+ logTable(log_shortPath).level<4) LOG(log_profile, 4, (" ADD_TRK T%d:%d",
+ GetTrkIndex(trk), ep))
+ SetTrkBits(trk, TB_PROFILEPATH);
+ DrawTrack(trk, &mainD, profilePathColor);
+ rc0 = 0;
+ break;
+
+ case SPTC_VALID:
+ rc0 = 1;
+ break;
+
+ default:
+ break;
+ }
+ return rc0;
}
static int FindProfileShortestPath(
- track_p trkN,
- EPINX_T epN )
+ track_p trkN,
+ EPINX_T epN)
{
-LOG( log_profile, 4, ( "Searching from T%d:%d to T%d:%d or T%d:%d\n",
- GetTrkIndex(trkN), epN,
- pathStartTrk?GetTrkIndex(pathStartTrk):-1, pathStartTrk?pathStartEp:-1,
- pathEndTrk?GetTrkIndex(pathEndTrk):-1, pathEndTrk?pathEndEp:-1 ) )
- profileShortestPathMatch = -1;
- return FindShortestPath( trkN, epN, TRUE, ProfileShortestPathFunc, NULL );
+ LOG(log_profile, 4, ("Searching from T%d:%d to T%d:%d or T%d:%d\n",
+ GetTrkIndex(trkN), epN,
+ pathStartTrk?GetTrkIndex(pathStartTrk):-1, pathStartTrk?pathStartEp:-1,
+ pathEndTrk?GetTrkIndex(pathEndTrk):-1, pathEndTrk?pathEndEp:-1))
+ profileShortestPathMatch = -1;
+ return FindShortestPath(trkN, epN, TRUE, ProfileShortestPathFunc, NULL);
}
@@ -884,502 +1046,494 @@ LOG( log_profile, 4, ( "Searching from T%d:%d to T%d:%d or T%d:%d\n",
#define ONPATH_END (1<<1)
#define ONPATH_MID (1<<2)
#define ONPATH_BRANCH (1<<3)
-static int OnPath( track_p trk, EPINX_T ep )
+static int OnPath(track_p trk, EPINX_T ep)
{
- track_p trk0;
- if ( GetTrkBits(trk)&TB_PROFILEPATH ) {
- trk0 = GetTrkEndTrk( profilePopupTrk, profilePopupEp );
- if ( trk0 && (GetTrkBits(trk0)&TB_PROFILEPATH) ) {
- return ONPATH_MID;
- }
- if ( ( trk == pathStartTrk && ep == pathStartEp ) ||
- ( trk == pathStartTrk && ep == pathStartEp ) ) {
- return ONPATH_END;
- }
- return ONPATH_BRANCH;
- }
- return ONPATH_NOT;
+ if (GetTrkBits(trk)&TB_PROFILEPATH) {
+ track_p trk0;
+ trk0 = GetTrkEndTrk(profilePopupTrk, profilePopupEp);
+ if (trk0 && (GetTrkBits(trk0)&TB_PROFILEPATH)) {
+ return ONPATH_MID;
+ }
+ if (trk == pathStartTrk && ep == pathStartEp) {
+ return ONPATH_END;
+ }
+ return ONPATH_BRANCH;
+ }
+ return ONPATH_NOT;
}
-static BOOL_T PathListCheck( void )
+static BOOL_T PathListCheck(void)
{
- track_p trk;
- if (PathListEmpty() || PathListSingle())
- return TRUE;
- if (!(GetTrkBits(pathStartTrk)&TB_PROFILEPATH)) {
- ErrorMessage( MSG_PST_NOT_ON_PATH );
- return FALSE;
- }
- if (!(GetTrkBits(pathEndTrk)&TB_PROFILEPATH)) {
- ErrorMessage( MSG_PET_NOT_ON_PATH );
- return FALSE;
- }
- trk = GetTrkEndTrk(pathStartTrk,pathStartEp);
- if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) {
- ErrorMessage( MSG_INV_PST_ON_PATH );
- return FALSE;
- }
- trk = GetTrkEndTrk(pathEndTrk,pathEndEp);
- if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) {
- ErrorMessage( MSG_INV_PET_ON_PATH );
- return FALSE;
- }
- return TRUE;
+ track_p trk;
+ if (PathListEmpty() || PathListSingle()) {
+ return TRUE;
+ }
+ if (!(GetTrkBits(pathStartTrk)&TB_PROFILEPATH)) {
+ ErrorMessage(MSG_PST_NOT_ON_PATH);
+ return FALSE;
+ }
+ if (!(GetTrkBits(pathEndTrk)&TB_PROFILEPATH)) {
+ ErrorMessage(MSG_PET_NOT_ON_PATH);
+ return FALSE;
+ }
+ trk = GetTrkEndTrk(pathStartTrk,pathStartEp);
+ if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) {
+ ErrorMessage(MSG_INV_PST_ON_PATH);
+ return FALSE;
+ }
+ trk = GetTrkEndTrk(pathEndTrk,pathEndEp);
+ if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) {
+ ErrorMessage(MSG_INV_PET_ON_PATH);
+ return FALSE;
+ }
+ return TRUE;
}
static void RemoveTracksFromPath(
- track_p *Rtrk,
- EPINX_T *Rep,
- track_p trkEnd,
- EPINX_T epEnd )
+ track_p *Rtrk,
+ EPINX_T *Rep,
+ track_p trkEnd,
+ EPINX_T epEnd)
{
- EPINX_T ep2;
- track_p trk = *Rtrk, trkN;
- EPINX_T ep = *Rep;
-
- PASSERT( "removeTracksFromPath", trk, NOP );
- PASSERT( "removeTracksFromPath", !PathListSingle(), NOP );
- while (1) {
- DrawTrack( trk, &mainD, drawColorWhite );
- ClrTrkBits( trk, TB_PROFILEPATH );
- DrawTrack( trk, &mainD, drawColorBlack );
-
- if (trk == trkEnd) {
- pathStartTrk = trkEnd;
- pathStartEp = epEnd;
- pathEndTrk = GetTrkEndTrk(pathStartTrk,pathStartEp);
- if (pathEndTrk)
- pathEndEp = GetEndPtConnectedToMe(pathEndTrk,pathStartTrk);
- return;
- }
-
- ep2 = GetNextTrkOnPath( trk, ep );
- PASSERT( "removeTracksFromPath", ep2 >= 0,NOP );
- trkN = GetTrkEndTrk(trk,ep2);
- PASSERT( "removeTracksFromPath", trkN != NULL, NOP );
- ep = GetEndPtConnectedToMe(trkN,trk);
- trk = trkN;
- if (EndPtIsDefinedElev(trk,ep)) {
- *Rtrk = trk;
- *Rep = ep;
- return;
- }
- }
+ track_p trk = *Rtrk, trkN;
+ EPINX_T ep = *Rep;
+
+ PASSERT("removeTracksFromPath", trk, NOP);
+ PASSERT("removeTracksFromPath", !PathListSingle(), NOP);
+ while (1) {
+ EPINX_T ep2;
+ DrawTrack(trk, &mainD, drawColorWhite);
+ ClrTrkBits(trk, TB_PROFILEPATH);
+ DrawTrack(trk, &mainD, drawColorBlack);
+
+ if (trk == trkEnd) {
+ pathStartTrk = trkEnd;
+ pathStartEp = epEnd;
+ pathEndTrk = GetTrkEndTrk(pathStartTrk,pathStartEp);
+ if (pathEndTrk) {
+ pathEndEp = GetEndPtConnectedToMe(pathEndTrk,pathStartTrk);
+ }
+ return;
+ }
+
+ ep2 = GetNextTrkOnPath(trk, ep);
+ PASSERT("removeTracksFromPath", ep2 >= 0,NOP);
+ trkN = GetTrkEndTrk(trk,ep2);
+ PASSERT("removeTracksFromPath", trkN != NULL, NOP);
+ ep = GetEndPtConnectedToMe(trkN,trk);
+ trk = trkN;
+ if (EndPtIsDefinedElev(trk,ep)) {
+ *Rtrk = trk;
+ *Rep = ep;
+ return;
+ }
+ }
}
-static void ChkElev( track_p trk, EPINX_T ep, EPINX_T ep2, DIST_T dist, BOOL_T * defined )
+static void ChkElev(track_p trk, EPINX_T ep, EPINX_T ep2, DIST_T dist,
+ BOOL_T * defined)
{
- profElem_p p;
- station_p s;
- EPINX_T epDefElev = -1, ep1;
- int mode;
- BOOL_T undefined;
-
- mode = GetTrkEndElevMode( trk, ep );
- if (mode == ELEV_DEF) {
- epDefElev = ep;
- } else if (mode == ELEV_STATION) {
- DYNARR_APPEND( station_t, station_da, 10 );
- s = &station(station_da.cnt-1);
- s->dist = dist;
- s->name = GetTrkEndElevStation(trk,ep);
- }
- undefined = FALSE;
- if (epDefElev<0) {
- if ( (trk == pathStartTrk && ep == pathStartEp) ||
- (trk == pathEndTrk && ep == pathEndEp) ) {
- epDefElev = ep;
- }
- }
- if (epDefElev<0) {
- if (ep == ep2 ||
- GetTrkEndElevMode(trk,ep2) != ELEV_DEF )
- for ( ep1=0; ep1<GetTrkEndPtCnt(trk); ep1++ ) {
- if ( ep1==ep || ep1==ep2 )
- continue;
- if (EndPtIsDefinedElev(trk,ep1)) {
- epDefElev = ep1;
- dist -= GetTrkLength( trk, ep, ep1 );
- break;
- }
- if (GetTrkEndTrk(trk,ep1)) {
- if (!EndPtIsIgnoredElev(trk,ep1))
- undefined = TRUE;
- }
- }
- }
-
- if (epDefElev>=0) {
- DYNARR_APPEND( profElem_t, profElem_da, 10 );
- p = &profElem(profElem_da.cnt-1);
- p->trk = trk;
- p->ep = epDefElev;
- p->dist = dist;
- if (GetTrkEndElevMode(trk,epDefElev) == ELEV_DEF)
- p->elev = GetTrkEndElevHeight(trk,epDefElev);
- else
- ComputeElev( trk, epDefElev, TRUE, &p->elev, NULL );
- p->defined = *defined;
- *defined = TRUE;
- } else if (undefined) {
- *defined = FALSE;
- }
+ profElem_p p;
+ station_p s;
+ EPINX_T epDefElev = -1;
+ int mode;
+ BOOL_T undefined;
+
+ mode = GetTrkEndElevMode(trk, ep);
+ if (mode == ELEV_DEF) {
+ epDefElev = ep;
+ } else if (mode == ELEV_STATION) {
+ DYNARR_APPEND(station_t, station_da, 10);
+ s = &station(station_da.cnt-1);
+ s->dist = dist;
+ s->name = GetTrkEndElevStation(trk,ep);
+ }
+ undefined = FALSE;
+ if (epDefElev<0) {
+ if ((trk == pathStartTrk && ep == pathStartEp) ||
+ (trk == pathEndTrk && ep == pathEndEp)) {
+ epDefElev = ep;
+ }
+ }
+ if (epDefElev<0) {
+ if (ep == ep2 ||
+ GetTrkEndElevMode(trk,ep2) != ELEV_DEF)
+ for (EPINX_T ep1=0; ep1<GetTrkEndPtCnt(trk); ep1++) {
+ if (ep1==ep || ep1==ep2) {
+ continue;
+ }
+ if (EndPtIsDefinedElev(trk,ep1)) {
+ epDefElev = ep1;
+ dist -= GetTrkLength(trk, ep, ep1);
+ break;
+ }
+ if (GetTrkEndTrk(trk,ep1)) {
+ if (!EndPtIsIgnoredElev(trk,ep1)) {
+ undefined = TRUE;
+ }
+ }
+ }
+ }
+
+ if (epDefElev>=0) {
+ DYNARR_APPEND(profElem_t, profElem_da, 10);
+ p = &profElem(profElem_da.cnt-1);
+ p->trk = trk;
+ p->ep = epDefElev;
+ p->dist = dist;
+ if (GetTrkEndElevMode(trk,epDefElev) == ELEV_DEF) {
+ p->elev = GetTrkEndElevHeight(trk,epDefElev);
+ } else {
+ ComputeElev(trk, epDefElev, TRUE, &p->elev, NULL, TRUE);
+ }
+ p->defined = *defined;
+ *defined = TRUE;
+ } else if (undefined) {
+ *defined = FALSE;
+ }
}
-static void ComputeProfElem( void )
+static void ComputeProfElem(void)
{
- track_p trk = pathStartTrk, trkN;
- EPINX_T ep = pathStartEp, ep2;
- BOOL_T go;
- DIST_T dist;
- BOOL_T defined;
-
- profElem_da.cnt = 0;
- station_da.cnt = 0;
- dist = 0;
- defined = TRUE;
- if (PathListEmpty())
- return;
- ChkElev( trk, ep, ep, dist, &defined );
- if (PathListSingle())
- return;
- go = TRUE;
- while ( go ) {
- if (trk == pathEndTrk) {
- go = FALSE;
- ep2 = pathEndEp;
- } else {
- ep2 = GetNextTrkOnPath( trk, ep );
- PASSERT( "computeProfElem", ep2 >= 0, NOP );
- }
- dist += GetTrkLength( trk, ep, ep2 );
- ChkElev( trk, ep2, ep, dist, &defined );
- if (!go)
- break;
- trkN = GetTrkEndTrk(trk,ep2);
- ep = GetEndPtConnectedToMe(trkN,trk);
- trk = trkN;
- }
+ track_p trk = pathStartTrk, trkN;
+ EPINX_T ep = pathStartEp, ep2;
+ BOOL_T go;
+ DIST_T dist;
+ BOOL_T defined;
+
+ profElem_da.cnt = 0;
+ station_da.cnt = 0;
+ dist = 0;
+ defined = TRUE;
+ if (PathListEmpty()) {
+ return;
+ }
+ ChkElev(trk, ep, ep, dist, &defined);
+ if (PathListSingle()) {
+ return;
+ }
+ go = TRUE;
+ while (go) {
+ if (trk == pathEndTrk) {
+ go = FALSE;
+ ep2 = pathEndEp;
+ } else {
+ ep2 = GetNextTrkOnPath(trk, ep);
+ //PASSERT( "computeProfElem", ep2 >= 0, NOP );
+ }
+ dist += GetTrkLength(trk, ep, ep2);
+ ChkElev(trk, ep2, ep, dist, &defined);
+ if (!go) {
+ break;
+ }
+ trkN = GetTrkEndTrk(trk,ep2);
+ ep = GetEndPtConnectedToMe(trkN,trk);
+ trk = trkN;
+ }
}
-static void DumpProfElems( void )
+static void DumpProfElems(void)
{
- track_p trk, trkN;
- EPINX_T ep, ep2;
- BOOL_T go;
-
- trk = pathStartTrk;
- ep = pathStartEp;
-
- if (pathStartTrk==NULL) lprintf( "s--:- e--:-" );
- else if (pathEndTrk == NULL) lprintf( "sT%d:%d e--:-", GetTrkIndex(pathStartTrk), pathStartEp );
- else lprintf( "sT%d:%d eT%d:%d", GetTrkIndex(pathStartTrk), pathStartEp, GetTrkIndex(pathEndTrk), pathEndEp );
- lprintf( " { " );
- go = TRUE;
- if (!PathListSingle())
- while ( trk ) {
- if (trk==pathEndTrk) {
- ep2 = pathEndEp;
- go = FALSE;
- } else {
- ep2 = GetNextTrkOnPath( trk, ep );
- PASSERT( "computeProfElem", ep2 >= 0, NOP );
- }
- lprintf( "T%d:%d:%d ", GetTrkIndex(trk), ep, ep2 );
- if (!go)
- break;
- trkN = GetTrkEndTrk(trk,ep2);
- ep = GetEndPtConnectedToMe(trkN,trk);
- trk = trkN;
- }
- lprintf( "}" );
+ track_p trk, trkN;
+ EPINX_T ep;
+ BOOL_T go;
+
+ trk = pathStartTrk;
+ ep = pathStartEp;
+
+ if (pathStartTrk==NULL) {
+ lprintf("s--:- e--:-");
+ } else if (pathEndTrk == NULL) {
+ lprintf("sT%d:%d e--:-", GetTrkIndex(pathStartTrk), pathStartEp);
+ } else {
+ lprintf("sT%d:%d eT%d:%d", GetTrkIndex(pathStartTrk), pathStartEp,
+ GetTrkIndex(pathEndTrk), pathEndEp);
+ }
+ lprintf(" { ");
+ go = TRUE;
+ if (!PathListSingle())
+ while (trk) {
+ EPINX_T ep2;
+ if (trk==pathEndTrk) {
+ ep2 = pathEndEp;
+ go = FALSE;
+ } else {
+ ep2 = GetNextTrkOnPath(trk, ep);
+ PASSERT("computeProfElem", ep2 >= 0, NOP);
+ }
+ lprintf("T%d:%d:%d ", GetTrkIndex(trk), ep, ep2);
+ if (!go) {
+ break;
+ }
+ trkN = GetTrkEndTrk(trk,ep2);
+ ep = GetEndPtConnectedToMe(trkN,trk);
+ trk = trkN;
+ }
+ lprintf("}");
}
-static void ProfileSelect( track_p trkN, EPINX_T epN )
+static void ProfileSelect(track_p trkN, EPINX_T epN)
{
- track_p trkP;
- EPINX_T epP=-1;
- int rc;
-
-if (log_profile>=1) {
- DumpProfElems();
- lprintf( " @ T%d:%d ", GetTrkIndex(trkN), epN );
- if (log_profile>=2) lprintf("\n");
- }
-
-#ifdef LATER
- if (!EndPtIsDefinedElev(trkN, epN)) {
- ErrorMessage( MSG_EP_NOT_DEP );
- return;
- }
-#endif
-
- trkP = GetTrkEndTrk( trkN, epN );
- if (trkP)
- epP = GetEndPtConnectedToMe( trkP, trkN );
-
- if (!PathListCheck())
- return;
-
- HilightProfileElevations( FALSE );
-
- if ( PathListEmpty() ) {
- pathStartTrk = trkN;
- pathStartEp = epN;
- pathEndTrk = trkP;
- pathEndEp = epP;
-LOG( log_profile, 2, ("Adding first element\n") )
-
- } else if ( PathListSingle() &&
- ( ( trkN == pathStartTrk && epN == pathStartEp ) ||
- ( trkP && trkP == pathStartTrk && epP == pathStartEp ) ) ) {
- pathStartTrk = pathEndTrk = NULL;
-LOG( log_profile, 2, ("Clearing list\n") )
-
- } else if ( (trkN == pathStartTrk && epN == pathStartEp ) ||
- (trkP && trkP == pathStartTrk && epP == pathStartEp) ) {
- RemoveTracksFromPath( &pathStartTrk, &pathStartEp, pathEndTrk, pathEndEp );
-LOG( log_profile, 2, ("Removing first element\n") )
-
- } else if ( (trkN == pathEndTrk && epN == pathEndEp) ||
- (trkP && trkP == pathEndTrk && epP == pathEndEp) ) {
- RemoveTracksFromPath( &pathEndTrk, &pathEndEp, pathStartTrk, pathStartEp );
-LOG( log_profile, 2, ("Removing last element\n") )
-
- } else if ( (GetTrkBits(trkN)&TB_PROFILEPATH) || (trkP && (GetTrkBits(trkP)&TB_PROFILEPATH)) ) {
- ErrorMessage( MSG_EP_ON_PATH );
- HilightProfileElevations( TRUE );
- return;
-
- } else if ( ( rc = FindProfileShortestPath( trkN, epN ) ) > 0 ) {
- if (!(GetTrkBits(trkN)&TB_PROFILEPATH)) {
- PASSERT( "profileSelect", trkP != NULL, NOP );
- trkN = trkP;
- epN = epP;
-LOG( log_profile, 2, ("Invert selected EP\n") )
- }
-
- switch (profileShortestPathMatch) {
- case 1:
- /* extend Start */
- pathStartTrk = trkN;
- pathStartEp = epN;
-LOG( log_profile, 2, ( "Prepending Path\n" ) )
- break;
- case 2:
- /* extend End */
- pathEndTrk = trkN;
- pathEndEp = epN;
-LOG( log_profile, 2, ( "Appending Path\n" ) )
- break;
- case 3:
- /* need to flip */
- pathStartTrk = pathEndTrk;
- pathStartEp = pathEndEp;
- pathEndTrk = trkN;
- pathEndEp = epN;
-LOG( log_profile, 2, ( "Flip/Appending Path\n" ) )
- break;
- default:
- AbortProg( "findPaths:1" );
- }
-
- } else {
- ErrorMessage( MSG_NO_PATH_TO_EP );
- HilightProfileElevations( TRUE );
- return;
- }
-
- HilightProfileElevations( TRUE );
- ComputeProfElem();
- RedrawProfileW();
- DoProfileChangeMode( NULL );
-if (log_profile>=1) {
- lprintf( " = " );
- DumpProfElems();
- lprintf( "\n" );
- }
- PathListCheck();
+ track_p trkP;
+ EPINX_T epP=-1;
+ int rc;
+
+ if (log_profile>=1) {
+ DumpProfElems();
+ lprintf(" @ T%d:%d ", GetTrkIndex(trkN), epN);
+ if (log_profile>=2) {
+ lprintf("\n");
+ }
+ }
+
+ trkP = GetTrkEndTrk(trkN, epN);
+ if (trkP) {
+ epP = GetEndPtConnectedToMe(trkP, trkN);
+ }
+
+ if (!PathListCheck()) {
+ return;
+ }
+
+ if (PathListEmpty()) {
+ pathStartTrk = trkN;
+ pathStartEp = epN;
+ pathEndTrk = trkP;
+ pathEndEp = epP;
+ LOG(log_profile, 2, ("Adding first element\n"))
+
+ } else if (PathListSingle() &&
+ ((trkN == pathStartTrk && epN == pathStartEp) ||
+ (trkP && trkP == pathStartTrk && epP == pathStartEp))) {
+ pathStartTrk = pathEndTrk = NULL;
+ LOG(log_profile, 2, ("Clearing list\n"))
+
+ } else if ((trkN == pathStartTrk && epN == pathStartEp) ||
+ (trkP && trkP == pathStartTrk && epP == pathStartEp)) {
+ RemoveTracksFromPath(&pathStartTrk, &pathStartEp, pathEndTrk, pathEndEp);
+ LOG(log_profile, 2, ("Removing first element\n"))
+
+ } else if ((trkN == pathEndTrk && epN == pathEndEp) ||
+ (trkP && trkP == pathEndTrk && epP == pathEndEp)) {
+ RemoveTracksFromPath(&pathEndTrk, &pathEndEp, pathStartTrk, pathStartEp);
+ LOG(log_profile, 2, ("Removing last element\n"))
+
+ } else if ((GetTrkBits(trkN)&TB_PROFILEPATH) || (trkP &&
+ (GetTrkBits(trkP)&TB_PROFILEPATH))) {
+ ErrorMessage(MSG_EP_ON_PATH);
+ return;
+
+ } else if ((rc = FindProfileShortestPath(trkN, epN)) > 0) {
+ if (!(GetTrkBits(trkN)&TB_PROFILEPATH)) {
+ PASSERT("profileSelect", trkP != NULL, NOP);
+ trkN = trkP;
+ epN = epP;
+ LOG(log_profile, 2, ("Invert selected EP\n"))
+ }
+
+ switch (profileShortestPathMatch) {
+ case 1:
+ /* extend Start */
+ pathStartTrk = trkN;
+ pathStartEp = epN;
+ LOG(log_profile, 2, ("Prepending Path\n"))
+ break;
+ case 2:
+ /* extend End */
+ pathEndTrk = trkN;
+ pathEndEp = epN;
+ LOG(log_profile, 2, ("Appending Path\n"))
+ break;
+ case 3:
+ /* need to flip */
+ pathStartTrk = pathEndTrk;
+ pathStartEp = pathEndEp;
+ pathEndTrk = trkN;
+ pathEndEp = epN;
+ LOG(log_profile, 2, ("Flip/Appending Path\n"))
+ break;
+ default:
+ AbortProg("findPaths:1");
+ }
+
+ } else {
+ ErrorMessage(MSG_NO_PATH_TO_EP);
+ return;
+ }
+
+ DestroyCopyOfProfileElements();
+ ComputeProfElem();
+ CreateCopyProfileElements();
+
+ RedrawProfileW();
+ DoProfileChangeMode(NULL);
+ if (log_profile>=1) {
+ lprintf(" = ");
+ DumpProfElems();
+ lprintf("\n");
+ }
+ PathListCheck();
}
-static void ProfileSubCommand( wBool_t set, void* pcmd )
+static void ProfileSubCommand(wBool_t set, void* pcmd)
{
- long cmd = (long)pcmd;
- int mode;
- coOrd pos = oldMarker;
- DIST_T elev;
- DIST_T radius;
-
- if ((profilePopupTrk = OnTrack( &pos, TRUE, TRUE )) == NULL ||
- (profilePopupEp = PickEndPoint( pos, profilePopupTrk )) < 0)
- return;
- if (profileUndo==0) {
- profileUndo = TRUE;
- UndoStart(_("Profile Command"), "Profile");
- }
- radius = 0.05*mainD.scale;
- if ( radius < trackGauge/2.0 )
- radius = trackGauge/2.0;
- pos = GetTrkEndPos( profilePopupTrk, profilePopupEp );
- mode = GetTrkEndElevMode( profilePopupTrk, profilePopupEp );
- if ( (mode&ELEV_MASK)==ELEV_DEF || (mode&ELEV_MASK)==ELEV_IGNORE )
- DrawFillCircle( &tempD, pos, radius,
- ((mode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore));
- if ( (mode&ELEV_MASK)==ELEV_DEF )
-
- DrawEndPt2( &mainD, profilePopupTrk, profilePopupEp, drawColorWhite );
- elev = 0.0;
- switch (cmd) {
- case 0:
- /* define */
- ComputeElev( profilePopupTrk, profilePopupEp, TRUE, &elev, NULL );
- mode = ELEV_DEF|ELEV_VISIBLE;
- break;
- case 1:
- /* ignore */
- mode = ELEV_IGNORE|ELEV_VISIBLE;
- break;
- case 2:
- default:
- /* none */
- mode = ELEV_NONE;
- break;
- }
- UpdateTrkEndElev( profilePopupTrk, profilePopupEp, mode, elev, NULL );
- if ( (mode&ELEV_MASK)==ELEV_DEF || (mode&ELEV_MASK)==ELEV_IGNORE )
- DrawFillCircle( &tempD, pos, radius,
- ((mode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore));
- ComputeProfElem();
- RedrawProfileW();
+ long cmd = (long)pcmd;
+ int mode;
+ coOrd pos = oldMarker;
+ DIST_T elev;
+ DIST_T radius;
+
+ if ((profilePopupTrk = OnTrack(&pos, TRUE, TRUE)) == NULL ||
+ (profilePopupEp = PickEndPoint(pos, profilePopupTrk)) < 0) {
+ return;
+ }
+ if (profileUndo==0) {
+ profileUndo = TRUE;
+ UndoStart(_("Profile Command"), "Profile");
+ }
+ radius = 0.05*mainD.scale;
+ if (radius < trackGauge/2.0) {
+ radius = trackGauge/2.0;
+ }
+ pos = GetTrkEndPos(profilePopupTrk, profilePopupEp);
+ mode = GetTrkEndElevMode(profilePopupTrk, profilePopupEp);
+
+ elev = 0.0;
+ switch (cmd) {
+ case 0:
+ /* define */
+ ComputeElev(profilePopupTrk, profilePopupEp, TRUE, &elev, NULL, TRUE);
+ mode = ELEV_DEF|ELEV_VISIBLE;
+ break;
+ case 1:
+ /* ignore */
+ mode = ELEV_IGNORE|ELEV_VISIBLE;
+ break;
+ case 2:
+ default:
+ /* none */
+ mode = ELEV_NONE;
+ break;
+ }
+ UpdateTrkEndElev(profilePopupTrk, profilePopupEp, mode, elev, NULL);
+ ComputeProfElem();
+ RedrawProfileW();
+ TempRedraw(); // ProfileSubCommand
}
-static STATUS_T CmdProfile( wAction_t action, coOrd pos )
+static STATUS_T CmdProfile(wAction_t action, coOrd pos)
{
- track_p trk0;
- EPINX_T ep0;
- coOrd textsize;
-
- switch (action) {
- case C_START:
- if ( profileW == NULL ) {
- profileColorDefinedProfile = drawColorBlue;
- profileColorUndefinedProfile = drawColorRed;
- profileColorFill = drawColorAqua;
- DrawTextSize( &mainD, "999", wStandardFont( F_HELV, FALSE, FALSE ), screenProfileFontSize, FALSE, &textsize );
- labelH = textsize.y;
- profileW = ParamCreateDialog( &profilePG, MakeWindowTitle(_("Profile")), _("Done"), DoProfileDone, (paramActionCancelProc)Reset, TRUE, NULL, F_RESIZE, NULL );
- }
- ParamLoadControls( &profilePG );
- ParamGroupRecord( &profilePG );
- wShow( profileW );
- ParamLoadMessage( &profilePG, I_PROFILEMSG, _("Drag to change Elevation") );
- HilightProfileElevations( TRUE );
- profElem_da.cnt = 0;
- station_da.cnt = 0;
- RedrawProfileW();
- if ( ClrAllTrkBits( TB_PROFILEPATH ) ) {
- MainRedraw();
- MapRedraw();
- }
- pathStartTrk = NULL;
- SetAllTrackSelect( FALSE );
- profileUndo = FALSE;
- InfoMessage( _("Select a Defined Elevation to start profile") );
- return C_CONTINUE;
- case C_LCLICK:
- InfoMessage( "" );
- if ((trk0 = OnTrack( &pos, TRUE, TRUE )) != NULL) {
- ep0 = PickEndPoint( pos, trk0 );
- if ( ep0 >= 0 ) {
- ProfileSelect( trk0, ep0 );
- }
- }
- return C_CONTINUE;
- case C_CMDMENU:
- if ((profilePopupTrk = OnTrack( &pos, TRUE, TRUE )) != NULL ) {
- profilePopupEp = PickEndPoint( pos, profilePopupTrk );
- if (profilePopupEp >= 0) {
- int mode;
- mode = GetTrkEndElevMode( profilePopupTrk, profilePopupEp );
- if (mode != ELEV_DEF && mode != ELEV_IGNORE && mode != ELEV_NONE ) {
- ErrorMessage( MSG_CHANGE_ELEV_MODE );
- } else {
- wMenuToggleEnable( profilePopupToggles[1], TRUE );
- if ( OnPath( profilePopupTrk, profilePopupEp ) & (ONPATH_END|ONPATH_MID) )
- wMenuToggleEnable( profilePopupToggles[1], FALSE );
- wMenuToggleSet( profilePopupToggles[0], mode == ELEV_DEF );
- wMenuToggleSet( profilePopupToggles[1], mode == ELEV_IGNORE );
- wMenuToggleSet( profilePopupToggles[2], mode == ELEV_NONE );
- wMenuPopupShow( profilePopupM );
- }
- }
- }
-#ifdef LATER
- InfoMessage( "" );
- if ((trk0 = OnTrack( &pos, TRUE, TRUE )) == NULL)
- return C_CONTINUE;
- ep0 = PickEndPoint( pos, trk0 );
- if (ep0 < 0)
- return C_CONTINUE;
- if (profileMode == 0) {
- ;
- } else {
- ProfileIgnore( trk0, ep0 );
- }
- DoProfileChangeMode( NULL );
-#endif
- return C_CONTINUE;
- case C_OK:
- DoProfileDone(NULL);
- return C_TERMINATE;
- case C_CANCEL:
- wHide(profileW);
- HilightProfileElevations( FALSE );
- if (ClrAllTrkBits(TB_PROFILEPATH)) {
- MainRedraw();
- MapRedraw();
- }
- return C_TERMINATE;
- case C_REDRAW:
- if ( wWinIsVisible(profileW) ) {
- HilightProfileElevations( wWinIsVisible(profileW) );
- /*RedrawProfileW();*/
- }
- return C_CONTINUE;
- }
- return C_CONTINUE;
+ track_p trk0;
+ coOrd textsize;
+
+ switch (action) {
+ case C_START:
+ if (profileW == NULL) {
+ profileColorDefinedProfile = drawColorBlue;
+ profileColorUndefinedProfile = drawColorRed;
+ profileColorFill = drawColorGrey80;
+ DrawTextSize(&mainD, "999.9", wStandardFont(F_HELV, FALSE, FALSE),
+ screenProfileFontSize, FALSE, &textsize);
+ labelH = textsize.y;
+ labelW = textsize.x;
+ profileW = ParamCreateDialog(&profilePG, MakeWindowTitle(_("Profile")), NULL,
+ NULL, wHide, TRUE, NULL, F_RESIZE, CloseProfileWindow);
+ }
+ ParamLoadControls(&profilePG);
+ ParamGroupRecord(&profilePG);
+ wShow(profileW);
+ ParamLoadMessage(&profilePG, I_PROFILEMSG, _("Drag to change Elevation"));
+ profElem_da.cnt = 0;
+ station_da.cnt = 0;
+ RedrawProfileW();
+ ClrAllTrkBitsRedraw(TB_PROFILEPATH, TRUE);
+ pathStartTrk = NULL;
+ SetAllTrackSelect(FALSE);
+ profileUndo = FALSE;
+ InfoMessage(_("Select a Defined Elevation to start profile"));
+ TempRedraw(); // CmdProfile C_START
+ return C_CONTINUE;
+ case C_LCLICK:
+ InfoMessage("");
+ if ((trk0 = OnTrack(&pos, TRUE, TRUE)) != NULL) {
+ EPINX_T ep0;
+ ep0 = PickEndPoint(pos, trk0);
+ if (ep0 >= 0) {
+ ProfileSelect(trk0, ep0);
+ }
+ }
+ return C_CONTINUE;
+ case C_CMDMENU:
+ if ((profilePopupTrk = OnTrack(&pos, TRUE, TRUE)) != NULL) {
+ profilePopupEp = PickEndPoint(pos, profilePopupTrk);
+ if (profilePopupEp >= 0) {
+ int mode;
+ mode = GetTrkEndElevMode(profilePopupTrk, profilePopupEp);
+ if (mode != ELEV_DEF && mode != ELEV_IGNORE && mode != ELEV_NONE) {
+ ErrorMessage(MSG_CHANGE_ELEV_MODE);
+ } else {
+ wMenuToggleEnable(profilePopupToggles[1], TRUE);
+ if (OnPath(profilePopupTrk, profilePopupEp) & (ONPATH_END|ONPATH_MID)) {
+ wMenuToggleEnable(profilePopupToggles[1], FALSE);
+ }
+ wMenuToggleSet(profilePopupToggles[0], mode == ELEV_DEF);
+ wMenuToggleSet(profilePopupToggles[1], mode == ELEV_IGNORE);
+ wMenuToggleSet(profilePopupToggles[2], mode == ELEV_NONE);
+ menuPos = pos;
+ wMenuPopupShow(profilePopupM);
+ }
+ }
+ }
+ return C_CONTINUE;
+ case C_OK:
+ DoProfileDone(NULL);
+ return C_TERMINATE;
+ case C_CANCEL:
+ wHide(profileW);
+ ClrAllTrkBitsRedraw(TB_PROFILEPATH, TRUE);
+ return C_TERMINATE;
+ case C_REDRAW:
+ if (wWinIsVisible(profileW)) {
+ HilightProfileElevations(wWinIsVisible(profileW));
+ }
+ return C_CONTINUE;
+ }
+ return C_CONTINUE;
}
-static void ProfileChange( long changes )
+static void ProfileChange(long changes)
{
- if ( (changes & CHANGE_UNITS) && screenProfileD.d )
- RedrawProfileW();
+ if ((changes & CHANGE_UNITS) && screenProfileD.d) {
+ RedrawProfileW();
+ }
}
-
#include "bitmaps/profile.xpm"
-EXPORT void InitCmdProfile( wMenu_p menu )
+EXPORT void InitCmdProfile(wMenu_p menu)
{
- log_profile = LogFindIndex( "profile" );
- ParamRegister( &profilePG );
-#ifdef LATER
- AddPlaybackProc( "PROFILEMOUSE", (playbackProc_p)profilePlayback, NULL );
-#endif
- AddMenuButton( menu, CmdProfile, "cmdProfile", _("Profile"), wIconCreatePixMap(profile_xpm), LEVEL0_50, IC_LCLICK|IC_CMDMENU|IC_POPUP2, ACCL_PROFILE, NULL );
- profilePopupM = MenuRegister( "Profile Mode" );
- profilePopupToggles[0] = wMenuToggleCreate( profilePopupM, "", _("Define"), 0, FALSE, ProfileSubCommand, (void*)0 );
- profilePopupToggles[1] = wMenuToggleCreate( profilePopupM, "", _("Ignore"), 0, FALSE, ProfileSubCommand, (void*)1 );
- profilePopupToggles[2] = wMenuToggleCreate( profilePopupM, "", _("None"), 0, FALSE, ProfileSubCommand, (void*)2 );
- RegisterChangeNotification( ProfileChange );
+ log_profile = LogFindIndex("profile");
+ ParamRegister(&profilePG);
+
+ AddMenuButton(menu, CmdProfile, "cmdProfile", _("Profile"),
+ wIconCreatePixMap(profile_xpm), LEVEL0_50, IC_LCLICK|IC_CMDMENU|IC_POPUP3,
+ ACCL_PROFILE, NULL);
+ profilePopupM = MenuRegister("Profile Mode");
+ profilePopupToggles[0] = wMenuToggleCreate(profilePopupM, "", _("Define"), 0,
+ FALSE, ProfileSubCommand, (void*)0);
+ profilePopupToggles[1] = wMenuToggleCreate(profilePopupM, "", _("Ignore"), 0,
+ FALSE, ProfileSubCommand, (void*)1);
+ profilePopupToggles[2] = wMenuToggleCreate(profilePopupM, "", _("None"), 0,
+ FALSE, ProfileSubCommand, (void*)2);
+ RegisterChangeNotification(ProfileChange);
}
diff --git a/app/bin/cpull.c b/app/bin/cpull.c
index d7f7c80..7f27864 100644
--- a/app/bin/cpull.c
+++ b/app/bin/cpull.c
@@ -60,6 +60,9 @@ static dynArr_t section_da;
#define section(N) DYNARR_N( section_t, section_da, N )
static double contribL, contribR;
+static dynArr_t anchors_da;
+#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N)
+
typedef enum { freeEnd, connectedEnd, loopEnd } ending_e;
@@ -452,12 +455,15 @@ static void PullTracks(
int cnt1, cnt2;
int rc;
- if (QueryTrack(trk1,Q_CAN_ADD_ENDPOINTS) || QueryTrack(trk2,Q_CAN_ADD_ENDPOINTS)) {
+ if (QueryTrack(trk1,Q_CAN_ADD_ENDPOINTS)) {
ConnectTurntableTracks(trk1, ep1, trk2, ep2 );
return;
+ } else if (QueryTrack(trk2,Q_CAN_ADD_ENDPOINTS)) {
+ ConnectTurntableTracks(trk2, ep2, trk1, ep1 );
+ return;
}
- if (ep1<0 || ep1<0 ) return;
+ if (ep1<0 || ep2<0 ) return;
if (ConnectAbuttingTracks( trk1, ep1, trk2, ep2 ))
return;
@@ -589,57 +595,202 @@ printf("T%d [%0.3f %0.3f %0.3f]\n", GetTrkIndex(trk1), p1.x, p1.y, a1 );
InfoMessage( _("%d tracks moved"), cnt );
}
+static void CreateConnectAnchor(EPINX_T ep, track_p t, BOOL_T shift) {
+ coOrd pos = GetTrkEndPos(t,ep);
+ DIST_T d = tempD.scale*0.15;
+ DIST_T w = tempD.scale/tempD.dpi*4;
+ ANGLE_T a = GetTrkEndAngle(t,ep);
+ int i;
+ if (!shift) {
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).color = wDrawColorBlue;
+ anchors(i).u.l.pos[0] = pos;
+ Translate(&anchors(i).u.l.pos[1],pos,a+90,-GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a,-d);
+ anchors(i).width = w;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).color = wDrawColorBlue;
+ anchors(i).u.l.pos[0] = pos;
+ Translate(&anchors(i).u.l.pos[1],pos,a+90,GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a,-d);
+ anchors(i).width = w;
+ } else {
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).color = wDrawColorBlue;
+ Translate(&anchors(i).u.l.pos[0],pos,a+90,GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[0],anchors(i).u.l.pos[0],a,d);
+ Translate(&anchors(i).u.l.pos[1],pos,a+90,-GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a,-d);
+ anchors(i).width = w;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).color = wDrawColorBlue;
+ Translate(&anchors(i).u.l.pos[0],pos,a+90,GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[0],anchors(i).u.l.pos[0],a,-d);
+ Translate(&anchors(i).u.l.pos[1],pos,a+90,-GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a,d);
+ anchors(i).width = w;
+ }
+}
+
+STATUS_T ConnectMultiple() {
+ int countTracksR0 =0,countTracksR1 =0, possibleEndPoints =0;
+ if (selectedTrackCount==0) {
+ ErrorMessage(_("Connect Multiple Tracks - Select multiple tracks to join first"));
+ return C_CONTINUE;
+ }
+ if (NoticeMessage(_("Try to Connect all Selected Tracks?"), _("Yes"), _("No"))<=0) return C_CONTINUE;
+ track_p trk1 = NULL;
+ track_p trk2 = NULL;
+ EPINX_T ep1,ep2;
+ ANGLE_T a;
+ DIST_T d;
+ UndoStart( _("ReConnect"),"Try to reconnect all selected tracks");
+ for (int i=0;i<2;i++) { // Try twice - in case later joins help earlier ones and to try close ones first
+ while ( TrackIterate( &trk1 ) ) {
+ BOOL_T found = FALSE;
+ if ( GetTrkSelected( trk1 ) ) {
+ for (ep1=0; ep1<GetTrkEndPtCnt(trk1); ep1++) {
+ if (!GetTrkEndTrk( trk1, ep1 )) {
+ trk2 = NULL;
+ while (!found && TrackIterate(&trk2) ) {
+ if (trk1 == trk2) continue;
+ for (ep2=0; ep2<GetTrkEndPtCnt(trk2); ep2++) {
+ if (GetTrkEndTrk( trk2, ep2 )) continue;
+ d = FindDistance(GetTrkEndPos(trk1,ep1),GetTrkEndPos(trk2,ep2));
+ a = NormalizeAngle( 180+GetTrkEndAngle( trk1, ep1 ) - GetTrkEndAngle( trk2, ep2 )+(connectAngle/2.0));
+ // Take two passes. In round one favor closer connections. In round two try anything.
+ if ( (i==0 && (d < connectDistance) && (a < connectAngle)) ||
+ (i>0 && (d<3.0 && a<7.5))) { // Match PullTracks criteria in round 2
+ PullTracks(trk1,ep1,trk2,ep2);
+ if (GetTrkEndTrk( trk2, ep2 )) {
+ found = TRUE;
+ if (i==0)
+ countTracksR0++;
+ else
+ countTracksR1++;
+ break; //Stop looking
+ } else if (i==1) possibleEndPoints++;
+ }
+ }
+ }
+ if (found) break; //Next EndPoint
+ }
+ }
+ }
+ }
+ }
+ UndoEnd();
+ NoticeMessage(_("Round 1 %d and Round 2 %d tracks connected, %d close pairs of end Points were not connected"), _("Ok"), NULL, countTracksR0, countTracksR1, possibleEndPoints);
+ return C_TERMINATE;
+}
+
+static wMenu_p pullPopupM;
static STATUS_T CmdPull(
wAction_t action,
coOrd pos )
{
- static track_p trk1;
- static EPINX_T ep1;
+ static track_p trk1, t1, t2;
+ static BOOL_T t_turn1, t_turn2;
+ static EPINX_T ep1, t_ep1, t_ep2;
track_p trk2;
EPINX_T ep2;
static BOOL_T turntable;
int countTracksR0 = 0, countTracksR1 = 0, possibleEndPoints = 0;
BOOL_T found = FALSE;
- ANGLE_T a;
- DIST_T d;
- switch (action) {
+ switch (action&0xFF) {
case C_START:
if (selectedTrackCount==0)
- InfoMessage( _("Select first end-point to connect") );
+ InfoMessage( _("Select first endpoint or turntable to connect, +Shift to tighten") );
else
- InfoMessage( _("Select first end-point to connect, or Right-Click for connecting selected tracks") );
+ InfoMessage( _("Select first endpoint to connect, or Right-Click for connecting selected tracks (not turntable)") );
trk1 = NULL;
turntable = FALSE;
+ t1 = t2 = NULL;
+ t_turn1 = t_turn2 = FALSE;
return C_CONTINUE;
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if ((MyGetKeyState() & WKEY_SHIFT) == 0 ) {
+ if (trk1 == NULL) {
+ if ((t1= OnTrack( &pos, FALSE, TRUE )) != NULL) {
+ if ((t_ep1 = PickUnconnectedEndPointSilent( pos, t1 )) < 0) {
+ if (QueryTrack(t1, Q_CAN_ADD_ENDPOINTS)) {
+ DrawTrack(t1,&mainD,wDrawColorBlue);
+ t_turn1 = TRUE;
+ } else t1 = NULL;
+ }
+ if (t1 && t_ep1 >=0)
+ CreateConnectAnchor(t_ep1,t1,FALSE);
+ }
+ } else {
+ if (t1 != NULL) {
+ if (t_turn1) DrawTrack(t1,&mainD,wDrawColorBlue);
+ else CreateConnectAnchor(t_ep1,t1,FALSE);
+ }
+ if ((t2= OnTrackIgnore( &pos, FALSE, TRUE, t1 )) != NULL) {
+ if ((t_ep2 = PickUnconnectedEndPointSilent( pos, t2 )) < 0) {
+ if (QueryTrack(t2, Q_CAN_ADD_ENDPOINTS)) {
+ DrawTrack(t2,&mainD,wDrawColorBlue);
+ t_turn2 = TRUE;
+ } else t2 = NULL;
+ }
+ if (t2 && t_ep2 >=0)
+ CreateConnectAnchor(t_ep2,t2,FALSE);
+ }
+
+ }
+ } else { //Shift, tighten
+ t1 = OnTrack( &pos, FALSE, TRUE );
+ if (t1 == NULL)
+ return C_CONTINUE;
+ t_ep1 = PickUnconnectedEndPointSilent( pos, t1 );
+ if ( t_ep1 < 0 )
+ return C_CONTINUE;
+ CreateConnectAnchor(t_ep1,t1,TRUE);
+ }
+ break;
+
case C_LCLICK:
- if ( (MyGetKeyState() & WKEY_SHIFT) == 0 ) {
+ if ( (MyGetKeyState() & WKEY_SHIFT) == 0 ) { //No shift - try and join
if (trk1 == NULL) {
- if ((trk1 = OnTrack( &pos, TRUE, FALSE )) != NULL) {
+ if ((trk1 = OnTrack( &pos, TRUE, TRUE )) != NULL) {
if ((ep1 = PickUnconnectedEndPoint( pos, trk1 )) < 0) {
if (QueryTrack(trk1, Q_CAN_ADD_ENDPOINTS)) {
turntable = TRUE;
ep1 = -1;
} else trk1 = NULL;
} else {
- InfoMessage( _("Select second end-point to connect") );
+ InfoMessage( _("Select second endpoint or turntable to connect") );
}
}
} else {
- if ((trk2 = OnTrack( &pos, TRUE, FALSE )) != NULL) {
+ if ((trk2 = OnTrackIgnore( &pos, TRUE, TRUE, trk1 )) != NULL) {
+ if (trk2 == trk1) {
+ InfoMessage( _("Same Track! - please select another") );
+ return C_CONTINUE;
+ }
if ((ep2 = PickUnconnectedEndPoint( pos, trk2 )) >= 0 ) {
PullTracks( trk1, ep1, trk2, ep2 );
trk1 = NULL;
inError = TRUE;
return C_TERMINATE;
}
- if (!turntable && QueryTrack(trk2, Q_CAN_ADD_ENDPOINTS)) {
+ if (!turntable && QueryTrack(trk2, Q_CAN_ADD_ENDPOINTS)) { /*Second end a turntable */
ep2 = -1;
turntable = TRUE;
PullTracks( trk2, ep2, trk1, ep1);
@@ -651,7 +802,7 @@ static STATUS_T CmdPull(
}
}
} else {
- trk1 = OnTrack( &pos, TRUE, FALSE );
+ trk1 = OnTrack( &pos, TRUE, TRUE );
if (trk1 == NULL)
return C_CONTINUE;
ep1 = PickUnconnectedEndPoint( pos, trk1 );
@@ -664,56 +815,23 @@ static STATUS_T CmdPull(
}
return C_CONTINUE;
- case C_RCLICK:
- if (selectedTrackCount==0) {
- ErrorMessage(_("Connect Multiple Tracks - Select multiple tracks to join first"));
- return C_CONTINUE;
- }
- if (NoticeMessage(_("Try to Connect all Selected Tracks?"), _("Yes"), _("No"))<=0) return C_CONTINUE;
- trk1 = NULL;
- trk2 = NULL;
- UndoStart( _("ReConnect"),"Try to reconnect all selected tracks");
- for (int i=0;i<2;i++) { // Try twice - in case later joins help earlier ones and to try close ones first
- while ( TrackIterate( &trk1 ) ) {
- found = FALSE;
- if ( GetTrkSelected( trk1 ) ) {
- for (ep1=0; ep1<GetTrkEndPtCnt(trk1); ep1++) {
- if (!GetTrkEndTrk( trk1, ep1 )) {
- trk2 = NULL;
- while (!found && TrackIterate(&trk2) ) {
- if (trk1 == trk2) continue;
- for (ep2=0; ep2<GetTrkEndPtCnt(trk2); ep2++) {
- if (GetTrkEndTrk( trk2, ep2 )) continue;
- d = FindDistance(GetTrkEndPos(trk1,ep1),GetTrkEndPos(trk2,ep2));
- a = NormalizeAngle( 180+GetTrkEndAngle( trk1, ep1 ) - GetTrkEndAngle( trk2, ep2 )+(connectAngle/2.0));
- // Take two passes. In round one favor closer connections. In round two try anything.
- if ( (i==0 && (d < connectDistance) && (a < connectAngle)) ||
- (i>0 && (d<3.0 && a<7.5))) { // Match PullTracks criteria in round 2
- PullTracks(trk1,ep1,trk2,ep2);
- if (GetTrkEndTrk( trk2, ep2 )) {
- found = TRUE;
- if (i==0)
- countTracksR0++;
- else
- countTracksR1++;
- break; //Stop looking
- } else if (i==1) possibleEndPoints++;
- }
- }
- }
- if (found) break; //Next EndPoint
- }
- }
- }
- }
- }
- UndoEnd();
- NoticeMessage(_("Round 1 %d and Round 2 %d tracks connected, %d close pairs of end Points were not connected"), _("Ok"), NULL, countTracksR0, countTracksR1, possibleEndPoints);
- return C_TERMINATE;
-
case C_REDRAW:
+ if (anchors_da.cnt)
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ if (t1 && t_turn1)
+ DrawTrack(t1,&tempD,wDrawColorBlue);
+ if (t2 && t_turn2)
+ DrawTrack(t2,&tempD,wDrawColorBlue);
return C_CONTINUE;
+ case C_TEXT:
+ if (action>>8 == 'S') {
+ wBool_t rc = ConnectMultiple();
+ MainRedraw(); // CmdPull: ConnectMultiple
+ return rc;
+ }
+ break;
+
case C_CANCEL:
return C_TERMINATE;
@@ -723,16 +841,35 @@ static STATUS_T CmdPull(
case C_CONFIRM:
return C_CONTINUE;
+ case C_CMDMENU:
+ menuPos = pos;
+ wMenuPopupShow( pullPopupM );
+ return C_CONTINUE;
+ break;
+
+
default:
return C_CONTINUE;
}
+ return C_CONTINUE;
}
#include "bitmaps/pull.xpm"
+wMenuPush_p pullConnectMultiple;
+
+void pullMenuEnter(int key) {
+ int action;
+ action = C_TEXT;
+ action |= key<<8;
+ CmdPull(action,zero);
+}
+
void InitCmdPull( wMenu_p menu )
{
- AddMenuButton( menu, CmdPull, "cmdConnect", _("Connect Two Tracks"), wIconCreatePixMap(pull_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP2|IC_RCLICK, ACCL_CONNECT, NULL );
+ AddMenuButton( menu, CmdPull, "cmdConnect", _("Connect Two Tracks"), wIconCreatePixMap(pull_xpm), LEVEL0_50, IC_STICKY|IC_INITNOTSTICKY|IC_LCLICK|IC_POPUP3|IC_CMDMENU|IC_WANT_MOVE, ACCL_CONNECT, NULL );
+ pullPopupM = MenuRegister( "Connect Options" );
+ pullConnectMultiple = wMenuPushCreate( pullPopupM, "", _("Connect All Selected - 'S'"), 0, (wMenuCallBack_p)pullMenuEnter, (void*) 'S');
}
diff --git a/app/bin/cruler.c b/app/bin/cruler.c
index b1addc6..d3f2926 100644
--- a/app/bin/cruler.c
+++ b/app/bin/cruler.c
@@ -62,43 +62,34 @@ static STATUS_T CmdRuler( wAction_t action, coOrd pos )
case C_START:
switch (Dr.state) {
case DR_OFF:
- DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
Dr.state = DR_ON;
InfoMessage( "%s", FormatDistance( FindDistance( Dr.pos0, Dr.pos1 ) ) );
break;
case DR_ON:
- DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
Dr.state = DR_OFF;
break;
}
- MainRedraw();
return C_CONTINUE;
case C_DOWN:
- if (Dr.state == DR_ON) {
- DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
- }
Dr.pos0 = Dr.pos1 = pos;
Dr.state = DR_ON;
- DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
InfoMessage( "0.0" );
- MainRedraw();
return C_CONTINUE;
case C_MOVE:
- DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
Dr.pos1 = pos;
- DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
InfoMessage( "%s", FormatDistance( FindDistance( Dr.pos0, Dr.pos1 ) ) );
- MainRedraw();
return C_CONTINUE;
case C_UP:
inError = TRUE;
- MainRedraw();
return C_TERMINATE;
case C_REDRAW:
+ if (Dr.state == DR_ON) {
+ DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
+ }
return C_CONTINUE;
case C_CANCEL:
@@ -126,21 +117,22 @@ STATUS_T ModifyRuler(
return C_ERROR;
}
case C_MOVE:
- DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
if ( Dr.modifyingEnd == 0 ) {
Dr.pos0 = pos;
} else {
Dr.pos1 = pos;
}
- DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
InfoMessage( "%s", FormatDistance( FindDistance( Dr.pos0, Dr.pos1 ) ) );
- MainRedraw();
return C_CONTINUE;
case C_UP:
return C_CONTINUE;
+ case C_REDRAW:
+ DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, wDrawColorBlack );
+ break;
default:
return C_ERROR;
}
+ return C_CONTINUE;
}
diff --git a/app/bin/cselect.c b/app/bin/cselect.c
index 8ff68c0..4e4e8eb 100644
--- a/app/bin/cselect.c
+++ b/app/bin/cselect.c
@@ -23,9 +23,11 @@
#include <math.h>
#include <string.h>
+#include "draw.h"
#include "ccurve.h"
#include "tcornu.h"
#include "tbezier.h"
+#include "track.h"
#define PRIVATE_EXTRADATA
#include "compound.h"
#include "cselect.h"
@@ -38,6 +40,10 @@
#include "param.h"
#include "track.h"
#include "utility.h"
+#include "draw.h"
+#include "misc.h"
+#include "trackx.h"
+
#include "bitmaps/bmendpt.xbm"
#include "bitmaps/bma0.xbm"
@@ -59,10 +65,12 @@ struct extraData { char junk[2000]; };
static wDrawBitMap_p endpt_bm;
static wDrawBitMap_p angle_bm[4];
+track_p IsInsideABox(coOrd pos);
- long quickMove = 0;
- BOOL_T importMove = 0;
- int incrementalDrawLimit = 20;
+static track_p moveDescTrk;
+static coOrd moveDescPos;
+
+int incrementalDrawLimit = 20;
static int microCount = 0;
static dynArr_t tlist_da;
@@ -71,12 +79,169 @@ static dynArr_t tlist_da;
#define TlistAppend( T ) \
{ DYNARR_APPEND( track_p, tlist_da, 10 );\
Tlist(tlist_da.cnt-1) = T; }
-static track_p *tlist2 = NULL;
+
+BOOL_T TListSearch(track_p T) {
+ for (int i=0;i<tlist_da.cnt-1;i++) { \
+ if (Tlist(i) == T) return TRUE;
+ }
+ return FALSE;
+}
static wMenu_p selectPopup1M;
+static wMenu_p selectPopup1CM;
static wMenu_p selectPopup2M;
+static wMenu_p selectPopup2CM;
+static wMenu_p selectPopup2RM;
+static wMenu_p selectPopup2TM;
+static wMenu_p selectPopup2TYM;
+static wMenuPush_p menuPushModify;
+static wMenuPush_p rotateAlignMI;
+static wMenuPush_p descriptionMI;
+static wMenuPush_p hideMI;
+static wMenuPush_p bridgeMI;
+static wMenuPush_p tiesMI;
+
+
+static BOOL_T doingAlign = FALSE;
+static enum { AREA, MOVE } mode;
+static void SelectOneTrack(
+ track_p trk,
+ wBool_t selected );
static void DrawSelectedTracksD( drawCmd_p d, wDrawColor color );
+
+static dynArr_t anchors_da;
+#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N)
+
+void CreateArrowAnchor(coOrd pos,ANGLE_T a,DIST_T len) {
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).width = 0;
+ anchors(i).u.l.pos[0] = pos;
+ Translate(&anchors(i).u.l.pos[1],pos,NormalizeAngle(a+135),len);
+ anchors(i).color = wDrawColorBlue;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).width = 0;
+ anchors(i).u.l.pos[0] = pos;
+ Translate(&anchors(i).u.l.pos[1],pos,NormalizeAngle(a-135),len);
+ anchors(i).color = wDrawColorBlue;
+}
+
+void static CreateRotateAnchor(coOrd pos) {
+ DIST_T d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_CRVLIN;
+ anchors(i).width = d/8;
+ anchors(i).u.c.center = pos;
+ anchors(i).u.c.a0 = 180.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).u.c.radius = d*2;
+ anchors(i).color = wDrawColorAqua;
+ coOrd head; //Arrows
+ for (int j=0;j<3;j++) {
+ Translate(&head,pos,j*120,d*2);
+ CreateArrowAnchor(head,NormalizeAngle((j*120)+90),d);
+ }
+}
+
+void static CreateModifyAnchor(coOrd pos) {
+ DIST_T d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_FILCRCL;
+ anchors(i).width = 0;
+ anchors(i).u.c.center = pos;
+ anchors(i).u.c.a0 = 180.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).u.c.radius = d/2;
+ anchors(i).color = wDrawColorPowderedBlue;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_CRVLIN;
+ anchors(i).width = 0;
+ anchors(i).u.c.center = pos;
+ anchors(i).u.c.a0 = 180.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).u.c.radius = d;
+ anchors(i).color = wDrawColorPowderedBlue;
+
+}
+
+void CreateDescribeAnchor(coOrd pos) {
+ DIST_T d = tempD.scale*0.15;
+ for (int j=0;j<2;j++) {
+ pos.x += j*d*3/4;
+ pos.y += j*d/2;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_CRVLIN;
+ anchors(i).width = d/4;
+ anchors(i).u.c.center = pos;
+ anchors(i).u.c.a0 = 270.0;
+ anchors(i).u.c.a1 = 270.0;
+ anchors(i).u.c.radius = d*3/4;
+ anchors(i).color = wDrawColorPowderedBlue;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).width = d/4;
+ Translate(&anchors(i).u.l.pos[0],pos,180.0,d*3/4);
+ Translate(&anchors(i).u.l.pos[1],pos,180.0,d*1.5);
+ anchors(i).color = wDrawColorPowderedBlue;
+ }
+}
+
+void CreateActivateAnchor(coOrd pos) {
+ DIST_T d = tempD.scale*0.15;
+ coOrd c = pos;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_CRVLIN;
+ anchors(i).width = 0;
+ c.x -= d*3/4;
+ anchors(i).u.c.center = c;
+ anchors(i).u.c.a0 = 0.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).u.c.radius = d;
+ anchors(i).color = wDrawColorPowderedBlue;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ c.x += d*1.5;
+ anchors(i).type = SEG_CRVLIN;
+ anchors(i).width = 0;
+ anchors(i).u.c.center = pos;
+ anchors(i).u.c.a0 = 0.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).u.c.radius = d;
+ anchors(i).color = wDrawColorPowderedBlue;
+}
+
+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);
+}
+
+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;
+}
+
+
/*****************************************************************************
*
@@ -122,6 +287,88 @@ static void DrawTrackAndEndPts(
}
+
+static void RedrawSelectedTracksBoundary()
+{
+/* Truth table: 4 cases for a track trk, connected to trk1
+ * SELREDRAW
+ * trk, trk1: F, F - No changes, nothing to draw
+ * T, F - trk changes but trk1 didn't, flip drawing of select boundary marker
+ * F, T - trk didn't change but trk1 did, handle redrawing when we get to 2nd track
+ * T, T - both changed, but we don't need to redraw anything
+ * unfortunately we will do a redundant redraw when we get to the 2nd track
+ */
+// if (importTrack != NULL)
+// return;
+ track_p trk;
+ TRK_ITERATE( trk ) {
+ if ( GetTrkBits(trk) & TB_SELREDRAW ) {
+ // This track has changed
+ for ( EPINX_T ep = 0; ep < GetTrkEndPtCnt(trk); ep++ ) {
+ track_p trk1 = GetTrkEndTrk( trk, ep );
+ if ( trk1 == NULL )
+ continue;
+
+// if ( GetTrkIndex( trk ) < GetTrkIndex( trk1 )
+// continue;
+ if ( ( GetTrkBits(trk1) & TB_SELREDRAW ) == 0 ) {
+ // Connected track hasn't changed
+ wDrawColor color = selectedColor;
+ if ( ( GetTrkBits(trk) & TB_SELECTED ) == ( GetTrkBits(trk1) & TB_SELECTED ) ) {
+ // There was a select boundary here, but not now.
+ // Undraw old X
+ color = wDrawColorWhite;
+ }
+ DIST_T len;
+ coOrd p = GetTrkEndPos( trk, ep );
+ ANGLE_T a = GetTrkEndAngle( trk, ep );
+ coOrd p0, p1, p2;
+ len = GetTrkGauge(trk)*2.0;
+ if (len < 0.10*mainD.scale)
+ len = 0.10*mainD.scale;
+ Translate( &p1, p, a+45, len );
+ Translate( &p2, p, a+225, len );
+ DrawLine( &mainD, p1, p2, 2, color );
+ Translate( &p1, p, a-45, len );
+ Translate( &p2, p, a-225, len );
+ DrawLine( &mainD, p1, p2, 2, color );
+ if ( color == wDrawColorWhite ) {
+ // Fill in holes by undraw cross
+ DIST_T len2 = sqrt( GetTrkGauge(trk)*GetTrkGauge(trk)/2.0 );
+ DIST_T len3 = 0.1*mainD.scale;
+ color = GetTrkColor( trk, &mainD );
+ if ( mainD.scale < twoRailScale ) {
+ Translate( &p0, p, a-225, len2 );
+ Translate( &p1, p0, a, len3 );
+ Translate( &p2, p0, a+180, len3 );
+ DrawLine( &mainD, p1, p2, GetTrkWidth(trk), color );
+ Translate( &p0, p, a+225, len2 );
+ Translate( &p1, p0, a, len3 );
+ Translate( &p2, p0, a+180, len3 );
+ DrawLine( &mainD, p1, p2, GetTrkWidth(trk), color );
+ color = GetTrkColor( trk1, &mainD );
+ Translate( &p0, p, a-45, len2 );
+ Translate( &p1, p0, a, len3 );
+ Translate( &p2, p0, a+180, len3 );
+ DrawLine( &mainD, p1, p2, GetTrkWidth(trk1), color );
+ Translate( &p0, p, a+45, len2 );
+ Translate( &p1, p0, a, len3 );
+ Translate( &p2, p0, a+180, len3 );
+ DrawLine( &mainD, p1, p2, GetTrkWidth(trk1), color );
+ } else {
+ Translate( &p1, p, a, len3 );
+ Translate( &p2, p, a+180, len3 );
+ DrawLine( &mainD, p1, p2, GetTrkWidth(trk), color );
+ }
+ }
+ }
+ }
+ ClrTrkBits( trk, TB_SELREDRAW );
+ }
+ }
+}
+
+
EXPORT void SetAllTrackSelect( BOOL_T select )
{
track_p trk;
@@ -139,27 +386,26 @@ EXPORT void SetAllTrackSelect( BOOL_T select )
if (select)
selectedTrackCount++;
if ((GetTrkSelected(trk)!=0) != select) {
- if (!doRedraw)
- DrawTrackAndEndPts( trk, wDrawColorWhite );
if (select)
SetTrkBits( trk, TB_SELECTED );
else
ClrTrkBits( trk, TB_SELECTED );
if (!doRedraw)
+ SetTrkBits( trk, TB_SELREDRAW );
DrawTrackAndEndPts( trk, wDrawColorBlack );
}
}
}
SelectedTrackCountChange();
if (doRedraw) {
- MainRedraw();
- MapRedraw();
+ MainRedraw(); // SetAllTrackSelect
} else {
+ RedrawSelectedTracksBoundary();
wDrawDelayUpdate( mainD.d, FALSE );
}
}
-/* Invert selected state of all visible objects.
+/* Invert selected state of all visible non-module objects.
*
* \param none
* \return none
@@ -171,21 +417,15 @@ EXPORT void InvertTrackSelect( void *ptr )
trk = NULL;
while ( TrackIterate( &trk ) ) {
- if (GetLayerVisible( GetTrkLayer( trk ))) {
- if (GetTrkSelected(trk))
- {
- ClrTrkBits( trk, TB_SELECTED );
- selectedTrackCount--;
- }
- else
- SetTrkBits( trk, TB_SELECTED );
- selectedTrackCount++;
+ if (GetLayerVisible( GetTrkLayer( trk )) &&
+ !GetLayerModule(GetTrkLayer( trk ))) {
+ SelectOneTrack( trk, GetTrkSelected(trk)==0 );
}
}
+ RedrawSelectedTracksBoundary();
SelectedTrackCountChange();
- MainRedraw();
- MapRedraw();
+ MainRedraw(); // InvertTrackSelect
}
/* Select orphaned (ie single) track pieces.
@@ -204,7 +444,7 @@ EXPORT void OrphanedTrackSelect( void *ptr )
while( TrackIterate( &trk ) ) {
cnt = 0;
- if( GetLayerVisible( GetTrkLayer( trk ))) {
+ if( GetLayerVisible( GetTrkLayer( trk ) && !GetLayerModule(GetTrkLayer(trk)))) {
for( ep = 0; ep < GetTrkEndPtCnt( trk ); ep++ ) {
if( GetTrkEndTrk( trk, ep ) )
cnt++;
@@ -217,17 +457,21 @@ EXPORT void OrphanedTrackSelect( void *ptr )
}
}
}
+ RedrawSelectedTracksBoundary();
SelectedTrackCountChange();
- MainRedraw();
- MapRedraw();
+ MainRedraw(); // OrphanTrackSelect
}
-
static void SelectOneTrack(
track_p trk,
wBool_t selected )
{
- DrawTrackAndEndPts( trk, wDrawColorWhite );
+ BOOL_T bRedraw = (GetTrkSelected(trk) != 0) != selected;
+ if ( !bRedraw ) {
+ ClrTrkBits( trk, TB_SELREDRAW );
+ return;
+ }
+ SetTrkBits( trk, TB_SELREDRAW );
if (selected) {
SetTrkBits( trk, TB_SELECTED );
selectedTrackCount++;
@@ -240,8 +484,27 @@ static void SelectOneTrack(
}
+static void HighlightSelectedTracks(
+ track_p trk_ignore, BOOL_T box, BOOL_T invert )
+{
+ track_p trk = NULL;
+ if ( selectedTrackCount == 0 )
+ return;
+ while ( TrackIterate( &trk ) ) {
+ if (trk == trk_ignore) continue;
+ if(GetTrkSelected(trk)) {
+ if (!GetLayerVisible( GetTrkLayer( trk ))) continue;
+ if (invert)
+ DrawTrack(trk,&tempD,wDrawColorPreviewUnselected);
+ else
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected );
+ }
+ }
+
+}
+
static void SelectConnectedTracks(
- track_p trk )
+ track_p trk, BOOL_T display_only )
{
track_p trk1;
int inx;
@@ -249,32 +512,65 @@ static void SelectConnectedTracks(
tlist_da.cnt = 0;
TlistAppend( trk );
InfoCount( 0 );
- wDrawDelayUpdate( mainD.d, FALSE );
+ if (!display_only) wDrawDelayUpdate( mainD.d, FALSE );
for (inx=0; inx<tlist_da.cnt; inx++) {
- if ( inx > 0 && selectedTrackCount == 0 )
+ if ( inx > 0 && (selectedTrackCount == 0) && !display_only )
return;
trk = Tlist(inx);
if (inx!=0 &&
- GetTrkSelected(trk))
+ GetTrkSelected(trk)) {
+ if (display_only)
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected );
continue;
+ } else if (GetTrkSelected(trk)) {
+ if (display_only)
+ DrawTrack(trk,&tempD,wDrawColorPreviewUnselected);
+ continue;
+ }
for (ep=0; ep<GetTrkEndPtCnt(trk); ep++) {
trk1 = GetTrkEndTrk( trk, ep );
- if (trk1 && (!GetTrkSelected(trk1)) && GetLayerVisible( GetTrkLayer( trk1 )) ) {
- TlistAppend( trk1 )
+ if (trk1 && !TListSearch(trk1) && GetLayerVisible( GetTrkLayer( trk1 ))) {
+ if (GetTrkSelected(trk1)) {
+ if (display_only) DrawTrack(trk1,&tempD,wDrawColorPreviewSelected );
+ } else TlistAppend( trk1 );
}
}
- if (!GetTrkSelected(trk)) {
- SelectOneTrack( trk, TRUE );
- InfoCount( inx+1 );
+ if (display_only) DrawTrack(trk,&tempD,wDrawColorPreviewSelected );
+ else if (!GetTrkSelected(trk)) {
+ if (GetLayerModule(GetTrkLayer(trk))) {
+ continue;
+ } else {
+ SelectOneTrack( trk, TRUE );
+ InfoCount( inx+1 );
+ }
}
- SetTrkBits(trk, TB_SELECTED);
}
- wDrawDelayUpdate( mainD.d, TRUE );
- wFlush();
- InfoCount( trackCount );
+ if (!display_only) {
+ RedrawSelectedTracksBoundary();
+ wDrawDelayUpdate( mainD.d, TRUE );
+ wFlush();
+ InfoCount( trackCount );
+ }
}
+typedef void (*doModuleTrackCallBack_t)(track_p, BOOL_T);
+static int DoModuleTracks( int moduleLayer, doModuleTrackCallBack_t doit, BOOL_T val)
+{
+ track_p trk;
+ trk = NULL;
+ int cnt = 0;
+ while ( TrackIterate( &trk ) ) {
+ if (GetTrkLayer(trk) == moduleLayer) {
+ doit( trk, val );
+ cnt++;
+ }
+ }
+ return cnt;
+}
+static void DrawSingleTrack(track_p trk, BOOL_T bit) {
+ DrawTrack(trk,&tempD,bit?wDrawColorPreviewSelected:wDrawColorPreviewUnselected);
+}
typedef BOOL_T (*doSelectedTrackCallBack_t)(track_p, BOOL_T);
static void DoSelectedTracks( doSelectedTrackCallBack_t doit )
@@ -331,9 +627,41 @@ EXPORT void SelectTrackWidth( void* width )
UndoEnd();
}
+EXPORT void SelectLineType( void* width )
+{
+ track_p trk;
+ if (SelectedTracksAreFrozen())
+ return;
+ if (selectedTrackCount<=0) {
+ ErrorMessage( MSG_NO_SELECTED_TRK );
+ return;
+ }
+ UndoStart( _("Change Line Type"), "linetype" );
+ trk = NULL;
+ wDrawDelayUpdate( mainD.d, TRUE );
+ while ( TrackIterate( &trk ) ) {
+ if (GetTrkSelected(trk)) {
+ UndoModify( trk );
+ if (QueryTrack(trk, Q_CAN_MODIFY_CONTROL_POINTS))
+ SetBezierLineType(trk, (int) (long) width);
+ else if (QueryTrack(trk, Q_IS_DRAW))
+ SetLineType( trk, (int)(long)width );
+ else if (QueryTrack(trk, Q_IS_STRUCTURE)) {
+ SetCompoundLineType(trk, (int)(long)width);
+ }
+ }
+ }
+ wDrawDelayUpdate( mainD.d, FALSE );
+ UndoEnd();
+}
+
+static BOOL_T doingDouble;
EXPORT void SelectDelete( void )
{
+ if (GetCurrentCommand() != selectCmdInx) return;
+ if (doingDouble) return;
+
if (SelectedTracksAreFrozen())
return;
if (selectedTrackCount>0) {
@@ -341,6 +669,7 @@ EXPORT void SelectDelete( void )
wDrawDelayUpdate( mainD.d, TRUE );
wDrawDelayUpdate( mapD.d, TRUE );
DoSelectedTracks( DeleteTrack );
+ DoRedraw(); // SelectDelete
wDrawDelayUpdate( mainD.d, FALSE );
wDrawDelayUpdate( mapD.d, FALSE );
selectedTrackCount = 0;
@@ -368,8 +697,10 @@ static BOOL_T FlipHidden( track_p trk, BOOL_T junk )
if ( drawTunnel == 0 )
flipHiddenDoSelectRecount = TRUE;
if (GetTrkVisible(trk)) {
- ClrTrkBits( trk, TB_VISIBLE|(drawTunnel==0?TB_SELECTED:0) );
- } else {
+ ClrTrkBits( trk, TB_VISIBLE|(drawTunnel==0?(TB_SELECTED|TB_SELREDRAW):0) );
+ ClrTrkBits (trk, TB_BRIDGE);
+ ClrTrkBits (trk, TB_NOTIES);
+; } else {
SetTrkBits( trk, TB_VISIBLE );
}
/*DrawNewTrack( trk );*/
@@ -382,6 +713,29 @@ static BOOL_T FlipHidden( track_p trk, BOOL_T junk )
return TRUE;
}
+static BOOL_T FlipBridge( track_p trk, BOOL_T junk )
+{
+ UndoModify( trk );
+ if (GetTrkBridge(trk)) {
+ ClrTrkBits( trk, TB_BRIDGE );
+ } else {
+ SetTrkBits( trk, TB_BRIDGE );
+ SetTrkBits( trk, TB_VISIBLE);
+ }
+ return TRUE;
+}
+
+static BOOL_T FlipTies( track_p trk, BOOL_T junk )
+{
+ UndoModify( trk );
+ if (GetTrkNoTies(trk)) {
+ ClrTrkBits( trk, TB_NOTIES );
+ } else {
+ SetTrkBits( trk, TB_NOTIES );
+ SetTrkBits( trk, TB_VISIBLE );
+ }
+ return TRUE;
+}
EXPORT void SelectTunnel( void )
{
@@ -401,6 +755,39 @@ EXPORT void SelectTunnel( void )
SelectRecount();
}
+EXPORT void SelectBridge( void )
+{
+ if (SelectedTracksAreFrozen())
+ return;
+ if (selectedTrackCount>0) {
+ flipHiddenDoSelectRecount = FALSE;
+ UndoStart( _("Bridge Tracks "), "bridge" );
+ wDrawDelayUpdate( mainD.d, TRUE );
+ DoSelectedTracks( FlipBridge );
+ wDrawDelayUpdate( mainD.d, FALSE );
+ UndoEnd();
+ } else {
+ ErrorMessage( MSG_NO_SELECTED_TRK );
+ }
+ MainRedraw(); // SelectBridge
+}
+
+EXPORT void SelectTies( void )
+{
+ if (SelectedTracksAreFrozen())
+ return;
+ if (selectedTrackCount>0) {
+ flipHiddenDoSelectRecount = FALSE;
+ UndoStart( _("Ties Tracks "), "noties" );
+ wDrawDelayUpdate( mainD.d, TRUE );
+ DoSelectedTracks( FlipTies );
+ wDrawDelayUpdate( mainD.d, FALSE );
+ UndoEnd();
+ } else {
+ ErrorMessage( MSG_NO_SELECTED_TRK );
+ }
+ MainRedraw(); // SelectTies
+}
void SelectRecount( void )
{
@@ -445,6 +832,7 @@ EXPORT void SelectCurrentLayer( void )
SelectOneTrack( trk, TRUE );
}
}
+ RedrawSelectedTracksBoundary();
}
@@ -530,8 +918,7 @@ EXPORT void DoRefreshCompound( void )
DoSelectedTracks( RefreshCompound );
RefreshCompound( NULL, FALSE );
UndoEnd();
- MainRedraw();
- MapRedraw();
+ MainRedraw(); // DoRefreshCompound
} else {
ErrorMessage( MSG_NO_SELECTED_TRK );
}
@@ -539,15 +926,12 @@ EXPORT void DoRefreshCompound( void )
static drawCmd_t tempSegsD = {
- NULL, &tempSegDrawFuncs, DC_GROUP, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix };
+ NULL, &tempSegDrawFuncs, 0, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix };
EXPORT void WriteSelectedTracksToTempSegs( void )
{
track_p trk;
- long oldOptions;
DYNARR_RESET( trkSeg_t, tempSegs_da );
tempSegsD.dpi = mainD.dpi;
- oldOptions = tempSegDrawFuncs.options;
- tempSegDrawFuncs.options = wDrawOptTemp;
for ( trk=NULL; TrackIterate(&trk); ) {
if ( GetTrkSelected( trk ) ) {
if ( IsTrack( trk ) )
@@ -557,7 +941,6 @@ EXPORT void WriteSelectedTracksToTempSegs( void )
SetTrkBits( trk, TB_SELECTED );
}
}
- tempSegDrawFuncs.options = oldOptions;
}
static char rescaleFromScale[20];
@@ -619,6 +1002,7 @@ static BOOL_T RescaleDoIt( track_p trk, BOOL_T junk )
{
EPINX_T ep, ep1;
track_p trk1;
+ UndrawNewTrack( trk );
UndoModify(trk);
if ( rescalePercent != 100.0 ) {
for (ep=0; ep<GetTrkEndPtCnt(trk); ep++) {
@@ -636,6 +1020,7 @@ static BOOL_T RescaleDoIt( track_p trk, BOOL_T junk )
if ( rescaleMode==0 )
SetTrkScale( trk, rescaleToInx );
getboundsCount++;
+ DrawNewTrack( trk );
return TRUE;
}
@@ -688,7 +1073,6 @@ static void RescaleDlgOk(
rescaleToInx = GetScaleInx( rescaleToScaleInx, rescaleToGaugeInx );
DoSelectedTracks( RescaleDoIt );
- DoRedraw();
wHide( rescalePG.win );
}
@@ -799,38 +1183,6 @@ EXPORT void DoRescale( void )
wShow( rescalePG.win );
}
-
-
-#define MOVE_NORMAL (0)
-#define MOVE_FAST (1)
-#define MOVE_QUICK (2)
-static char *quickMoveMsgs[] = {
- N_("Draw moving track normally"),
- N_("Draw moving track simply"),
- N_("Draw moving track as end-points") };
-static wMenuToggle_p quickMove1M[3];
-static wMenuToggle_p quickMove2M[3];
-
-static void ChangeQuickMove( wBool_t set, void * mode )
-{
- long inx;
- quickMove = (long)mode;
- InfoMessage( quickMoveMsgs[quickMove] );
- DoChangeNotification( CHANGE_CMDOPT );
- for (inx = 0; inx<3; inx++) {
- wMenuToggleSet( quickMove1M[inx], quickMove == inx );
- wMenuToggleSet( quickMove2M[inx], quickMove == inx );
- }
-}
-
-EXPORT void UpdateQuickMove( void * junk )
-{
- long inx;
- for (inx = 0; inx<3; inx++) {
- wMenuToggleSet( quickMove1M[inx], quickMove == inx );
- wMenuToggleSet( quickMove2M[inx], quickMove == inx );
- }
-}
static void DrawSelectedTracksD( drawCmd_p d, wDrawColor color )
@@ -846,7 +1198,11 @@ static void DrawSelectedTracksD( drawCmd_p d, wDrawColor color )
if ( OFF_D( d->orig, d->size, lo, hi ) )
continue;
}
+ if (color != wDrawColorWhite)
+ ClrTrkBits(trk, TB_UNDRAWN);
DrawTrack( trk, d, color );
+ if (color == wDrawColorWhite)
+ SetTrkBits( trk, TB_UNDRAWN );
}
/*wDrawDelayUpdate( d->d, FALSE );*/
}
@@ -865,7 +1221,7 @@ static ANGLE_T moveAngle;
static coOrd moveD_hi, moveD_lo;
static drawCmd_t moveD = {
- NULL, &tempDrawFuncs, DC_SIMPLE, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix };
+ NULL, &tempSegDrawFuncs, DC_SIMPLE, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix };
@@ -884,61 +1240,56 @@ static void AccumulateTracks( void )
coOrd lo, hi;
/*wDrawDelayUpdate( moveD.d, TRUE );*/
- if (quickMove == MOVE_FAST)
- moveD.options |= DC_QUICK;
- for ( inx = 0; inx<tlist_da.cnt; inx++ ) {
- trk = tlist2[inx];
- if (trk) {
- GetBoundingBox( trk, &hi, &lo );
- if (lo.x <= moveD_hi.x && hi.x >= moveD_lo.x &&
- lo.y <= moveD_hi.y && hi.y >= moveD_lo.y ) {
- if (quickMove != MOVE_QUICK) {
-#if defined(WINDOWS) && ! defined(WIN32)
- if ( tempSegs_da.cnt+100 > 65500 / sizeof(*(trkSeg_p)NULL) ) {
- ErrorMessage( MSG_TOO_MANY_SEL_TRKS );
-
- quickMove = MOVE_QUICK;
- } else
-#endif
- DrawTrack( trk, &moveD, wDrawColorBlack );
- }
- tlist2[inx] = NULL;
- movedCnt++;
+ movedCnt =0;
+ for ( inx = 0; inx<tlist_da.cnt; inx++ ) {
+ trk = Tlist(inx);
+ if (trk) {
+ GetBoundingBox( trk, &hi, &lo );
+ if (lo.x <= moveD_hi.x && hi.x >= moveD_lo.x &&
+ lo.y <= moveD_hi.y && hi.y >= moveD_lo.y ) {
+ if (!QueryTrack(trk,Q_IS_CORNU))
+ DrawTrack( trk, &moveD, wDrawColorBlack );
}
+ movedCnt++;
}
- }
- moveD.options &= ~DC_QUICK;
+ }
InfoCount( movedCnt );
/*wDrawDelayUpdate( moveD.d, FALSE );*/
}
+static void AddEndCornus() {
+ for (int i=0;i<tlist_da.cnt;i++) {
+ track_p trk = DYNARR_N(track_p,tlist_da,i);
+ track_p tc;
+ for (int j=GetTrkEndPtCnt(trk)-1;j>=0;j--) {
+ tc = GetTrkEndTrk(trk,j);
+ if (tc && !GetTrkSelected(tc) && QueryTrack(tc,Q_IS_CORNU) && !QueryTrack(trk,Q_IS_CORNU)) { //On end and cornu
+ SelectOneTrack( tc, TRUE );
+ DYNARR_APPEND(track_p,tlist_da,1); //Add to selected list
+ DYNARR_LAST(track_p,tlist_da) = tc;
+ }
+ }
+ }
+}
+
static void GetMovedTracks( BOOL_T undraw )
{
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
DYNARR_RESET( track_p, tlist_da );
DoSelectedTracks( AddSelectedTrack );
- tlist2 = (track_p*)MyRealloc( tlist2, (tlist_da.cnt+1) * sizeof *(track_p*)0 );
- if (tlist_da.ptr)
- memcpy( tlist2, tlist_da.ptr, (tlist_da.cnt) * sizeof *(track_p*)0 );
- tlist2[tlist_da.cnt] = NULL;
+ AddEndCornus(); //Include Cornus that are attached at ends of selected
DYNARR_RESET( trkSeg_p, tempSegs_da );
- moveD = mainD;
- moveD.funcs = &tempSegDrawFuncs;
- moveD.options = DC_SIMPLE;
- tempSegDrawFuncs.options = wDrawOptTemp;
moveOrig = mainD.orig;
movedCnt = 0;
InfoCount(0);
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
moveD_hi = moveD_lo = mainD.orig;
moveD_hi.x += mainD.size.x;
moveD_hi.y += mainD.size.y;
AccumulateTracks();
if (undraw) {
DrawSelectedTracksD( &mainD, wDrawColorWhite );
- /*DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt,
- trackGauge, wDrawColorBlack );*/
}
}
@@ -989,48 +1340,50 @@ static void DrawMovedTracks( void )
{
int inx;
track_p trk;
- track_p other;
- EPINX_T i;
- coOrd pos;
- wDrawBitMap_p bm;
- ANGLE_T a;
- int ia;
-
- if ( quickMove != MOVE_QUICK) {
- DrawSegs( &tempD, moveOrig, moveAngle, &tempSegs(0), tempSegs_da.cnt,
- 0.0, wDrawColorBlack );
- return;
- }
+ dynArr_t cornu_segs;
+
+ DrawSegs( &tempD, moveOrig, moveAngle, &tempSegs(0), tempSegs_da.cnt,
+ 0.0, wDrawColorBlack );
+
for ( inx=0; inx<tlist_da.cnt; inx++ ) {
trk = Tlist(inx);
- if (tlist2[inx] != NULL)
- continue;
- for (i=GetTrkEndPtCnt(trk)-1; i>=0; i--) {
- pos = GetTrkEndPos(trk,i);
- if (!move0B) {
- Rotate( &pos, zero, moveAngle );
- }
- pos.x += moveOrig.x;
- pos.y += moveOrig.y;
- if ((other=GetTrkEndTrk(trk,i)) == NULL ||
- !GetTrkSelected(other)) {
- bm = endpt_bm;
- } else if (other != NULL && GetTrkIndex(trk) < GetTrkIndex(other)) {
- a = GetTrkEndAngle(trk,i)+22.5;
- if (!move0B)
- a += moveAngle;
- a = NormalizeAngle( a );
- if (a>=180.0)
- a -= 180.0;
- ia = (int)(a/45.0);
- bm = angle_bm[ia];
- } else {
- continue;
+ if (QueryTrack(trk,Q_IS_CORNU)) {
+ DYNARR_RESET(trkSeg_t,cornu_segs);
+ coOrd pos[2];
+ DIST_T radius[2];
+ ANGLE_T angle[2];
+ coOrd center[2];
+ trackParams_t trackParams;
+ if (GetTrackParams(PARAMS_CORNU, trk, zero, &trackParams)) {
+ for (int i=0;i<2;i++) {
+ pos[i] = trackParams.cornuEnd[i];
+ center[i] = trackParams.cornuCenter[i];
+ angle[i] = trackParams.cornuAngle[i];
+ radius[i] = trackParams.cornuRadius[i];
+ if (!GetTrkEndTrk(trk,i) ||
+ (GetTrkEndTrk(trk,i) && GetTrkSelected(GetTrkEndTrk(trk,i)))) {
+ if (!move0B) {
+ Rotate( &pos[i], zero, moveAngle );
+ Rotate( &center[i],zero, moveAngle );
+ angle[i] = NormalizeAngle(angle[i]+moveAngle);
+ }
+ pos[i].x += moveOrig.x;
+ pos[i].y += moveOrig.y;
+ center[i].x +=moveOrig.x;
+ center[i].y +=moveOrig.y;
+ }
+ }
+ CallCornu0(&pos[0],&center[0],&angle[0],&radius[0],&cornu_segs, FALSE);
+ trkSeg_p cornu_p = &DYNARR_N(trkSeg_t,cornu_segs,0);
+
+ DrawSegsO(&tempD, trk, zero, 0.0, cornu_p,cornu_segs.cnt,
+ GetTrkGauge(trk), wDrawColorBlack, DTS_LEFT|DTS_RIGHT );
}
- if ( !OFF_MAIND( pos, pos ) )
- DrawBitMap( &tempD, pos, bm, selectedColor );
+
}
+
}
+ return;
}
@@ -1041,7 +1394,8 @@ static void MoveTracks(
BOOL_T rotate,
coOrd base,
coOrd orig,
- ANGLE_T angle )
+ ANGLE_T angle,
+ BOOL_T undo)
{
track_p trk, trk1;
EPINX_T ep, ep1;
@@ -1051,48 +1405,47 @@ static void MoveTracks(
DIST_T endRadius;
coOrd endCenter;
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
/*UndoStart( "Move/Rotate Tracks", "move/rotate" );*/
if (tlist_da.cnt <= incrementalDrawLimit) {
- DrawMapBoundingBox( FALSE );
- if (eraseFirst)
+ if (eraseFirst) {
DrawSelectedTracksD( &mainD, wDrawColorWhite );
- DrawSelectedTracksD( &mapD, wDrawColorWhite );
+ DrawSelectedTracksD( &mapD, wDrawColorWhite );
+ }
}
for ( inx=0; inx<tlist_da.cnt; inx++ ) {
trk = Tlist(inx);
UndoModify( trk );
- if (move)
- MoveTrack( trk, base );
- if (rotate)
- RotateTrack( trk, orig, angle );
- for (ep=0; ep<GetTrkEndPtCnt(trk); ep++) {
- if ((trk1 = GetTrkEndTrk(trk,ep)) != NULL &&
- !GetTrkSelected(trk1)) {
- ep1 = GetEndPtConnectedToMe( trk1, trk );
- DisconnectTracks( trk, ep, trk1, ep1 );
- if (QueryTrack(trk1,Q_IS_CORNU)) { //Cornu at end stays connected
- GetTrackParams(PARAMS_CORNU,trk,GetTrkEndPos(trk,ep),&trackParms);
- if (trackParms.type == curveTypeStraight) {
- endRadius = 0;
- endCenter = zero;
- } else {
- endRadius = trackParms.arcR;
- endCenter = trackParms.arcP;
- }
- DrawTrack(trk1,&mainD,wDrawColorWhite);
- DrawTrack(trk1,&mapD,wDrawColorWhite);
- endAngle = NormalizeAngle(GetTrkEndAngle(trk,ep)+180);
- if (SetCornuEndPt(trk1,ep1,GetTrkEndPos(trk,ep),endCenter,endAngle,endRadius)) {
- ConnectTracks(trk,ep,trk1,ep1);
- DrawTrack(trk1,&mainD,wDrawColorBlack);
- DrawTrack(trk1,&mapD,wDrawColorBlack);
- } else {
- DeleteTrack(trk1,TRUE);
- ErrorMessage(_("Cornu too tight - it was deleted"));
- }
- } else {
- if (QueryTrack(trk,Q_IS_CORNU)) { //I am a Cornu myself!
+ BOOL_T fixed_end;
+ fixed_end = FALSE;
+ if (QueryTrack(trk, Q_IS_CORNU)) {
+ for (int i=0;i<2;i++) {
+ track_p te;
+ if ((te = GetTrkEndTrk(trk,i)) && !GetTrkSelected(te)) {
+ fixed_end = TRUE;
+ }
+ }
+ }
+
+ if (!fixed_end) {
+ if (move)
+ MoveTrack( trk, base );
+ if (rotate)
+ RotateTrack( trk, orig, angle );
+ for (ep=0; ep<GetTrkEndPtCnt(trk); ep++) {
+ if ((trk1 = GetTrkEndTrk(trk,ep)) != NULL &&
+ !GetTrkSelected(trk1)) {
+ ep1 = GetEndPtConnectedToMe( trk1, trk );
+ DisconnectTracks( trk, ep, trk1, ep1 );
+ DrawEndPt( &mainD, trk1, ep1, wDrawColorBlack );
+ }
+ }
+ } else {
+ if (QueryTrack(trk, Q_IS_CORNU)) { //Cornu will be at the end of selected set
+ for (int i=0;i<2;i++) {
+ if ((trk1 = GetTrkEndTrk(trk,i)) && GetTrkSelected(trk1)) {
+ ep1 = GetEndPtConnectedToMe( trk1, trk );
+ DisconnectTracks(trk,i,trk1,ep1);
GetTrackParams(PARAMS_CORNU,trk1,GetTrkEndPos(trk1,ep1),&trackParms);
if (trackParms.type == curveTypeStraight) {
endRadius = 0;
@@ -1102,39 +1455,55 @@ static void MoveTracks(
endCenter = trackParms.arcP;
}
DrawTrack(trk,&mainD,wDrawColorWhite);
- DrawTrack(trk1,&mapD,wDrawColorWhite);
+ DrawTrack(trk,&mapD,wDrawColorWhite);
endAngle = NormalizeAngle(GetTrkEndAngle(trk1,ep1)+180);
- if (SetCornuEndPt(trk,ep,GetTrkEndPos(trk1,ep1),endCenter,endAngle,endRadius)) {
- ConnectTracks(trk,ep,trk1,ep1);
+ if (SetCornuEndPt(trk,i,GetTrkEndPos(trk1,ep1),endCenter,endAngle,endRadius)) {
+ ConnectTracks(trk,i,trk1,ep1);
DrawTrack(trk,&mainD,wDrawColorBlack);
DrawTrack(trk,&mapD,wDrawColorBlack);
} else {
- ErrorMessage(_("Cornu selected too tight after move - it was left alone"));
- DrawTrack(trk,&mainD,wDrawColorBlack);
- DrawTrack(trk,&mapD,wDrawColorBlack);
+ DeleteTrack(trk,TRUE);
+ ErrorMessage(_("Cornu too tight - it was deleted"));
+ DoRedraw(); // MoveTracks: Cornu/delete
+ return;
+ }
+ } else if (!trk1) { //No end track
+ DrawTrack(trk,&mainD,wDrawColorWhite);
+ DrawTrack(trk,&mapD,wDrawColorWhite);
+ GetTrackParams(PARAMS_CORNU,trk,GetTrkEndPos(trk,i),&trackParms);
+ if (move) {
+ coOrd end_pos, end_center;
+ end_pos = trackParms.cornuEnd[i];
+ end_pos.x += base.x;
+ end_pos.y += base.y;
+ end_center = trackParms.cornuCenter[i];
+ end_center.x += base.x;
+ end_center.y += base.y;
+ SetCornuEndPt(trk,i,end_pos,end_center,trackParms.cornuAngle[i],trackParms.cornuRadius[i]);
+ }
+ if (rotate) {
+ coOrd end_pos, end_center;
+ ANGLE_T end_angle;
+ end_pos = trackParms.cornuEnd[i];
+ end_center = trackParms.cornuCenter[i];
+ Rotate(&end_pos, orig, angle);
+ Rotate(&end_center, orig, angle);
+ end_angle = NormalizeAngle( trackParms.cornuAngle[i] + angle );
+ SetCornuEndPt(trk,i,end_pos,end_center,end_angle,trackParms.cornuRadius[i]);
}
+ DrawTrack(trk,&mainD,wDrawColorBlack);
+ DrawTrack(trk,&mapD,wDrawColorBlack);
}
}
- DrawEndPt( &mainD, trk1, ep1, wDrawColorBlack );
}
- }
+ }
InfoCount( inx );
-#ifdef LATER
- if (tlist_da.cnt <= incrementalDrawLimit)
- DrawNewTrack( trk );
-#endif
- }
- if (tlist_da.cnt > incrementalDrawLimit) {
- DoRedraw();
- } else {
- DrawSelectedTracksD( &mainD, wDrawColorBlack );
- DrawSelectedTracksD( &mapD, wDrawColorBlack );
- DrawMapBoundingBox( TRUE );
}
- wSetCursor( wCursorNormal );
- UndoEnd();
- tempSegDrawFuncs.options = 0;
+ ClrAllTrkBits(TB_UNDRAWN);
+ DoRedraw();
+ wSetCursor( mainD.d, defaultCursor );
+ if (undo) UndoEnd();
InfoCount( trackCount );
}
@@ -1159,7 +1528,7 @@ void MoveToJoin(
angle += 180.0;
angle = NormalizeAngle( angle );
GetMovedTracks( FALSE );
- MoveTracks( TRUE, TRUE, TRUE, base, orig, angle );
+ MoveTracks( TRUE, TRUE, TRUE, base, orig, angle, TRUE );
UndrawNewTrack( trk0 );
UndrawNewTrack( trk1 );
ConnectTracks( trk0, ep0, trk1, ep1 );
@@ -1176,6 +1545,145 @@ void FreeTempStrings() {
}
}
}
+
+
+wBool_t FindEndIntersection(coOrd base, coOrd orig, ANGLE_T angle, track_p * t1, EPINX_T * ep1, track_p * t2, EPINX_T * ep2) {
+ *ep1 = -1;
+ *ep2 = -1;
+ *t1 = NULL;
+ *t2 = NULL;
+ for ( int inx=0; inx<tlist_da.cnt; inx++ ) { //All selected
+ track_p ts = Tlist(inx);
+ for (int i=0; i<GetTrkEndPtCnt(ts); i++) { //All EndPoints
+ track_p ct;
+ if ((ct = GetTrkEndTrk(ts,i))!=NULL) {
+ if (GetTrkSelected(ct) || QueryTrack(ts,Q_IS_CORNU)) continue; // Another selected track or Cornu - ignore
+ }
+
+ coOrd pos1 = GetTrkEndPos(ts,i);
+ if (angle != 0.0)
+ Rotate(&pos1,orig,angle);
+ else {
+ pos1.x +=base.x;
+ pos1.y +=base.y;
+ }
+ coOrd pos2;
+ pos2 = pos1;
+ track_p tt;
+ if ((tt=OnTrackIgnore(&pos2,FALSE,TRUE,ts))!=NULL) {
+ if (GetTrkGauge(ts) != GetTrkGauge(tt)) continue; //Ignore if different gauges
+ if (!GetTrkSelected(tt)) { //Ignore if new track is selected
+ EPINX_T epp = PickUnconnectedEndPointSilent(pos2, tt);
+ if (epp>=0) {
+ DIST_T d = FindDistance(pos1,GetTrkEndPos(tt,epp));
+ if (IsClose(d)) {
+ *ep1 = epp;
+ *ep2 = i;
+ *t1 = tt;
+ *t2 = ts;
+ return TRUE;
+ }
+ } else {
+ epp = PickEndPoint(pos2,tt); //Any close end point (even joined)
+ if (epp>=0) {
+ ct = GetTrkEndTrk(tt,epp);
+ if (ct && GetTrkSelected(ct)) { //Point is junction to selected track - so will be broken
+ DIST_T d = FindDistance(pos1,GetTrkEndPos(tt,epp));
+ if (IsClose(d)) {
+ *ep1 = epp;
+ *ep2 = i;
+ *t1 = tt;
+ *t2 = ts;
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+void DrawHighlightLayer(int layer) {
+ track_p ts = NULL;
+ BOOL_T initial = TRUE;
+ coOrd layer_hi = zero,layer_lo = zero;
+ while ( TrackIterate( &ts ) ) {
+ if ( !GetLayerVisible( GetTrkLayer( ts))) continue;
+ if (!GetTrkSelected(ts)) continue;
+ if (GetTrkLayer(ts) != layer) continue;
+ coOrd hi,lo;
+ GetBoundingBox(ts, &hi, &lo);
+ if (initial) {
+ layer_hi = hi;
+ layer_lo = lo;
+ initial = FALSE;
+ } else {
+ if (layer_hi.x < hi.x ) layer_hi.x = hi.x;
+ if (layer_hi.y < hi.y ) layer_hi.y = hi.y;
+ if (layer_lo.x > lo.x ) layer_lo.x = lo.x;
+ if (layer_lo.y > lo.y ) layer_lo.y = lo.y;
+ }
+ }
+ wPos_t margin = (wPos_t)(10.5*mainD.scale/mainD.dpi);
+ layer_hi.x +=margin;
+ layer_hi.y +=margin;
+ layer_lo.x -=margin;
+ layer_lo.y -=margin;
+
+ wPos_t rect[4][2];
+ int type[4];
+ coOrd top_left, bot_right;
+ top_left.x = layer_lo.x; top_left.y = layer_hi.y;
+ bot_right.x = layer_hi.x; bot_right.y = layer_lo.y;
+ type[0] = type[1] = type[2] = type[3] = 0;
+ mainD.CoOrd2Pix(&mainD,layer_lo,&rect[0][0],&rect[0][1]);
+ mainD.CoOrd2Pix(&mainD,top_left,&rect[1][0],&rect[1][1]);
+ mainD.CoOrd2Pix(&mainD,layer_hi,&rect[2][0],&rect[2][1]);
+ mainD.CoOrd2Pix(&mainD,bot_right,&rect[3][0],&rect[3][1]);
+ wDrawPolygon(tempD.d,rect,(wPolyLine_e *)type,4,wDrawColorPowderedBlue,0,wDrawLineDash,wDrawOptTemp,0,0);
+}
+
+void SetUpMenu2(coOrd pos, track_p trk) {
+ wMenuPushEnable( menuPushModify,FALSE);
+ wMenuPushEnable(descriptionMI,FALSE);
+ wMenuPushEnable( rotateAlignMI, FALSE );
+ wMenuPushEnable( hideMI, FALSE );
+ wMenuPushEnable( bridgeMI, FALSE );
+ wMenuPushEnable( tiesMI, FALSE );
+ if ((trk) &&
+ QueryTrack(trk,Q_CAN_ADD_ENDPOINTS)) { //Turntable snap to center if within 1/4 radius
+ trackParams_t trackParams;
+ if (GetTrackParams(PARAMS_CORNU, trk, pos, &trackParams)) {
+ DIST_T dist = FindDistance(pos, trackParams.ttcenter);
+ if (dist < trackParams.ttradius/4) {
+ cmdMenuPos = trackParams.ttcenter;
+ }
+ }
+ }
+ if (trk && !QueryTrack( trk, Q_IS_DRAW )) {
+ wMenuPushEnable( hideMI, TRUE );
+ wMenuPushEnable( bridgeMI, TRUE );
+ wMenuPushEnable( tiesMI, TRUE );
+ }
+ if (trk) {
+ wMenuPushEnable( menuPushModify,
+ (QueryTrack( trk, Q_CAN_MODIFY_CONTROL_POINTS ) ||
+ QueryTrack( trk, Q_IS_CORNU ) ||
+ (QueryTrack( trk, Q_IS_DRAW ) && !QueryTrack( trk, Q_IS_TEXT )) ||
+ QueryTrack( trk, Q_IS_ACTIVATEABLE)));
+ }
+ if ((trk)) {
+ wMenuPushEnable(descriptionMI, QueryTrack( trk, Q_HAS_DESC ));
+ moveDescTrk = trk;
+ moveDescPos = pos;
+ }
+ if (selectedTrackCount>0)
+ wMenuPushEnable( rotateAlignMI, TRUE );
+}
+
static STATUS_T CmdMove(
wAction_t action,
@@ -1185,9 +1693,16 @@ static STATUS_T CmdMove(
static coOrd orig;
static int state;
- switch( action&0xFF) {
+ static EPINX_T ep1;
+ static EPINX_T ep2;
+ static track_p t1;
+ static track_p t2;
+ static BOOL_T doingMove;
+
+ switch( action & 0xFF) {
case C_START:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if (selectedTrackCount == 0) {
ErrorMessage( MSG_NO_SELECTED_TRK );
return C_TERMINATE;
@@ -1197,63 +1712,123 @@ static STATUS_T CmdMove(
}
InfoMessage( _("Drag to move selected tracks - Shift+Ctrl+Arrow micro-steps the move") );
state = 0;
+ ep1 = -1;
+ ep2 = -1;
+ doingMove = FALSE;
+ break;
+
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ CreateMoveAnchor(pos);
break;
case C_DOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (doingMove) {
+ doingMove = FALSE;
+ UndoEnd();
+ }
+
if (SelectedTracksAreFrozen()) {
return C_TERMINATE;
}
UndoStart( _("Move Tracks"), "move" );
base = zero;
orig = pos;
- GetMovedTracks(quickMove != MOVE_QUICK);
+
+ GetMovedTracks(TRUE);
SetMoveD( TRUE, base, 0.0 );
- //DrawMovedTracks();
drawCount = 0;
state = 1;
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
case C_MOVE:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ ep1=-1;
+ ep2=-1;
drawEnable = enableMoveDraw;
- //DrawMovedTracks();
base.x = pos.x - orig.x;
base.y = pos.y - orig.y;
SnapPos( &base );
SetMoveD( TRUE, base, 0.0 );
- //DrawMovedTracks();
+ if (((MyGetKeyState()&(WKEY_ALT)) == 0) == magneticSnap) { // ALT
+ if (FindEndIntersection(base,zero,0.0,&t1,&ep1,&t2,&ep2)) {
+ coOrd pos2 = GetTrkEndPos(t2,ep2);
+ pos2.x +=base.x;
+ pos2.y +=base.y;
+ CreateEndAnchor(pos2,FALSE);
+ CreateEndAnchor(GetTrkEndPos(t1,ep1),TRUE);
+ }
+ }
#ifdef DRAWCOUNT
InfoMessage( " [%s %s] #%ld", FormatDistance(base.x), FormatDistance(base.y), drawCount );
#else
InfoMessage( " [%s %s]", FormatDistance(base.x), FormatDistance(base.y) );
#endif
drawEnable = TRUE;
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
case C_UP:
+ DYNARR_RESET(trkSeg_t,anchors_da);
state = 0;
- //DrawMovedTracks();
FreeTempStrings();
- MoveTracks( quickMove==MOVE_QUICK, TRUE, FALSE, base, zero, 0.0 );
+ if (t1 && ep1>=0 && t2 && ep2>=0) {
+ MoveToJoin(t2,ep2,t1,ep1);
+ } else {
+ MoveTracks( FALSE, TRUE, FALSE, base, zero, 0.0, TRUE );
+ }
+ ep1 = -1;
+ ep2 = -1;
+ tlist_da.cnt = 0;
return C_TERMINATE;
case C_CMDMENU:
- wMenuPopupShow( selectPopup1M );
+ if (doingMove) UndoEnd();
+ doingMove = FALSE;
+ base = pos;
+ track_p trk = OnTrack(&pos, FALSE, FALSE); //Note pollutes pos if turntable
+ if ((trk) &&
+ QueryTrack(trk,Q_CAN_ADD_ENDPOINTS)) { //Turntable snap to center if within 1/4 radius
+ trackParams_t trackParams;
+ if (GetTrackParams(PARAMS_CORNU, trk, pos, &trackParams)) {
+ DIST_T dist = FindDistance(base, trackParams.ttcenter);
+ if (dist < trackParams.ttradius/4) {
+ cmdMenuPos = trackParams.ttcenter;
+ }
+ }
+ }
+ moveDescPos = pos;
+ moveDescTrk = trk;
+ SetUpMenu2(pos,trk);
+ menuPos = pos;
+ wMenuPopupShow( selectPopup2M );
return C_CONTINUE;
+ case C_TEXT:
+ if ((action>>8) == 'c') {
+ panCenter = pos;
+ LOG( log_pan, 2, ( "PanCenter:Sel-%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)0);
+ }
+ if ((action>>8) == 'e') {
+ DoZoomExtents(0);
+ }
+ if ((action>>8) == '0' || (action>>8 == 'o')) {
+ PanMenuEnter('o');
+ }
+ break;
case C_REDRAW:
/* DO_REDRAW */
+ if (anchors_da.cnt)
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
if ( state == 0 )
break;
- DrawSelectedTracksD( &mainD, wDrawColorWhite );
DrawMovedTracks();
+
break;
case wActionExtKey:
if (state) return C_CONTINUE;
if (SelectedTracksAreFrozen()) return C_TERMINATE;
if ((MyGetKeyState() &
- (WKEY_SHIFT | WKEY_CTRL)) == (WKEY_SHIFT | WKEY_CTRL)) {
+ (WKEY_SHIFT | WKEY_CTRL)) == (WKEY_SHIFT | WKEY_CTRL)) { //Both
base = zero;
DIST_T w = tempD.scale/tempD.dpi;
switch((wAccelKey_e) action>>8) {
@@ -1275,21 +1850,35 @@ static STATUS_T CmdMove(
}
drawEnable = enableMoveDraw;
- GetMovedTracks(quickMove!=MOVE_QUICK);
- UndoStart( _("Move Tracks"), "move" );
+ GetMovedTracks(TRUE);
+ if (!doingMove) UndoStart( _("Move Tracks"), "move" );
+ doingMove = TRUE;
SetMoveD( TRUE, base, 0.0 );
- DrawSelectedTracksD( &mainD, wDrawColorWhite );
- MoveTracks( quickMove==MOVE_QUICK, TRUE, FALSE, base, zero, 0.0 );
+ MoveTracks( FALSE, TRUE, FALSE, base, zero, 0.0, FALSE );
++microCount;
if (microCount>5) {
microCount = 0;
- MainRedraw();
- MapRedraw();
+ MainRedraw(); // Micro step move
}
return C_CONTINUE;
}
break;
+ case C_FINISH:
+ if (doingMove) {
+ doingMove = FALSE;
+ UndoEnd();
+ }
+ tlist_da.cnt = 0;
+ break;
+ case C_CONFIRM:
+ case C_CANCEL:
+ if (doingMove) {
+ doingMove = FALSE;
+ UndoUndo();
+ }
+ tlist_da.cnt = 0;
+ break;
default:
break;
}
@@ -1297,13 +1886,18 @@ static STATUS_T CmdMove(
}
-wMenuPush_p rotateAlignMI;
-int rotateAlignState = 0;
-static void RotateAlign( void )
+static int rotateAlignState = 0;
+
+static void RotateAlign( BOOL_T align )
{
- rotateAlignState = 1;
- InfoMessage( _("Click on selected object to align") );
+ rotateAlignState = 0;
+ if (align) {
+ rotateAlignState = 1;
+ doingAlign = TRUE;
+ mode = MOVE;
+ InfoMessage( _("Align: Click on a selected object to be aligned") );
+ }
}
static STATUS_T CmdRotate(
@@ -1311,18 +1905,27 @@ static STATUS_T CmdRotate(
coOrd pos )
{
static coOrd base;
+ static coOrd orig_base;
static coOrd orig;
static ANGLE_T angle;
static BOOL_T drawnAngle;
static ANGLE_T baseAngle;
+ static BOOL_T clockwise;
+ static BOOL_T direction_set;
static track_p trk;
ANGLE_T angle1;
coOrd pos1;
static int state;
+ static EPINX_T ep1;
+ static EPINX_T ep2;
+ static track_p t1;
+ static track_p t2;
+
switch( action ) {
case C_START:
+ DYNARR_RESET(trkSeg_t,anchors_da);
state = 0;
if (selectedTrackCount == 0) {
ErrorMessage( MSG_NO_SELECTED_TRK );
@@ -1334,8 +1937,15 @@ static STATUS_T CmdRotate(
InfoMessage( _("Drag to rotate selected tracks, Shift+RightClick for QuickRotate Menu") );
wMenuPushEnable( rotateAlignMI, TRUE );
rotateAlignState = 0;
+ ep1 = -1;
+ ep2 = -1;
+ break;
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ CreateRotateAnchor(pos);
break;
case C_DOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
state = 1;
if (SelectedTracksAreFrozen()) {
return C_TERMINATE;
@@ -1357,12 +1967,15 @@ static STATUS_T CmdRotate(
}
}
}
- GetMovedTracks(FALSE);
+ CreateRotateAnchor(orig);
+ GetMovedTracks(TRUE);
SetMoveD( FALSE, base, angle );
+
/*DrawLine( &mainD, base, orig, 0, wDrawColorBlack );
DrawMovedTracks(FALSE, orig, angle);*/
} else {
pos1 = pos;
+ drawnAngle = FALSE;
onTrackInSplit = TRUE;
trk = OnTrack( &pos, TRUE, FALSE );
onTrackInSplit = FALSE;
@@ -1396,13 +2009,13 @@ static STATUS_T CmdRotate(
}
GetMovedTracks(TRUE);
SetMoveD( FALSE, orig, angle );
- //DrawMovedTracks();
}
}
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
case C_MOVE:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ ep1=-1;
+ ep2=-1;
if ( rotateAlignState == 1 )
return C_CONTINUE;
if ( rotateAlignState == 2 ) {
@@ -1416,7 +2029,6 @@ static STATUS_T CmdRotate(
ErrorMessage( MSG_2ND_TRACK_MUST_BE_UNSELECTED );
return C_CONTINUE;
}
- //DrawMovedTracks();
angle1 = NormalizeAngle( GetAngleAtPoint( trk, pos, NULL, NULL ) );
angle = NormalizeAngle(angle1-baseAngle);
if ( angle > 90 && angle < 270 )
@@ -1427,65 +2039,95 @@ static STATUS_T CmdRotate(
InfoMessage( _("Angle %0.3f"), angle1 );
SetMoveD( FALSE, orig, angle );
/*printf( "angle 2 = %0.3f\n", angle );*/
- //DrawMovedTracks();
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
}
- if ( FindDistance( orig, pos ) > (6.0/75.0)*mainD.scale ) {
- drawEnable = enableMoveDraw;
- if (drawnAngle) {
- DrawLine( &tempD, base, orig, 0, wDrawColorBlack );
- DrawMovedTracks();
- } else if (quickMove != MOVE_QUICK) {
- DrawSelectedTracksD( &mainD, wDrawColorWhite );
- }
+ ANGLE_T diff_angle = 0.0;
+ base = pos;
+ drawEnable = enableMoveDraw;
+ if ( FindDistance( orig, pos ) > (20.0/75.0)*mainD.scale ) {
+ ANGLE_T old_angle = angle;
angle = FindAngle( orig, pos );
if (!drawnAngle) {
baseAngle = angle;
drawnAngle = TRUE;
+ direction_set = FALSE;
+ } else {
+ if (!direction_set) {
+ if (DifferenceBetweenAngles(baseAngle,angle)>=0) clockwise = TRUE;
+ else clockwise = FALSE;
+ direction_set = TRUE;
+ } else {
+ if (clockwise) {
+ if (DifferenceBetweenAngles(baseAngle,angle)<0 && fabs(DifferenceBetweenAngles(baseAngle, old_angle))<5)
+ clockwise = FALSE;
+ } else {
+ if (DifferenceBetweenAngles(baseAngle,angle)>=0 && fabs(DifferenceBetweenAngles(baseAngle,old_angle))<5)
+ clockwise = TRUE;
+ }
+ }
}
- base = pos;
- angle = NormalizeAngle( angle-baseAngle );
- if ( MyGetKeyState()&WKEY_CTRL ) {
- angle = NormalizeAngle(floor((angle+7.5)/15.0)*15.0);
- Translate( &base, orig, angle+baseAngle, FindDistance(orig,pos) );
+ orig_base = base = pos;
+ //angle = NormalizeAngle( angle-baseAngle );
+ diff_angle = DifferenceBetweenAngles(baseAngle,angle);
+ if ( (MyGetKeyState() & (WKEY_CTRL|WKEY_SHIFT)) == (WKEY_CTRL|WKEY_SHIFT) ) { //Both Shift+Ctrl
+ if (clockwise) {
+ if (diff_angle<0) diff_angle+=360;
+ } else {
+ if (diff_angle>0) diff_angle-=360;
+ }
+ diff_angle = floor((diff_angle+7.5)/15.0)*15.0;
+ angle = baseAngle+diff_angle;
}
- DrawLine( &tempD, base, orig, 0, wDrawColorBlack );
- SetMoveD( FALSE, orig, angle );
- //DrawMovedTracks();
+ Translate( &base, orig, angle, FindDistance(orig,pos) ); //Line one
+ Translate( &orig_base,orig, baseAngle, FindDistance(orig,pos)<=(60.0/75.00*mainD.scale)?FindDistance(orig,pos):60.0/75.00*mainD.scale ); //Line two
+ SetMoveD( FALSE, orig, NormalizeAngle( angle-baseAngle ) );
+ if (((MyGetKeyState()&(WKEY_ALT)) == WKEY_ALT) != magneticSnap) { //Just Shift
+ if (FindEndIntersection(zero,orig,NormalizeAngle( angle-baseAngle ),&t1,&ep1,&t2,&ep2)) {
+ coOrd pos2 = GetTrkEndPos(t2,ep2);
+ coOrd pos1 = GetTrkEndPos(t1,ep1);
+ Rotate(&pos2,orig,NormalizeAngle( angle-baseAngle ));
+ CreateEndAnchor(pos2,FALSE);
+ CreateEndAnchor(pos1,TRUE);
+ }
+ }
+
#ifdef DRAWCOUNT
- InfoMessage( _(" Angle %0.3f #%ld"), angle, drawCount );
+ InfoMessage( _("Angle %0.3f #%ld"), fabs(diff_angle), drawCount );
#else
- InfoMessage( _(" Angle %0.3f"), angle );
+ InfoMessage( _("Angle %0.3f %s"), fabs(diff_angle), clockwise?"Clockwise":"Counter-Clockwise" );
#endif
wFlush();
drawEnable = TRUE;
- }
- MainRedraw();
- MapRedraw();
+ } else
+ InfoMessage( _("Origin Set. Drag away to set start angle"));
+
return C_CONTINUE;
+
case C_UP:
+ DYNARR_RESET(trkSeg_t,anchors_da);
state = 0;
- if ( rotateAlignState == 1 ) {
- if ( trk && GetTrkSelected(trk) ) {
- InfoMessage( _("Click on the 2nd Unselected object") );
- rotateAlignState = 2;
- }
- return C_CONTINUE;
- }
- FreeTempStrings();
- if ( rotateAlignState == 2 ) {
- //DrawMovedTracks();
- MoveTracks( quickMove==MOVE_QUICK, FALSE, TRUE, zero, orig, angle );
+ if (t1 && ep1>=0 && t2 && ep2>=0) {
+ MoveToJoin(t2,ep2,t1,ep1);
+ CleanSegs(&tempSegs_da);
rotateAlignState = 0;
- } else if (drawnAngle) {
- DrawLine( &tempD, base, orig, 0, wDrawColorBlack );
- //DrawMovedTracks();
- MoveTracks( quickMove==MOVE_QUICK, FALSE, TRUE, zero, orig, angle );
+ } else {
+ if ( rotateAlignState == 1 ) {
+ if ( trk && GetTrkSelected(trk) ) {
+ InfoMessage( _("Align: Click on the 2nd unselected object") );
+ rotateAlignState = 2;
+ }
+ return C_CONTINUE;
+ }
+ CleanSegs(&tempSegs_da);
+ if ( rotateAlignState == 2 ) {
+ MoveTracks( FALSE, FALSE, TRUE, zero, orig, angle, TRUE );
+ rotateAlignState = 0;
+ } else if (drawnAngle) {
+ MoveTracks( FALSE, FALSE, TRUE, zero, orig, NormalizeAngle( angle-baseAngle ), TRUE );
+ }
}
- MainRedraw();
- MapRedraw();
+ UndoEnd();
+ tlist_da.cnt = 0;
return C_TERMINATE;
case C_CMDMENU:
@@ -1501,16 +2143,65 @@ static STATUS_T CmdRotate(
}
}
}
+ moveDescPos = pos;
+ moveDescTrk = trk;
+ SetUpMenu2(pos,trk);
+ menuPos = pos;
wMenuPopupShow( selectPopup2M );
return C_CONTINUE;
+ case C_TEXT:
+ if ((action>>8) == 'd') {
+ panCenter = pos;
+ LOG( log_pan, 2, ( "PanCenter:Sel-%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)0);
+ }
+ if ((action>>8) == 'e') {
+ DoZoomExtents(0);
+ }
+ if ((action>>8) == '0' || (action>>8 == 'o')) {
+ PanMenuEnter('o');
+ }
+ break;
case C_REDRAW:
+ if (anchors_da.cnt)
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
/* DO_REDRAW */
if ( state == 0 )
break;
- if ( rotateAlignState != 2 )
- DrawLine( &tempD, base, orig, 0, wDrawColorBlack );
- DrawSelectedTracksD( &mainD, wDrawColorWhite );
+ if ( rotateAlignState != 2 ) {
+ DIST_T width = mainD.scale*0.5;
+ DrawLine( &tempD, base, orig, 0, wDrawColorBlue );
+ if (drawnAngle) {
+ DrawLine( &tempD, orig_base, orig, (wDrawWidth)width, wDrawColorBlue );
+ ANGLE_T a = DifferenceBetweenAngles(FindAngle(orig, orig_base),FindAngle(orig, base));
+
+ DIST_T dist = FindDistance(orig,base);
+ if (dist>(60.0/75.0)*mainD.scale) dist = (60.0/75.0)*mainD.scale;
+
+ if (direction_set) {
+ if (clockwise) {
+ if (a<0) a = a + 360;
+ DrawArc( &tempD, orig, dist/2, FindAngle(orig,orig_base), a, FALSE, 0, wDrawColorBlue);
+ } else {
+ if (a>0) a = a - 360;
+ DrawArc( &tempD, orig, dist/2, FindAngle(orig,base), fabs(a), FALSE, 0, wDrawColorBlue);
+ }
+ DIST_T d;
+ d = mainD.scale*0.25;
+ ANGLE_T arrow_a = NormalizeAngle(FindAngle(orig,orig_base)+a/2);
+ coOrd arr1,arr2,arr3;
+ Translate(&arr2,orig,arrow_a,dist/2);
+ if (clockwise) arrow_a +=90;
+ else arrow_a -=90;
+ Translate(&arr1,arr2,arrow_a+135,d/2);
+ Translate(&arr3,arr2,arrow_a-135,d/2);
+ DrawLine( &tempD, arr1, arr2, 0, wDrawColorBlue );
+ DrawLine( &tempD, arr2, arr3, 0, wDrawColorBlue );
+ }
+ }
+
+ }
DrawMovedTracks();
break;
@@ -1524,12 +2215,9 @@ static void QuickMove( void* pos) {
return;
wDrawDelayUpdate( mainD.d, TRUE );
GetMovedTracks(FALSE);
- DrawSelectedTracksD( &mainD, wDrawColorWhite );
UndoStart( _("Move Tracks"), "Move Tracks" );
- MoveTracks( quickMove==MOVE_QUICK, TRUE, FALSE, move_pos, zero, 0.0 );
+ MoveTracks( TRUE, TRUE, FALSE, move_pos, zero, 0.0, TRUE );
wDrawDelayUpdate( mainD.d, FALSE );
- MainRedraw();
- MapRedraw();
}
static void QuickRotate( void* pangle )
@@ -1539,18 +2227,16 @@ static void QuickRotate( void* pangle )
return;
wDrawDelayUpdate( mainD.d, TRUE );
GetMovedTracks(FALSE);
- DrawSelectedTracksD( &mainD, wDrawColorWhite );
+ //DrawSelectedTracksD( &mainD, wDrawColorWhite );
UndoStart( _("Rotate Tracks"), "Rotate Tracks" );
- MoveTracks( quickMove==MOVE_QUICK, FALSE, TRUE, zero, cmdMenuPos, angle );
+ MoveTracks( TRUE, FALSE, TRUE, zero, cmdMenuPos, (double)angle/1000, TRUE);
wDrawDelayUpdate( mainD.d, FALSE );
- MainRedraw();
- MapRedraw();
}
static wMenu_p moveDescM;
static wMenuToggle_p moveDescMI;
-static track_p moveDescTrk;
+
static void ChangeDescFlag( wBool_t set, void * mode )
{
wDrawDelayUpdate( mainD.d, TRUE );
@@ -1565,113 +2251,228 @@ static void ChangeDescFlag( wBool_t set, void * mode )
wDrawDelayUpdate( mainD.d, FALSE );
}
-STATUS_T CmdMoveDescription(
- wAction_t action,
- coOrd pos )
-{
- static track_p trk;
- static EPINX_T ep;
- track_p trk1;
- EPINX_T ep1;
- DIST_T d, dd;
- static int mode;
-
- switch (action) {
- case C_START:
- if ( labelWhen < 2 || mainD.scale > labelScale ||
- (labelEnable&(LABELENABLE_TRKDESC|LABELENABLE_LENGTHS|LABELENABLE_ENDPT_ELEV))==0 ) {
- ErrorMessage( MSG_DESC_NOT_VISIBLE );
- return C_TERMINATE;
- }
- InfoMessage( _("Select and drag a description") );
- break;
- case C_DOWN:
- if ( labelWhen < 2 || mainD.scale > labelScale )
- return C_TERMINATE;
- trk = NULL;
- dd = 10000;
- trk1 = NULL;
+track_p FindTrackDescription(coOrd pos, EPINX_T * ep_o, int * mode_o, BOOL_T show_hidden, BOOL_T * hidden_o) {
+ track_p trk = NULL;
+ DIST_T d, dd = 10000;
+ track_p trk1 = NULL;
+ EPINX_T ep1=-1, ep=-1;
+ BOOL_T hidden_t, hidden;
+ coOrd dpos = pos;
+ coOrd cpos;
+ int mode = -1;
while ( TrackIterate( &trk1 ) ) {
if ( !GetLayerVisible(GetTrkLayer(trk1)) )
continue;
if ( (!GetTrkVisible(trk1)) && drawTunnel==0 )
continue;
- for ( ep1=0; ep1<GetTrkEndPtCnt(trk1); ep1++ ) {
- d = EndPtDescriptionDistance( pos, trk1, ep1 );
- if ( d < dd ) {
- dd = d;
- trk = trk1;
- ep = ep1;
- mode = 0;
+ if ( (labelEnable&LABELENABLE_ENDPT_ELEV)!=0 && *mode_o <= 0) {
+ for ( ep1=0; ep1<GetTrkEndPtCnt(trk1); ep1++ ) {
+ d = EndPtDescriptionDistance( pos, trk1, ep1, &dpos, FALSE, NULL ); //No hidden
+ if ( d < dd ) {
+ dd = d;
+ trk = trk1;
+ ep = ep1;
+ mode = 0;
+ hidden = FALSE;
+ cpos= dpos;
+ }
}
}
- if ( !QueryTrack( trk1, Q_HAS_DESC ) )
+ if ( !QueryTrack( trk1, Q_HAS_DESC ) && (mode <0 || mode > 0) )
continue;
- if ( ( GetTrkBits( trk1 ) & TB_HIDEDESC ) != 0 )
+ if ((labelEnable&LABELENABLE_TRKDESC)==0)
continue;
- d = CompoundDescriptionDistance( pos, trk1 );
+ if ( ( GetTrkBits( trk1 ) & TB_HIDEDESC ) != 0 ) {
+ if ( !show_hidden ) continue;
+ }
+ d = CompoundDescriptionDistance( pos, trk1, &dpos, show_hidden, &hidden_t );
if ( d < dd ) {
dd = d;
trk = trk1;
ep = -1;
mode = 1;
+ hidden = hidden_t;
+ cpos = dpos;
}
- d = CurveDescriptionDistance( pos, trk1 );
+ d = CurveDescriptionDistance( pos, trk1, &dpos, show_hidden, &hidden_t );
if ( d < dd ) {
dd = d;
trk = trk1;
ep = -1;
mode = 2;
+ hidden = hidden_t;
+ cpos = dpos;
}
- d = CornuDescriptionDistance( pos, trk1 );
+ d = CornuDescriptionDistance( pos, trk1, &dpos, show_hidden, &hidden_t );
if ( d < dd ) {
dd = d;
trk = trk1;
ep = -1;
mode = 3;
+ hidden = hidden_t;
+ cpos = dpos;
}
- d = BezierDescriptionDistance( pos, trk1 );
+ d = BezierDescriptionDistance( pos, trk1, &dpos, show_hidden, &hidden_t );
if ( d < dd ) {
dd = d;
trk = trk1;
ep = -1;
mode = 4;
+ hidden = hidden_t;
+ cpos = dpos;
}
}
- if (trk != NULL) {
- UndoStart( _("Move Label"), "Modedesc( T%d )", GetTrkIndex(trk) );
- UndoModify( trk );
+ if ((trk != NULL && (trk == OnTrack(&pos, FALSE, FALSE))) ||
+ IsClose(d) || IsClose(FindDistance( pos, cpos) )) { //Only when close to a label or the track - not anywhere on layout!
+ if (ep_o) *ep_o = ep;
+ if (mode_o) *mode_o = mode;
+ if (hidden_o) *hidden_o = hidden;
+ return trk;
+ }
+ else return NULL;
+}
+
+static long moveDescMode;
+
+STATUS_T CmdMoveDescription(
+ wAction_t action,
+ coOrd pos )
+{
+ static track_p trk;
+ static EPINX_T ep;
+ static BOOL_T hidden;
+ static int mode;
+ BOOL_T bChanged;
+
+ moveDescMode = (long)commandContext; //Context 0 = everything, 1 means elevations, 2 means descriptions
+
+ bChanged = FALSE;
+ switch (action&0xFF) {
+ case C_START:
+ moveDescTrk = NULL;
+ moveDescPos = zero;
+ trk = NULL;
+ hidden = FALSE;
+ mode = -1;
+ if ( labelWhen < 2 || mainD.scale > labelScale ||
+ (labelEnable&(LABELENABLE_TRKDESC|LABELENABLE_ENDPT_ELEV))==0 ) {
+ ErrorMessage( MSG_DESC_NOT_VISIBLE );
+ return C_TERMINATE;
+ }
+ InfoMessage( _("Select and drag a description") );
+ break;
+ case C_TEXT:
+ if (!moveDescTrk) return C_CONTINUE;
+ bChanged = FALSE;
+ if (action>>8 == 's') {
+ if ( ( GetTrkBits( moveDescTrk ) & TB_HIDEDESC) != 0 )
+ bChanged = TRUE;
+ ClrTrkBits( moveDescTrk, TB_HIDEDESC );
+ } else if (action>>8 == 'h') {
+ if ( ( GetTrkBits( moveDescTrk ) & TB_HIDEDESC) == 0 )
+ bChanged = TRUE;
+ SetTrkBits( moveDescTrk, TB_HIDEDESC );
+ }
+ if ( bChanged ) {
+ // We should push the draw/undraw of the description down
+ // but there is no clear way to do that
+ MainRedraw(); // CmdMoveDescription
+ }
+ /*no break*/
+ case wActionMove:
+ if ( labelWhen < 2 || mainD.scale > labelScale ) return C_CONTINUE;
+ mode = moveDescMode-1; // -1 means everything, 0 means elevations only, 1 means descriptions only
+ if ((trk=FindTrackDescription(pos,&ep,&mode,TRUE,&hidden))!=NULL) {
+ if (mode==0) {
+ InfoMessage(_("Elevation description"));
+ } else {
+ if (hidden) {
+ InfoMessage(_("Hidden description - 's' to Show"));
+ moveDescTrk = trk;
+ moveDescPos = pos;
+ } else {
+ InfoMessage(_("Shown description - 'h' to Hide"));
+ moveDescTrk = trk;
+ moveDescPos = pos;
+ }
+ }
+ return C_CONTINUE;
+ }
+ InfoMessage( _("Select and drag a description") );
+ break;
+ case C_DOWN:
+ if (( labelWhen < 2 || mainD.scale > labelScale ) ||
+ (labelEnable&(LABELENABLE_TRKDESC|LABELENABLE_ENDPT_ELEV))==0 ) {
+ ErrorMessage( MSG_DESC_NOT_VISIBLE );
+ return C_TERMINATE;
+ }
+ mode = moveDescMode-1;
+ trk = FindTrackDescription(pos,&ep,&mode,TRUE,&hidden);
+ if (trk == NULL )
+ return C_CONTINUE;
+ if (hidden) {
+ ClrTrkBits( trk, TB_HIDEDESC );
+ InfoMessage(_("Hidden Label - Drag to reveal"));
+ } else {
+ InfoMessage(_("Drag label"));
}
+ UndoStart( _("Move Label"), "Modedesc( T%d )", GetTrkIndex(trk) );
+ UndoModify( trk );
/* no break */
case C_MOVE:
case C_UP:
case C_REDRAW:
if ( labelWhen < 2 || mainD.scale > labelScale )
return C_TERMINATE;
- if (trk != NULL) {
- switch (mode) {
- case 0:
- return EndPtDescriptionMove( trk, ep, action, pos );
- case 1:
- return CompoundDescriptionMove( trk, action, pos );
- case 2:
- return CurveDescriptionMove( trk, action, pos );
- case 3:
- return CornuDescriptionMove( trk, action, pos );
- case 4:
- return BezierDescriptionMove( trk, action, pos );
+ if ( trk == NULL )
+ return C_CONTINUE;
+ STATUS_T status = C_ERROR;
+ if ( action == C_REDRAW ) {
+ if (mode==0) {
+ DrawEndPt2( &tempD, trk, ep, wDrawColorBlue );
+ } else {
+ if (hidden) {
+ DrawTrack( trk,&tempD,wDrawColorAqua);
+ } else {
+ DrawTrack( trk,&tempD,wDrawColorBlue);
+ }
}
}
+ switch (mode) {
+ case 0:
+ return EndPtDescriptionMove( trk, ep, action, pos );
+ case 1:
+ return CompoundDescriptionMove( trk, action, pos );
+ case 2:
+ return CurveDescriptionMove( trk, action, pos );
+ case 3:
+ return CornuDescriptionMove( trk, action, pos );
+ case 4:
+ return BezierDescriptionMove( trk, action, pos );
+ }
+ hidden = FALSE;
+ if ( action == C_UP ) {
+ trk = NULL;
+ InfoMessage(_("To Hide, use Context Menu"));
+ }
break;
+
case C_CMDMENU:
- moveDescTrk = OnTrack( &pos, TRUE, FALSE );
+ if (trk == NULL) {
+ moveDescTrk = OnTrack( &pos, TRUE, FALSE );
+ moveDescPos = pos;
+ } else {
+ moveDescTrk = trk;
+ moveDescPos = pos;
+ }
if ( moveDescTrk == NULL ) break;
if ( ! QueryTrack( moveDescTrk, Q_HAS_DESC ) ) break;
if ( moveDescM == NULL ) {
moveDescM = MenuRegister( "Move Desc Toggle" );
- moveDescMI = wMenuToggleCreate( moveDescM, "", _("Show Description"), 0, TRUE, ChangeDescFlag, NULL );
+ moveDescMI = wMenuToggleCreate( moveDescM, "", _("Show/Hide Description"), 0, TRUE, ChangeDescFlag, NULL );
}
wMenuToggleSet( moveDescMI, ( GetTrkBits( moveDescTrk ) & TB_HIDEDESC ) == 0 );
+ menuPos = pos;
wMenuPopupShow( moveDescM );
break;
@@ -1690,10 +2491,9 @@ static void FlipTracks(
track_p trk, trk1;
EPINX_T ep, ep1;
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
/*UndoStart( "Move/Rotate Tracks", "move/rotate" );*/
if (selectedTrackCount <= incrementalDrawLimit) {
- DrawMapBoundingBox( FALSE );
wDrawDelayUpdate( mainD.d, TRUE );
wDrawDelayUpdate( mapD.d, TRUE );
}
@@ -1724,12 +2524,10 @@ static void FlipTracks(
} else {
wDrawDelayUpdate( mainD.d, FALSE );
wDrawDelayUpdate( mapD.d, FALSE );
- DrawMapBoundingBox( TRUE );
}
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
UndoEnd();
InfoCount( trackCount );
- MainRedraw();
}
@@ -1759,25 +2557,15 @@ static STATUS_T CmdFlip(
return C_TERMINATE;
}
pos0 = pos1 = pos;
- DrawLine( &tempD, pos0, pos1, 0, wDrawColorBlack );
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
case C_MOVE:
- DrawLine( &tempD, pos0, pos1, 0, wDrawColorBlack );
pos1 = pos;
- DrawLine( &tempD, pos0, pos1, 0, wDrawColorBlack );
InfoMessage( _("Angle %0.2f"), FindAngle( pos0, pos1 ) );
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
case C_UP:
- DrawLine( &tempD, pos0, pos1, 0, wDrawColorBlack );
UndoStart( _("Flip Tracks"), "flip" );
FlipTracks( pos0, FindAngle( pos0, pos1 ) );
state = 0;
- MainRedraw();
- MapRedraw();
return C_TERMINATE;
#ifdef LATER
@@ -1795,13 +2583,15 @@ static STATUS_T CmdFlip(
return C_CONTINUE;
}
-static STATUS_T SelectArea(
+static BOOL_T SelectArea(
wAction_t action,
coOrd pos )
{
static coOrd pos0;
static int state;
static coOrd base, size, lo, hi;
+ static BOOL_T add;
+ static BOOL_T subtract;
int cnt;
track_p trk;
@@ -1810,19 +2600,21 @@ static STATUS_T SelectArea(
case C_START:
state = 0;
- return C_CONTINUE;
+ add = FALSE;
+ subtract = FALSE;
+ return FALSE;
case C_DOWN:
case C_RDOWN:
pos0 = pos;
- return C_CONTINUE;
+ add = (action == C_DOWN);
+ subtract = (action == C_RDOWN);
+ return TRUE;
case C_MOVE:
case C_RMOVE:
if (state == 0) {
state = 1;
- } else {
- DrawHilight( &mainD, base, size );
}
base = pos0;
size.x = pos.x - pos0.x;
@@ -1835,24 +2627,24 @@ static STATUS_T SelectArea(
size.y = - size.y;
base.y = pos.y;
}
- DrawHilight( &mainD, base, size );
- return C_CONTINUE;
+ return TRUE;
case C_UP:
case C_RUP:
if (state == 1) {
state = 0;
- DrawHilight( &mainD, base, size );
+ add = (action == C_UP);
+ subtract = (action == C_RUP);
cnt = 0;
trk = NULL;
+ if (add && (selectMode == 0)) SetAllTrackSelect( FALSE ); //Remove all tracks first
while ( TrackIterate( &trk ) ) {
GetBoundingBox( trk, &hi, &lo );
if (GetLayerVisible( GetTrkLayer( trk ) ) &&
lo.x >= base.x && hi.x <= base.x+size.x &&
lo.y >= base.y && hi.y <= base.y+size.y) {
- if ( (GetTrkSelected( trk )==0) == (action==C_UP) ) {
- cnt++;
- }
+ if ( (GetTrkSelected( trk )==0) == (action==C_UP) )
+ cnt++;
}
}
trk = NULL;
@@ -1862,41 +2654,85 @@ static STATUS_T SelectArea(
lo.x >= base.x && hi.x <= base.x+size.x &&
lo.y >= base.y && hi.y <= base.y+size.y) {
if ( (GetTrkSelected( trk )==0) == (action==C_UP) ) {
- if (cnt > incrementalDrawLimit) {
+ if (GetLayerModule(GetTrkLayer(trk))) {
+ if (add)
+ DoModuleTracks(GetTrkLayer(trk),SelectOneTrack,TRUE);
+ else
+ DoModuleTracks(GetTrkLayer(trk),SelectOneTrack,FALSE);
+ } else if (cnt > incrementalDrawLimit) {
selectedTrackCount += (action==C_UP?1:-1);
- if (action==C_UP)
+ if (add)
SetTrkBits( trk, TB_SELECTED );
else
ClrTrkBits( trk, TB_SELECTED );
} else {
- SelectOneTrack( trk, action==C_UP );
+ SelectOneTrack( trk, add );
}
}
}
}
+ add = FALSE;
+ subtract = FALSE;
+ if (cnt > incrementalDrawLimit) {
+ MainRedraw(); // SelectArea C_UP
+ } else {
+ RedrawSelectedTracksBoundary();
+ }
SelectedTrackCountChange();
- if (cnt > incrementalDrawLimit)
- MainRedraw();
}
- return C_CONTINUE;
+ return FALSE;
case C_CANCEL:
- if (state == 1) {
- DrawHilight( &mainD, base, size );
- state = 0;
- }
+ state = 0;
+ add = FALSE;
+ subtract = FALSE;
break;
case C_REDRAW:
if (state == 0)
break;
- DrawHilight( &mainD, base, size );
+ //Draw to-be selected tracks versus not.
+ trk = NULL;
+ if (selectMode == 0 && add) HighlightSelectedTracks(NULL, TRUE, TRUE);
+ while ( TrackIterate( &trk ) ) {
+ GetBoundingBox( trk, &hi, &lo );
+ if (GetLayerVisible( GetTrkLayer( trk ) ) &&
+ lo.x >= base.x && hi.x <= base.x+size.x &&
+ lo.y >= base.y && hi.y <= base.y+size.y) {
+ if (GetLayerModule(GetTrkLayer(trk))) {
+ if (add)
+ DoModuleTracks(GetTrkLayer(trk),DrawSingleTrack,TRUE);
+ else if (subtract)
+ DoModuleTracks(GetTrkLayer(trk),DrawSingleTrack,FALSE);
+ } else {
+ if (add) {
+ if (selectMode == 0 && add)
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
+ if (!GetTrkSelected(trk))
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
+ }
+ else if (subtract) {
+ if (GetTrkSelected(trk))
+ DrawTrack(trk,&tempD,wDrawColorPreviewUnselected);
+ }
+ }
+ }
+ }
+ if (add || subtract) {
+ DrawHilight( &tempD, base, size, add );
+ return TRUE;
+ }
break;
}
- return C_CONTINUE;
+ return FALSE;
}
+extern BOOL_T inDescribeCmd;
+extern wIndex_t modifyCmdInx;
+extern wIndex_t describeCmdInx;
+extern wIndex_t panCmdInx;
+extern wIndex_t trainCmdInx;
static STATUS_T SelectTrack(
coOrd pos )
@@ -1904,124 +2740,515 @@ static STATUS_T SelectTrack(
track_p trk;
char msg[STR_SIZE];
- if ((trk = OnTrack( &pos, TRUE, FALSE )) == NULL) {
- return C_CONTINUE;
+ if (((trk = OnTrack( &pos, FALSE, FALSE )) == NULL) && selectZero) { //If option set and !ctrl or unset and ctrl
+ SetAllTrackSelect( FALSE ); //Unselect all
+ return C_CONTINUE;
}
+ if (trk == NULL) return C_CONTINUE;
+ inDescribeCmd = FALSE;
DescribeTrack( trk, msg, sizeof msg );
InfoMessage( msg );
- if (MyGetKeyState() & WKEY_SHIFT) {
- SelectConnectedTracks( trk );
+ if (GetLayerModule(GetTrkLayer(trk))) {
+ if (((MyGetKeyState() & WKEY_CTRL) && (selectMode==0)) || (!(MyGetKeyState() & WKEY_CTRL) && (selectMode==1)) ) {
+ DoModuleTracks(GetTrkLayer(trk),SelectOneTrack,!GetTrkSelected(trk));
+ } else {
+ SetAllTrackSelect( FALSE ); //Just this Track if selectMode = 0 and !CTRL or selectMode = 1 and CTRL
+ DoModuleTracks(GetTrkLayer(trk),SelectOneTrack,TRUE);
+ }
+ RedrawSelectedTracksBoundary();
+ return C_CONTINUE;
+ }
+ if (MyGetKeyState() & WKEY_SHIFT) { //All track up to
+ SelectConnectedTracks( trk, FALSE );
+ } else if ((MyGetKeyState() & WKEY_CTRL) && (selectMode==0)) {
+ SelectOneTrack( trk, !GetTrkSelected(trk) );
+ } else if (!(MyGetKeyState() & WKEY_CTRL) && (selectMode==1)) {
+ SelectOneTrack( trk, !GetTrkSelected(trk) );
} else {
+ SetAllTrackSelect( FALSE ); //Just this Track
SelectOneTrack( trk, !GetTrkSelected(trk) );
}
+ RedrawSelectedTracksBoundary();
+
return C_CONTINUE;
}
+static STATUS_T Activate( coOrd pos) {
+ track_p trk;
+ if ((trk = OnTrack( &pos, TRUE, FALSE )) == NULL) {
+ return C_CONTINUE;
+ }
+ if (GetLayerModule(GetTrkLayer(trk))) {
+ return C_CONTINUE;
+ }
+ if (QueryTrack(trk,Q_IS_ACTIVATEABLE)) ActivateTrack(trk);
+
+ return C_CONTINUE;
+
+}
+
+track_p IsInsideABox(coOrd pos) {
+ track_p ts = NULL;
+ while ( TrackIterate( &ts ) ) {
+ if (!GetLayerVisible( GetTrkLayer( ts))) continue;
+ if (!GetTrkSelected(ts)) continue;
+ coOrd hi,lo;
+ GetBoundingBox(ts, &hi, &lo);
+ double boundary = mainD.scale*5/mainD.dpi;
+ if ((pos.x>=lo.x-boundary && pos.x<=hi.x+boundary) && (pos.y>=lo.y-boundary && pos.y<=hi.y+boundary)) {
+ return ts;
+ }
+ }
+ return NULL;
+}
+
+void DrawHighlightBoxes(BOOL_T highlight_selected, BOOL_T select, track_p not_this) {
+ track_p ts = NULL;
+ coOrd origin,max;
+ BOOL_T first = TRUE;
+ while ( TrackIterate( &ts ) ) {
+ if ( !GetLayerVisible( GetTrkLayer( ts))) continue;
+ if (!GetTrkSelected(ts)) continue;
+ if (GetLayerModule(GetTrkLayer(ts))) {
+ DrawHighlightLayer(GetTrkLayer(ts));
+ }
+ coOrd hi,lo;
+ if (highlight_selected && (ts != not_this)) DrawTrack(ts,&tempD,select?wDrawColorPreviewSelected:wDrawColorPreviewUnselected );
+ GetBoundingBox(ts, &hi, &lo);
+ if (first) {
+ origin = lo;
+ max = hi;
+ first = FALSE;
+ } else {
+ if (lo.x <origin.x) origin.x = lo.x;
+ if (lo.y <origin.y) origin.y = lo.y;
+ if (hi.x >max.x) max.x = hi.x;
+ if (hi.y >max.y) max.y = hi.y;
+ }
+ }
+ if (!first) {
+ coOrd size;
+ size.x = max.x-origin.x;
+ size.y = max.y-origin.y;
+ wPos_t w,h;
+ w = (wPos_t)((size.x/mainD.scale)*mainD.dpi+0.5+10);
+ h = (wPos_t)((size.y/mainD.scale)*mainD.dpi+0.5+10);
+ wPos_t x, y;
+ tempD.CoOrd2Pix(&tempD,origin,&x,&y);
+ wDrawFilledRectangle(tempD.d, x-5, y-5, w, h, wDrawColorPowderedBlue, wDrawOptTemp|wDrawOptTransparent);
+ }
+
+}
+
+static STATUS_T CallModify(wAction_t action,
+ coOrd pos ) {
+ int rc = CmdModify(action,pos);
+ if (rc != C_CONTINUE)
+ doingDouble = FALSE;
+ return rc;
+}
+
+static STATUS_T CallDescribe(wAction_t action, coOrd pos) {
+ int rc = CmdDescribe(action, pos);
+ return rc;
+}
+
+static void CallPushDescribe(void * func) {
+ if (moveDescTrk) {
+ CallDescribe(C_START, moveDescPos);
+ CallDescribe(C_DOWN, moveDescPos);
+ CallDescribe(C_UP, moveDescPos);
+ }
+ return;
+}
+
+static STATUS_T CmdSelect(wAction_t,coOrd);
+
+static void CallPushModify(void * func) {
+ if (moveDescTrk) {
+ CmdSelect(C_LDOUBLE, moveDescPos);
+ }
+ return;
+}
static STATUS_T CmdSelect(
wAction_t action,
coOrd pos )
{
- static enum { AREA, MOVE, MOVEDESC, NONE } mode;
- static BOOL_T doingMove = TRUE;
- STATUS_T rc=C_CONTINUE;
- if ( (action == C_DOWN || action == C_RDOWN) ) {
- mode = AREA;
- if (MyGetKeyState() & WKEY_SHIFT) {
- mode = MOVE;
- } else if (MyGetKeyState() & WKEY_CTRL) {
- mode = MOVEDESC;
+ static BOOL_T doingMove;
+ static BOOL_T doingRotate;
+
+
+
+ STATUS_T rc=C_CONTINUE;
+ static track_p trk = NULL;
+ typedef enum {NOSHOW,SHOWMOVE,SHOWROTATE,SHOWMODIFY,SHOWACTIVATE} showType;
+ static showType showMode;
+
+ mode = AREA;
+ if (doingAlign || doingRotate || doingMove )
+ mode = MOVE;
+ else {
+ if ( (action == C_DOWN) || (action == C_RDOWN) || ((action&0xFF) == wActionExtKey) ) {
+ mode = AREA;
+ if ( ((action&0xFF) == wActionExtKey) || ( //Moves don't need to be in a box
+ ( MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) && IsInsideABox(pos)) ) //But cursors do
+ {
+ mode = MOVE;
+ }
}
}
- switch (action) {
+
+ switch (action&0xFF) {
case C_START:
- InfoMessage( _("Select tracks") );
-#ifdef LATER
- if ((!importMove) && selectedTrackCount > 0) {
- SetAllTrackSelect( FALSE );
- }
-#endif
- importMove = FALSE;
+ InfoMessage( _("Select track") );
+ doingMove = FALSE;
+ doingRotate = FALSE;
+ doingAlign = FALSE;
+ doingDouble = FALSE;
+ showMode = NOSHOW;
SelectArea( action, pos );
wMenuPushEnable( rotateAlignMI, FALSE );
+ wSetCursor(mainD.d,defaultCursor);
+ mode = AREA;
+ trk = NULL;
+ break;
+
+ case wActionModKey:
+ case wActionMove:
+ if (doingDouble) {
+ return CallModify(action,pos);
+ }
+ showMode = NOSHOW;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ coOrd p = pos;
+ trk = OnTrack( &p, FALSE, FALSE );
+ track_p ht;
+ if ((selectedTrackCount==0) && (trk == NULL)) return C_CONTINUE;
+ if (trk && !CheckTrackLayerSilent( trk ) ) {
+ if (GetLayerFrozen(GetTrkLayer(trk)) ) {
+ trk = NULL;
+ InfoMessage(_("Track is in Frozen Layer"));
+ return C_CONTINUE;
+ }
+ }
+ if (selectedTrackCount>0) {
+ if ((ht = IsInsideABox(pos)) != NULL) {
+ if ((MyGetKeyState()&WKEY_SHIFT)) {
+ CreateMoveAnchor(pos);
+ showMode = SHOWMOVE;
+ } else if ((MyGetKeyState()&WKEY_CTRL)) {
+ CreateRotateAnchor(pos);
+ showMode = SHOWROTATE;
+ } else if (!GetLayerModule(GetTrkLayer(ht))) {
+ if (QueryTrack( ht, Q_CAN_MODIFY_CONTROL_POINTS ) ||
+ QueryTrack( ht, Q_IS_CORNU ) ||
+ (QueryTrack( ht, Q_IS_DRAW ) && !QueryTrack( ht, Q_IS_TEXT))) {
+ CreateModifyAnchor(pos);
+ showMode = SHOWMODIFY;
+ } else {
+ if (QueryTrack(ht,Q_IS_ACTIVATEABLE))
+ CreateActivateAnchor(pos);
+ showMode = SHOWACTIVATE;
+ }
+ }
+ }
+ }
break;
case C_DOWN:
- case C_UP:
- case C_MOVE:
case C_RDOWN:
- case C_RUP:
- case C_RMOVE:
- case C_REDRAW:
+ if (doingDouble) {
+ return CallModify(action,pos);
+ }
+ DYNARR_RESET(trkSeg_t,anchors_da);
switch (mode) {
+ rc = C_CONTINUE;
case MOVE:
- if (SelectedTracksAreFrozen()) {
+ if (SelectedTracksAreFrozen() || (selectedTrackCount==0)) {
rc = C_TERMINATE;
- mode = NONE;
- } else if (action >= C_DOWN && action <= C_UP) {
- rc = CmdMove( action, pos );
- doingMove = TRUE;
- } else if (action >= C_RDOWN && action <= C_RUP) {
- rc = CmdRotate( action-C_RDOWN+C_DOWN, pos );
doingMove = FALSE;
- } else if (action == C_REDRAW) {
- if (doingMove) {
- rc = CmdMove( C_REDRAW, pos );
- } else {
- rc = CmdRotate( C_REDRAW, pos );
- }
+ } else if ((MyGetKeyState()&(WKEY_CTRL|WKEY_SHIFT))==WKEY_CTRL) {
+ doingRotate = TRUE;
+ doingMove = FALSE;
+ RotateAlign( FALSE );
+ rc = CmdRotate( action, pos );
+ } else if ((MyGetKeyState()&(WKEY_SHIFT|WKEY_CTRL))==WKEY_SHIFT) {
+ doingMove = TRUE;
+ doingRotate = FALSE;
+ rc = CmdMove( action, pos );
}
break;
- case MOVEDESC:
- rc = CmdMoveDescription( action, pos );
+ case AREA:
+ doingMove = FALSE;
+ doingRotate = FALSE;
+ SelectArea( action, pos );
+ break;
+ default: ;
+ }
+ trk = NULL;
+ return rc;
+ break;
+ case wActionExtKey:
+ case C_RMOVE:
+ case C_MOVE:
+ if (doingDouble) {
+ return CallModify(action,pos);
+ }
+ if ((action&0xFF) == wActionExtKey && ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL)) == (WKEY_SHIFT|WKEY_CTRL))) { //Both + arrow
+ doingMove = TRUE;
+ mode = MOVE;
+ }
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ switch (mode) {
+ case MOVE:
+ if (SelectedTracksAreFrozen() || (selectedTrackCount==0)) {
+ rc = C_TERMINATE;
+ tlist_da.cnt = 0;
+ doingMove = FALSE;
+ doingRotate = FALSE;
+ } else if (doingRotate == TRUE) {
+ RotateAlign( FALSE );
+ rc = CmdRotate( action, pos );
+ } else if (doingMove == TRUE) {
+ rc = CmdMove( action, pos );
+ }
break;
case AREA:
- rc = SelectArea( action, pos );
+ doingMove = FALSE;
+ doingRotate = FALSE;
+ SelectArea( action, pos );
+ break;
+ default: ;
+ }
+ if ((action&0xFF) == wActionExtKey && ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL)) == (WKEY_SHIFT|WKEY_CTRL))) //Both
+ doingMove = FALSE;
+ return rc;
+ break;
+ case C_RUP:
+ case C_UP:
+ if (doingDouble) {
+ return CallModify(action,pos);
+ }
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ switch (mode) {
+ case MOVE:
+ if (SelectedTracksAreFrozen() || (selectedTrackCount==0)) {
+ rc = C_TERMINATE;
+ doingMove = FALSE;
+ doingRotate = FALSE;
+ } else if (doingRotate == TRUE) {
+ RotateAlign( FALSE );
+ rc = CmdRotate( action, pos );
+ } else if (doingMove == TRUE) {
+ rc = CmdMove( action, pos );
+ }
break;
- case NONE:
+ case AREA:
+ doingMove = FALSE;
+ doingRotate = FALSE;
+ SelectArea( action, pos );
+ rc = C_CONTINUE;
break;
+ default: ;
}
- if (action == C_UP || action == C_RUP)
- mode = AREA;
+ doingMove = FALSE;
+ doingRotate = FALSE;
+ mode = AREA;
return rc;
-
- case wActionMove:
break;
+ case C_REDRAW:
+ if (doingDouble) {
+ return CallModify(action,pos);
+ }
+ if (doingMove) {
+ rc = CmdMove( C_REDRAW, pos );
+ } else if (doingRotate) {
+ rc = CmdRotate( C_REDRAW, pos );
+ }
+
+ //Once doing a move or a rotate, make an early exit
+ if (doingMove || doingRotate) {
+ if (anchors_da.cnt) {
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ }
+ return C_CONTINUE;
+ }
+ BOOL_T AreaSelect = FALSE;
+ // Draw the selected area, no-op if none selected
+ if (mode==AREA) {
+ AreaSelect = SelectArea( action, pos );
+ if (AreaSelect) return C_CONTINUE;
+ }
+
+ // Highlight a whole Module's worth of tracks if we are hovering over one
+ if (trk && GetLayerModule(GetTrkLayer(trk))) {
+ if ( (selectMode == 1) && ((MyGetKeyState() & (WKEY_CTRL|WKEY_SHIFT)) != WKEY_CTRL) )
+ DoModuleTracks(GetTrkLayer(trk),DrawSingleTrack,!GetTrkSelected(trk)); //Toggle
+ else
+ DoModuleTracks(GetTrkLayer(trk),DrawSingleTrack,TRUE);
+ DrawHighlightLayer(GetTrkLayer(trk));
+ }
+
+ //Draw all existing highlight boxes only
+ DrawHighlightBoxes(FALSE, FALSE, trk);
+
+ // If not on a track, show all tracks as going to be de-selected if selectZero on
+ if (!trk && selectZero ) {
+ HighlightSelectedTracks(NULL, TRUE, TRUE);
+ //Handle the SHIFT+ which means SelectAllConnected case
+ } else if ( trk && !IsTrackDeleted(trk)) {
+ if ((MyGetKeyState() & WKEY_SHIFT) )
+ SelectConnectedTracks(trk, TRUE); //Highlight all connected
+ //Normal case - handle track we are hovering over
+ else {
+ //Select=Add
+ if (selectMode == 1) {
+ if ((MyGetKeyState() & (WKEY_CTRL|WKEY_SHIFT)) == WKEY_CTRL) {
+ //Only Highlight if adding
+ if (!GetTrkSelected(trk))
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
+ } else {
+ if (GetTrkSelected(trk))
+ DrawTrack(trk,&tempD,wDrawColorPreviewUnselected); //Toggle
+ else
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
+ }
+ //Select=Only
+ } else {
+ if ((MyGetKeyState() & (WKEY_CTRL|WKEY_SHIFT)) == WKEY_CTRL) {
+ if (GetTrkSelected(trk))
+ DrawTrack(trk,&tempD,wDrawColorPreviewUnselected); //Toggle
+ else
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
+ } else {
+ //Only Highlight if adding
+ if (!GetTrkSelected(trk))
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected );
+ }
+ }
+ }
+ // Now Highlight the rest of the tracks or Module
+ if (GetLayerModule(GetTrkLayer(trk))) {
+ if (selectMode == 1 && ((MyGetKeyState() & (WKEY_CTRL|WKEY_SHIFT)) != WKEY_CTRL) )
+ DoModuleTracks(GetTrkLayer(trk),DrawSingleTrack,!GetTrkSelected(trk)); //Toggle
+ else
+ DoModuleTracks(GetTrkLayer(trk),DrawSingleTrack,TRUE);
+ DrawHighlightLayer(GetTrkLayer(trk));
+ } else {
+ //Select=Add
+ if (selectMode == 1) {
+ if (((MyGetKeyState() & (WKEY_CTRL|WKEY_SHIFT)) == WKEY_CTRL))
+ HighlightSelectedTracks(trk, TRUE, TRUE);
+ //else
+ // HighlightSelectedTracks(trk, TRUE, FALSE); Highlight all selected
+ //Select=Only
+ } else {
+ if (((MyGetKeyState() & (WKEY_CTRL|WKEY_SHIFT)) != WKEY_CTRL))
+ HighlightSelectedTracks(trk, TRUE, TRUE);
+ //else
+ // HighlightSelectedTracks(trk, TRUE, TRUE); Highlight all selected
+ }
+ }
+ }
+ //Finally add the anchors for any actions or snaps
+ if (anchors_da.cnt) {
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ }
+
+ return rc;
+
case C_LCLICK:
+ if (doingDouble) {
+ return CallModify(action,pos);
+ }
switch (mode) {
case MOVE:
- case MOVEDESC:
- break;
case AREA:
- case NONE:
- return SelectTrack( pos );
+ if (doingAlign) {
+ rc = CmdRotate (C_DOWN, pos);
+ rc = CmdRotate (C_UP, pos);
+ } else
+ rc = SelectTrack( pos );
+ doingRotate = FALSE;
+ doingMove = FALSE;
+ return rc;
}
mode = AREA;
break;
+ case C_LDOUBLE:
+ if (doingDouble) {
+ return C_CONTINUE;
+ }
+ switch (mode) {
+ case AREA:
+ if ((ht = OnTrack(&pos,FALSE,FALSE))!=NULL) {
+ if (QueryTrack( ht, Q_CAN_MODIFY_CONTROL_POINTS ) ||
+ QueryTrack( ht, Q_IS_CORNU ) ||
+ (QueryTrack( ht, Q_IS_DRAW ) && !QueryTrack( ht, Q_IS_TEXT ))) {
+ doingDouble = TRUE;
+ CallModify(C_START,pos);
+ if (doingDouble == FALSE) return C_CONTINUE;
+ CallModify(C_LDOUBLE,pos);
+ } else if (QueryTrack( ht, Q_IS_ACTIVATEABLE)){
+ return Activate(pos);
+ }
+ }
+ break;
+ case MOVE:
+ default:
+ break;
+ }
+ break;
+
case C_CMDMENU:
+ if (doingDouble) {
+ return CallModify(action,pos);
+ }
+ menuPos = pos;
if (selectedTrackCount <= 0) {
wMenuPopupShow( selectPopup1M );
} else {
- coOrd base = pos;
track_p trk = OnTrack(&pos, FALSE, FALSE); //Note pollutes pos if turntable
- if ((trk) &&
- QueryTrack(trk,Q_CAN_ADD_ENDPOINTS)) { //Turntable snap to center if within 1/4 radius
- trackParams_t trackParams;
- if (GetTrackParams(PARAMS_CORNU, trk, pos, &trackParams)) {
- DIST_T dist = FindDistance(base, trackParams.ttcenter);
- if (dist < trackParams.ttradius/4) {
- cmdMenuPos = trackParams.ttcenter;
- }
- }
- }
+ SetUpMenu2(pos,trk);
wMenuPopupShow( selectPopup2M );
}
return C_CONTINUE;
+ case C_TEXT:
+ if (doingDouble) {
+ return CallModify(action,pos);
+ }
+ if ((action>>8) == 'c') {
+ panCenter = pos;
+ LOG( log_pan, 2, ( "PanCenter:Sel-%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)0);
+ }
+ if ((action>>8) == 'e') {
+ DoZoomExtents(0);
+ }
+ if ((action>>8) == '0' || (action>>8 == 'o')) {
+ PanMenuEnter('o');
+ }
+ if ((action>>8) == '?') {
+ if((moveDescTrk = OnTrack(&pos,FALSE,FALSE)) != NULL)
+ moveDescPos = pos;
+ CallPushDescribe((void*)0);
+ wSetCursor(mainD.d,defaultCursor);
+ moveDescTrk = NULL;
+ }
+ break;
+ case C_FINISH:
+ if (doingMove) UndoEnd();
+ doingDouble = FALSE;
+ break;
+ default:
+ if (doingDouble) return CallModify(action, pos);
}
+
return C_CONTINUE;
}
@@ -2029,6 +3256,7 @@ static STATUS_T CmdSelect(
#include "bitmaps/select.xpm"
#include "bitmaps/delete.xpm"
#include "bitmaps/tunnel.xpm"
+#include "bitmaps/bridge.xpm"
#include "bitmaps/move.xpm"
#include "bitmaps/rotate.xpm"
#include "bitmaps/flip.xpm"
@@ -2044,11 +3272,27 @@ static void SetMoveMode( char * line )
enableMoveDraw = ((tmp&0x10) == 0);
}
+static void moveDescription( void ) {
+ if (!moveDescTrk) return;
+ int hidden = GetTrkBits( moveDescTrk) &TB_HIDEDESC ;
+ if (hidden)
+ ClrTrkBits( moveDescTrk, TB_HIDEDESC );
+ else
+ SetTrkBits( moveDescTrk, TB_HIDEDESC );
+}
+
EXPORT void InitCmdSelect( wMenu_p menu )
{
selectCmdInx = AddMenuButton( menu, CmdSelect, "cmdSelect", _("Select"), wIconCreatePixMap(select_xpm),
- LEVEL0, IC_CANCEL|IC_POPUP|IC_LCLICK|IC_CMDMENU, ACCL_SELECT, NULL );
+ LEVEL0, IC_CANCEL|IC_POPUP|IC_LCLICK|IC_CMDMENU|IC_WANT_MOVE|IC_WANT_MODKEYS, ACCL_SELECT, NULL );
+}
+
+extern wIndex_t trainCmdInx;
+
+EXPORT void InitCmdSelect2( wMenu_p menu ) {
+
+
endpt_bm = wDrawBitMapCreate( mainD.d, bmendpt_width, bmendpt_width, 7, 7, bmendpt_bits );
angle_bm[0] = wDrawBitMapCreate( mainD.d, bma90_width, bma90_width, 7, 7, bma90_bits );
angle_bm[1] = wDrawBitMapCreate( mainD.d, bma135_width, bma135_width, 7, 7, bma135_bits );
@@ -2058,24 +3302,76 @@ EXPORT void InitCmdSelect( wMenu_p menu )
wPrefGetInteger( "draw", "movemode", &moveMode, MAXMOVEMODE );
if (moveMode > MAXMOVEMODE || moveMode < 0)
moveMode = MAXMOVEMODE;
-
- selectPopup1M = MenuRegister( "Move Draw Mode" );
- quickMove1M[0] = wMenuToggleCreate( selectPopup1M, "", _("Normal"), 0, quickMove==0, ChangeQuickMove, (void *) 0 );
- quickMove1M[1] = wMenuToggleCreate( selectPopup1M, "", _("Simple"), 0, quickMove==1, ChangeQuickMove, (void *) 1 );
- quickMove1M[2] = wMenuToggleCreate( selectPopup1M, "", _("End Points"), 0, quickMove==2, ChangeQuickMove, (void *) 2 );
- selectPopup2M = MenuRegister( "Move Draw Mode " );
- quickMove2M[0] = wMenuToggleCreate( selectPopup2M, "", _("Normal"), 0, quickMove==0, ChangeQuickMove, (void *) 0 );
- quickMove2M[1] = wMenuToggleCreate( selectPopup2M, "", _("Simple"), 0, quickMove==1, ChangeQuickMove, (void *) 1 );
- quickMove2M[2] = wMenuToggleCreate( selectPopup2M, "", _("End Points"), 0, quickMove==2, ChangeQuickMove, (void *) 2 );
+ selectPopup1M = MenuRegister( "Select Mode Menu" );
+ wMenuPushCreate(selectPopup1M, "", _("Undo"), 0,(wMenuCallBack_p) UndoUndo, (void *) 0);
+ wMenuPushCreate(selectPopup1M, "", _("Redo"), 0,(wMenuCallBack_p) UndoRedo, (void *) 0);
+ wMenuSeparatorCreate( selectPopup1M );
+ wMenuPushCreate(selectPopup1M, "cmdDescribeMode", GetBalloonHelpStr("cmdModifyMode"), 0, DoCommandB, (void*) (intptr_t) modifyCmdInx);
+ wMenuPushCreate(selectPopup1M, "cmdPanMode", GetBalloonHelpStr("cmdPanMode"), 0, DoCommandB, (void*) (intptr_t) panCmdInx);
+ wMenuPushCreate(selectPopup1M, "cmdTrainMode", GetBalloonHelpStr("cmdTrainMode"), 0, DoCommandB, (void*) (intptr_t) trainCmdInx);
+ wMenuSeparatorCreate( selectPopup1M );
+ wMenuPushCreate(selectPopup1M, "", _("Zoom In"), 0,(wMenuCallBack_p) DoZoomUp, (void*) 1);
+ wMenuPushCreate( selectPopup1M, "", _("Zoom to extents - 'e'"), 0, (wMenuCallBack_p)DoZoomExtents, (void*) 0);
+ wMenu_p zoomPop1 = wMenuMenuCreate(selectPopup1M, "", _("&Zoom"));
+ InitCmdZoom(NULL, NULL, zoomPop1, NULL);
+ wMenuPushCreate(selectPopup1M, "", _("Zoom Out"), 0, (wMenuCallBack_p) DoZoomDown, (void*) 1);
+ wMenuPushCreate(selectPopup1M, "", _("Pan to Origin - 'o'/'0'"), 0, (wMenuCallBack_p) PanMenuEnter, (void*) 'o');
+ wMenuPushCreate(selectPopup1M, "", _("Pan Center Here - 'c'"), 0, (wMenuCallBack_p) PanHere, (void*) 3);
+ wMenuSeparatorCreate( selectPopup1M );
+ wMenuPushCreate(selectPopup1M, "", _("Select All"), 0,(wMenuCallBack_p) SetAllTrackSelect, (void *) 1);
+ wMenuPushCreate(selectPopup1M, "",_("Select Current Layer"), 0,(wMenuCallBack_p) SelectCurrentLayer, (void *) 0);
+ wMenuSeparatorCreate( selectPopup1M );
+
+ selectPopup2M = MenuRegister( "Track Selected Menu " );
+ wMenuPushCreate(selectPopup2M, "", _("Undo"), 0,(wMenuCallBack_p) UndoUndo, (void *) 0);
+ wMenuPushCreate(selectPopup2M, "", _("Redo"), 0,(wMenuCallBack_p) UndoRedo, (void *) 0);
+ wMenuSeparatorCreate( selectPopup2M );
+ wMenuPushCreate(selectPopup2M, "", _("Zoom In"), 0,(wMenuCallBack_p) DoZoomUp, (void*) 1);
+ wMenuPushCreate(selectPopup2M, "", _("Zoom Out"), 0, (wMenuCallBack_p) DoZoomDown, (void*) 1);
+ wMenuPushCreate(selectPopup2M, "", _("Pan Center Here - 'c'"), 0, (wMenuCallBack_p) PanHere, (void*) 3);
wMenuSeparatorCreate( selectPopup2M );
+ wMenuPushCreate(selectPopup2M, "", _("Deselect All"), 0, (wMenuCallBack_p) SetAllTrackSelect, (void *) 0);
+ wMenuSeparatorCreate( selectPopup2M );
+ wMenuPushCreate(selectPopup2M, "", _("Properties -'?'"), 0,(wMenuCallBack_p) CallPushDescribe, (void*)0);
+ menuPushModify = wMenuPushCreate(selectPopup2M, "", _("Modify/Activate Track"), 0,(wMenuCallBack_p) CallPushModify, (void*)0);
+ wMenuSeparatorCreate( selectPopup2M );
+ wMenuPushCreate(selectPopup2M, "", _("Cut"), 0,(wMenuCallBack_p) EditCut, (void *) 0);
+ wMenuPushCreate(selectPopup2M, "", _("Copy"), 0,(wMenuCallBack_p) EditCopy, (void *) 0);
+ wMenuPushCreate(selectPopup2M, "", _("Paste"), 0, (wMenuCallBack_p) EditPaste, (void *) 0);
+ wMenuPushCreate(selectPopup2M, "", _("Clone"), 0, (wMenuCallBack_p) EditClone, (void *) 0);
AddMoveMenu( selectPopup2M, QuickMove);
+ selectPopup2RM = wMenuMenuCreate(selectPopup2M, "", _("Rotate..."));
+ AddRotateMenu( selectPopup2RM, QuickRotate );
+ rotateAlignMI = wMenuPushCreate( selectPopup2RM, "", _("Align"), 0, (wMenuCallBack_p)RotateAlign, (void* ) 1 );
+ wMenuSeparatorCreate( selectPopup2M );
+ descriptionMI = wMenuPushCreate(selectPopup2M, "cmdMoveLabel", _("Show/Hide Description"), 0, (wMenuCallBack_p)moveDescription, (void*) 0);
+ wMenuSeparatorCreate( selectPopup2M );
+ hideMI = wMenuPushCreate(selectPopup2M, "", _("Hide/NoHide"), 0,(wMenuCallBack_p) SelectTunnel, (void *) 0);
+ bridgeMI = wMenuPushCreate(selectPopup2M, "", _("Bridge/NoBridge"), 0,(wMenuCallBack_p) SelectBridge, (void *) 0);
+ tiesMI = wMenuPushCreate(selectPopup2M, "", _("NoTies/Ties"), 0,(wMenuCallBack_p) SelectTies, (void *) 0);
+ selectPopup2TM = wMenuMenuCreate(selectPopup2M, "", _("Thickness..."));
+ wMenuPushCreate( selectPopup2TM, "", _("Thin Tracks"), 0, (void*)(wMenuCallBack_p)SelectTrackWidth, (void *)0 );
+ wMenuPushCreate( selectPopup2TM, "", _("Medium Tracks"), 0, (void*)(wMenuCallBack_p)SelectTrackWidth, (void *)2 );
+ wMenuPushCreate( selectPopup2TM, "", _("Thick Tracks"), 0, (void*)(wMenuCallBack_p)SelectTrackWidth, (void *)3 );
+ selectPopup2TYM = wMenuMenuCreate( selectPopup2M, "", _("LineType...") );
+ wMenuPushCreate( selectPopup2TYM, "", _("Solid Line"), 0, (wMenuCallBack_p)SelectLineType, (void*)0 );
+ wMenuPushCreate( selectPopup2TYM, "", _("Dashed Line"), 0, (wMenuCallBack_p)SelectLineType, (void*)1 );
+ wMenuPushCreate( selectPopup2TYM, "", _("Dotted Line"), 0, (wMenuCallBack_p)SelectLineType, (void*)2 );
+ wMenuPushCreate( selectPopup2TYM, "", _("Dash-Dotted Line"), 0, (wMenuCallBack_p)SelectLineType, (void*)3 );
+ wMenuPushCreate( selectPopup2TYM, "", _("Dash-Dot-Dotted Line"), 0, (wMenuCallBack_p)SelectLineType, (void*)4 );
+ wMenuSeparatorCreate( selectPopup2M );
+ wMenuPushCreate(selectPopup2M, "", _("Move To Front"), 0,(wMenuCallBack_p) SelectAbove,(void *) 0);
+ wMenuPushCreate(selectPopup2M, "", _("Move To Back"), 0,(wMenuCallBack_p) SelectBelow, (void *) 0);
wMenuSeparatorCreate( selectPopup2M );
- AddRotateMenu( selectPopup2M, QuickRotate );
- rotateAlignMI = wMenuPushCreate( selectPopup2M, "", _("Align"), 0, (wMenuCallBack_p)RotateAlign, NULL );
+ wMenuPushCreate(selectPopup2M, "", _("Group"), 0,(wMenuCallBack_p) DoGroup, (void *) 0);
+ wMenuPushCreate(selectPopup2M, "", _("UnGroup"), 0,(wMenuCallBack_p) DoUngroup, (void *) 0);
+ wMenuSeparatorCreate( selectPopup2M );
+
ParamRegister( &rescalePG );
}
+
EXPORT void InitCmdDelete( void )
{
wIcon_p icon;
@@ -2091,27 +3387,29 @@ EXPORT void InitCmdTunnel( void )
wIcon_p icon;
icon = wIconCreatePixMap( tunnel_xpm );
AddToolbarButton( "cmdTunnel", icon, IC_SELECTED|IC_POPUP, (addButtonCallBack_t)SelectTunnel, NULL );
-#ifdef LATER
- tunnelCmdInx = AddButton( "cmdTunnel", _("Tunnel"),
- (addButtonCallBack_t)SelectTunnel, NULL, IC_SELECTED|IC_POPUP, NULL, LEVEL0_50, ACCL_TUNNEL,
- (wControl_p)wButtonCreate(mainW, 0, 0, "cmdTunnel", (char*)bm_p, BO_ICON, 0, (wButtonCallBack_p)SelectTunnel, 0 ) );
-#endif
+}
+
+EXPORT void InitCmdBridge( void)
+{
+ wIcon_p icon;
+ icon = wIconCreatePixMap( bridge_xpm );
+ AddToolbarButton( "cmdBridge", icon, IC_SELECTED|IC_POPUP, (addButtonCallBack_t)SelectBridge, NULL );
}
EXPORT void InitCmdMoveDescription( wMenu_p menu )
{
AddMenuButton( menu, CmdMoveDescription, "cmdMoveLabel", _("Move Description"), wIconCreatePixMap(movedesc_xpm),
- LEVEL0, IC_STICKY|IC_POPUP|IC_CMDMENU, ACCL_MOVEDESC, NULL );
+ LEVEL0, IC_STICKY|IC_POPUP3|IC_CMDMENU|IC_WANT_MOVE, ACCL_MOVEDESC, (void*) 0 );
}
EXPORT void InitCmdMove( wMenu_p menu )
{
moveCmdInx = AddMenuButton( menu, CmdMove, "cmdMove", _("Move"), wIconCreatePixMap(move_xpm),
- LEVEL0, IC_STICKY|IC_SELECTED|IC_CMDMENU, ACCL_MOVE, NULL );
+ LEVEL0, IC_STICKY|IC_SELECTED|IC_CMDMENU|IC_WANT_MOVE, ACCL_MOVE, NULL );
rotateCmdInx = AddMenuButton( menu, CmdRotate, "cmdRotate", _("Rotate"), wIconCreatePixMap(rotate_xpm),
- LEVEL0, IC_STICKY|IC_SELECTED|IC_CMDMENU, ACCL_ROTATE, NULL );
+ LEVEL0, IC_STICKY|IC_SELECTED|IC_CMDMENU|IC_WANT_MOVE, ACCL_ROTATE, NULL );
/*flipCmdInx =*/ AddMenuButton( menu, CmdFlip, "cmdFlip", _("Flip"), wIconCreatePixMap(flip_xpm),
LEVEL0, IC_STICKY|IC_SELECTED|IC_CMDMENU, ACCL_FLIP, NULL );
}
diff --git a/app/bin/cselect.h b/app/bin/cselect.h
index c02cc1c..a9913bf 100644
--- a/app/bin/cselect.h
+++ b/app/bin/cselect.h
@@ -25,11 +25,9 @@
#include "common.h"
#include "track.h"
-wIndex_t selectCmdInx;
-wIndex_t moveCmdInx;
-wIndex_t rotateCmdInx;
-long quickMove;
-BOOL_T importMove;
+extern wIndex_t selectCmdInx;
+extern wIndex_t moveCmdInx;
+extern wIndex_t rotateCmdInx;
extern int incrementalDrawLimit;
extern long selectedTrackCount;
@@ -37,6 +35,8 @@ void InvertTrackSelect( void * );
void OrphanedTrackSelect( void * );
void SetAllTrackSelect( BOOL_T );
void SelectTunnel( void );
+void SelectBridge( void );
+void SelectTies( void );
void SelectRecount( void );
void SelectTrackWidth( void* );
void SelectDelete( void );
@@ -49,6 +49,6 @@ void DoRefreshCompound( void );
void WriteSelectedTracksToTempSegs( void );
void DoRescale( void );
STATUS_T CmdMoveDescription( wAction_t, coOrd );
-void UpdateQuickMove( void * );
+void DrawHighlightBoxes(BOOL_T, BOOL_T,track_p);
#endif
diff --git a/app/bin/csensor.c b/app/bin/csensor.c
index 871b8d6..4f395c2 100644
--- a/app/bin/csensor.c
+++ b/app/bin/csensor.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"
@@ -246,7 +249,7 @@ static void DescribeSensor (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(sensorProperties.name,xx->name,STR_SHORT_SIZE-1);
@@ -270,14 +273,22 @@ static BOOL_T WriteSensor ( track_p t, FILE * f )
{
BOOL_T rc = TRUE;
sensorData_p xx = GetsensorData(t);
- rc &= fprintf(f, "SENSOR %d %d %s %d %0.6f %0.6f \"%s\" \"%s\"\n",
+ char *sensorName = MyStrdup(xx->name);
+
+#ifdef WINDOWS
+ sensorName = Convert2UTF8(sensorName);
+#endif // WINDOWS
+
+ rc &= fprintf(f, "SENSOR %d %u %s %d %0.6f %0.6f \"%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, sensorName,
xx->script)>0;
+
+ MyFree(sensorName);
return rc;
}
-static void ReadSensor ( char * line )
+static BOOL_T ReadSensor ( char * line )
{
wIndex_t index;
/*TRKINX_T trkindex;*/
@@ -291,8 +302,13 @@ static void ReadSensor ( char * line )
wIndex_t layer;
sensorData_p xx;
if (!GetArgs(line+7,"dLsdpqq",&index,&layer,scale, &visible, &orig,&name,&script)) {
- return;
+ return FALSE;
}
+
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(name);
+#endif // WINDOWS
+
trk = NewTrack(index, T_SENSOR, 0, sizeof(sensorData_t));
SetTrkVisible(trk, visible);
SetTrkScale(trk, LookupScale( scale ));
@@ -302,6 +318,7 @@ static void ReadSensor ( char * line )
xx->orig = orig;
xx->script = script;
ComputeSensorBoundingBox(trk);
+ return TRUE;
}
static void MoveSensor (track_p trk, coOrd orig )
@@ -457,23 +474,30 @@ static void CreateNewSensor (coOrd orig)
static STATUS_T CmdSensor ( wAction_t action, coOrd pos )
{
+ static coOrd sensor_pos;
+ static BOOL_T create;
switch (action) {
case C_START:
InfoMessage(_("Place sensor"));
+ create = FALSE;
return C_CONTINUE;
case C_DOWN:
+ create = TRUE;
+ /* no break */
case C_MOVE:
SnapPos(&pos);
- DDrawSensor( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
+ sensor_pos = pos;
return C_CONTINUE;
case C_UP:
SnapPos(&pos);
- DDrawSensor( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
CreateNewSensor(pos);
return C_TERMINATE;
case C_REDRAW:
+ if (create)
+ DDrawSensor( &tempD, sensor_pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
+ return C_CONTINUE;
case C_CANCEL:
- DDrawSensor( &tempD, pos, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
+ create = FALSE;
return C_CONTINUE;
default:
return C_CONTINUE;
@@ -491,7 +515,7 @@ static void DrawSensorTrackHilite( 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( tempD.d, x, y, w, h, ctlhiliteColor, wDrawOptTemp|wDrawOptTransparent );
}
static int SensorMgmProc ( int cmd, void * data )
diff --git a/app/bin/csignal.c b/app/bin/csignal.c
index fb9bee8..0fc09e6 100644
--- a/app/bin/csignal.c
+++ b/app/bin/csignal.c
@@ -59,6 +59,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"
@@ -308,7 +311,7 @@ static void DescribeSignal (track_p trk, char * str, CSIZE_T len )
*str = tolower((unsigned char)*str);
str++;
}
- sprintf( str, _("(%d [%s]): Layer=%d, %d heads at %0.3f,%0.3f A%0.3f"),
+ sprintf( str, _("(%d [%s]): Layer=%u, %d heads at %0.3f,%0.3f A%0.3f"),
GetTrkIndex(trk),
xx->name,GetTrkLayer(trk)+1, xx->numHeads,
xx->orig.x, xx->orig.y,xx->angle );
@@ -338,20 +341,28 @@ static BOOL_T WriteSignal ( track_p t, FILE * f )
BOOL_T rc = TRUE;
wIndex_t ia;
signalData_p xx = GetsignalData(t);
- rc &= fprintf(f, "SIGNAL %d %d %s %d %0.6f %0.6f %0.6f %d \"%s\"\n",
+ char *signalName = MyStrdup(xx->name);
+
+#ifdef WINDOWS
+ signalName = Convert2UTF8(signalName);
+#endif // WINDOWS
+
+ rc &= fprintf(f, "SIGNAL %d %u %s %d %0.6f %0.6f %0.6f %d \"%s\"\n",
GetTrkIndex(t), GetTrkLayer(t), GetTrkScaleName(t),
GetTrkVisible(t), xx->orig.x, xx->orig.y, xx->angle,
- xx->numHeads, xx->name)>0;
+ xx->numHeads, signalName)>0;
for (ia = 0; ia < xx->numAspects; ia++) {
rc &= fprintf(f, "\tASPECT \"%s\" \"%s\"\n",
(&(xx->aspectList))[ia].aspectName,
(&(xx->aspectList))[ia].aspectScript)>0;
}
- rc &= fprintf( f, "\tEND\n" )>0;
+ rc &= fprintf( f, "\t%s\n",END_SIGNAL )>0;
+
+ MyFree(signalName);
return rc;
}
-static void ReadSignal ( char * line )
+static BOOL_T ReadSignal ( char * line )
{
/*TRKINX_T trkindex;*/
wIndex_t index;
@@ -369,19 +380,24 @@ static void ReadSignal ( char * line )
signalData_p xx;
if (!GetArgs(line+6,"dLsdpfdq",&index,&layer,scale, &visible, &orig,
&angle, &numHeads,&name)) {
- return;
+ return FALSE;
}
+
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(name);
+#endif // WINDOWS
+
DYNARR_RESET( signalAspect_p, signalAspect_da );
while ( (cp = GetNextLine()) != NULL ) {
- while (isspace((unsigned char)*cp)) cp++;
- if ( strncmp( cp, "END", 3 ) == 0 ) {
+ if ( IsEND( END_SIGNAL) ) {
break;
}
+ while (isspace((unsigned char)*cp)) cp++;
if ( *cp == '\n' || *cp == '#' ) {
continue;
}
if ( strncmp( cp, "ASPECT", 6 ) == 0 ) {
- if (!GetArgs(cp+4,"qq",&aspname,&aspscript)) return;
+ if (!GetArgs(cp+4,"qq",&aspname,&aspscript)) return FALSE;
DYNARR_APPEND( signalAspect_p *, signalAspect_da, 10 );
signalAspect(signalAspect_da.cnt-1).aspectName = aspname;
signalAspect(signalAspect_da.cnt-1).aspectScript = aspscript;
@@ -402,6 +418,7 @@ static void ReadSignal ( char * line )
(&(xx->aspectList))[ia].aspectScript = signalAspect(ia).aspectScript;
}
ComputeSignalBoundingBox(trk);
+ return TRUE;
}
static void MoveSignal (track_p trk, coOrd orig )
@@ -772,20 +789,21 @@ static ANGLE_T orient;
static STATUS_T CmdSignal ( wAction_t action, coOrd pos )
{
-
+ static BOOL_T create;
switch (action) {
case C_START:
InfoMessage(_("Place base of signal"));
+ create = FALSE;
return C_CONTINUE;
case C_DOWN:
SnapPos(&pos);
pos0 = pos;
+ create = TRUE;
InfoMessage(_("Drag to orient signal"));
return C_CONTINUE;
case C_MOVE:
SnapPos(&pos);
orient = FindAngle(pos0,pos);
- DDrawSignal( &tempD, pos0, orient, 1, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
return C_CONTINUE;
case C_UP:
SnapPos(&pos);
@@ -793,8 +811,11 @@ static STATUS_T CmdSignal ( wAction_t action, coOrd pos )
CreateNewSignal(pos0,orient);
return C_TERMINATE;
case C_REDRAW:
+ if (create)
+ DDrawSignal( &tempD, pos0, orient, 1, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
+ return C_CONTINUE;
case C_CANCEL:
- DDrawSignal( &tempD, pos0, orient, 1, GetScaleRatio(GetLayoutCurScale()), wDrawColorBlack );
+ create = FALSE;
return C_CONTINUE;
default:
return C_CONTINUE;
@@ -812,7 +833,7 @@ static void DrawSignalTrackHilite( void )
w = (wPos_t)((sighiliteSize.x/mainD.scale)*mainD.dpi+0.5);
h = (wPos_t)((sighiliteSize.y/mainD.scale)*mainD.dpi+0.5);
mainD.CoOrd2Pix(&mainD,sighiliteOrig,&x,&y);
- wDrawFilledRectangle( mainD.d, x, y, w, h, sighiliteColor, wDrawOptTemp );
+ wDrawFilledRectangle( tempD.d, x, y, w, h, sighiliteColor, wDrawOptTemp|wDrawOptTransparent );
}
static int SignalMgmProc ( int cmd, void * data )
diff --git a/app/bin/csnap.c b/app/bin/csnap.c
index 4c4d948..eb58bc4 100644
--- a/app/bin/csnap.c
+++ b/app/bin/csnap.c
@@ -209,7 +209,7 @@ EXPORT void DrawGrid(
cross0_bm = wDrawBitMapCreate( mainD.d, cross0_width, cross0_height, 2, 2, cross0_bits );
#endif
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
dpi = D->dpi/D->scale;
Gdx = cos(D2R(Gangle));
Gdy = sin(D2R(Gangle));
@@ -329,7 +329,7 @@ EXPORT void DrawGrid(
done:
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
}
@@ -368,45 +368,41 @@ EXPORT STATUS_T GridAction(
switch (action) {
case C_DOWN:
pos1 = pos;
- DrawBigCross( pos1, *angle );
return C_CONTINUE;
case C_MOVE:
- DrawBigCross( pos1, *angle );
*orig = pos1 = pos;
- DrawBigCross( pos1, *angle );
return C_CONTINUE;
case C_UP:
- DrawBigCross( pos1, *angle );
*orig = pos1;
return C_CONTINUE;
case C_RDOWN:
pos0 = pos1 = pos;
oldAngle = newAngle = *angle;
- DrawBigCross( pos0, newAngle );
return C_CONTINUE;
case C_RMOVE:
if ( FindDistance(pos0, pos) > 0.1*mainD.scale ) {
- DrawBigCross( pos0, newAngle );
pos1 = pos;
newAngle = FindAngle( pos0, pos1 );
if (angleSystem!=ANGLE_POLAR)
newAngle = newAngle-90.0;
newAngle = NormalizeAngle( floor( newAngle*10.0 ) / 10.0 );
*angle = newAngle;
- DrawBigCross( pos0, newAngle );
}
return C_CONTINUE;
case C_RUP:
- DrawBigCross( pos0, newAngle );
Rotate( orig, pos0, newAngle-oldAngle );
*orig = pos0;
*angle = newAngle;
return C_CONTINUE;
+
+ case C_REDRAW:
+ DrawBigCross( *orig, *angle );
+ break;
}
return C_CONTINUE;
}
@@ -564,8 +560,7 @@ static void RedrawGrid( void )
if (grid.Show != oldGrid.Show ||
GridChanged() ) {
wDrawDelayUpdate( tempD.d, TRUE );
- DrawASnapGrid( &oldGrid, &tempD, mapD.size, TRUE );
- DrawASnapGrid( &grid, &tempD, mapD.size, TRUE );
+ MainRedraw(); // RedrawGrid
wDrawDelayUpdate( tempD.d, FALSE );
}
}
@@ -674,12 +669,9 @@ static void GridDlgUpdate(
GridButtonUpdate( CHK_SHOW );
break;
default:
- wDrawDelayUpdate( tempD.d, TRUE );
- DrawASnapGrid( &oldGrid, &tempD, mapD.size, TRUE );
ParamLoadData( &gridPG );
GridButtonUpdate( 0 );
- DrawASnapGrid( &grid, &tempD, mapD.size, TRUE );
- wDrawDelayUpdate( tempD.d, FALSE );
+ MainRedraw(); // GridDlgUpdate
}
}
@@ -688,9 +680,8 @@ static void SnapGridRotate( void * pangle )
{
ANGLE_T angle = (ANGLE_T)(long)pangle;
wDrawDelayUpdate( tempD.d, TRUE );
- DrawASnapGrid( &oldGrid, &tempD, mapD.size, TRUE );
grid.Orig = cmdMenuPos;
- grid.Angle += angle;
+ grid.Angle += angle/1000;
oldGrid = grid;
DrawASnapGrid( &grid, &tempD, mapD.size, TRUE );
wDrawDelayUpdate( tempD.d, FALSE );
@@ -719,12 +710,12 @@ EXPORT STATUS_T CmdGrid(
return C_CONTINUE;
case C_REDRAW:
- return C_TERMINATE;
+ DrawBigCross( grid.Orig, grid.Angle );
+ return C_CONTINUE;
case C_CANCEL:
grid = oldGrid;
wHide( gridW );
- MainRedraw();
return C_TERMINATE;
case C_OK:
@@ -767,6 +758,7 @@ EXPORT STATUS_T CmdGrid(
return rc;
case C_CMDMENU:
+ menuPos = pos;
wMenuPopupShow( snapGridPopupM );
break;
}
diff --git a/app/bin/csplit.c b/app/bin/csplit.c
index 6cfdcc8..c2b516a 100644
--- a/app/bin/csplit.c
+++ b/app/bin/csplit.c
@@ -21,16 +21,20 @@
*/
#include "cundo.h"
+#include "compound.h"
#include "i18n.h"
#include "messages.h"
#include "track.h"
#include "utility.h"
+#include "fileio.h"
static wMenu_p splitPopupM[2];
static wMenuToggle_p splitPopupMI[2][4];
static track_p splitTrkTrk[2];
static EPINX_T splitTrkEP[2];
static BOOL_T splitTrkFlip;
+static dynArr_t anchors_da;
+#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N)
static void ChangeSplitEPMode( wBool_t set, void * mode )
{
@@ -55,6 +59,45 @@ static void ChangeSplitEPMode( wBool_t set, void * mode )
DrawEndPt( &mainD, splitTrkTrk[1], splitTrkEP[1], wDrawColorBlack );
}
+static void CreateSplitAnchorAngle(coOrd pos, track_p t, BOOL_T end, ANGLE_T a) {
+ DIST_T d = tempD.scale*0.1;
+ DIST_T w = tempD.scale/tempD.dpi*4;
+ int i;
+ if (!end) {
+ 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;
+ } else {
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).color = wDrawColorBlue;
+ Translate(&anchors(i).u.l.pos[0],pos,a,GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[0],anchors(i).u.l.pos[0],a+90,d);
+ Translate(&anchors(i).u.l.pos[1],pos,a,-GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a+90,-d);
+ anchors(i).width = w;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).color = wDrawColorBlue;
+ Translate(&anchors(i).u.l.pos[0],pos,a,GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[0],anchors(i).u.l.pos[0],a+90,-d);
+ Translate(&anchors(i).u.l.pos[1],pos,a,-GetTrkGauge(t));
+ Translate(&anchors(i).u.l.pos[1],anchors(i).u.l.pos[1],a+90,d);
+ anchors(i).width = w;
+ }
+}
+
+static void CreateSplitAnchor(coOrd pos, track_p t, BOOL_T end) {
+ ANGLE_T a = NormalizeAngle(GetAngleAtPoint(t,pos,NULL,NULL)+90.0);
+ CreateSplitAnchorAngle(pos,t,end,a);
+}
+
static STATUS_T CmdSplitTrack( wAction_t action, coOrd pos )
{
track_p trk0, trk1;
@@ -66,6 +109,7 @@ static STATUS_T CmdSplitTrack( wAction_t action, coOrd pos )
switch (action) {
case C_START:
InfoMessage( _("Select track to split") );
+ DYNARR_RESET(trkSeg_t,anchors_da);
/* no break */
case C_DOWN:
case C_MOVE:
@@ -79,12 +123,16 @@ static STATUS_T CmdSplitTrack( wAction_t action, coOrd pos )
onTrackInSplit = FALSE;
return C_TERMINATE;
}
- if (!QueryTrack(trk0,Q_MODIFY_CAN_SPLIT)) {
- onTrackInSplit = FALSE;
- InfoMessage(_("Can't Split that Track"));
- return C_CONTINUE;
- }
ep0 = PickEndPoint( pos, trk0 );
+ if (IsClose(FindDistance(GetTrkEndPos(trk0,ep0),pos)) && (GetTrkEndTrk(trk0,ep0)!=NULL)) {
+ pos = GetTrkEndPos(trk0,ep0);
+ } else {
+ if (!QueryTrack(trk0,Q_MODIFY_CAN_SPLIT)) {
+ onTrackInSplit = FALSE;
+ InfoMessage(_("Can't Split that Track"));
+ return C_CONTINUE;
+ }
+ }
onTrackInSplit = FALSE;
if (ep0 < 0) {
return C_CONTINUE;
@@ -139,9 +187,38 @@ static STATUS_T CmdSplitTrack( wAction_t action, coOrd pos )
mode |= 1;
for ( inx=0; inx<4; inx++ )
wMenuToggleSet( splitPopupMI[quad&1][inx], mode == inx );
+ menuPos = pos;
wMenuPopupShow( splitPopupM[quad&1] );
break;
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ onTrackInSplit = TRUE;
+ if ((trk0 = OnTrack( &pos, FALSE, TRUE ))!=NULL && CheckTrackLayerSilent( trk0 )) {
+ ep0 = PickEndPoint( pos, trk0 );
+ if (IsClose(FindDistance(GetTrkEndPos(trk0,ep0),pos)) && (GetTrkEndTrk(trk0,ep0)!=NULL)) {
+ CreateSplitAnchor(GetTrkEndPos(trk0,ep0),trk0,TRUE);
+ } else if (QueryTrack(trk0,Q_IS_TURNOUT)) {
+ if ((MyGetKeyState()&WKEY_SHIFT) != 0 ) {
+ if (SplitTurnoutCheck(trk0,pos,ep0,NULL,NULL,NULL,TRUE,&pos,&angle)) {
+ angle = NormalizeAngle(angle+90);
+ CreateSplitAnchorAngle(pos,trk0,FALSE,angle);
+ }
+ } else {
+ CreateSplitAnchor(GetTrkEndPos(trk0,ep0),trk0,TRUE);
+ }
+ break;
+ } else if (QueryTrack(trk0,Q_MODIFY_CAN_SPLIT)) {
+ CreateSplitAnchor(pos,trk0,FALSE);
+ }
+ }
+ onTrackInSplit = FALSE;
+ break;
+ case C_REDRAW:
+ if (anchors_da.cnt)
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ break;
}
+
return C_CONTINUE;
}
@@ -152,6 +229,6 @@ static STATUS_T CmdSplitTrack( wAction_t action, coOrd pos )
void InitCmdSplit( wMenu_p menu )
{
- AddMenuButton( menu, CmdSplitTrack, "cmdSplitTrack", _("Split Track"), wIconCreatePixMap(splittrk_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_CMDMENU, ACCL_SPLIT, NULL );
+ AddMenuButton( menu, CmdSplitTrack, "cmdSplitTrack", _("Split Track"), wIconCreatePixMap(splittrk_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_CMDMENU|IC_WANT_MOVE, ACCL_SPLIT, NULL );
}
diff --git a/app/bin/cstraigh.c b/app/bin/cstraigh.c
index 7be25ee..464f16e 100644
--- a/app/bin/cstraigh.c
+++ b/app/bin/cstraigh.c
@@ -29,6 +29,7 @@
#include "param.h"
#include "track.h"
#include "utility.h"
+#include "layout.h"
/*
* STATE INFO
@@ -40,6 +41,23 @@ static struct {
BOOL_T down;
} Dl;
+static dynArr_t anchors_da;
+#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N)
+
+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 STATUS_T CmdStraight( wAction_t action, coOrd pos )
{
@@ -47,40 +65,37 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
DIST_T dist;
coOrd p;
- switch (action) {
+ switch (action&0xFF) {
case C_START:
+ DYNARR_RESET(trkSeg_t,anchors_da);
Dl.pos0=pos;
Dl.pos1=pos;
Dl.trk = NULL;
Dl.ep=-1;
Dl.down = FALSE;
- InfoMessage( _("Place 1st end point of straight track + Shift -> snap to unconnected endpoint") );
+ InfoMessage( _("Place 1st endpoint of straight track, snap to unconnected endpoint") );
return C_CONTINUE;
case C_DOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
p = pos;
BOOL_T found = FALSE;
Dl.trk = NULL;
- if ((MyGetKeyState() & WKEY_SHIFT) != 0) {
+ if (((MyGetKeyState() & WKEY_ALT) == 0) == magneticSnap) {
if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) {
EPINX_T ep = PickUnconnectedEndPointSilent(p, t);
if (ep != -1) {
+ if (GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) {
+ wBeep();
+ InfoMessage(_("Track is different gauge"));
+ return C_CONTINUE;
+ }
Dl.trk = t;
Dl.ep = ep;
pos = GetTrkEndPos(t, ep);
found = TRUE;
- } else {
- InfoMessage(_("No unconnected end-point on track - Try again or release Shift and click"));
- Dl.pos0=pos;
- Dl.pos1=pos;
- return C_CONTINUE;
}
- } else {
- InfoMessage(_("Not on a track - Try again or release Shift and click"));
- Dl.pos0=pos;
- Dl.pos1=pos;
- return C_CONTINUE;
}
}
Dl.down = TRUE;
@@ -96,10 +111,25 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
return C_CONTINUE;
case C_MOVE:
- if (!Dl.down) return C_CONTINUE;
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (!Dl.down) {
+ if (((MyGetKeyState() & WKEY_ALT) == 0) == magneticSnap) {
+ p = pos;
+ if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) {
+ if (GetTrkGauge(t) == GetScaleTrackGauge(GetLayoutCurScale())) {
+ EPINX_T ep = PickUnconnectedEndPointSilent(pos, t);
+ if (ep != -1) {
+ if (GetTrkGauge(t) == GetScaleTrackGauge(GetLayoutCurScale()))
+ CreateEndAnchor(GetTrkEndPos(t,ep),FALSE);
+ }
+ }
+ }
+ }
+ return C_CONTINUE;
+ }
ANGLE_T angle, angle2;
- if (Dl.trk) {
+ if (Dl.trk && !(MyGetKeyState() & WKEY_SHIFT)) {
angle = NormalizeAngle(GetTrkEndAngle( Dl.trk, Dl.ep));
angle2 = NormalizeAngle(FindAngle(pos, Dl.pos0)-angle);
if (angle2 > 90.0 && angle2 < 270.0)
@@ -112,14 +142,13 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
PutAngle(FindAngle( Dl.pos0, pos )) );
tempSegs(0).u.l.pos[1] = pos;
tempSegs_da.cnt = 1;
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
return C_CONTINUE;
case C_UP:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if (!Dl.down) return C_CONTINUE;
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
tempSegs_da.cnt = 0;
- if (Dl.trk) {
+ if (Dl.trk && !(MyGetKeyState() & WKEY_SHIFT)) {
angle = NormalizeAngle(GetTrkEndAngle( Dl.trk, Dl.ep));
angle2 = NormalizeAngle(FindAngle(pos, Dl.pos0)-angle);
if (angle2 > 90.0 && angle2 < 270.0)
@@ -132,7 +161,7 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
}
UndoStart( _("Create Straight Track"), "newStraight" );
t = NewStraightTrack( Dl.pos0, pos );
- if (Dl.trk) {
+ if (Dl.trk && !(MyGetKeyState() & WKEY_SHIFT)) {
ConnectTracks(Dl.trk, Dl.ep, t, 0);
}
UndoEnd();
@@ -140,8 +169,12 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
return C_TERMINATE;
case C_REDRAW:
+ if (anchors_da.cnt)
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ if (Dl.down)
+ DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ return C_CONTINUE;
case C_CANCEL:
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
Dl.down = FALSE;
return C_CONTINUE;
@@ -155,5 +188,5 @@ static STATUS_T CmdStraight( wAction_t action, coOrd pos )
void InitCmdStraight( wMenu_p menu )
{
- AddMenuButton( menu, CmdStraight, "cmdStraight", _("Straight Track"), wIconCreatePixMap(straight_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_STRAIGHT, NULL );
+ AddMenuButton( menu, CmdStraight, "cmdStraight", _("Straight Track"), wIconCreatePixMap(straight_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2|IC_WANT_MOVE, ACCL_STRAIGHT, NULL );
}
diff --git a/app/bin/cstruct.c b/app/bin/cstruct.c
index 6ad240c..6907e2c 100644
--- a/app/bin/cstruct.c
+++ b/app/bin/cstruct.c
@@ -33,13 +33,13 @@
#include "layout.h"
#include "messages.h"
#include "param.h"
+#include "include/paramfile.h"
#include "track.h"
#include "utility.h"
+#include "ccurve.h"
EXPORT TRKTYP_T T_STRUCTURE = -1;
-#define STRUCTCMD
-
EXPORT dynArr_t structureInfo_da;
typedef struct compoundData extraData;
@@ -51,7 +51,6 @@ static int log_structure = 0;
static wMenu_p structPopupM;
-#ifdef STRUCTCMD
static drawCmd_t structureD = {
NULL,
&screenDrawFuncs,
@@ -86,7 +85,7 @@ static paramData_t structurePLs[] = {
#define I_MSGHEIGHT (5)
{ PD_MESSAGE, NULL, NULL, 0, (void*)80 } };
static paramGroup_t structurePG = { "structure", 0, structurePLs, sizeof structurePLs/sizeof structurePLs[0] };
-#endif
+
/****************************************
@@ -133,24 +132,103 @@ EXPORT turnoutInfo_t * CreateNewStructure(
#endif
to->paramFileIndex = curParamFileIndex;
if (curParamFileIndex == PARAM_CUSTOM)
- to->contentsLabel = "Custom Structures";
+ to->contentsLabel = MyStrdup("Custom Structures");
else
to->contentsLabel = curSubContents;
to->endCnt = 0;
to->pathLen = 0;
to->paths = (PATHPTR_T)"";
-#ifdef STRUCTCMD
if (updateList && structureListL != NULL) {
FormatCompoundTitle( LABEL_TABBED|LABEL_MANUF|LABEL_PARTNO|LABEL_DESCR, to->title );
if (message[0] != '\0')
wListAddValue( structureListL, message, NULL, to );
}
-#endif
to->barScale = curBarScale>0?curBarScale:-1;
return to;
}
+/**
+ * Delete a structure definition from memory.
+ * \TODO Find a better way to handle Custom Structures (see CreateNewStructure)
+ *
+ * \param [IN] structure the structure to be deleted
+ */
+
+BOOL_T
+StructureDelete(void *structure)
+{
+ turnoutInfo_t * to = (turnoutInfo_t *)structure;
+ MyFree(to->title);
+ MyFree(to->segs);
+
+ MyFree(to);
+ return(TRUE);
+}
+
+/**
+ * Delete all structure definitions that came from a specific parameter
+ * file. Due to the way the definitions are loaded from file it is safe to
+ * assume that they form a contiguous block in the array.
+ *
+ * \param fileIndex parameter file.
+ */
+
+void
+DeleteStructures(int fileIndex)
+{
+ int inx = 0;
+ int startInx = -1;
+ int cnt = 0;
+
+ // go to the start of the block
+ while (inx < structureInfo_da.cnt &&
+ structureInfo(inx)->paramFileIndex != fileIndex) {
+ startInx = inx++;
+ }
+
+ // delete them
+ for (; inx < structureInfo_da.cnt &&
+ structureInfo(inx)->paramFileIndex == fileIndex; inx++) {
+ turnoutInfo_t * to = structureInfo(inx);
+ if (to->paramFileIndex == fileIndex) {
+ StructureDelete(to);
+ cnt++;
+ }
+ }
+
+ // copy down the rest of the list to fill the gap
+ startInx++;
+ while (inx < structureInfo_da.cnt) {
+ structureInfo(startInx++) = structureInfo(inx++);
+ }
+
+ // and reduce the actual number
+ structureInfo_da.cnt -= cnt;
+}
+
+enum paramFileState
+GetStructureCompatibility(int paramFileIndex, SCALEINX_T scaleIndex)
+{
+ int i;
+ enum paramFileState ret = PARAMFILE_NOTUSABLE;
+ DIST_T ratio = GetScaleRatio(scaleIndex);
+
+ if (!IsParamValid(paramFileIndex)) {
+ return(PARAMFILE_UNLOADED);
+ }
+
+ for (i = 0; i < structureInfo_da.cnt; i++) {
+ turnoutInfo_t *to = structureInfo(i);
+ if (to->paramFileIndex == paramFileIndex) {
+ if (GetScaleRatio(to->scaleInx) == ratio || to->scaleInx == SCALE_ANY) {
+ ret = PARAMFILE_FIT;
+ break;
+ }
+ }
+ }
+ return(ret);
+}
static BOOL_T ReadStructureParam(
char * firstLine )
@@ -164,7 +242,8 @@ static dynArr_t pierInfo_da;
if ( !GetArgs( firstLine+10, "sq", scale, &title ) )
return FALSE;
- ReadSegs();
+ if ( !ReadSegs() )
+ return FALSE;
to = CreateNewStructure( scale, title, tempSegs_da.cnt, &tempSegs(0), FALSE );
if (to == NULL)
return FALSE;
@@ -175,7 +254,8 @@ static dynArr_t pierInfo_da;
cp = tempSpecial+strlen(PIER);
while (cp) {
DYNARR_APPEND( pierInfo_t, pierInfo_da, 10 );
- GetArgs( cp, "fqc", &pierInfo(pierInfo_da.cnt-1).height, &pierInfo(pierInfo_da.cnt-1).name, &cp );
+ if ( !GetArgs( cp, "fqc", &pierInfo(pierInfo_da.cnt-1).height, &pierInfo(pierInfo_da.cnt-1).name, &cp ) )
+ return FALSE;
}
to->u.pierInfo.cnt = pierInfo_da.cnt;
to->u.pierInfo.info = (pierInfo_t*)MyMalloc( pierInfo_da.cnt * sizeof *(pierInfo_t*)NULL );
@@ -196,6 +276,7 @@ EXPORT turnoutInfo_t * StructAdd( long mode, SCALEINX_T scale, wList_p list, coO
{
wIndex_t inx;
turnoutInfo_t * to, *to1=NULL;
+ structureInx = 0;
for ( inx = 0; inx < structureInfo_da.cnt; inx++ ) {
to = structureInfo(inx);
if ( IsParamValid(to->paramFileIndex) &&
@@ -204,6 +285,10 @@ EXPORT turnoutInfo_t * StructAdd( long mode, SCALEINX_T scale, wList_p list, coO
to->segCnt != 0 ) {
if (to1 == NULL)
to1 = to;
+ if ( to == curStructure ) {
+ to1 = to;
+ structureInx = wListGetCount( list );
+ }
FormatCompoundTitle( mode, to->title );
if (message[0] != '\0') {
wListAddValue( list, message, NULL, to );
@@ -232,38 +317,45 @@ static void DrawStructure(
wDrawColor color )
{
struct extraData *xx = GetTrkExtraData(t);
- coOrd p00, px0, pxy, p0y, orig, size;
-
- if (d->options&DC_QUICK) {
- GetSegBounds( zero, 0.0, xx->segCnt, xx->segs, &orig, &size );
- p00.x = p0y.x = orig.x;
- p00.y = px0.y = orig.y;
- px0.x = pxy.x = orig.x + size.x;
- p0y.y = pxy.y = orig.y + size.y;
- REORIGIN1( p00, xx->angle, xx->orig )
- REORIGIN1( px0, xx->angle, xx->orig )
- REORIGIN1( p0y, xx->angle, xx->orig )
- REORIGIN1( pxy, xx->angle, xx->orig )
- DrawLine( d, p00, px0, 0, color );
- DrawLine( d, px0, pxy, 0, color );
- DrawLine( d, pxy, p0y, 0, color );
- DrawLine( d, p0y, p00, 0, color );
- } else {
- DrawSegs( d, xx->orig, xx->angle, xx->segs, xx->segCnt, 0.0, color );
- if ( ((d->funcs->options&wDrawOptTemp)==0) &&
- (labelWhen == 2 || (labelWhen == 1 && (d->options&DC_PRINT))) &&
- labelScale >= d->scale &&
- ( GetTrkBits( t ) & TB_HIDEDESC ) == 0 ) {
- DrawCompoundDescription( t, d, color );
- }
+
+ d->options &= ~DC_NOTSOLIDLINE;
+ switch(xx->lineType) {
+ case DRAWLINESOLID:
+ break;
+ case DRAWLINEDASH:
+ d->options |= DC_DASH;
+ break;
+ case DRAWLINEDOT:
+ d->options |= DC_DOT;
+ break;
+ case DRAWLINEDASHDOT:
+ d->options |= DC_DASHDOT;
+ break;
+ case DRAWLINEDASHDOTDOT:
+ d->options |= DC_DASHDOTDOT;
+ break;
+ case DRAWLINECENTER:
+ d->options |= DC_CENTER;
+ break;
+ case DRAWLINEPHANTOM:
+ d->options |= DC_CENTER;
+ break;
+ }
+ DrawSegs( d, xx->orig, xx->angle, xx->segs, xx->segCnt, 0.0, color );
+ d->options &= ~DC_NOTSOLIDLINE;
+ if ( ((d->options & DC_SIMPLE)==0) &&
+ (labelWhen == 2 || (labelWhen == 1 && (d->options&DC_PRINT))) &&
+ labelScale >= d->scale &&
+ ( GetTrkBits( t ) & TB_HIDEDESC ) == 0 ) {
+ DrawCompoundDescription( t, d, color );
}
}
-static void ReadStructure(
+static BOOL_T ReadStructure(
char * line )
{
- ReadCompound( line+10, T_STRUCTURE );
+ return ReadCompound( line+10, T_STRUCTURE );
}
@@ -291,12 +383,31 @@ static BOOL_T QueryStructure( track_p trk, int query )
switch ( query ) {
case Q_HAS_DESC:
return TRUE;
+ case Q_IS_STRUCTURE:
+ return TRUE;
default:
return FALSE;
}
}
+static wBool_t CompareStruct( 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( "Flipped", xx1, xx2, flipped )
+ REGRESS_CHECK_INT( "Ungrouped", xx1, xx2, ungrouped )
+ REGRESS_CHECK_INT( "Split", xx1, xx2, split )
+ /* desc orig is not stable
+ REGRESS_CHECK_POS( "DescOrig", xx1, xx2, descriptionOrig ) */
+ REGRESS_CHECK_POS( "DescOff", xx1, xx2, descriptionOff )
+ REGRESS_CHECK_POS( "DescSize", xx1, xx2, descriptionSize )
+ return CompareSegs( xx1->segs, xx1->segCnt, xx1->segs, xx1->segCnt );
+}
+
static trackCmd_t structureCmds = {
"STRUCTURE",
DrawStructure,
@@ -322,7 +433,17 @@ static trackCmd_t structureCmds = {
NULL, /* moveEndPt */
QueryStructure,
UngroupCompound,
- FlipCompound };
+ FlipCompound,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CompareStruct };
static paramData_t pierPLs[] = {
{ PD_DROPLIST, &pierListInx, "inx", 0, (void*)50, N_("Pier Number") } };
@@ -360,7 +481,6 @@ static void ShowPierL( void )
}
-#ifdef STRUCTCMD
/*****************************************
*
* Structure Dialog
@@ -404,13 +524,14 @@ static void structureChange( long changes )
(changes&CHANGE_PARAMS) == 0 ) )
return;
lastScaleName = curScaleName;
- curStructure = NULL;
+ //curStructure = NULL;
wControlShow( (wControl_p)structureListL, FALSE );
wListClear( structureListL );
maxStructureDim.x = maxStructureDim.y = 0.0;
if (structureInfo_da.cnt <= 0)
return;
curStructure = StructAdd( LABEL_TABBED|LABEL_MANUF|LABEL_PARTNO|LABEL_DESCR, GetLayoutCurScale(), structureListL, &maxStructureDim );
+ wListSetIndex( structureListL, structureInx );
wControlShow( (wControl_p)structureListL, TRUE );
if (curStructure == NULL) {
wDrawClear( structureD.d );
@@ -468,7 +589,7 @@ static void DoStructOk( void )
Reset();
}
-#endif
+
/****************************************
*
@@ -488,6 +609,51 @@ static struct {
static track_p pierTrk;
static EPINX_T pierEp;
+static dynArr_t anchors_da;
+#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N)
+
+void static CreateArrowAnchor(coOrd pos,ANGLE_T a,DIST_T len) {
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).width = 0;
+ anchors(i).u.l.pos[0] = pos;
+ Translate(&anchors(i).u.l.pos[1],pos,NormalizeAngle(a+135),len);
+ anchors(i).color = wDrawColorBlue;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).width = 0;
+ anchors(i).u.l.pos[0] = pos;
+ Translate(&anchors(i).u.l.pos[1],pos,NormalizeAngle(a-135),len);
+ anchors(i).color = wDrawColorBlue;
+}
+
+void static CreateRotateAnchor(coOrd pos) {
+ DIST_T d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_CRVLIN;
+ anchors(i).width = 0.5;
+ anchors(i).u.c.center = pos;
+ anchors(i).u.c.a0 = 180.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).u.c.radius = d*2;
+ anchors(i).color = wDrawColorAqua;
+ coOrd head; //Arrows
+ for (int j=0;j<3;j++) {
+ Translate(&head,pos,j*120,d*2);
+ CreateArrowAnchor(head,NormalizeAngle((j*120)+90),d);
+ }
+}
+
+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);
+}
+
static ANGLE_T PlaceStructure(
coOrd p0,
coOrd p1,
@@ -537,11 +703,9 @@ static void NewStructure( void )
wListGetIndex(pierL) == -1) {
return;
}
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
UndoStart( _("Place Structure"), "newStruct" );
titleLen = strlen( curStructure->title );
- trk = NewCompound( T_STRUCTURE, 0, Dst.pos, Dst.angle, curStructure->title, 0, NULL, 0, "", curStructure->segCnt, curStructure->segs );
+ trk = NewCompound( T_STRUCTURE, 0, Dst.pos, Dst.angle, curStructure->title, 0, NULL, NULL, 0, "", curStructure->segCnt, curStructure->segs );
xx = GetTrkExtraData(trk);
#ifdef LATER
trk = NewTrack( 0, T_STRUCTURE, 0, sizeof (*xx) + 1 );
@@ -581,6 +745,8 @@ static void NewStructure( void )
}
SetTrkVisible( trk, TRUE );
+ SetTrkNoTies( trk, FALSE);
+ SetTrkBridge( trk, FALSE);
#ifdef LATER
ComputeCompoundBoundingBox( trk );
@@ -600,17 +766,14 @@ static void NewStructure( void )
static void StructRotate( void * pangle )
{
+ if (Dst.state == 0)
+ return;
ANGLE_T angle = (ANGLE_T)(long)pangle;
- if (Dst.state == 1)
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
- else
- Dst.pos = cmdMenuPos;
+ angle /= 1000.0;
+ Dst.pos = cmdMenuPos;
Rotate( &Dst.pos, cmdMenuPos, angle );
Dst.angle += angle;
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
- Dst.state = 1;
+ TempRedraw(); // StructRotate
}
@@ -629,64 +792,62 @@ EXPORT STATUS_T CmdStructureAction(
switch (action & 0xFF) {
case C_START:
+ DYNARR_RESET(trkSeg_t,anchors_da);
Dst.state = 0;
Dst.angle = 00.0;
ShowPierL();
+ InfoMessage(_("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel"));
return C_CONTINUE;
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (Dst.state && (MyGetKeyState()&WKEY_CTRL)) {
+ CreateRotateAnchor(pos);
+ } else {
+ CreateMoveAnchor(pos);
+ }
+ return C_CONTINUE;
+ break;
+
case C_DOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curStructure == NULL ) return C_CONTINUE;
ShowPierL();
- if (Dst.state == 1) {
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
- } else {
- Dst.pos = pos;
- }
+ Dst.pos = pos;
rot0 = pos;
origPos = Dst.pos;
PlaceStructure( rot0, pos, origPos, &Dst.pos, &Dst.angle );
Dst.state = 1;
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
InfoMessage( _("Drag to place") );
+ CreateMoveAnchor(pos);
return C_CONTINUE;
case C_MOVE:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curStructure == NULL ) return C_CONTINUE;
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
PlaceStructure( rot0, pos, origPos, &Dst.pos, &Dst.angle );
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
- MainRedraw();
- MapRedraw();
+ CreateMoveAnchor(pos);
InfoMessage( "[ %0.3f %0.3f ]", pos.x - origPos.x, pos.y - origPos.y );
return C_CONTINUE;
case C_RDOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curStructure == NULL ) return C_CONTINUE;
- if (Dst.state == 1)
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
- else
- Dst.pos = pos;
+ if (Dst.state == 0) {
+ Dst.pos = pos; // If first, use pos, otherwise use current
+ }
rot0 = rot1 = pos;
- DrawLine( &tempD, rot0, rot1, 0, wDrawColorBlack );
- Dst.state = 1;
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
+ CreateRotateAnchor(pos);
origPos = Dst.pos;
origAngle = Dst.angle;
InfoMessage( _("Drag to rotate") );
+ Dst.state = 2;
validAngle = FALSE;
return C_CONTINUE;
case C_RMOVE:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curStructure == NULL ) return C_CONTINUE;
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
- DrawLine( &tempD, rot0, rot1, 0, wDrawColorBlack );
rot1 = pos;
if ( FindDistance( rot0, rot1 ) > (6.0/75.0)*mainD.scale ) {
angle = FindAngle( rot0, rot1 );
@@ -700,36 +861,37 @@ EXPORT STATUS_T CmdStructureAction(
Rotate( &Dst.pos, rot0, angle );
}
InfoMessage( _("Angle = %0.3f"), Dst.angle );
- DrawLine( &tempD, rot0, rot1, 0, wDrawColorBlack );
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
+ Dst.state = 2;
+ CreateRotateAnchor(rot0);
return C_CONTINUE;
case C_RUP:
- DrawLine( &tempD, rot0, rot1, 0, wDrawColorBlack );
case C_UP:
- MainRedraw();
- MapRedraw();
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ CreateMoveAnchor(pos);
+ Dst.state = 1;
+ InfoMessage(_("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel"));
return C_CONTINUE;
case C_CMDMENU:
- if ( structPopupM == NULL ) {
- structPopupM = MenuRegister( "Structure Rotate" );
- AddRotateMenu( structPopupM, StructRotate );
- }
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ menuPos = pos;
wMenuPopupShow( structPopupM );
return C_CONTINUE;
case C_REDRAW:
- if (Dst.state == 1)
+ if (Dst.state)
DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
+ curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlue );
+ if (anchors_da.cnt>0) {
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ }
+ if (Dst.state == 2)
+ DrawLine( &tempD, rot0, rot1, 0, wDrawColorBlack );
return C_CONTINUE;
case C_CANCEL:
- if (Dst.state == 1)
- DrawSegs( &tempD, Dst.pos, Dst.angle,
- curStructure->segs, curStructure->segCnt, 0.0, wDrawColorBlack );
+ DYNARR_RESET(trkSeg_t,anchors_da);
Dst.state = 0;
InfoSubstituteControls( NULL, NULL );
HotBarCancel();
@@ -739,12 +901,15 @@ EXPORT STATUS_T CmdStructureAction(
case C_TEXT:
if ((action>>8) != ' ')
return C_CONTINUE;
+ /*no break*/
case C_OK:
+ DYNARR_RESET(trkSeg_t,anchors_da);
NewStructure();
InfoSubstituteControls( NULL, NULL );
return C_TERMINATE;
case C_FINISH:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if (Dst.state != 0)
CmdStructureAction( C_OK, pos );
else
@@ -791,17 +956,37 @@ static STATUS_T CmdStructure(
ParamGroupRecord( &structurePG );
return CmdStructureAction( action, pos );
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (Dst.state && (MyGetKeyState()&WKEY_CTRL)) {
+ CreateRotateAnchor(pos);
+ } else {
+ CreateMoveAnchor(pos);
+ }
+ return C_CONTINUE;
+ break;
case C_DOWN:
+ if (MyGetKeyState()&WKEY_CTRL) {
+ return CmdStructureAction( C_RDOWN, pos );
+ }
+ /* no break*/
case C_RDOWN:
ParamDialogOkActive( &structurePG, TRUE );
if (hideStructureWindow)
wHide( structureW );
+ return CmdStructureAction( action, pos );
case C_MOVE:
+ if (MyGetKeyState()&WKEY_CTRL) {
+ return CmdStructureAction( C_RMOVE, pos );
+ }
+ /*no break*/
case C_RMOVE:
return CmdStructureAction( action, pos );
-
case C_RUP:
case C_UP:
+ if (MyGetKeyState()&WKEY_CTRL) {
+ return CmdStructureAction( C_RUP, pos );
+ }
if (hideStructureWindow)
wShow( structureW );
InfoMessage( _("Left drag to move, right drag to rotate, or press Return or click Ok to finalize") );
@@ -810,11 +995,12 @@ static STATUS_T CmdStructure(
case C_CANCEL:
wHide( structureW );
+ /*no break*/
+ case C_REDRAW:
case C_TEXT:
case C_OK:
case C_FINISH:
case C_CMDMENU:
- case C_REDRAW:
return CmdStructureAction( action, pos );
default:
@@ -848,6 +1034,8 @@ static char * CmdStructureHotBarProc(
case HB_FULLTITLE:
return to->title;
case HB_DRAW:
+ origP->x -= to->orig.x;
+ origP->y -= to->orig.y;
DrawSegs( d, *origP, 0.0, to->segs, to->segCnt, trackGauge, wDrawColorBlack );
return NULL;
}
@@ -867,7 +1055,7 @@ EXPORT void AddHotBarStructures( void )
/*( (strcmp( to->scale, "*" ) == 0 && strcasecmp( curScaleName, "DEMO" ) != 0 ) ||
strncasecmp( to->scale, curScaleName, strlen(to->scale) ) == 0 ) ) )*/
continue;
- AddHotBarElement( to->contentsLabel, to->size, to->orig, FALSE, to->barScale, to, CmdStructureHotBarProc );
+ AddHotBarElement( to->contentsLabel, to->size, to->orig, FALSE, FALSE, to->barScale, to, CmdStructureHotBarProc );
}
}
@@ -885,47 +1073,72 @@ static STATUS_T CmdStructureHotBar(
}
FormatCompoundTitle( listLabels|LABEL_DESCR, curStructure->title );
InfoMessage( _("Place %s and draw into position"), message );
- ParamLoadControls( &structurePG );
- ParamGroupRecord( &structurePG );
+ wIndex_t listIndex = FindListItemByContext( structureListL, curStructure );
+ if ( listIndex > 0 )
+ structureInx = listIndex;
+ //ParamLoadControls( &structurePG );
+ //ParamGroupRecord( &structurePG );
+ return CmdStructureAction( action, pos );
+
+ case wActionMove:
+ return CmdStructureAction( action, pos );
+
+ case C_RDOWN:
+ case C_DOWN:
+ if (MyGetKeyState()&WKEY_CTRL) {
+ return CmdStructureAction( C_RDOWN, pos );
+ }
+ return CmdStructureAction( action, pos );
+
+ case C_RMOVE:
+ case C_MOVE:
+ if (MyGetKeyState()&WKEY_CTRL) {
+ return CmdStructureAction( C_RMOVE, pos );
+ }
return CmdStructureAction( action, pos );
case C_RUP:
case C_UP:
- InfoMessage( _("Left drag to move, right drag to rotate, or press Return or click Ok to finalize") );
+ if (MyGetKeyState()&WKEY_CTRL) {
+ return CmdStructureAction( C_RUP, pos );
+ }
+ InfoMessage( _("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel") );
return CmdStructureAction( action, pos );
case C_TEXT:
if ((action>>8) != ' ')
return C_CONTINUE;
+ /*no break*/
case C_OK:
CmdStructureAction( action, pos );
return C_CONTINUE;
case C_CANCEL:
HotBarCancel();
+ /* no break*/
default:
return CmdStructureAction( action, pos );
}
}
-
-#ifdef STRUCTCMD
#include "bitmaps/struct.xpm"
EXPORT void InitCmdStruct( wMenu_p menu )
{
- AddMenuButton( menu, CmdStructure, "cmdStructure", _("Structure"), wIconCreatePixMap(struct_xpm), LEVEL0_50, IC_STICKY|IC_CMDMENU|IC_POPUP2, ACCL_STRUCTURE, NULL );
- structureHotBarCmdInx = AddMenuButton( menu, CmdStructureHotBar, "cmdStructureHotBar", "", NULL, LEVEL0_50, IC_STICKY|IC_CMDMENU|IC_POPUP2, 0, NULL );
+ AddMenuButton( menu, CmdStructure, "cmdStructure", _("Structure"), wIconCreatePixMap(struct_xpm), LEVEL0_50, IC_WANT_MOVE|IC_STICKY|IC_CMDMENU|IC_POPUP2, ACCL_STRUCTURE, NULL );
+ structureHotBarCmdInx = AddMenuButton( menu, CmdStructureHotBar, "cmdStructureHotBar", "", NULL, LEVEL0_50, IC_WANT_MOVE|IC_STICKY|IC_CMDMENU|IC_POPUP2, 0, NULL );
ParamRegister( &structurePG );
+ if ( structPopupM == NULL ) {
+ structPopupM = MenuRegister( "Structure Rotate" );
+ AddRotateMenu( structPopupM, StructRotate );
+ }
}
-#endif
-
EXPORT void InitTrkStruct( void )
{
T_STRUCTURE = InitObject( &structureCmds );
log_structure = LogFindIndex( "Structure" );
- AddParam( "STRUCTURE ", ReadStructureParam );
+ AddParam( "STRUCTURE ", ReadStructureParam);
ParamRegister( &pierPG );
}
diff --git a/app/bin/cswitchmotor.c b/app/bin/cswitchmotor.c
index 09e6709..a8e1c54 100644
--- a/app/bin/cswitchmotor.c
+++ b/app/bin/cswitchmotor.c
@@ -60,6 +60,9 @@
#include "param.h"
#include "track.h"
#include "trackx.h"
+#ifdef WINDOWS
+#include "include/utf8convert.h"
+#endif // WINDOWS
#include "utility.h"
#include "messages.h"
@@ -83,6 +86,9 @@ static char switchmotorReverse[STR_LONG_SIZE];
static char switchmotorPointSense[STR_LONG_SIZE];
static track_p switchmotorTurnout;
+static track_p last_motor;
+static track_p first_motor;
+
static paramData_t switchmotorPLs[] = {
/*0*/ { PD_STRING, switchmotorName, "name", PDO_NOPREF|PDO_STRINGLIMITLENGTH, (void*)200, N_("Name"), 0, 0, sizeof(switchmotorName)},
/*1*/ { PD_STRING, switchmotorNormal, "normal", PDO_NOPREF|PDO_STRINGLIMITLENGTH, (void*)350, N_("Normal"), 0, 0, sizeof(switchmotorNormal)},
@@ -126,6 +132,7 @@ typedef struct switchmotorData_t {
BOOL_T IsHilite;
TRKINX_T turnindx;
track_p turnout;
+ track_p next_motor;
} switchmotorData_t, *switchmotorData_p;
static switchmotorData_p GetswitchmotorData ( track_p trk )
@@ -201,7 +208,7 @@ static void DrawSwitchMotor (track_p t, drawCmd_p d, wDrawColor color )
Translate (&p[iPoint], orig, x_angle, switchmotorPoly_Pix[iPoint].x * switchmotorPoly_SF / scaleRatio );
Translate (&p[iPoint], p[iPoint], y_angle, (10+switchmotorPoly_Pix[iPoint].y) * switchmotorPoly_SF / scaleRatio );
}
- DrawFillPoly(d, switchmotorPoly_CNT, p, wDrawColorBlack);
+ DrawPoly(d, switchmotorPoly_CNT, p, NULL, color, 0, 1, 0);
}
static struct {
@@ -308,7 +315,13 @@ static DIST_T DistanceSwitchMotor (track_p t, coOrd * p )
{
switchmotorData_p xx = GetswitchmotorData(t);
if (xx->turnout == NULL) return 0;
- return GetTrkDistance(xx->turnout,p);
+ coOrd center,hi,lo;
+ GetBoundingBox(t,&hi,&lo);
+ center.x = (hi.x+lo.x)/2;
+ center.y = (hi.y+lo.y)/2;
+ DIST_T d = FindDistance(center,*p);
+ *p = center;
+ return d;
}
static void DescribeSwitchMotor (track_p trk, char * str, CSIZE_T len )
@@ -326,7 +339,7 @@ static void DescribeSwitchMotor (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 );
strncpy(switchmotorData.name,xx->name,STR_SHORT_SIZE-1);
switchmotorData.name[STR_SHORT_SIZE-1] = '\0';
@@ -364,52 +377,89 @@ static void switchmotorDebug (track_p trk)
static void DeleteSwitchMotor ( track_p trk )
{
- LOG( log_switchmotor, 1,("*** DeleteSwitchMotor(%p)\n",trk))
- LOG( log_switchmotor, 1,("*** DeleteSwitchMotor(): index is %d\n",GetTrkIndex(trk)))
- switchmotorData_p xx = GetswitchmotorData(trk);
- LOG( log_switchmotor, 1,("*** DeleteSwitchMotor(): xx = %p, xx->name = %p, xx->normal = %p, xx->reverse = %p, xx->pointsense = %p\n",
+
+ track_p trk1;
+ switchmotorData_p xx1;
+
+ LOG( log_switchmotor, 1,("*** DeleteSwitchMotor(%p)\n",trk))
+ LOG( log_switchmotor, 1,("*** DeleteSwitchMotor(): index is %d\n",GetTrkIndex(trk)))
+ switchmotorData_p xx = GetswitchmotorData(trk);
+ LOG( log_switchmotor, 1,("*** DeleteSwitchMotor(): xx = %p, xx->name = %p, xx->normal = %p, xx->reverse = %p, xx->pointsense = %p\n",
xx,xx->name,xx->normal,xx->reverse,xx->pointsense))
MyFree(xx->name); xx->name = NULL;
MyFree(xx->normal); xx->normal = NULL;
MyFree(xx->reverse); xx->reverse = NULL;
MyFree(xx->pointsense); xx->pointsense = NULL;
+ if (first_motor == trk)
+ first_motor = xx->next_motor;
+ trk1 = first_motor;
+ while(trk1) {
+ xx1 = GetswitchmotorData (trk1);
+ if (xx1->next_motor == trk) {
+ xx1->next_motor = xx->next_motor;
+ break;
+ }
+ trk1 = xx1->next_motor;
+ }
+ if (trk == last_motor)
+ last_motor = trk1;
}
static BOOL_T WriteSwitchMotor ( track_p t, FILE * f )
{
BOOL_T rc = TRUE;
switchmotorData_p xx = GetswitchmotorData(t);
+ char *switchMotorName = MyStrdup(xx->name);
- if (xx->turnout == NULL) return FALSE;
+#ifdef WINDOWS
+ switchMotorName = Convert2UTF8(switchMotorName);
+#endif // WINDOWS
+
+ if (xx->turnout == NULL)
+ return FALSE;
rc &= fprintf(f, "SWITCHMOTOR %d %d \"%s\" \"%s\" \"%s\" \"%s\"\n",
- GetTrkIndex(t), GetTrkIndex(xx->turnout), xx->name,
+ GetTrkIndex(t), GetTrkIndex(xx->turnout), switchMotorName,
xx->normal, xx->reverse, xx->pointsense)>0;
+
+ MyFree(switchMotorName);
return rc;
}
-static void ReadSwitchMotor ( char * line )
+static BOOL_T ReadSwitchMotor ( char * line )
{
TRKINX_T trkindex;
wIndex_t index;
- track_p trk;
- switchmotorData_p xx;
+ track_p trk,last_trk;
+ switchmotorData_p xx,xx1;
char *name, *normal, *reverse, *pointsense;
LOG( log_switchmotor, 1, ("*** ReadSwitchMotor: line is '%s'\n",line))
if (!GetArgs(line+12,"ddqqqq",&index,&trkindex,&name,&normal,&reverse,&pointsense)) {
- return;
+ return FALSE;
}
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(name);
+#endif // WINDOWS
trk = NewTrack(index, T_SWITCHMOTOR, 0, sizeof(switchmotorData_t)+1);
xx = GetswitchmotorData( trk );
xx->name = name;
xx->normal = normal;
xx->reverse = reverse;
xx->pointsense = pointsense;
- xx->turnindx = trkindex;
+ xx->turnindx = trkindex;
+ if (last_motor) {
+ last_trk = last_motor;
+ xx1 = GetswitchmotorData(last_trk);
+ xx1->next_motor = trk;
+ } else first_motor = trk;
+ xx->next_motor = NULL;
+ last_motor = trk;
+
LOG( log_switchmotor, 1,("*** ReadSwitchMotor(): trk = %p (%d), xx = %p\n",trk,GetTrkIndex(trk),xx))
LOG( log_switchmotor, 1,("*** ReadSwitchMotor(): name = %p, normal = %p, reverse = %p, pointsense = %p\n",
name,normal,reverse,pointsense))
switchmotorDebug(trk);
+ return TRUE;
}
EXPORT void ResolveSwitchmotorTurnout ( track_p trk )
@@ -472,19 +522,21 @@ static track_p FindSwitchMotor (track_p trk)
track_p a_trk;
switchmotorData_p xx;
- for (a_trk = NULL; TrackIterate( &a_trk ) ;) {
- if (GetTrkType(a_trk) == T_SWITCHMOTOR) {
- xx = GetswitchmotorData(a_trk);
+ a_trk = first_motor;
+ while (a_trk) {
+ xx = GetswitchmotorData(a_trk);
+ if (!IsTrackDeleted(a_trk)) {
if (xx->turnout == trk) return a_trk;
}
+ a_trk = xx->next_motor;
}
return NULL;
}
static void SwitchMotorOk ( void * junk )
{
- switchmotorData_p xx;
- track_p trk;
+ switchmotorData_p xx,xx1;
+ track_p trk,trk1;
LOG( log_switchmotor, 1, ("*** SwitchMotorOk()\n"))
ParamUpdate (&switchmotorPG );
@@ -502,12 +554,19 @@ static void SwitchMotorOk ( void * junk )
xx->reverse = MyStrdup(switchmotorReverse);
xx->pointsense = MyStrdup(switchmotorPointSense);
xx->turnout = switchmotorTurnout;
- LOG( log_switchmotor, 1,("*** SwitchMotorOk(): trk = %p (%d), xx = %p\n",trk,GetTrkIndex(trk),xx))
+ trk1 = last_motor;
+ if (trk1) {
+ xx1 = GetswitchmotorData( trk1 );
+ xx1->next_motor = trk;
+ } else first_motor = trk;
+ xx->next_motor = NULL;
+ last_motor = trk;
+ LOG( log_switchmotor, 1,("*** SwitchMotorOk(): trk = %p (%d), xx = %p\n",trk,GetTrkIndex(trk),xx))
switchmotorDebug(trk);
UndoEnd();
- wHide( switchmotorW );
- ComputeSwitchMotorBoundingBox(trk);
- DrawNewTrack(trk);
+ wHide( switchmotorW );
+ ComputeSwitchMotorBoundingBox(trk);
+ DrawNewTrack(trk);
}
static void NewSwitchMotorDialog(track_p trk)
@@ -704,7 +763,7 @@ static void DrawSWMotorTrackHilite( void )
w = (wPos_t)((swmhiliteSize.x/mainD.scale)*mainD.dpi+0.5);
h = (wPos_t)((swmhiliteSize.y/mainD.scale)*mainD.dpi+0.5);
mainD.CoOrd2Pix(&mainD,swmhiliteOrig,&x,&y);
- wDrawFilledRectangle( mainD.d, x, y, w, h, swmhiliteColor, wDrawOptTemp );
+ wDrawFilledRectangle( mainD.d, x, y, w, h, swmhiliteColor, wDrawOptTemp|wDrawOptTransparent );
}
static int SwitchmotorMgmProc ( int cmd, void * data )
@@ -805,6 +864,7 @@ EXPORT void CheckDeleteSwitchmotor(track_p t)
{
track_p sm;
switchmotorData_p xx;
+ if (GetTrkType( t ) != T_TURNOUT) return; // SMs only on turnouts
while ((sm = FindSwitchMotor( t ))) { //Cope with multiple motors for one Turnout!
xx = GetswitchmotorData (sm);
diff --git a/app/bin/ctext.c b/app/bin/ctext.c
index ca0c7c7..c292d1c 100644
--- a/app/bin/ctext.c
+++ b/app/bin/ctext.c
@@ -30,7 +30,7 @@
#include "draw.h"
#include "misc.h"
-track_p NewText( wIndex_t index, coOrd p, ANGLE_T angle, char * text, CSIZE_T textSize, wDrawColor color );
+track_p NewText( wIndex_t index, coOrd p, ANGLE_T angle, char * text, CSIZE_T textSize, wDrawColor color, BOOL_T boxed );
void LoadFontSizeList( wList_p, long );
void UpdateFontSizeList( long *, wList_p, wIndex_t );
@@ -57,13 +57,17 @@ static struct {
wIndex_t fontSizeInx;
char text[STR_LONG_SIZE];
wDrawColor color;
+ BOOL_T boxed;
} Dt;
+static char * boxLabels[] = { "", NULL };
static paramData_t textPLs[] = {
#define textPD (textPLs[0])
- { PD_DROPLIST, &Dt.fontSizeInx, "fontsize", 0, NULL, N_("Font Size"), BL_EDITABLE },
+ { PD_DROPLIST, &Dt.fontSizeInx, "Fontsize", 0, NULL, N_("Font Size"), BL_EDITABLE },
#define colorPD (textPLs[1])
- { PD_COLORLIST, &Dt.color, "color", PDO_NORECORD, NULL, N_("Color") }
+ { PD_COLORLIST, &Dt.color, "Color", PDO_NORECORD, NULL, N_("Color") },
+#define boxPD (textPLs[2])
+ { PD_TOGGLE, &Dt.boxed, "Boxed", 0, boxLabels, N_("Boxed"), 0 }
};
static paramGroup_t textPG = { "text", 0, textPLs, sizeof textPLs/sizeof textPLs[0] };
@@ -83,29 +87,21 @@ static void TextDlgUpdate(
switch (inx) {
case 0:
case 1:
- if ( Dt.state == SHOW_TEXT) {
- DrawMultiString( &tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0, NULL, NULL );
- DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- }
+ case 2:
UpdateFontSizeList( &Dt.size, (wList_p)textPLs[0].control, Dt.fontSizeInx );
- /*wWinSetBusy( mainW, TRUE );*/
if ( Dt.state == SHOW_TEXT) {
DrawMultiLineTextSize( &mainD, Dt.text, NULL, Dt.size, TRUE, &size, &lastline);
Dt.textLen = size.x;
Dt.lastLineLen = lastline.x;
Dt.lastLineOffset = lastline.y;
}
+ wSetSelectedFontSize((wFontSize_t)Dt.size); //Update for next time
DrawTextSize( &mainD, "Aquilp", NULL, Dt.size, TRUE, &size );
Dt.cursHeight = size.y;
- /*wWinSetBusy( mainW, FALSE );*/
if ( Dt.state == SHOW_TEXT) {
Dt.cursPos0.x = Dt.cursPos1.x = Dt.pos.x+Dt.lastLineLen;
Dt.cursPos1.y = Dt.pos.y+Dt.cursHeight+Dt.lastLineOffset;
- DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- DrawMultiString( &tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0, NULL, NULL );
}
- MainRedraw();
- MapRedraw();
break;
}
}
@@ -115,8 +111,8 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
{
track_p t;
unsigned char c;
- wControl_p controls[3];
- char * labels[2];
+ wControl_p controls[4];
+ char * labels[3];
coOrd size, lastline;
switch (action & 0xFF) {
@@ -141,23 +137,21 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
ParamLoadControls(&textPG);
ParamGroupRecord( &textPG );
- if (!inPlayback)
- wWinSetBusy(mainW, TRUE);
DrawTextSize(&mainD, "Aquilp", NULL, Dt.size, TRUE, &size);
Dt.cursHeight = size.y;
- if (!inPlayback)
- wWinSetBusy(mainW, FALSE);
controls[0] = textPD.control;
controls[1] = colorPD.control;
- controls[2] = 0;
+ controls[2] = boxPD.control;
+ controls[3] = 0;
labels[0] = N_("Font Size");
labels[1] = N_("Color");
+ labels[2] = N_("Boxed");
InfoSubstituteControls( controls, labels );
return C_CONTINUE;
break;
case C_DOWN:
- if (Dt.state != 0) {
+ if (Dt.state != POSITION_TEXT) {
}
Dt.pos = pos;
Dt.cursPos0.y = Dt.cursPos1.y = pos.y + Dt.lastLineOffset;
@@ -165,21 +159,13 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
DrawTextSize(&mainD, "Aquilp", NULL, Dt.size, TRUE, &size); //In case fontsize change
Dt.cursHeight = size.y;
Dt.cursPos1.y += Dt.cursHeight;
- DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
Dt.state = SHOW_TEXT;
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
case C_MOVE:
Dt.pos = pos;
Dt.cursPos0.y = Dt.cursPos1.y = pos.y + Dt.lastLineOffset;
Dt.cursPos0.x = Dt.cursPos1.x = pos.x + Dt.lastLineLen;
Dt.cursPos1.y += Dt.cursHeight;
- DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, wDrawColorBlack );
- DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
case C_UP:
return C_CONTINUE;
@@ -188,8 +174,7 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
NoticeMessage( MSG_SEL_POS_FIRST, _("Ok"), NULL );
return C_CONTINUE;
}
- DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
+
c = (unsigned char)(action >> 8);
switch (c) {
case '\b':
@@ -209,7 +194,7 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
break;
case '\015':
UndoStart( _("Create Text"), "newText - CR" );
- t = NewText( 0, Dt.pos, Dt.angle, Dt.text, (CSIZE_T)Dt.size, Dt.color );
+ t = NewText( 0, Dt.pos, Dt.angle, Dt.text, (CSIZE_T)Dt.size, Dt.color, Dt.boxed );
UndoEnd();
DrawNewTrack(t);
Dt.state = POSITION_TEXT;
@@ -227,42 +212,33 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
Dt.lastLineOffset = lastline.y;
Dt.cursPos0.x = Dt.cursPos1.x = Dt.pos.x + Dt.lastLineLen;
Dt.cursPos0.y = Dt.cursPos1.y = Dt.pos.y + Dt.lastLineOffset;
- DrawTextSize(&mainD, "Aquilp", NULL, Dt.size, TRUE, &size); //In case fontsize change
+ POS_T descent, ascent;
+ DrawTextSize2(&mainD, "Aquilp", NULL, Dt.size, TRUE, &size, &descent, &ascent); //In case fontsize change
Dt.cursHeight = size.y;
+ Dt.cursPos0.y -=descent;
Dt.cursPos1.y +=Dt.cursHeight;
- MainRedraw();
- MapRedraw();
- //DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- //DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
return C_CONTINUE;
case C_REDRAW:
- if (Dt.state == 1) {
- DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
- DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL );
- }
+ DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
+ DrawMultiString(&tempD, Dt.pos, Dt.text, NULL, (FONTSIZE_T)Dt.size, Dt.color, 0.0, NULL, NULL, Dt.boxed );
return C_CONTINUE;
case C_CANCEL:
if (Dt.state != POSITION_TEXT) {
Dt.state = POSITION_TEXT;
}
InfoSubstituteControls( NULL, NULL );
- MainRedraw();
- MapRedraw();
return C_TERMINATE;
case C_OK:
if (Dt.state != POSITION_TEXT) {
- DrawLine( &tempD, Dt.cursPos0, Dt.cursPos1, 0, Dt.color );
Dt.state = POSITION_TEXT;
if (Dt.len) {
UndoStart( _("Create Text"), "newText - OK" );
- t = NewText( 0, Dt.pos, Dt.angle, Dt.text, (CSIZE_T)Dt.size, Dt.color );
+ t = NewText( 0, Dt.pos, Dt.angle, Dt.text, (CSIZE_T)Dt.size, Dt.color, Dt.boxed );
UndoEnd();
DrawNewTrack(t);
}
}
InfoSubstituteControls( NULL, NULL );
- MainRedraw();
- MapRedraw();
return C_TERMINATE;
case C_FINISH:
@@ -273,6 +249,7 @@ static STATUS_T CmdText( wAction_t action, coOrd pos )
return C_TERMINATE;
case C_CMDMENU:
+ menuPos = pos;
wMenuPopupShow( textPopupM );
return C_CONTINUE;
}
diff --git a/app/bin/ctodesgn.c b/app/bin/ctodesgn.c
index 27acbb6..dc118a1 100644
--- a/app/bin/ctodesgn.c
+++ b/app/bin/ctodesgn.c
@@ -41,9 +41,17 @@
#include "param.h"
#include "track.h"
#include "utility.h"
+#include "ccornu.h"
+#include "cbezier.h"
+#include "misc.h"
+
+dynArr_t tempSegs_da;
+dynArr_t tempEndPts_da;
+char tempCustom[4096];
#define TURNOUTDESIGNER "CTURNOUT DESIGNER"
+dynArr_t tempSegs_da;
/*****************************************
@@ -67,6 +75,9 @@
#define NTO_CRV_SECTION (12)
#define NTO_BUMPER (13)
#define NTO_TURNTABLE (14)
+#define NTO_CORNU (15)
+#define NTO_CORNUWYE (16)
+#define NTO_CORNU3WAY (17)
#define FLOAT (1)
@@ -78,7 +89,7 @@ typedef struct {
int index;
char * winLabel;
char * printLabel;
- enum { Dim_e, Frog_e, Angle_e } mode;
+ enum { Dim_e, Frog_e, Angle_e, Rad_e } mode;
} toDesignFloat_t;
typedef struct {
@@ -97,27 +108,48 @@ typedef struct {
toDesignSchema_t * paths;
int angleModeCnt;
wLine_p lineC;
+ wBool_t slipmode;
} toDesignDesc_t;
static wWin_p newTurnW;
+
+static FLOAT_T newTurnRad0;
+static FLOAT_T newTurnAngle0;
static FLOAT_T newTurnLen0;
+static FLOAT_T newTurnOff0;
+
+static FLOAT_T newTurnRad1;
+static FLOAT_T newTurnAngle1;
static FLOAT_T newTurnLen1;
static FLOAT_T newTurnOff1;
-static FLOAT_T newTurnAngle1;
+
+static FLOAT_T newTurnRad2;
+static FLOAT_T newTurnAngle2;
static FLOAT_T newTurnLen2;
static FLOAT_T newTurnOff2;
-static FLOAT_T newTurnAngle2;
+
+static FLOAT_T newTurnRad3;
+static FLOAT_T newTurnAngle3;
+static FLOAT_T newTurnOff3;
+static FLOAT_T newTurnLen3;
+
+static FLOAT_T newTurnToeL;
+static FLOAT_T newTurnToeR;
+
static long newTurnAngleMode = 1;
+static long newTurnSlipMode = 0;
static char newTurnRightDesc[STR_SIZE], newTurnLeftDesc[STR_SIZE];
static char newTurnRightPartno[STR_SIZE], newTurnLeftPartno[STR_SIZE];
static char newTurnManufacturer[STR_SIZE];
static char *newTurnAngleModeLabels[] = { N_("Frog #"), N_("Degrees"), NULL };
+static char *newTurnSlipModeLabels[] = { N_("Dual Path"), N_("Quad Path"), NULL };
static DIST_T newTurnRoadbedWidth;
static long newTurnRoadbedLineWidth = 0;
static wDrawColor roadbedColor;
static DIST_T newTurnTrackGauge;
static char * newTurnScaleName;
static paramFloatRange_t r0_10000 = { 0, 10000, 80 };
+static paramFloatRange_t r_10000_10000 = {-10000, 10000, 80 };
static paramFloatRange_t r0_360 = { 0, 360, 80 };
static paramFloatRange_t r0_100 = { 0, 100, 80 };
static paramIntegerRange_t i0_100 = { 0, 100, 40 };
@@ -126,7 +158,13 @@ static void ShowTurnoutDesigner( void * );
static coOrd points[20];
-static DIST_T radii[10] = { 0.0 };
+static coOrd end_points[20];
+static coOrd end_centers[20];
+static double end_arcs[20];
+static double end_angles[20];
+static DIST_T radii[10];
+static double angles[10];
+
#define POSX(X) ((wPos_t)((X)*newTurnout_d.dpi))
#define POSY(Y) ((wPos_t)((Y)*newTurnout_d.dpi))
@@ -134,22 +172,35 @@ static DIST_T radii[10] = { 0.0 };
static paramData_t turnDesignPLs[] = {
#define I_TOLENGTH (0)
#define I_TO_FIRST_FLOAT (0)
+ { PD_FLOAT, &newTurnLen0, "len0", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0_10000, N_("Length") },
{ PD_FLOAT, &newTurnLen1, "len1", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0_10000, N_("Length") },
{ PD_FLOAT, &newTurnLen2, "len2", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0_10000, N_("Length") },
- { PD_FLOAT, &newTurnLen0, "len0", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0_10000, N_("Length") },
-#define I_TOOFFSET (3)
- { PD_FLOAT, &newTurnOff1, "off1", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0_10000, N_("Offset") },
- { PD_FLOAT, &newTurnOff2, "off2", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0_10000, N_("Offset") },
-#define I_TOANGLE (5)
+ { PD_FLOAT, &newTurnLen3, "len3", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0_10000, N_("Length") },
+#define I_TOOFFSET (4)
+ { PD_FLOAT, &newTurnOff0, "off0", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Offset") },
+ { PD_FLOAT, &newTurnOff1, "off1", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Offset") },
+ { PD_FLOAT, &newTurnOff2, "off2", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Offset") },
+ { PD_FLOAT, &newTurnOff3, "off3", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Offset") },
+#define I_TORAD (8)
+ { PD_FLOAT, &newTurnRad0, "rad0", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Radius") },
+ { PD_FLOAT, &newTurnRad1, "rad1", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Radius") },
+ { PD_FLOAT, &newTurnRad2, "rad2", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Radius") },
+ { PD_FLOAT, &newTurnRad3, "rad3", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Radius") },
+#define I_TOTOELENGTH (12)
+ { PD_FLOAT, &newTurnToeL, "toeL", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0_10000, N_("Length") },
+ { PD_FLOAT, &newTurnToeR, "toeR", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0_10000, N_("Length") },
+#define I_TOANGLE (14)
+ { PD_FLOAT, &newTurnAngle0, "angle0", PDO_DLGIGNORELABELWIDTH, &r0_360, N_("Angle") },
{ PD_FLOAT, &newTurnAngle1, "angle1", PDO_DLGIGNORELABELWIDTH, &r0_360, N_("Angle") },
-#define I_TO_LAST_FLOAT (6)
{ PD_FLOAT, &newTurnAngle2, "angle2", PDO_DLGIGNORELABELWIDTH, &r0_360, N_("Angle") },
-#define I_TOMANUF (7)
+#define I_TO_LAST_FLOAT (17)
+ { PD_FLOAT, &newTurnAngle3, "angle3", PDO_DLGIGNORELABELWIDTH, &r0_360, N_("Angle") },
+#define I_TOMANUF (18)
{ PD_STRING, &newTurnManufacturer, "manuf", PDO_STRINGLIMITLENGTH, NULL, N_("Manufacturer"), 0, 0, sizeof(newTurnManufacturer)},
-#define I_TOLDESC (8)
+#define I_TOLDESC (19)
{ PD_STRING, &newTurnLeftDesc, "desc1", PDO_STRINGLIMITLENGTH, NULL, N_("Left Description"), 0, 0, sizeof(newTurnLeftDesc)},
{ PD_STRING, &newTurnLeftPartno, "partno1", PDO_DLGHORZ | PDO_STRINGLIMITLENGTH, NULL, N_(" #"), 0, 0, sizeof(newTurnLeftPartno)},
-#define I_TORDESC (10)
+#define I_TORDESC (21)
{ PD_STRING, &newTurnRightDesc, "desc2", PDO_STRINGLIMITLENGTH, NULL, N_("Right Description"),0, 0, sizeof(newTurnRightDesc)},
{ PD_STRING, &newTurnRightPartno, "partno2", PDO_DLGHORZ | PDO_STRINGLIMITLENGTH, NULL, N_(" #"),0, 0, sizeof(newTurnRightPartno)},
{ PD_FLOAT, &newTurnRoadbedWidth, "roadbedWidth", PDO_DIM, &r0_100, N_("Roadbed Width") },
@@ -157,11 +208,13 @@ static paramData_t turnDesignPLs[] = {
{ PD_COLORLIST, &roadbedColor, "color", PDO_DLGHORZ|PDO_DLGBOXEND, NULL, N_("Color") },
{ PD_BUTTON, (void*)NewTurnOk, "done", PDO_DLGCMDBUTTON, NULL, N_("Ok") },
{ PD_BUTTON, (void*)wPrintSetup, "printsetup", 0, NULL, N_("Print Setup") },
-#define I_TOANGMODE (17)
- { PD_RADIO, &newTurnAngleMode, "angleMode", 0, newTurnAngleModeLabels }
+#define I_TOANGMODE (28)
+ { PD_RADIO, &newTurnAngleMode, "angleMode", 0, newTurnAngleModeLabels },
+#define I_TOSLIPMODE (29)
+ { PD_RADIO, &newTurnSlipMode, "slipMode", 0, newTurnSlipModeLabels }
};
-
#ifndef MKTURNOUT
+
static paramGroup_t turnDesignPG = { "turnoutNew", 0, turnDesignPLs, sizeof turnDesignPLs/sizeof turnDesignPLs[0] };
static turnoutInfo_t * customTurnout1, * customTurnout2;
@@ -188,7 +241,7 @@ static toDesignFloat_t RegFloats[] = {
{ { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Diverging Length"), Dim_e },
{ { 400, 28 }, I_TOANGLE+0, N_("Angle"), N_("Diverging Angle"), Frog_e },
{ { 325, 68 }, I_TOOFFSET+0, N_("Offset"), N_("Diverging Offset"), Dim_e },
-{ { 100, 120 }, I_TOLENGTH+2, N_("Length"), N_("Overall Length"), Dim_e },
+{ { 100, 120 }, I_TOLENGTH+1, N_("Length"), N_("Overall Length"), Dim_e },
};
static signed char RegPaths[] = {
'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 2, 0, 0,
@@ -241,6 +294,34 @@ static toDesignDesc_t CrvDesc = {
sizeof CrvFloats/sizeof CrvFloats[0], CrvFloats,
&Crv1Schema, 1 };
+static wLines_t CornuLines[] = {
+#include "tocornu.lin"
+ };
+static toDesignFloat_t CornuFloats[] = {
+{ { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Inner Length"), Dim_e },
+{ { 375, 0 }, I_TOANGLE+0, N_("Angle"), N_("Inner Angle"), Frog_e },
+{ { 375, 22 }, I_TOOFFSET+0, N_("Offset"), N_("Inner Offset"), Dim_e },
+{ { 375, 44 }, I_TORAD+0, N_("Radius"), N_("Inner Radius"), Dim_e },
+{ { 400, 62 }, I_TOANGLE+1, N_("Angle"), N_("Outer Angle"), Frog_e },
+{ { 400, 84 }, I_TOOFFSET+1, N_("Offset"), N_("Outer Offset"), Dim_e },
+{ { 400, 106 }, I_TORAD+1, N_("Radius"), N_("Outer Radius"), Dim_e },
+{ { 175, 120 }, I_TOLENGTH+1, N_("Length"), N_("Outer Length"), Dim_e },
+{ { 50, 90 }, I_TORAD+2, N_("Radius"), N_("Toe Radius"), Dim_e },
+{ { 50, 40 }, I_TOTOELENGTH+0, N_("Length"), N_("Toe Length"), Dim_e } };
+static signed char CornuPaths[] = {
+ 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 4, 0, 0, 0,
+ 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 2, 0, 0, 0, 0 };
+static toDesignSchema_t CornuSchema = {
+ CornuPaths,
+ "033" "343" "413" };
+
+static toDesignDesc_t CornuDesc = {
+ NTO_CORNU,
+ N_("Cornu Curved Turnout"),
+ 2,
+ sizeof CornuLines/sizeof CornuLines[0], CornuLines,
+ sizeof CornuFloats/sizeof CornuFloats[0], CornuFloats,
+ &CornuSchema, 1 };
static wLines_t WyeLines[] = {
#include "towye.lin"
@@ -279,6 +360,35 @@ static toDesignDesc_t WyeDesc = {
sizeof WyeFloats/sizeof WyeFloats[0], WyeFloats,
NULL, 1 };
+static wLines_t CornuWyeLines[] = {
+#include "tocornuwye.lin"
+ };
+static toDesignFloat_t CornuWyeFloats[] = {
+{ { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Left Length"), Dim_e },
+{ { 400, 28 }, I_TOANGLE+0, N_("Angle"), N_("Left Angle"), Frog_e },
+{ { 400, 48 }, I_TOOFFSET+0, N_("Offset"), N_("Left Offset"), Dim_e },
+{ { 400, 68 }, I_TORAD+0, N_("Radius"), N_("Left Radius"), Dim_e },
+{ { 400, 108 }, I_TORAD+1, N_("Radius"), N_("Right Radius"), Dim_e },
+{ { 400, 128 }, I_TOOFFSET+1, N_("Offset"), N_("Right Offset"), Dim_e },
+{ { 400, 148 }, I_TOANGLE+1, N_("Angle"), N_("Right Angle"), Frog_e },
+{ { 175, 170 }, I_TOLENGTH+1, N_("Length"), N_("Right Length"), Dim_e },
+{ { 80, 48 }, I_TOTOELENGTH+0, N_("Length"), N_("Toe Length"), Dim_e },
+{ { 80, 28 }, I_TORAD+2, N_("Radius"), N_("Toe Radius"), Dim_e },
+ };
+static signed char CornuWyePaths[] = {
+ 'L', 'e', 'f', 't', 0, 1, 2, 3, 0, 0,
+ 'R', 'i', 'g', 'h', 't', 0, 1, 4, 5, 0, 0, 0 }; /* Not Used */
+static toDesignSchema_t CornuWyeSchema = {
+ CornuWyePaths,
+ "030" "341" "410" "362" "620" }; /* Not Used */
+static toDesignDesc_t CornuWyeDesc = {
+ NTO_CORNUWYE,
+ N_("Cornu Wye Turnout"),
+ 1,
+ sizeof CornuWyeLines/sizeof CornuWyeLines[0], CornuWyeLines,
+ sizeof CornuWyeFloats/sizeof CornuWyeFloats[0], CornuWyeFloats,
+ NULL, 1 };
+
static wLines_t ThreewayLines[] = {
#include "to3way.lin"
};
@@ -320,6 +430,41 @@ static toDesignDesc_t ThreewayDesc = {
sizeof ThreewayFloats/sizeof ThreewayFloats[0], ThreewayFloats,
NULL, 1 };
+static wLines_t CornuThreewayLines[] = {
+#include "tocornu3way.lin"
+ };
+static toDesignFloat_t CornuThreewayFloats[] = {
+{ { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Left Length"), Dim_e },
+{ { 380, 10 }, I_TOANGLE+0, N_("Angle"), N_("Left Angle"), Frog_e },
+{ { 380, 50 }, I_TOOFFSET+0, N_("Offset"), N_("Left Offset"), Dim_e },
+{ { 380, 30 }, I_TORAD+0, N_("Radius"), N_("Left Radius"), Dim_e },
+{ { 130, 90 }, I_TOLENGTH+3, N_("Length"), N_("Center Length"), Dim_e },
+{ { 400, 70 }, I_TOANGLE+3, N_("Angle"), N_("Center Angle"), Dim_e },
+{ { 400, 90}, I_TOOFFSET+3, N_("Offset"), N_("Center Offset"), Dim_e },
+{ { 400, 110 }, I_TORAD+3, N_("Radius"), N_("Center Radius"), Dim_e },
+{ { 420, 150 }, I_TORAD+1, N_("Radius"), N_("Right Radius"), Dim_e },
+{ { 420, 130 }, I_TOOFFSET+1, N_("Offset"), N_("Right Offset"), Dim_e },
+{ { 420, 170 }, I_TOANGLE+1, N_("Angle"), N_("Right Angle"), Frog_e },
+{ { 175, 170 }, I_TOLENGTH+1, N_("Length"), N_("Right Length"), Dim_e },
+{ { 45, 50 }, I_TOTOELENGTH+0, N_("Length"), N_("Toe Length Left"), Dim_e },
+{ { 55, 140 }, I_TOTOELENGTH+1, N_("Length"), N_("Toe Length Right"), Dim_e },
+{ { 40, 105 }, I_TORAD+2, N_("Radius"), N_("Toe Radius"), Dim_e },
+ };
+static signed char CornuTriPaths[] = {
+ 'L', 'e', 'f', 't', 0, 1, 2, 3, 0, 0,
+ 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 6, 0, 0,
+ 'R', 'i', 'g', 'h', 't', 0, 1, 4, 5, 0, 0, 0 };
+static toDesignSchema_t CornuTriSchema = {
+ CornuTriPaths,
+ "030" "341" "410" "362" "620" "370" };
+static toDesignDesc_t CornuThreewayDesc = {
+ NTO_CORNU3WAY,
+ N_("Cornu 3-way Turnout"),
+ 1,
+ sizeof CornuThreewayLines/sizeof CornuThreewayLines[0], CornuThreewayLines,
+ sizeof CornuThreewayFloats/sizeof CornuThreewayFloats[0], CornuThreewayFloats,
+ NULL, 1 };
+
static wLines_t CrossingLines[] = {
#include "toxing.lin"
};
@@ -371,9 +516,17 @@ static toDesignFloat_t DoubleSlipFloats[] = {
static signed char DoubleSlipPaths[] = {
'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 2, 3, 0, 4, 5, 6, 0, 0,
'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 7, 6, 0, 4, 8, 3, 0, 0, 0 };
+static signed char DoubleSlipPaths2[] = {
+ 'C', 'r', 'o', 's', 's', '1', 0, 1, 2, 3, 0, 0,
+ 'C', 'r', 'o', 's', 's', '2', 0, 4, 5, 6, 0, 0,
+ 'S', 'l', 'i', 'p', '1', 0, 1, 7, 6, 0, 0,
+ 'S', 'l', 'i', 'p', '2', 0, 4, 8, 3, 0, 0, 0 };
static toDesignSchema_t DoubleSlipSchema = {
DoubleSlipPaths,
"040" "460" "610" "270" "750" "530" "451" "762" };
+static toDesignSchema_t DoubleSlipSchema2 = {
+ DoubleSlipPaths2,
+ "040" "460" "610" "270" "750" "530" "451" "762" };
static toDesignDesc_t DoubleSlipDesc = {
NTO_D_SLIP,
N_("Double Slipswitch"),
@@ -595,8 +748,11 @@ static toDesignDesc_t TurntableDesc = {
static toDesignDesc_t * designDescs[] = {
&RegDesc,
&CrvDesc,
+ &CornuDesc,
&WyeDesc,
+ &CornuWyeDesc,
&ThreewayDesc,
+ &CornuThreewayDesc,
&CrossingDesc,
&SingleSlipDesc,
&DoubleSlipDesc,
@@ -1059,6 +1215,73 @@ static BOOL_T ComputeCurve(
return TRUE;
}
+#ifndef MKTURNOUT
+/* For Bezier Segs we need to duplicate the subSegs Array as well */
+void AppendSegs(dynArr_t * target, dynArr_t * source) {
+
+#define sourceSegs(N) DYNARR_N( trkSeg_t, *source, N )
+#define targetSegs(N) DYNARR_N( trkSeg_t, *target, N )
+
+ trkSeg_p src;
+
+ for (int i=0;i<source->cnt; i++) {
+ src = &sourceSegs(i);
+ addSegBezier(target, src);
+ }
+}
+
+/* Bezier Segs will have subSegs Array - free it before resetting the array */
+void ClearSegs(dynArr_t * target) {
+ for (int i=0;i<(*target).cnt;i++) {
+ if (targetSegs(i).type == SEG_BEZTRK)
+ if (targetSegs(i).bezSegs.ptr) MyFree(targetSegs(i).bezSegs.ptr);
+ targetSegs(i).bezSegs.ptr = NULL;
+ targetSegs(i).bezSegs.cnt = 0;
+ targetSegs(i).bezSegs.max = 0;
+ }
+ DYNARR_RESET( trkSeg_t, *target );
+}
+
+BOOL_T CallCornuNoBez(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p) {
+
+ dynArr_t temp_array;
+ DYNARR_RESET(trkSeg_t,temp_array);
+ temp_array.ptr=0;
+ temp_array.max=0;
+
+
+ wBool_t rc = CallCornu0(pos,center,angle,radius, &temp_array, FALSE);
+
+ if (!rc) return FALSE;
+
+ for (int i=0;i<temp_array.cnt;i++) {
+ trkSeg_p from_seg = &DYNARR_N(trkSeg_t,temp_array,i);
+ if ((from_seg->type == SEG_BEZTRK) || (from_seg->type == SEG_BEZLIN)) {
+ for (int j=0;j<from_seg->bezSegs.cnt;j++) {
+ trkSeg_p sub_seg = &DYNARR_N(trkSeg_t,from_seg->bezSegs,j);
+ DYNARR_APPEND(trkSeg_t,*array_p,5);
+ trkSeg_p to_seg = &DYNARR_N(trkSeg_t,*array_p,(*array_p).cnt-1);
+ to_seg->u = sub_seg->u;
+ to_seg->type = sub_seg->type;
+ to_seg->color = wDrawColorBlack;
+ to_seg->width = sub_seg->width;
+ }
+ } else {
+ DYNARR_APPEND(trkSeg_t,*array_p,5);
+ trkSeg_p to_seg = &DYNARR_N(trkSeg_t,*array_p,(*array_p).cnt-1);
+ to_seg->u = from_seg->u;
+ to_seg->type = from_seg->type;
+ to_seg->color = wDrawColorBlack;
+ to_seg->width = from_seg->width;
+ }
+ }
+
+ ClearSegs(&temp_array);
+
+ return TRUE;
+}
+
+#endif
static toDesignSchema_t * LoadSegs(
@@ -1076,52 +1299,72 @@ static toDesignSchema_t * LoadSegs(
char *segOrder;
coOrd pos;
wIndex_t segCnt;
- ANGLE_T angle1, angle2;
+ ANGLE_T angle0, angle1, angle2, angle3;
trkSeg_p segPtr;
+#ifndef MKTURNOUT
+ struct {
+ coOrd pos[10];
+ coOrd center[10];
+ DIST_T radius[10];
+ DIST_T angle[10];
+ } cornuData;
+#endif
DYNARR_RESET( trkSeg_t, tempSegs_da );
+ angle0 = newTurnAngle0;
angle1 = newTurnAngle1;
angle2 = newTurnAngle2;
+ angle3 = newTurnAngle3;
+
+
if ( newTurnAngleMode == 0 && dp->type != NTO_CRV_SECTION ) {
/* convert from Frog Num to degrees */
+ if ( angle0 > 0 )
+ angle0 = R2D(asin(1.0 / angle0));
if ( angle1 > 0 )
angle1 = R2D(asin(1.0 / angle1));
if ( angle2 > 0 )
angle2 = R2D(asin(1.0 / angle2));
+ if ( angle3 > 0 )
+ angle3 = R2D(asin(1.0 / angle3));
}
pp = dp->paths;
if (loadPoints) {
DYNARR_RESET( trkEndPt_t, tempEndPts_da );
for ( i=0; i<dp->floatCnt; i++ )
- if ( *(FLOAT_T*)(turnDesignPLs[dp->floats[i].index].valueP) == 0.0 ) {
- NoticeMessage( MSG_TODSGN_VALUES_GTR_0, _("Ok"), NULL );
- return NULL;
+ if ( *(FLOAT_T*)(turnDesignPLs[dp->floats[i].index].valueP) == 0.0 )
+ if (dp->type != NTO_CORNU &&
+ dp->type != NTO_CORNUWYE &&
+ dp->type != NTO_CORNU3WAY
+ ) {
+ NoticeMessage( MSG_TODSGN_VALUES_GTR_0, _("Ok"), NULL );
+ return NULL;
}
switch (dp->type) {
case NTO_REGULAR:
DYNARR_SET( trkEndPt_t, tempEndPts_da, 3 );
if ( !ComputeCurve( &points[3], &points[4], &radii[0],
- (newTurnLen1), (newTurnOff1), angle1 ) )
+ (newTurnLen0), fabs(newTurnOff0), angle0 ) )
return NULL;
radii[0] = - radii[0];
points[0].x = points[0].y = points[1].y = 0.0;
- points[1].x = (newTurnLen0);
- points[2].y = (newTurnOff1);
- points[2].x = (newTurnLen1);
+ points[1].x = (newTurnLen1);
+ points[2].y = fabs(newTurnOff0);
+ points[2].x = (newTurnLen0);
tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0;
- tempEndPts(2).pos = points[2]; tempEndPts(2).angle = 90.0-angle1;
+ tempEndPts(2).pos = points[2]; tempEndPts(2).angle = 90.0-angle0;
break;
case NTO_CURVED:
DYNARR_SET( trkEndPt_t, tempEndPts_da, 3 );
if ( !ComputeCurve( &points[3], &points[4], &radii[0],
- (newTurnLen1), (newTurnOff1), angle1 ) )
+ (newTurnLen0), fabs(newTurnOff0), angle0 ) )
return NULL;
if ( !ComputeCurve( &points[5], &points[6], &radii[1],
- (newTurnLen2), (newTurnOff2), angle2 ) )
+ (newTurnLen1), fabs(newTurnOff1), angle1 ) )
return NULL;
d = points[3].x - points[5].x;
if ( d < -0.10 )
@@ -1133,32 +1376,51 @@ static toDesignSchema_t * LoadSegs(
radii[0] = - radii[0];
radii[1] = - radii[1];
points[0].x = points[0].y = 0.0;
- points[1].y = (newTurnOff1); points[1].x = (newTurnLen1);
- points[2].y = (newTurnOff2); points[2].x = (newTurnLen2);
+ points[1].y = fabs(newTurnOff0); points[1].x = (newTurnLen0);
+ points[2].y = fabs(newTurnOff1); points[2].x = (newTurnLen1);
tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
- tempEndPts(2).pos = points[1]; tempEndPts(2).angle = 90.0-angle1;
- tempEndPts(1).pos = points[2]; tempEndPts(1).angle = 90.0-angle2;
+ tempEndPts(2).pos = points[1]; tempEndPts(2).angle = 90.0-angle0;
+ tempEndPts(1).pos = points[2]; tempEndPts(1).angle = 90.0-angle1;
break;
+#ifndef MKTURNOUT
+ case NTO_CORNU:
+
+ radii[0] = fabs(newTurnRad2); /*Toe*/
+ radii[1] = fabs(newTurnRad0); /*Inner*/
+ radii[2] = fabs(newTurnRad1); /*Outer*/
+ angles[0] = 0.0; /*Base*/
+ angles[1] = newTurnAngle0; /*Inner*/
+ angles[2] = newTurnAngle1; /*Outer*/
+ pp = &CornuSchema;
+ points[0].x = points[0].y = 0.0;
+ points[1].y = (newTurnOff0); points[1].x = (newTurnLen0); /*Inner*/
+ points[2].y = (newTurnOff1); points[2].x = (newTurnLen1); /*Outer*/
+
+ tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
+ tempEndPts(2).pos = points[1]; tempEndPts(2).angle = 90.0-angles[1];
+ tempEndPts(1).pos = points[2]; tempEndPts(1).angle = 90.0-angles[2];
+ break;
+#endif
case NTO_WYE:
case NTO_3WAY:
DYNARR_SET( trkEndPt_t, tempEndPts_da, (dp->type==NTO_3WAY)?4:3 );
if ( !ComputeCurve( &points[3], &points[4], &radii[0],
- (newTurnLen1), (newTurnOff1), angle1 ) )
+ (newTurnLen0), fabs(newTurnOff0), angle0 ) )
return NULL;
if ( !ComputeCurve( &points[5], &points[6], &radii[1],
- (newTurnLen2), (newTurnOff2), angle2 ) )
+ (newTurnLen1), fabs(newTurnOff1), angle1 ) )
return NULL;
points[5].y = - points[5].y;
points[6].y = - points[6].y;
radii[0] = - radii[0];
points[0].x = points[0].y = 0.0;
- points[1].y = (newTurnOff1);
- points[1].x = (newTurnLen1);
- points[2].y = -(newTurnOff2);
- points[2].x = (newTurnLen2);
+ points[1].y = fabs(newTurnOff0);
+ points[1].x = (newTurnLen0);
+ points[2].y = -fabs(newTurnOff1);
+ points[2].x = (newTurnLen1);
points[7].y = 0;
- points[7].x = (newTurnLen0);
+ points[7].x = (newTurnLen2);
d = points[3].x - points[5].x;
if ( d < -0.10 ) {
pp = (dp->type==NTO_3WAY ? &Tri3Schema : &Wye3Schema );
@@ -1168,63 +1430,644 @@ static toDesignSchema_t * LoadSegs(
pp = (dp->type==NTO_3WAY ? &Tri1Schema : &Wye1Schema );
}
tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
- tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0-angle1;
- tempEndPts(2).pos = points[2]; tempEndPts(2).angle = 90.0+angle2;
+ tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0-angle0;
+ tempEndPts(2).pos = points[2]; tempEndPts(2).angle = 90.0+angle1;
if (dp->type == NTO_3WAY) {
tempEndPts(3).pos = points[7]; tempEndPts(3).angle = 90.0;
}
break;
+#ifndef MKTURNOUT
+ case NTO_CORNUWYE:
+ case NTO_CORNU3WAY:
+ DYNARR_SET( trkEndPt_t, tempEndPts_da, (dp->type==NTO_CORNU3WAY)?4:3 );
+
+ /*
+ * Construct Wye and 3 Way Turnouts with Cornu curves
+ * 1. Establish where the joint(s) (Toes) are by using the main curve
+ * 2. Rebuild the segments into a single set using those points
+ * 3. Build Path statements to suit the segments
+ * ---------------------------------------------------------------------------------------------
+ * 7 CornuData. Cheat Sheet - segment array parts
+ * =============+ Note - 6-7 is at Toe2 and 8-9 at Toe1 if RH comes before LH
+ * // Toe 2 - Toe2 and Toe1 are the same (no 2-3) if co-incident
+ * 0 6+ 3 4 5 - Toe2, 2-3 and 4-5 all only exist for 3WAY not WYE
+ * +=====+ +=====+ +==================+ - If zero radius at 0, curve starts at Toe 1
+ * 1 2 8+
+ * Toe 1 \\ 9
+ * =========+
+ *
+ * ---------------------------------------------------------------------------------------------
+ */
+
+ radii[0] = (newTurnRad2); /*Base*/
+ radii[1] = (newTurnRad0); /*Left*/
+ radii[2] = (newTurnRad1); /*Right*/
+ radii[3] = (newTurnRad3); /*Center*/
+ angles[0] = 0.0; /*Base*/
+ angles[1] = newTurnAngle0; /*Left*/
+ angles[2] = newTurnAngle1; /*Right*/
+ angles[3] = newTurnAngle3; /*Center*/
+ points[0].x = points[0].y = 0.0; /*Base*/
+ points[1].y = (newTurnOff0); /* Left */
+ points[1].x = (newTurnLen0);
+ points[2].y = -(newTurnOff1); /* Right */
+ points[2].x = (newTurnLen1);
+ if (dp->type==NTO_CORNU3WAY) {
+ points[3].y = (newTurnOff3); /* Center */
+ points[3].x = (newTurnLen3);
+ }
+
+ pp = (dp->type==NTO_CORNU3WAY ? &CornuTriSchema : &CornuWyeSchema );
+
+ tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
+
+ if (newTurnRad0<0.0) {
+ tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0+angles[1];
+ } else {
+ tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0-angles[1];
+ }
+ if (newTurnRad1<0.0) {
+ tempEndPts(2).pos = points[2]; tempEndPts(2).angle = 90.0-angles[2];
+ } else {
+ tempEndPts(2).pos = points[2]; tempEndPts(2).angle = 90.0+angles[2];
+ }
+ if (dp->type == NTO_CORNU3WAY) {
+ if (newTurnRad3<0.0) {
+ tempEndPts(3).pos = points[3]; tempEndPts(3).angle = 90.0+angles[3];
+ } else {
+ tempEndPts(3).pos = points[3]; tempEndPts(3).angle = 90.0-angles[3];
+ }
+ }
+
+ DIST_T end_length = minLength/2;
+
+ for (int i=0;i<((dp->type==NTO_CORNU3WAY)?4:3);i++) {
+ if (radii[i] == 0.0) {
+ Translate(&end_points[i], points[i], 90-angles[i]+(i==0?0:180), end_length);
+ end_angles[i] = angles[i];
+ } else {
+ if (((i==0) && radii[0]>0.0) || ((i==1 || i==3) && radii[i]>0.0)|| ((i==2) && radii[i]<0.0))
+ Translate(&end_centers[i], points[i], -angles[i], fabs(radii[i]));
+ else
+ Translate(&end_centers[i], points[i], angles[i], fabs(radii[i]));
+ end_arcs[i] = (radii[i]>=0?1:-1)*R2D(end_length/fabs(radii[i]));
+ end_points[i] = points[i];
+ Rotate(&end_points[i],end_centers[i],((i==0||i==3)?-1:1)*end_arcs[i]);
+ end_angles[i] = angles[i]-((i==0||i==3)?-1:1)*end_arcs[i];
+ }
+LogPrintf( "ctoDes0-%d: EP(%f,%f) NEP(%f,%f) EA(%f) NEA(%f) R(%f) ARC(%f) EC(%f,%f) \n",
+ i+1,points[i].x,points[i].y,end_points[i].x,end_points[i].y,angles[i],end_angles[i],radii[i],end_arcs[i],
+ end_centers[i].x,end_centers[i].y);
+ }
+
+ wBool_t LH_main = TRUE, LH_first = TRUE;
+
+ cornuData.pos[0] = end_points[0]; /*Start*/
+ if (dp->type == NTO_CORNU3WAY) {
+ if (newTurnToeR < newTurnToeL) LH_first = FALSE;
+ cornuData.pos[1] = end_points[3]; /*Center for First Time */
+ cornuData.pos[5] = end_points[3]; /*Center for last time*/
+ } else if (newTurnRad1>=0.0) {
+ cornuData.pos[1] = end_points[1]; /*Left is dominant curve */
+ newTurnToeR = newTurnToeL;
+ } else {
+ cornuData.pos[1] = end_points[2]; /*Right is dominant */
+ newTurnToeR = newTurnToeL;
+ LH_main = FALSE;
+ }
+
+ cornuData.pos[7] = end_points[1]; /*Left*/
+ cornuData.pos[9] = end_points[2]; /*Right*/
+ if (dp->type == NTO_CORNU3WAY) {
+ cornuData.pos[5] = end_points[3]; /*Center */
+ }
+
+ if (radii[0] == 0.0) /* Base */
+ cornuData.center[0] = zero;
+ else {
+ cornuData.center[0].x = end_points[0].x;
+ cornuData.center[0].y = end_points[0].y + radii[0];
+ }
+ if (radii[1] == 0.0) /* Left */
+ cornuData.center[7] = zero;
+ else if (radii[1] >0.0)
+ Translate(&cornuData.center[7], cornuData.pos[7], -end_angles[1], radii[1]);
+ else
+ Translate(&cornuData.center[7], cornuData.pos[7], 180.0+end_angles[1], radii[1]);
+
+ if (radii[2] == 0.0) /* Right */
+ cornuData.center[9] = zero;
+ else if (radii[2] >0.0)
+ Translate(&cornuData.center[9], cornuData.pos[9], 180.0+end_angles[2], radii[2]);
+ else
+ Translate(&cornuData.center[9], cornuData.pos[9], -end_angles[2], radii[2]);
+
+ if (dp->type == NTO_CORNU3WAY) {
+ if (radii[3] == 0.0) /* Center */
+ cornuData.center[5] = zero;
+ else if (radii[3] >0.0)
+ Translate(&cornuData.center[5], cornuData.pos[5], -end_angles[3], radii[3]);
+ else
+ Translate(&cornuData.center[5], cornuData.pos[5], 180.0+end_angles[3], radii[3]);
+ }
+
+ /* Set up for calculation of Toe(s) */
+
+ if (dp->type == NTO_CORNU3WAY) {
+ cornuData.center[1] = cornuData.center[5]; /*For Toe1 calc always use center */
+ cornuData.center[3] = cornuData.center[5]; /*For Toe2 calc always use center*/
+ } else if (LH_main) {
+ cornuData.center[1] = cornuData.center[7]; /* Dominant Curve Left */
+ } else
+ cornuData.center[1] = cornuData.center[9]; /* Right */
+
+ cornuData.angle[0] = 270.0; /*Always*/
+ if (dp->type == NTO_CORNU3WAY) {
+ cornuData.angle[1] = 90.0-end_angles[3];
+ cornuData.angle[3] = 90.0-end_angles[3];
+ cornuData.angle[5] = 90.0-end_angles[3]; /* Only used for 3way */
+ } else if (LH_main) {
+ cornuData.angle[1] = 90.0-end_angles[1];
+ } else {
+ cornuData.angle[1] = 90.0+end_angles[2];
+ }
+ cornuData.angle[7] = 90.0-end_angles[1]; /*Left*/
+ cornuData.angle[9] = 90.0+end_angles[2]; /*Right*/
+
+ cornuData.radius[0] = fabs(radii[0]);
+ if (dp->type == NTO_CORNU3WAY) {
+ cornuData.radius[1] = fabs(radii[3]);
+ cornuData.radius[3] = fabs(radii[3]);
+ cornuData.radius[5] = fabs(radii[3]);
+ } else if (LH_main) {
+ cornuData.radius[1] = fabs(radii[1]);
+ } else {
+ cornuData.radius[1] = fabs(radii[2]);
+ }
+ cornuData.radius[7] = fabs(radii[1]); /*Left*/
+ cornuData.radius[9] = fabs(radii[2]); /*Right*/
+
+ /* Ready to find Toe points */
+
+ DYNARR_RESET( trkSeg_t, tempSegs_da );
+ trkSeg_t * temp_p;
+ temp_p = &tempSegs(0);
+
+
+ DIST_T radius;
+ coOrd center;
+ ANGLE_T angle;
+ int inx,subSeg;
+ wBool_t back, neg;
+
+ CallCornu0(&cornuData.pos[0],&cornuData.center[0],&cornuData.angle[0],&cornuData.radius[0],&tempSegs_da, FALSE);
+
+ /* Override if a "Y" has zero radius at base to be a straight until the Toe
+ * We set the start of the curve to be at the Toe position */
+ if (cornuData.radius[0] == 0.0) {
+ pos.x = end_points[0].x+(LH_first?newTurnToeL:newTurnToeR);
+ pos.y = 0.0;
+ angle = 90.0;
+ radius = 0.0;
+ center = zero;
+
+ } else {
+
+ /*Find Toe 1 from curve */
+
+ /*Get ToeAngle/Radius/Center for first toe */
+ pos.x = end_points[0].x+(LH_first?newTurnToeL:newTurnToeR);
+ pos.y = end_points[0].y; /* This will be close to but not on the curve */
+ angle = GetAngleSegs(tempSegs_da.cnt,(trkSeg_t *)(tempSegs_da.ptr),&pos,&inx,NULL,&back,&subSeg,&neg);
+ segPtr = &DYNARR_N(trkSeg_t, tempSegs_da, inx);
+
+ if (segPtr->type == SEG_BEZTRK) {
+ segPtr = &DYNARR_N(trkSeg_t,segPtr->bezSegs,subSeg);
+ }
+
+ if (segPtr->type == SEG_STRTRK) {
+ radius = 0.0;
+ center = zero;
+ } else if (segPtr->type == SEG_CRVTRK) {
+ center = segPtr->u.c.center;
+ radius = fabs(segPtr->u.c.radius);
+ }
+ }
+
+ /* Set up 2-3 even if we don't use it */
+ cornuData.pos[1] = pos;
+ cornuData.center[1] = center;
+ cornuData.angle[1] = angle;
+ cornuData.radius[1] = radius;
+
+ cornuData.pos[2] = pos;
+ cornuData.center[2] = center;
+ cornuData.angle[2] = NormalizeAngle(180.0+angle);
+ cornuData.radius[2] = radius;
+
+ if ((dp->type == NTO_CORNU3WAY) && (newTurnToeR!=newTurnToeL)) {
+ if (LH_first) {
+ cornuData.pos[6] = pos;
+ cornuData.center[6] = center;
+ cornuData.angle[6] = NormalizeAngle(180.0+angle);
+ cornuData.radius[6] = radius;
+ } else {
+ cornuData.pos[8] = pos;
+ cornuData.center[8] = center;
+ cornuData.angle[8] = NormalizeAngle(180.0+angle);
+ cornuData.radius[8] = radius;
+ }
+ } else { /* Just one toe */
+ cornuData.pos[8] = pos;
+ cornuData.center[8] = center;
+ cornuData.angle[8] = NormalizeAngle(180.0+angle);
+ cornuData.radius[8] = radius;
+
+ cornuData.pos[6] = pos;
+ cornuData.center[6] = center;
+ cornuData.angle[6] = NormalizeAngle(180.0+angle);
+ cornuData.radius[6] = radius;
+ }
+
+ if (dp->type == NTO_CORNU3WAY) {
+ if (newTurnToeR!=newTurnToeL) {
+ /* Second Toe */
+ pos.x = end_points[0].x+(LH_first?newTurnToeR:newTurnToeL);
+ pos.y = end_points[0].y; /* This will be close to but not on the curve */
+ angle = GetAngleSegs(tempSegs_da.cnt,(trkSeg_t *)(tempSegs_da.ptr),&pos,&inx,NULL,&back,&subSeg,&neg);
+ segPtr = &DYNARR_N(trkSeg_t, tempSegs_da, inx);
+
+ if (segPtr->type == SEG_BEZTRK) {
+ segPtr = &DYNARR_N(trkSeg_t,segPtr->bezSegs,subSeg);
+ }
+
+ if (segPtr->type == SEG_STRTRK) {
+ radius = 0.0;
+ center = zero;
+ } else if (segPtr->type == SEG_CRVTRK) {
+ center = segPtr->u.c.center;
+ radius = fabs(segPtr->u.c.radius);
+ }
+ cornuData.pos[3] = pos;
+ cornuData.center[3] = center;
+ cornuData.angle[3] = angle;
+ cornuData.radius[3] = radius;
+
+ cornuData.pos[4] = pos;
+ cornuData.center[4] = center;
+ cornuData.angle[4] = NormalizeAngle(180.0+angle);
+ cornuData.radius[4] = radius;
+
+ if (LH_first) {
+ cornuData.pos[8] = pos;
+ cornuData.center[8] = center;
+ cornuData.angle[8] = NormalizeAngle(180.0+angle);
+ cornuData.radius[8] = radius;
+
+ cornuData.pos[4] = pos;
+ cornuData.center[4] = center;
+ cornuData.angle[4] = NormalizeAngle(180.0+angle);
+ cornuData.radius[4] = radius;
+ } else {
+ cornuData.pos[6] = pos;
+ cornuData.center[6] = center;
+ cornuData.angle[6] = NormalizeAngle(180.0+angle);
+ cornuData.radius[6] = radius;
+
+ cornuData.pos[4] = pos;
+ cornuData.center[4] = center;
+ cornuData.angle[4] = NormalizeAngle(180.0+angle);
+ cornuData.radius[4] = radius;
+ }
+ } else { //Set next center start to same place
+ cornuData.pos[4] = pos;
+ cornuData.center[4] = center;
+ cornuData.angle[4] = NormalizeAngle(180.0+angle);
+ cornuData.radius[4] = radius;
+ }
+ }
+
+ static dynArr_t cornuSegs_da;
+
+ ClearSegs(&tempSegs_da);
+ ClearSegs(&cornuSegs_da);
+
+ int Toe1Seg = 0 , Toe2Seg = 0, CenterEndSeg = 0, LeftEndSeg = 0, RightEndSeg = 0;
+
+ /* Override if at zero radius at base don't compute end */
+ if (cornuData.radius[0] == 0.0) {
+ DYNARR_APPEND(trkSeg_t,tempSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,tempSegs_da);
+ temp_p->type = SEG_STRTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.l.pos[0] = zero;
+ temp_p->u.l.pos[1] = cornuData.pos[0];
+LogPrintf( "ctoDes1: P0(%f,%f) P1(%f,%f) \n",
+ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x,temp_p->u.l.pos[1].y );
+ } else {
+ DYNARR_APPEND(trkSeg_t,tempSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,tempSegs_da);
+ temp_p->type = SEG_CRVTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.c.radius = fabs(radii[0]);;
+ if (radii[0]>0.0)
+ temp_p->u.c.a0 = FindAngle(end_centers[0],end_points[0]);
+ else
+ temp_p->u.c.a0 = FindAngle(end_centers[0],points[0]);
+ temp_p->u.c.a1 = fabs(end_arcs[0]);
+ temp_p->u.c.center = end_centers[0];
+ coOrd rp0,rp1;
+ Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius);
+ Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1,temp_p->u.c.radius);
+LogPrintf( "ctoDes1: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f), EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n",
+ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x,temp_p->u.c.center.y,
+ points[0].x,points[0].y,end_points[0].x,end_points[0].y,
+ rp0.x,rp0.y,rp1.x,rp1.y);
+ }
+
+ if ((cornuData.pos[0].x != cornuData.pos[1].x) ||
+ (cornuData.pos[0].y != cornuData.pos[1].y) )
+ CallCornuNoBez(&cornuData.pos[0],&cornuData.center[0],&cornuData.angle[0],&cornuData.radius[0],&tempSegs_da);
+ Toe1Seg = tempSegs_da.cnt;
+
+ if (dp->type == NTO_CORNU3WAY) {
+ if (newTurnToeR!=newTurnToeL) {
+ /* Toe1 to Toe2 in tempSegs array */
+ if ((cornuData.pos[2].x != cornuData.pos[3].x) ||
+ (cornuData.pos[2].y != cornuData.pos[3].y) )
+ CallCornuNoBez(&cornuData.pos[2],&cornuData.center[2],&cornuData.angle[2],&cornuData.radius[2],&cornuSegs_da);
+
+ Toe2Seg = cornuSegs_da.cnt+Toe1Seg;
+ /* Add to second cornu to tempSegs array */
+ AppendSegs(&tempSegs_da,&cornuSegs_da);
+ /* Get ready to reuse cornuSegs array*/
+ ClearSegs(&cornuSegs_da);
+ } else {
+ Toe2Seg = Toe1Seg; //No Toe2
+ }
+ /* Toe2 to Center in cornuSegs array */
+ CallCornuNoBez(&cornuData.pos[4],&cornuData.center[4],&cornuData.angle[4],&cornuData.radius[4],&cornuSegs_da);
+
+ if (cornuData.radius[5] == 0.0) {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_STRTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.l.pos[0] = cornuData.pos[5];
+ temp_p->u.l.pos[1] = end_points[3];
+ LogPrintf( "ctoDes2: P0(%f,%f) P1(%f,%f) \n",
+ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x,temp_p->u.l.pos[1].y );
+ } else {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_CRVTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.c.radius = fabs(radii[3]);
+ if (radii[3]>0)
+ temp_p->u.c.a0 = FindAngle(end_centers[3],points[3]);
+ else
+ temp_p->u.c.a0 = FindAngle(end_centers[3],end_points[3]);
+ temp_p->u.c.a1 = fabs(end_arcs[3]);
+ temp_p->u.c.center = end_centers[3];
+ coOrd rp0,rp1;
+ Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius);
+ Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1,temp_p->u.c.radius);
+ LogPrintf( "ctoDes2: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n",
+ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x,temp_p->u.c.center.y,
+ points[3].x,points[3].y,end_points[3].x,end_points[3].y,
+ rp0.x,rp0.y,rp1.x,rp1.y);
+ }
+
+ CenterEndSeg = cornuSegs_da.cnt+Toe2Seg;
+ /* Add to second cornu to tempSegs array */
+ AppendSegs(&tempSegs_da,&cornuSegs_da);
+ /* Get ready to reuse cornuSegs array*/
+ ClearSegs(&cornuSegs_da);
+ } else {
+ CenterEndSeg = Toe2Seg = Toe1Seg; //No Toe2, No Center
+ }
+
+ /* Left in cornuSegs array*/
+ CallCornuNoBez(&cornuData.pos[6],&cornuData.center[6],&cornuData.angle[6],&cornuData.radius[6],&cornuSegs_da);
+
+ if (cornuData.radius[7] == 0.0) {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_STRTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.l.pos[0] = cornuData.pos[7];
+ temp_p->u.l.pos[1] = end_points[1];
+LogPrintf( "ctoDes2: P0(%f,%f) P1(%f,%f) \n",
+ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x,temp_p->u.l.pos[1].y );
+ } else {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_CRVTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.c.radius = fabs(radii[1]);
+ if (radii[1]>0)
+ temp_p->u.c.a0 = FindAngle(end_centers[1],points[1]);
+ else
+ temp_p->u.c.a0 = FindAngle(end_centers[1],end_points[1]);
+ temp_p->u.c.a1 = fabs(end_arcs[1]);
+ temp_p->u.c.center = end_centers[1];
+ coOrd rp0,rp1;
+ Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius);
+ Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1,temp_p->u.c.radius);
+LogPrintf( "ctoDes2: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n",
+ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x,temp_p->u.c.center.y,
+ points[1].x,points[1].y,end_points[1].x,end_points[1].y,
+ rp0.x,rp0.y,rp1.x,rp1.y);
+ }
+
+ LeftEndSeg = cornuSegs_da.cnt+CenterEndSeg;
+
+ /* Add to second cornu to tempSegs array */
+ AppendSegs(&tempSegs_da,&cornuSegs_da);
+ /* Get ready to reuse cornuSegs array*/
+ ClearSegs(&cornuSegs_da);
+
+ /* Right in cornuSegs array*/
+ CallCornuNoBez(&cornuData.pos[8],&cornuData.center[8],&cornuData.angle[8],&cornuData.radius[8],&cornuSegs_da);
+
+ if (cornuData.radius[9] == 0.0) {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_STRTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.l.pos[0] = cornuData.pos[9];
+ temp_p->u.l.pos[1] = end_points[2];
+LogPrintf( "ctoDes2: P0(%f,%f) P1(%f,%f) \n",
+ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x,temp_p->u.l.pos[1].y );
+ } else {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_CRVTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.c.radius = fabs(radii[2]);
+ if (radii[2]<0)
+ temp_p->u.c.a0 = FindAngle(end_centers[2],points[2]);
+ else
+ temp_p->u.c.a0 = FindAngle(end_centers[2],end_points[2]);
+ temp_p->u.c.a1 = fabs(end_arcs[2]);
+ temp_p->u.c.center = end_centers[2];
+ coOrd rp0,rp1;
+ Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius);
+ Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1,temp_p->u.c.radius);
+LogPrintf( "ctoDes2: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n",
+ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x,temp_p->u.c.center.y,
+ points[2].x,points[2].y,end_points[2].x,end_points[2].y,
+ rp0.x,rp0.y,rp1.x,rp1.y);
+ }
+
+ RightEndSeg = cornuSegs_da.cnt+LeftEndSeg;
+
+ /*Add Third Part to tempSegs Array */
+ AppendSegs(&tempSegs_da,&cornuSegs_da);
+ /* Safety - clear out cornu Array */
+ ClearSegs(&cornuSegs_da);
+
+ if (tempSegs_da.cnt >128 ) {
+ NoticeMessage( MSG_TODSGN_CORNU_TOO_COMPLEX, _("Ok"), NULL );
+ return NULL;
+ }
+
+ /* Generate Paths */
+
+ static char pathChar[512];
+ if (dp->type == NTO_CORNU3WAY) {
+ strcpy(pathChar,"Normal"); /* Also resets array */
+ pathLen = strlen(pathChar)+1;
+ for (uint8_t i=0;i<CenterEndSeg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+ pathChar[pathLen] = 0;
+ pathLen++;
+ pathChar[pathLen] = 0;
+ pathLen++;
+ sprintf(&pathChar[pathLen],"%s","Left");
+ pathLen += strlen(&pathChar[pathLen])+1;
+ } else {
+ strcpy(pathChar,"Left");
+ pathLen = strlen(pathChar)+1;
+ }
+ for (uint8_t i=0;i<Toe1Seg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+ if ((dp->type == NTO_CORNU3WAY) && !LH_first && (newTurnToeR != newTurnToeL)) {
+ for (uint8_t i=Toe1Seg;i<Toe2Seg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+ }
+
+ for (uint8_t i=CenterEndSeg;i<LeftEndSeg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+
+ pathChar[pathLen] = 0;
+ pathLen++;
+ pathChar[pathLen] = 0;
+ pathLen++;
+
+ sprintf(&pathChar[pathLen],"%s","Right");
+ pathLen += strlen(&pathChar[pathLen])+1;
+
+ for (uint8_t i=0;i<Toe1Seg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+ if ((dp->type == NTO_CORNU3WAY) && LH_first && (newTurnToeR != newTurnToeL)) {
+ for (uint8_t i=Toe1Seg;i<Toe2Seg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+ }
+ for (uint8_t i=LeftEndSeg;i<RightEndSeg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+ pathChar[pathLen] = 0;
+ pathLen++;
+ pathChar[pathLen] = 0;
+ pathLen++;
+ pathChar[pathLen] = 0;
+ pathLen++;
+
+ pp->paths = (signed char *)pathChar;
+ segCnt = tempSegs_da.cnt;
+
+ break;
+#endif
case NTO_D_SLIP:
case NTO_S_SLIP:
case NTO_CROSSING:
+ if (dp->type == NTO_D_SLIP) {
+ if (newTurnSlipMode == 1)
+ pp = &DoubleSlipSchema2;
+ else
+ pp = &DoubleSlipSchema;
+ }
DYNARR_SET( trkEndPt_t, tempEndPts_da, 4 );
points[0].x = points[0].y = points[1].y = 0.0;
- points[1].x = (newTurnLen1);
- pos.y = 0; pos.x = (newTurnLen1)/2.0;
- Translate( &points[3], pos, 90.0+angle1, (newTurnLen2)/2.0 );
+ points[1].x = (newTurnLen0);
+ pos.y = 0; pos.x = (newTurnLen0)/2.0;
+ coOrd cpos = pos;
+ Translate( &points[3], pos, 90.0+angle0, (newTurnLen1)/2.0 );
points[2].y = - points[3].y;
- points[2].x = (newTurnLen1)-points[3].x;
+ points[2].x = pos.x-(points[3].x-pos.x);
if (dp->type != NTO_CROSSING) {
- Translate( &pos, points[3], 90.0+angle1, -newTurnTrackGauge );
+ Translate( &pos, points[3], 90.0+angle0, -newTurnTrackGauge );
if (!ComputeCurve( &points[4], &points[5], &radii[0],
- pos.x, fabs(pos.y), angle1 )) /*???*/
+ pos.x, fabs(pos.y), angle0 )) /*???*/
return NULL;
radii[1] = - radii[0];
points[5].y = - points[5].y;
- points[6].y = 0; points[6].x = (newTurnLen1)-points[4].x;
+ points[6].y = 0; points[6].x = cpos.x-(points[4].x-cpos.x);
points[7].y = -points[5].y;
- points[7].x = (newTurnLen1)-points[5].x;
+ points[7].x = cpos.x-(points[5].x-cpos.x);
}
tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0;
- tempEndPts(2).pos = points[2]; tempEndPts(2).angle = 270.0+angle1;
- tempEndPts(3).pos = points[3]; tempEndPts(3).angle = 90.0+angle1;
+ tempEndPts(2).pos = points[2]; tempEndPts(2).angle = 270.0+angle0;
+ tempEndPts(3).pos = points[3]; tempEndPts(3).angle = 90.0+angle0;
break;
case NTO_R_CROSSOVER:
case NTO_L_CROSSOVER:
case NTO_D_CROSSOVER:
DYNARR_SET( trkEndPt_t, tempEndPts_da, 4 );
- d = (newTurnLen1)/2.0 - newTurnTrackGauge;
+ d = (newTurnLen0)/2.0 - newTurnTrackGauge;
if (d < 0.0) {
NoticeMessage( MSG_TODSGN_CROSSOVER_TOO_SHORT, _("Ok"), NULL );
return NULL;
}
- angle1 = R2D( atan2( (newTurnOff1), d ) );
+ angle0 = R2D( atan2( fabs(newTurnOff0), d ) );
points[0].y = 0.0; points[0].x = 0.0;
- points[1].y = 0.0; points[1].x = (newTurnLen1);
- points[2].y = (newTurnOff1); points[2].x = 0.0;
- points[3].y = (newTurnOff1); points[3].x = (newTurnLen1);
+ points[1].y = 0.0; points[1].x = (newTurnLen0);
+ points[2].y = fabs(newTurnOff0); points[2].x = 0.0;
+ points[3].y = fabs(newTurnOff0); points[3].x = (newTurnLen0);
if (!ComputeCurve( &points[4], &points[5], &radii[1],
- (newTurnLen1)/2.0, (newTurnOff1)/2.0, angle1 ) )
+ (newTurnLen0)/2.0, fabs(newTurnOff0)/2.0, angle0 ) )
return NULL;
radii[0] = - radii[1];
- points[6].y = 0.0; points[6].x = (newTurnLen1)-points[4].x;
- points[7].y = points[5].y; points[7].x = (newTurnLen1)-points[5].x;
- points[8].y = (newTurnOff1); points[8].x = points[4].x;
- points[9].y = (newTurnOff1)-points[5].y; points[9].x = points[5].x;
- points[10].y = (newTurnOff1); points[10].x = points[6].x;
+ points[6].y = 0.0; points[6].x = (newTurnLen0)-points[4].x;
+ points[7].y = points[5].y; points[7].x = (newTurnLen0)-points[5].x;
+ points[8].y = fabs(newTurnOff0); points[8].x = points[4].x;
+ points[9].y = fabs(newTurnOff0)-points[5].y; points[9].x = points[5].x;
+ points[10].y = fabs(newTurnOff0); points[10].x = points[6].x;
points[11].y = points[9].y; points[11].x = points[7].x;
tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0;
@@ -1235,7 +2078,7 @@ static toDesignSchema_t * LoadSegs(
case NTO_STR_SECTION:
DYNARR_SET( trkEndPt_t, tempEndPts_da, 2 );
points[0].y = points[0].x = 0;
- points[1].y = 0/*(newTurnOff1)*/; points[1].x = (newTurnLen1);
+ points[1].y = 0/*(newTurnOff1)*/; points[1].x = (newTurnLen0);
tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0;
break;
@@ -1243,17 +2086,17 @@ static toDesignSchema_t * LoadSegs(
case NTO_CRV_SECTION:
DYNARR_SET( trkEndPt_t, tempEndPts_da, 2 );
points[0].y = points[0].x = 0;
- points[1].y = (newTurnLen1) * (1.0 - cos( D2R(angle1) ) );
- points[1].x = (newTurnLen1) * sin( D2R(angle1) );
- radii[0] = -(newTurnLen1);
+ points[1].y = (newTurnLen0) * (1.0 - cos( D2R(angle0) ) );
+ points[1].x = (newTurnLen0) * sin( D2R(angle0) );
+ radii[0] = -(newTurnLen0);
tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
- tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0-angle1;
+ tempEndPts(1).pos = points[1]; tempEndPts(1).angle = 90.0-angle0;
break;
case NTO_BUMPER:
DYNARR_SET( trkEndPt_t, tempEndPts_da, 1 );
points[0].y = points[0].x = 0;
- points[1].y = 0/*(newTurnOff1)*/; points[1].x = (newTurnLen1);
+ points[1].y = 0/*(newTurnOff1)*/; points[1].x = (newTurnLen0);
tempEndPts(0).pos = points[0]; tempEndPts(0).angle = 270.0;
break;
@@ -1274,33 +2117,312 @@ static toDesignSchema_t * LoadSegs(
}
}
- segOrder = pp->segOrder;
- segCnt = strlen( segOrder );
- if (segCnt%3 != 0)
- AbortProg( dp->label );
- segCnt /= 3;
- DYNARR_SET( trkSeg_t, tempSegs_da, segCnt );
- tempSegs_da.cnt = segCnt;
- memset( &tempSegs(0), 0, segCnt * sizeof tempSegs(0) );
- for ( s=0; s<segCnt; s++ ) {
- segPtr = &tempSegs(s);
- segPtr->color = wDrawColorBlack;
- if (*segOrder <= '9')
- p0 = *segOrder++ - '0';
- else
- p0 = *segOrder++ - 'A' + 10;
- if (*segOrder <= '9')
- p1 = *segOrder++ - '0';
- else
- p1 = *segOrder++ - 'A' + 10;
- p = *segOrder++ - '0';
- if (p != 0) {
- segPtr->type = SEG_CRVTRK;
- ComputeCurvedSeg( segPtr, radii[p-1], points[p0], points[p1] );
- } else {
- segPtr->type = SEG_STRTRK;
- segPtr->u.l.pos[0] = points[p0];
- segPtr->u.l.pos[1] = points[p1];
+#ifndef MKTURNOUT
+ if(dp->type == NTO_CORNU) {
+ DYNARR_SET( trkEndPt_t, tempEndPts_da, 3 );
+
+ DIST_T end_length = minLength/2;
+
+ // Adjust end_points to impose small fixed end segments
+
+ for (int i=0;i<3;i++) {
+ if (radii[i] == 0.0) {
+ Translate(&end_points[i], points[i], 90-angles[i]+(i==0?0:180), end_length);
+ end_angles[i] = angles[i];
+ } else {
+ Translate(&end_centers[i], points[i], -angles[i], radii[i]);
+ end_arcs[i] = (radii[i]>=0?1:-1)*R2D(end_length/fabs(radii[i]));
+ end_points[i] = points[i];
+ Rotate(&end_points[i],end_centers[i],(i>0?1:-1)*end_arcs[i]);
+ end_angles[i] = angles[i]-(i>0?1:-1)*end_arcs[i];
+ }
+LogPrintf( "ctoDes0-%d: EP(%f,%f) NEP(%f,%f) EA(%f) NEA(%f) R(%f) ARC(%f) EC(%f,%f) \n",
+ i+1,points[i].x,points[i].y,end_points[i].x,end_points[i].y,angles[i],end_angles[i],radii[i],end_arcs[i],
+ end_centers[i].x,end_centers[i].y);
+ }
+
+
+ cornuData.pos[0] = end_points[0]; /*Start*/
+ cornuData.pos[1] = end_points[2]; /*Outer*/
+ cornuData.pos[3] = end_points[2]; /*Outer for second time*/
+ cornuData.pos[5] = end_points[1]; /*Inner*/
+
+
+ if (radii[0] == 0.0) /* Toe */
+ cornuData.center[0] = zero;
+ else {
+ cornuData.center[0].x = end_points[0].x;
+ cornuData.center[0].y = end_points[0].y + radii[0];
+ }
+ if (radii[1] == 0.0) /* Inner */
+ cornuData.center[5] = zero;
+ else
+ Translate(&cornuData.center[5], cornuData.pos[5], -end_angles[1], radii[1]);
+
+ if (radii[2] == 0.0) /* Outer */
+ cornuData.center[1] = zero;
+ else
+ Translate(&cornuData.center[1], cornuData.pos[1], -end_angles[2], radii[2]);
+ cornuData.center[3] = cornuData.center[1];
+
+ cornuData.angle[0] = 270.0;
+ cornuData.angle[1] = 90.0-end_angles[2];
+ cornuData.angle[3] = 90.0-end_angles[2];
+ cornuData.angle[5] = 90.0-end_angles[1]; /*Inner*/
+
+ cornuData.radius[0] = fabs(radii[0]);
+ cornuData.radius[1] = fabs(radii[2]);
+ cornuData.radius[3] = fabs(radii[2]);
+ cornuData.radius[5] = fabs(radii[1]); /*Inner*/
+
+ DYNARR_RESET( trkSeg_t, tempSegs_da );
+ trkSeg_t * temp_p, * cornu_p;
+ temp_p = &tempSegs(0);
+
+ /*Map out the full outer curve */
+
+ CallCornu0(&cornuData.pos[0],&cornuData.center[0],&cornuData.angle[0],&cornuData.radius[0],&tempSegs_da, FALSE);
+
+ /*Get ToeAngle/Radius/Center */
+ int inx,subSeg;
+ wBool_t back, neg;
+ DIST_T radius;
+ coOrd center;
+ pos.x = end_points[0].x+newTurnToeL;
+ pos.y = end_points[0].y; /* This will be close to but not on the curve */
+ ANGLE_T angle = GetAngleSegs(tempSegs_da.cnt,(trkSeg_t *)(tempSegs_da.ptr),&pos,&inx,NULL,&back,&subSeg,&neg);
+ segPtr = &DYNARR_N(trkSeg_t, tempSegs_da, inx);
+
+ if (segPtr->type == SEG_BEZTRK) {
+ segPtr = &DYNARR_N(trkSeg_t,segPtr->bezSegs,subSeg);
+ }
+
+ if (segPtr->type == SEG_STRTRK) {
+ radius = 0.0;
+ center = zero;
+ } else if (segPtr->type == SEG_CRVTRK) {
+ center = segPtr->u.c.center;
+ radius = fabs(segPtr->u.c.radius);
+ }
+ cornuData.pos[1] = pos;
+ cornuData.center[1] = center;
+ cornuData.angle[1] = angle;
+ cornuData.radius[1] = radius;
+ cornuData.pos[2] = pos;
+ cornuData.center[2] = center;
+ cornuData.angle[2] = NormalizeAngle(180.0+angle);
+ cornuData.radius[2] = radius;
+ cornuData.pos[4] = pos;
+ cornuData.center[4] = center;
+ cornuData.angle[4] = NormalizeAngle(180.0+angle);
+ cornuData.radius[4] = radius;
+
+ static dynArr_t cornuSegs_da;
+
+ ClearSegs(&tempSegs_da);
+ ClearSegs(&cornuSegs_da);
+
+ /* Override if at zero radius at base don't compute end */
+ if (cornuData.radius[0] == 0.0) {
+ DYNARR_APPEND(trkSeg_t,tempSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,tempSegs_da);
+ temp_p->type = SEG_STRTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.l.pos[0] = zero;
+ temp_p->u.l.pos[1] = cornuData.pos[1];
+LogPrintf( "ctoDes1: P0(%f,%f) P1(%f,%f) \n",
+ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x,temp_p->u.l.pos[1].y );
+ } else {
+ DYNARR_APPEND(trkSeg_t,tempSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,tempSegs_da);
+ temp_p->type = SEG_CRVTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.c.radius = fabs(radii[0]);;
+ if (radii[0]>0.0)
+ temp_p->u.c.a0 = FindAngle(end_centers[0],end_points[0]);
+ else
+ temp_p->u.c.a0 = FindAngle(end_centers[0],points[0]);
+ temp_p->u.c.a1 = fabs(end_arcs[0]);
+ temp_p->u.c.center = end_centers[0];
+ coOrd rp0,rp1;
+ Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius);
+ Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1,temp_p->u.c.radius);
+LogPrintf( "ctoDes1: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f), EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n",
+ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x,temp_p->u.c.center.y,
+ points[0].x,points[0].y,end_points[0].x,end_points[0].y,
+ rp0.x,rp0.y,rp1.x,rp1.y);
+
+ /* Base to Toe in tempSegs array */
+ CallCornuNoBez(&cornuData.pos[0],&cornuData.center[0],& cornuData.angle[0],&cornuData.radius[0],&tempSegs_da);
+ }
+
+ int ToeSeg = tempSegs_da.cnt;
+
+ /* Toe to Outer in cornuSegs array */
+ CallCornuNoBez(&cornuData.pos[2],&cornuData.center[2],&cornuData.angle[2],&cornuData.radius[2],&cornuSegs_da);
+
+ cornu_p = (trkSeg_p)cornuSegs_da.ptr;
+
+ if (cornuData.radius[3] == 0.0) {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_STRTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.l.pos[0] = cornuData.pos[3];
+ temp_p->u.l.pos[1] = end_points[2];
+LogPrintf( "ctoDes2: P0(%f,%f) P1(%f,%f) \n",
+ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x,temp_p->u.l.pos[1].y );
+ } else {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_CRVTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.c.radius = fabs(radii[2]);
+ if (radii[2]>0)
+ temp_p->u.c.a0 = FindAngle(end_centers[2],points[2]);
+ else
+ temp_p->u.c.a0 = FindAngle(end_centers[2],end_points[2]);
+ temp_p->u.c.a1 = fabs(end_arcs[2]);
+ temp_p->u.c.center = end_centers[2];
+ coOrd rp0,rp1;
+ Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius);
+ Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1,temp_p->u.c.radius);
+LogPrintf( "ctoDes2: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n",
+ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x,temp_p->u.c.center.y,
+ points[2].x,points[2].y,end_points[2].x,end_points[2].y,
+ rp0.x,rp0.y,rp1.x,rp1.y);
+ }
+
+ int OuterEndSeg = cornuSegs_da.cnt + ToeSeg;
+
+ /* Add to second cornu to tempSegs array */
+ AppendSegs(&tempSegs_da,&cornuSegs_da);
+
+ /* Get ready to reuse cornuSegs array*/
+ ClearSegs(&cornuSegs_da);
+
+ /* Toe to Inner in cornuSegs array*/
+ CallCornuNoBez(&cornuData.pos[4],&cornuData.center[4],&cornuData.angle[4],&cornuData.radius[4],&cornuSegs_da);
+
+ if (cornuData.radius[5] == 0.0) {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_STRTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.l.pos[0] = cornuData.pos[5];
+ temp_p->u.l.pos[1] = points[1];
+LogPrintf( "ctoDes3: P0(%f,%f) P1(%f,%f) \n",
+ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x,temp_p->u.l.pos[1].y );
+ } else {
+ DYNARR_APPEND(trkSeg_t,cornuSegs_da,1);
+ temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da);
+ temp_p->type = SEG_CRVTRK;
+ temp_p->color = wDrawColorBlack;
+ temp_p->width = 0.0;
+ temp_p->u.c.radius = fabs(radii[1]);
+ if (radii[1]>0)
+ temp_p->u.c.a0 = FindAngle(end_centers[1],points[1]);
+ else
+ temp_p->u.c.a0 = FindAngle(end_centers[1],end_points[1]);
+ temp_p->u.c.a1 = fabs(end_arcs[1]);
+ temp_p->u.c.center = end_centers[1];
+ coOrd rp0,rp1;
+ Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius);
+ Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1,temp_p->u.c.radius);
+LogPrintf( "ctoDes3: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n",
+ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x,temp_p->u.c.center.y,
+ points[1].x,points[1].y,end_points[1].x,end_points[1].y,
+ rp0.x,rp0.y,rp1.x,rp1.y);
+ }
+
+ int InnerEndSeg = cornuSegs_da.cnt + OuterEndSeg;
+
+ /*Add Third Part to tempSegs Array */
+ AppendSegs(&tempSegs_da,&cornuSegs_da);
+
+
+ /* Safety - clear out cornu Array */
+ ClearSegs(&cornuSegs_da);
+
+ if (tempSegs_da.cnt >128 ) {
+ NoticeMessage( MSG_TODSGN_CORNU_TOO_COMPLEX, _("Ok"), NULL );
+ return NULL;
+ }
+
+ static char pathChar[512];
+ strcpy(pathChar,"Normal"); /* Also resets array */
+
+ pathLen = strlen(pathChar)+1;
+
+ for (uint8_t i=0;i<OuterEndSeg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+ pathChar[pathLen] = 0;
+ pathLen++;
+ pathChar[pathLen] = 0;
+ pathLen++;
+
+ sprintf(&pathChar[pathLen],"%s","Reverse");
+
+ pathLen += strlen(&pathChar[pathLen])+1;
+ for (uint8_t i=0;i<ToeSeg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+ for (uint8_t i=OuterEndSeg;i<InnerEndSeg;i++) {
+ pathChar[pathLen] = i+1;
+ pathLen++;
+ }
+ pathChar[pathLen] = 0;
+ pathLen++;
+ pathChar[pathLen] = 0;
+ pathLen++;
+ pathChar[pathLen] = 0;
+ pathLen++;
+
+ pp->paths = (signed char *)pathChar;
+ segCnt = tempSegs_da.cnt;
+ }
+#endif
+
+ if (!( (dp->type== NTO_CORNU) || (dp->type == NTO_CORNUWYE) || (dp->type == NTO_CORNU3WAY))) {
+ segOrder = pp->segOrder;
+ segCnt = strlen( segOrder );
+ if (segCnt%3 != 0)
+ AbortProg( dp->label );
+ segCnt /= 3;
+ DYNARR_SET( trkSeg_t, tempSegs_da, segCnt );
+ tempSegs_da.cnt = segCnt;
+ memset( &tempSegs(0), 0, segCnt * sizeof tempSegs(0) );
+ for ( s=0; s<segCnt; s++ ) {
+ segPtr = &tempSegs(s);
+ segPtr->color = wDrawColorBlack;
+ if (*segOrder <= '9')
+ p0 = *segOrder++ - '0';
+ else
+ p0 = *segOrder++ - 'A' + 10;
+ if (*segOrder <= '9')
+ p1 = *segOrder++ - '0';
+ else
+ p1 = *segOrder++ - 'A' + 10;
+ p = *segOrder++ - '0';
+ if (p == 3) {
+ /* cornu */
+ } else if (p != 0) {
+ segPtr->type = SEG_CRVTRK;
+ ComputeCurvedSeg( segPtr, radii[p-1], points[p0], points[p1] );
+ } else {
+ segPtr->type = SEG_STRTRK;
+ segPtr->u.l.pos[0] = points[p0];
+ segPtr->u.l.pos[1] = points[p1];
+
+ }
}
}
@@ -1321,7 +2443,7 @@ static void CopyNonTracks( turnoutInfo_t * to )
{
trkSeg_p sp0;
for ( sp0=to->segs; sp0<&to->segs[to->segCnt]; sp0++ ) {
- if ( sp0->type != SEG_STRTRK && sp0->type != SEG_CRVTRK ) {
+ if ( sp0->type != SEG_STRTRK && sp0->type != SEG_CRVTRK && sp0->type != SEG_BEZTRK ) {
DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 );
tempSegs(tempSegs_da.cnt-1) = *sp0;
}
@@ -1477,7 +2599,7 @@ static void NewTurnPrint(
newTurnout_d.size.y/2.0 );
DrawStraightTrack( &newTurnout_d, pos, p0,
tempEndPts(ep).angle+270.0,
- NULL, newTurnTrackGauge, wDrawColorBlack, 0 );
+ NULL, wDrawColorBlack, 0 );
}
if ( !wPrintPageEnd( newTurnout_d.d ) )
@@ -1538,7 +2660,7 @@ static void NewTurnOk( void * context )
cp = Strcpytrimed( cp, newTurnLeftPartno, TRUE );
strcpy( cp, "\"" );
cp += 1;
- if (curDesign->type == NTO_REGULAR || curDesign->type == NTO_CURVED) {
+ if (curDesign->type == NTO_REGULAR || curDesign->type == NTO_CURVED || curDesign->type == NTO_CORNU ) {
strcpy( cp, " \"" );
cp += 2;
cp = Strcpytrimed( cp, newTurnRightDesc, TRUE );
@@ -1553,15 +2675,17 @@ static void NewTurnOk( void * context )
for ( i=0; i<curDesign->floatCnt; i++ ) {
flt = *(FLOAT_T*)(turnDesignPLs[curDesign->floats[i].index].valueP);
switch( curDesign->floats[i].mode ) {
- case Dim_e:
- flt = ( flt );
- break;
- case Frog_e:
- if (newTurnAngleMode == 0 && flt > 0.0)
- flt = R2D(asin(1.0/flt));
- break;
- case Angle_e:
- break;
+ case Dim_e:
+ flt = ( flt );
+ break;
+ case Frog_e:
+ if (newTurnAngleMode == 0 && flt > 0.0)
+ flt = R2D(asin(1.0/flt));
+ break;
+ case Angle_e:
+ break;
+ case Rad_e:
+ break;
}
sprintf( cp, " %0.6f", flt );
cp += strlen(cp);
@@ -1576,8 +2700,17 @@ static void NewTurnOk( void * context )
CopyNonTracks( customTurnout1 );
if ( customTurnout1 )
customTurnout1->segCnt = 0;
+
+ DIST_T * radii_ends = NULL;
+
+ if ((curDesign->type == NTO_CORNU) ||
+ (curDesign->type == NTO_CORNUWYE) ||
+ (curDesign->type == NTO_CORNU3WAY)) {
+ radii_ends = &radii[0];
+ }
+
to = CreateNewTurnout( newTurnScaleName, tempCustom, tempSegs_da.cnt, &tempSegs(0),
- pathLen, pp->paths, tempEndPts_da.cnt, &tempEndPts(0), FALSE );
+ pathLen, pp->paths, tempEndPts_da.cnt, &tempEndPts(0), radii, FALSE );
to->customInfo = customInfoP;
#endif
if (f) {
@@ -1593,6 +2726,7 @@ static void NewTurnOk( void * context )
switch (curDesign->type) {
case NTO_REGULAR:
points[2].y = - points[2].y;
+ points[3].y = - points[3].y;
points[4].y = - points[4].y;
radii[0] = - radii[0];
LoadSegs( curDesign, FALSE, &pathLen );
@@ -1606,7 +2740,7 @@ static void NewTurnOk( void * context )
if ( customTurnout2 )
customTurnout2->segCnt = 0;
to = CreateNewTurnout( newTurnScaleName, tempCustom, tempSegs_da.cnt, &tempSegs(0),
- pathLen, pp->paths, tempEndPts_da.cnt, &tempEndPts(0), FALSE );
+ pathLen, pp->paths, tempEndPts_da.cnt, &tempEndPts(0), NULL, FALSE );
to->customInfo = customInfoP;
#endif
if (f) {
@@ -1619,26 +2753,41 @@ static void NewTurnOk( void * context )
}
break;
case NTO_CURVED:
- points[1].y = - points[1].y;
+ case NTO_CORNU:
points[2].y = - points[2].y;
+ points[1].y = - points[1].y;
+ points[3].y = - points[3].y;
points[4].y = - points[4].y;
+ points[5].y = - points[5].y;
points[6].y = - points[6].y;
- radii[0] = - radii[0];
- radii[1] = - radii[1];
+ radii[0] = -radii[0];
+ radii[1] = -radii[1];
+ radii[2] = -radii[2];
+ radii[3] = -radii[3];
+ radii[4] = -radii[4];
+ radii[5] = -radii[5];
+ radii[6] = -radii[6];
+ angles[0] = -angles[0];
+ angles[1] = -angles[1];
+ angles[2] = -angles[2];
+ angles[3] = -angles[3];
+ angles[4] = -angles[4];
+ angles[5] = -angles[5];
+ angles[6] = -angles[6];
LoadSegs( curDesign, FALSE, &pathLen );
tempEndPts(1).pos.y = - tempEndPts(1).pos.y;
tempEndPts(1).angle = 180.0 - tempEndPts(1).angle;
tempEndPts(2).pos.y = - tempEndPts(2).pos.y;
tempEndPts(2).angle = 180.0 - tempEndPts(2).angle;
BuildTrimedTitle( tempCustom, "\t", newTurnManufacturer, newTurnRightDesc, newTurnRightPartno );
- tempSegs_da.cnt = segCnt;
+ //tempSegs_da.cnt = segCnt;
#ifndef MKTURNOUT
if (includeNontrackSegments && customTurnout2)
CopyNonTracks( customTurnout2 );
if ( customTurnout2 )
customTurnout2->segCnt = 0;
to = CreateNewTurnout( newTurnScaleName, tempCustom, tempSegs_da.cnt, &tempSegs(0),
- pathLen, pp->paths, tempEndPts_da.cnt, &tempEndPts(0), FALSE );
+ pathLen, pp->paths, tempEndPts_da.cnt, &tempEndPts(0), NULL, FALSE );
to->customInfo = customInfoP;
#endif
if (f) {
@@ -1782,6 +2931,13 @@ static void SetupTurnoutDesignerW( toDesignDesc_t * newDesign )
turnDesignPLs[I_TOANGMODE].option |= PDO_DLGIGNORE;
wControlShow( turnDesignPLs[I_TOANGMODE].control, FALSE );
}
+ if (curDesign->type == NTO_D_SLIP) {
+ turnDesignPLs[I_TOSLIPMODE].option &= ~PDO_DLGIGNORE;
+ wControlShow( turnDesignPLs[I_TOSLIPMODE].control, TRUE );
+ } else {
+ turnDesignPLs[I_TOSLIPMODE].option |= PDO_DLGIGNORE;
+ wControlShow( turnDesignPLs[I_TOSLIPMODE].control, FALSE );
+ }
w = turnDesignWidth-w;
wStringSetWidth( (wString_p)turnDesignPLs[I_TOMANUF].control, w );
@@ -1795,18 +2951,25 @@ static void SetupTurnoutDesignerW( toDesignDesc_t * newDesign )
static void ShowTurnoutDesigner( void * context )
{
+ wBool_t sameTurnout = FALSE;
if (recordF)
fprintf( recordF, TURNOUTDESIGNER " SHOW %s\n", ((toDesignDesc_t*)context)->label );
newTurnScaleName = curScaleName;
newTurnTrackGauge = trackGauge;
+ if (context && (curDesign == context))
+ sameTurnout = TRUE;
SetupTurnoutDesignerW( (toDesignDesc_t*)context );
- newTurnRightDesc[0] = '\0';
- newTurnRightPartno[0] = '\0';
- newTurnLeftDesc[0] = '\0';
- newTurnLeftPartno[0] = '\0';
- newTurnLen0 =
- newTurnOff1 = newTurnLen1 = newTurnAngle1 =
- newTurnOff2 = newTurnLen2 = newTurnAngle2 = 0.0;
+ if (!sameTurnout) { /* Clear Values unless same as last time */
+ newTurnRightDesc[0] = '\0';
+ newTurnRightPartno[0] = '\0';
+ newTurnLeftDesc[0] = '\0';
+ newTurnLeftPartno[0] = '\0';
+ newTurnOff0 = newTurnLen0 = newTurnAngle0 = newTurnRad0 =
+ newTurnOff1 = newTurnLen1 = newTurnAngle1 = newTurnRad1 =
+ newTurnOff2 = newTurnLen2 = newTurnAngle2 = newTurnRad2 =
+ newTurnOff3 = newTurnLen3 = newTurnAngle3 = newTurnRad3 =
+ newTurnToeL = newTurnToeR = 0.0;
+ }
ParamLoadControls( &turnDesignPG );
ParamGroupRecord( &turnDesignPG );
customTurnout1 = NULL;
@@ -1849,7 +3012,7 @@ EXPORT void EditCustomTurnout( turnoutInfo_t * to, turnoutInfo_t * to1 )
strcpy( newTurnManufacturer, mfg );
strcpy( newTurnLeftDesc, descL );
strcpy( newTurnLeftPartno, partL );
- if (dp->type == NTO_REGULAR || dp->type == NTO_CURVED) {
+ if (dp->type == NTO_REGULAR || dp->type == NTO_CURVED || dp->type == NTO_CORNU) {
if ( ! GetArgs( cp, "qqc", &descR, &partR, &cp ))
return;
strcpy( newTurnRightDesc, descR );
@@ -1872,6 +3035,8 @@ EXPORT void EditCustomTurnout( turnoutInfo_t * to, turnoutInfo_t * to1 )
break;
case Angle_e:
break;
+ case Rad_e:
+ break;
}
}
rgb = 0;
@@ -1917,6 +3082,7 @@ EXPORT void EditCustomTurnout( turnoutInfo_t * to, turnoutInfo_t * to1 )
break;
case SEG_STRTRK:
case SEG_CRVTRK:
+ case SEG_BEZTRK:
break;
default:
segsDiff = TRUE;
@@ -1924,34 +3090,42 @@ EXPORT void EditCustomTurnout( turnoutInfo_t * to, turnoutInfo_t * to1 )
}
} else {
for ( sp0=to->segs; (!segsDiff) && sp0<&to->segs[to->segCnt]; sp0++ ) {
- if ( sp0->type != SEG_STRTRK && sp0->type != SEG_CRVTRK )
+ if ( sp0->type != SEG_STRTRK && sp0->type != SEG_CRVTRK && sp0->type != SEG_BEZTRK)
segsDiff = TRUE;
}
}
}
- if ( (!segsDiff) && to1 && (dp->type==NTO_REGULAR||dp->type==NTO_CURVED) ) {
+ if ( (!segsDiff) && to1 && (dp->type==NTO_REGULAR||dp->type==NTO_CURVED||dp->type == NTO_CORNU) ) {
if ( dp->type==NTO_REGULAR ) {
points[2].y = - points[2].y;
- points[4].y = - points[4].y;
radii[0] = - radii[0];
- } else {
+ } else if (dp->type == NTO_CURVED) {
points[1].y = - points[1].y;
points[2].y = - points[2].y;
- points[4].y = - points[4].y;
- points[6].y = - points[6].y;
+ radii[0] = - radii[0];
+ radii[1] = - radii[1];
+ } else {
+ points[2].y = - points[2].y;
+ points[1].y = - points[1].y;
+ angles[1] = -angles[1];
+ angles[2] = -angles[2];
radii[0] = - radii[0];
radii[1] = - radii[1];
}
LoadSegs( dp, FALSE, &pathLen );
if ( dp->type==NTO_REGULAR ) {
points[2].y = - points[2].y;
- points[4].y = - points[4].y;
radii[0] = - radii[0];
- } else {
+ } else if (dp->type == NTO_CURVED) {
points[1].y = - points[1].y;
points[2].y = - points[2].y;
- points[4].y = - points[4].y;
- points[6].y = - points[6].y;
+ radii[0] = - radii[0];
+ radii[1] = - radii[1];
+ } else {
+ points[2].y = - points[2].y;
+ points[1].y = - points[1].y;
+ angles[1] = -angles[1];
+ angles[2] = -angles[2];
radii[0] = - radii[0];
radii[1] = - radii[1];
}
@@ -1982,6 +3156,7 @@ EXPORT void EditCustomTurnout( turnoutInfo_t * to, turnoutInfo_t * to1 )
break;
case SEG_STRTRK:
case SEG_CRVTRK:
+ case SEG_BEZTRK:
break;
default:
segsDiff = TRUE;
@@ -1989,7 +3164,7 @@ EXPORT void EditCustomTurnout( turnoutInfo_t * to, turnoutInfo_t * to1 )
}
} else {
for ( sp0=to1->segs; (!segsDiff) && sp0<&to1->segs[to1->segCnt]; sp0++ ) {
- if ( sp0->type != SEG_STRTRK && sp0->type != SEG_CRVTRK )
+ if ( sp0->type != SEG_STRTRK && sp0->type != SEG_CRVTRK && sp0->type != SEG_BEZTRK)
segsDiff = TRUE;
}
}
@@ -2033,7 +3208,7 @@ EXPORT void InitNewTurn( wMenu_p m )
#include <stdio.h>
#include <stdarg.h>
-char message[1024];
+char message[STR_HUGE_SIZE];
char * curScaleName;
double trackGauge;
long units = 0;
@@ -2201,11 +3376,11 @@ EXPORT BOOL_T WriteSegs(
segs[i].u.p.cnt )>0;
for ( j=0; j<segs[i].u.p.cnt; j++ )
rc &= fprintf( f, "\t\t%0.6f %0.6f\n",
- segs[i].u.p.pts[j].x, segs[i].u.p.pts[j].y )>0;
+ segs[i].u.p.pts[j].pt.x, segs[i].u.p.pts[j].pt.y )>0;
break;
}
}
- rc &= fprintf( f, "\tEND\n" )>0;
+ rc &= fprintf( f, "\t%s\n", END_SEGS )>0;
return rc;
}
@@ -2344,7 +3519,7 @@ int main ( int argc, char * argv[] )
if (argc != 7) Usage(argc0,argv0);
strcpy( newTurnLeftDesc, *argv++ );
strcpy( newTurnLeftPartno, *argv++ );
- newTurnLen1 = GetDim(atof( *argv++ ));
+ newTurnLen0 = GetDim(atof( *argv++ ));
curDesign = &StrSectionDesc;
NewTurnOk( &StrSectionDesc );
break;
@@ -2352,7 +3527,7 @@ int main ( int argc, char * argv[] )
if (argc != 7) Usage(argc0,argv0);
strcpy( newTurnLeftDesc, *argv++ );
strcpy( newTurnLeftPartno, *argv++ );
- newTurnLen1 = GetDim(atof( *argv++ ));
+ newTurnLen0 = GetDim(atof( *argv++ ));
curDesign = &StrSectionDesc;
NewTurnOk( &StrSectionDesc );
break;
@@ -2360,9 +3535,9 @@ int main ( int argc, char * argv[] )
if (argc != 8) Usage(argc0,argv0);
strcpy( newTurnLeftDesc, *argv++ );
strcpy( newTurnLeftPartno, *argv++ );
+ newTurnLen0 = GetDim(atof( *argv++ ));
newTurnLen1 = GetDim(atof( *argv++ ));
- newTurnLen2 = GetDim(atof( *argv++ ));
- sprintf( specialLine, "\tX adjustable %0.6f %0.6f", newTurnLen1, newTurnLen2 );
+ sprintf( specialLine, "\tX adjustable %0.6f %0.6f", newTurnLen0, newTurnLen1 );
curDesign = &StrSectionDesc;
NewTurnOk( &StrSectionDesc );
break;
@@ -2370,8 +3545,8 @@ int main ( int argc, char * argv[] )
if (argc != 8) Usage(argc0,argv0);
strcpy( newTurnLeftDesc, *argv++ );
strcpy( newTurnLeftPartno, *argv++ );
- newTurnLen1 = GetDim(atof( *argv++ ));
- newTurnAngle1 = atof( *argv++ );
+ newTurnLen0 = GetDim(atof( *argv++ ));
+ newTurnAngle0 = atof( *argv++ );
curDesign = &CrvSectionDesc;
NewTurnOk( &CrvSectionDesc );
break;
@@ -2381,10 +3556,10 @@ int main ( int argc, char * argv[] )
strcpy( newTurnLeftPartno, *argv++ );
strcpy( newTurnRightDesc, *argv++ );
strcpy( newTurnRightPartno, *argv++ );
- newTurnLen1 = GetDim(atof( *argv++ ));
- newTurnAngle1 = atof( *argv++ );
- newTurnOff1 = GetDim(atof( *argv++ ));
newTurnLen0 = GetDim(atof( *argv++ ));
+ newTurnAngle0 = atof( *argv++ );
+ newTurnOff0 = GetDim(atof( *argv++ ));
+ newTurnLen1 = GetDim(atof( *argv++ ));
curDesign = &RegDesc;
NewTurnOk( &RegDesc );
break;
@@ -2395,9 +3570,9 @@ int main ( int argc, char * argv[] )
strcpy( newTurnRightDesc, *argv++ );
strcpy( newTurnRightPartno, *argv++ );
radius = GetDim(atof( *argv++ ));
- newTurnAngle1 = atof( *argv++ );
+ newTurnAngle0 = atof( *argv++ );
newTurnLen0 = GetDim(atof( *argv++ ));
- newTurnLen1 = radius * sin(D2R(newTurnAngle1));
+ newTurnLen1 = radius * sin(D2R(newTurnAngle0));
newTurnOff1 = radius * (1-cos(D2R(newTurnAngle1)));
curDesign = &RegDesc;
NewTurnOk( &RegDesc );
@@ -2408,12 +3583,12 @@ int main ( int argc, char * argv[] )
strcpy( newTurnLeftPartno, *argv++ );
strcpy( newTurnRightDesc, *argv++ );
strcpy( newTurnRightPartno, *argv++ );
- newTurnLen2 = GetDim(atof( *argv++ ));
- newTurnAngle2 = atof( *argv++ );
- newTurnOff2 = GetDim(atof( *argv++ ));
newTurnLen1 = GetDim(atof( *argv++ ));
newTurnAngle1 = atof( *argv++ );
newTurnOff1 = GetDim(atof( *argv++ ));
+ newTurnLen0 = GetDim(atof( *argv++ ));
+ newTurnAngle0 = atof( *argv++ );
+ newTurnOff0 = GetDim(atof( *argv++ ));
curDesign = &CrvDesc;
NewTurnOk( &CrvDesc );
break;
@@ -2424,13 +3599,13 @@ int main ( int argc, char * argv[] )
strcpy( newTurnRightDesc, *argv++ );
strcpy( newTurnRightPartno, *argv++ );
radius = GetDim(atof( *argv++ ));
+ newTurnAngle0 = atof( *argv++ );
+ newTurnLen0 = radius * sin(D2R(newTurnAngle0));
+ newTurnOff0 = radius * (1-cos(D2R(newTurnAngle0)));
+ radius = GetDim(atof( *argv++ ));
newTurnAngle1 = atof( *argv++ );
newTurnLen1 = radius * sin(D2R(newTurnAngle1));
newTurnOff1 = radius * (1-cos(D2R(newTurnAngle1)));
- radius = GetDim(atof( *argv++ ));
- newTurnAngle2 = atof( *argv++ );
- newTurnLen2 = radius * sin(D2R(newTurnAngle2));
- newTurnOff2 = radius * (1-cos(D2R(newTurnAngle2)));
curDesign = &CrvDesc;
NewTurnOk( &CrvDesc );
break;
@@ -2440,12 +3615,12 @@ int main ( int argc, char * argv[] )
strcpy( newTurnLeftPartno, *argv++ );
strcpy( newTurnRightDesc, *argv++ );
strcpy( newTurnRightPartno, *argv++ );
+ newTurnLen0 = GetDim(atof( *argv++ ));
+ newTurnAngle0 = atof( *argv++ );
+ newTurnOff0 = GetDim(atof( *argv++ ));
newTurnLen1 = GetDim(atof( *argv++ ));
newTurnAngle1 = atof( *argv++ );
newTurnOff1 = GetDim(atof( *argv++ ));
- newTurnLen2 = GetDim(atof( *argv++ ));
- newTurnAngle2 = atof( *argv++ );
- newTurnOff2 = GetDim(atof( *argv++ ));
curDesign = &WyeDesc;
NewTurnOk( &WyeDesc );
break;
@@ -2453,13 +3628,13 @@ int main ( int argc, char * argv[] )
if (argc != 13) Usage(argc0,argv0);
strcpy( newTurnLeftDesc, *argv++ );
strcpy( newTurnLeftPartno, *argv++ );
+ newTurnLen2 = GetDim(atof( *argv++ ));
newTurnLen0 = GetDim(atof( *argv++ ));
+ newTurnAngle0 = atof( *argv++ );
+ newTurnOff0 = GetDim(atof( *argv++ ));
newTurnLen1 = GetDim(atof( *argv++ ));
newTurnAngle1 = atof( *argv++ );
newTurnOff1 = GetDim(atof( *argv++ ));
- newTurnLen2 = GetDim(atof( *argv++ ));
- newTurnAngle2 = atof( *argv++ );
- newTurnOff2 = GetDim(atof( *argv++ ));
curDesign = &ThreewayDesc;
NewTurnOk( &ThreewayDesc );
break;
@@ -2467,9 +3642,9 @@ int main ( int argc, char * argv[] )
if (argc<9) Usage(argc0,argv0);
strcpy( newTurnLeftDesc, *argv++ );
strcpy( newTurnLeftPartno, *argv++ );
+ newTurnLen0 = GetDim(atof( *argv++ ));
+ newTurnAngle0 = atof( *argv++ );
newTurnLen1 = GetDim(atof( *argv++ ));
- newTurnAngle1 = atof( *argv++ );
- newTurnLen2 = GetDim(atof( *argv++ ));
curDesign = &CrossingDesc;
NewTurnOk( &CrossingDesc );
break;
@@ -2477,9 +3652,9 @@ int main ( int argc, char * argv[] )
if (argc<9) Usage(argc0,argv0);
strcpy( newTurnLeftDesc, *argv++ );
strcpy( newTurnLeftPartno, *argv++ );
+ newTurnLen0 = GetDim(atof( *argv++ ));
+ newTurnAngle0 = atof( *argv++ );
newTurnLen1 = GetDim(atof( *argv++ ));
- newTurnAngle1 = atof( *argv++ );
- newTurnLen2 = GetDim(atof( *argv++ ));
curDesign = &SingleSlipDesc;
NewTurnOk( &SingleSlipDesc );
break;
@@ -2487,9 +3662,9 @@ int main ( int argc, char * argv[] )
strcpy( newTurnLeftDesc, *argv++ );
strcpy( newTurnLeftPartno, *argv++ );
if (argc<9) Usage(argc0,argv0);
+ newTurnLen0 = GetDim(atof( *argv++ ));
+ newTurnAngle0 = atof( *argv++ );
newTurnLen1 = GetDim(atof( *argv++ ));
- newTurnAngle1 = atof( *argv++ );
- newTurnLen2 = GetDim(atof( *argv++ ));
curDesign = &DoubleSlipDesc;
NewTurnOk( &DoubleSlipDesc );
break;
@@ -2497,8 +3672,8 @@ int main ( int argc, char * argv[] )
strcpy( newTurnLeftDesc, *argv++ );
strcpy( newTurnLeftPartno, *argv++ );
if (argc<8) Usage(argc0,argv0);
- newTurnLen1 = GetDim(atof( *argv++ ));
- newTurnOff1 = GetDim(atof( *argv++ ));
+ newTurnLen0 = GetDim(atof( *argv++ ));
+ newTurnOff0 = GetDim(atof( *argv++ ));
curDesign = &DoubleCrossoverDesc;
NewTurnOk( &DoubleCrossoverDesc );
break;
@@ -2531,12 +3706,12 @@ int main ( int argc, char * argv[] )
x1 = radius * sin(D2R(ang));
y1 = radius * cos(D2R(ang));
fprintf( stdout, "\tS 0 0 %0.6f %0.6f %0.6f %0.6f\n", x0, y0, x1, y1 );
- fprintf( stdout, "\tS 16777215 0 %0.6f %0.6f %0.6f %0.6f\n", x1, y1, -x1, -y1 );
+ fprintf( stdout, "\tS 0 0 %0.6f %0.6f %0.6f %0.6f\n", x1, y1, -x1, -y1 );
fprintf( stdout, "\tS 0 0 %0.6f %0.6f %0.6f %0.6f\n", -x1, -y1, -x0, -y0 );
}
fprintf( stdout, "\tA 16711680 0 %0.6f 0.000000 0.000000 0.000000 360.000000\n", radius2 );
fprintf( stdout, "\tA 16711680 0 %0.6f 0.000000 0.000000 0.000000 360.000000\n", radius );
- fprintf( stdout, "\tEND\n" );
+ fprintf( stdout, "\t%s\n", END_SEGS );
break;
default:
fprintf( stderr, "Invalid command: %s\n", argv[-1] );
diff --git a/app/bin/ctrain.c b/app/bin/ctrain.c
index fe41a39..b15cb91 100644
--- a/app/bin/ctrain.c
+++ b/app/bin/ctrain.c
@@ -58,6 +58,7 @@ struct extraData {
long state;
carItem_p item;
double speed;
+ BOOL_T pencils;
BOOL_T direction;
BOOL_T autoReverse;
trainStatus_e status;
@@ -92,7 +93,7 @@ static wButton_p newcarB;
static void ControllerDialogSyncAll(void);
static STATUS_T CmdTrain(wAction_t, coOrd);
static wMenu_p trainPopupM;
-static wMenuPush_p trainPopupMI[8];
+static wMenuPush_p trainPopupMI[10];
static track_p followTrain;
static coOrd followCenter;
static BOOL_T trainsTimeoutPending;
@@ -311,6 +312,24 @@ BOOL_T TraverseTrack2(
return TRUE;
}
+/***************
+ * When a track is deleted, cross check that the Traverse Track reference is removed.
+ */
+EXPORT void CheckCarTraverse(track_p track) {
+
+ track_p car;
+ for (car=NULL; TrackIterate(&car);) {
+ if (GetTrkType(car) == T_CAR) {
+ struct extraData * xx = GetTrkExtraData(car);
+ if (xx->trvTrk.trk == track) {
+ xx->trvTrk.trk=NULL;
+ xx->status = ST_NotOnTrack;
+ }
+ }
+ }
+
+}
+
static BOOL_T drawCarEnable = TRUE;
@@ -358,7 +377,9 @@ static void DrawCar(
}
}
- CarItemDraw(d, xx->item, color, xx->direction, IsLocoMaster(xx), coupler);
+
+
+ CarItemDraw(d, xx->item, color, xx->direction, IsLocoMaster(xx), coupler, xx->pencils, xx->trvTrk.trk);
}
@@ -467,10 +488,10 @@ static void DeleteCar(
}
-static void ReadCar(
+static BOOL_T ReadCar(
char * line)
{
- CarItemRead(line);
+ return CarItemRead(line);
}
@@ -521,6 +542,29 @@ static BOOL_T QueryCar(track_p trk, int query)
}
}
+static BOOL_T StoreCar(
+ track_p car,
+ void **data,
+ long * len) {
+
+ struct extraData *xx = GetTrkExtraData(car);
+ return StoreCarItem(xx->item,data,len);
+
+}
+
+static BOOL_T ReplayCar (track_p car, void *data,long len) {
+
+ struct extraData *xx = GetTrkExtraData(car);
+ return ReplayCarItem(xx->item,data,len);
+
+}
+
+
+static wBool_t CompareCar( track_cp trk1, track_cp trk2 )
+{
+ return TRUE;
+}
+
static trackCmd_t carCmds = {
"CAR ",
@@ -548,6 +592,16 @@ static trackCmd_t carCmds = {
QueryCar, /* query */
NULL, /* ungroup */
NULL, /* flip */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ReplayCar,
+ StoreCar,
+ NULL, /*activate*/
+ CompareCar
};
/*
@@ -699,13 +753,13 @@ static void SpeedRedraw(
pts[2][1] = pts[3][1] = y+SLIDER_THICKNESS/2;
pts[0][0] = pts[3][0] = 0;
pts[1][0] = pts[2][0] = SLIDER_WIDTH;
- wDrawFilledPolygon(d, pts, 4, drawColor, 0);
+ wDrawPolygon(d, pts, NULL, 4, drawColor, 0, 0, 0, 1, 0);
drawColor = wDrawFindColor(wRGB(220, 220, 220));
pts[0][1] = pts[1][1] = y+SLIDER_THICKNESS/2;
pts[2][1] = pts[3][1] = y;
pts[0][0] = pts[3][0] = 0;
pts[1][0] = pts[2][0] = SLIDER_WIDTH;
- wDrawFilledPolygon(d, pts, 4, drawColor, 0);
+ wDrawPolygon(d, pts, NULL, 4, drawColor, 0, 0, 0, 1, 0);
wDrawLine(d, 0, y, SLIDER_WIDTH, y, 1, wDrawLineSolid, drawColorRed, 0);
wDrawLine(d, 0, y+SLIDER_THICKNESS/2, SLIDER_WIDTH, y+SLIDER_THICKNESS/2, 1,
wDrawLineSolid, drawColorBlack, 0);
@@ -1068,13 +1122,11 @@ static void MoveMainWindow(
dist *= factor;
Translate(&pos, pos, angle, dist);
- //DrawMapBoundingBox(FALSE);
- mainCenter = pos;
mainD.orig.x = pos.x-mainD.size.x/2;;
mainD.orig.y = pos.y-mainD.size.y/2;;
- MainRedraw();
- MapRedraw();
- //DrawMapBoundingBox(TRUE);
+ panCenter = pos;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ MainLayout( TRUE, TRUE ); // MoveTrainWindow
}
@@ -1197,7 +1249,7 @@ static void ControllerDialogUpdate(
wButtonSetLabel((wButton_p)pg->paramPtr[I_DIR].control,
(dlg->direction?_("Reverse"):_("Forward")));
SetTrainDirection(dlg->train);
- DrawAllCars();
+ TempRedraw(); // ctrain: change direction
break;
case I_STOP:
@@ -1277,7 +1329,6 @@ static void DrawAllCars(void)
drawCarEnable = TRUE;
wDrawDelayUpdate(mainD.d, TRUE);
wDrawRestoreImage(mainD.d);
- DrawMarkers();
DrawPositionIndicators();
for (car=NULL; TrackIterate(&car);) {
@@ -1291,7 +1342,7 @@ static void DrawAllCars(void)
hi.y = lo.y + size.x;
if (!OFF_MAIND(lo, hi)) {
- DrawCar(car, &mainD, wDrawColorBlack);
+ DrawCar(car, &tempD, wDrawColorBlack);
}
}
}
@@ -1334,12 +1385,9 @@ static void PlaceCar(
{
struct extraData *xx = GetTrkExtraData(car);
DIST_T dists[2];
- int dir;
CarItemPlace(xx->item, &xx->trvTrk, dists);
- for (dir=0; dir<2; dir++) {
- xx->couplerPos[dir] = CarItemFindCouplerMountPoint(xx->item, xx->trvTrk, dir);
- }
+ CarItemFindCouplerMountPoint(xx->item, xx->trvTrk, xx->couplerPos);
car->endPt[0].angle = xx->trvTrk.angle;
Translate(&car->endPt[0].pos, xx->trvTrk.pos, car->endPt[0].angle, dists[0]);
@@ -1787,6 +1835,9 @@ static BOOL_T CheckCoupling(
/* Move second train back along track half a car length */
TraverseTrack2(&trvTrk1, distc/2.0-dist);
+ if ( trvTrk0.trk == NULL || trvTrk1.trk == NULL )
+ // fell off the end of track
+ return FALSE;
/* If tracks are not the same - dont couple */
if (trvTrk1.trk != trvTrk0.trk) {
@@ -2076,7 +2127,7 @@ static BOOL_T MoveTrains(long timeD)
}
ControllerDialogSyncAll();
- DrawAllCars();
+ TempRedraw(); // MoveTrains
return trains_moved;
}
@@ -2427,6 +2478,8 @@ static BOOL_T TrainOnMovableTrack(
#define DO_MUMASTER (5)
#define DO_CHANGEDIR (6)
#define DO_STOP (7)
+#define DO_PENCILS_ON (8)
+#define DO_PENCILS_OFF (9)
static track_p trainFuncCar;
static coOrd trainFuncPos;
static wButton_p trainPauseB;
@@ -2470,12 +2523,11 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
Dtrain.state = 0;
trk0 = NULL;
tempSegs_da.cnt = 0;
- DYNARR_SET(trkSeg_t, tempSegs_da, 8);
+ DYNARR_SET(trkSeg_t, tempSegs_da, 8);
RestartTrains();
wButtonSetLabel(trainPauseB, (char*)goI);
trainTime0 = 0;
AttachTrains();
- DrawAllCars();
curTrainDlg->train = NULL;
curTrainDlg->speed = -1;
wDrawClear((wDraw_p)curTrainDlg->trainPGp->paramPtr[I_SLIDER].control);
@@ -2484,6 +2536,7 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
wShow(curTrainDlg->win);
wControlShow((wControl_p)newcarB, (toolbarSet&(1<<BG_HOTBAR)) == 0);
currCarItemPtr = NULL;
+ TempRedraw(); // CmdTrain C_START
return C_CONTINUE;
case C_TEXT:
@@ -2516,6 +2569,7 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
}
xx = GetTrkExtraData(currCar);
+ xx->pencils = FALSE;
dist = CarItemCoupledLength(xx->item)/2.0;
Translate(&pos, xx->trvTrk.pos, xx->trvTrk.angle, dist);
SetTrkEndPoint(currCar, 0, pos, xx->trvTrk.angle);
@@ -2578,7 +2632,6 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
SetCurTrain(trk0);
}
- DrawAllCars();
return C_CONTINUE;
case C_MOVE:
@@ -2589,7 +2642,6 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
pos.x += delta.x;
pos.y += delta.y;
pos0 = pos;
- /*DrawCars( &tempD, currCar, FALSE );*/
xx = GetTrkExtraData(currCar);
trk0 = OnTrack(&pos0, FALSE, TRUE);
@@ -2613,7 +2665,6 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
PlaceTrainInit(currCar, trk0, pos0, xx->trvTrk.angle,
(MyGetKeyState()&WKEY_SHIFT) == 0);
ControllerDialogSync(curTrainDlg);
- DrawAllCars();
return C_CONTINUE;
case C_UP:
@@ -2629,11 +2680,9 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
}
Dtrain.state = 1;
- /*MainRedraw();*/
ControllerDialogSync(curTrainDlg);
}
- DrawAllCars();
InfoSubstituteControls(NULL, NULL);
currCar = trk0 = NULL;
currCarItemPtr = NULL;
@@ -2668,14 +2717,12 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
xx->trvTrk.pos = pos1;
xx->trvTrk.angle = angle1;
PlaceTrain(trk1, FALSE, TRUE);
- DrawAllCars();
}
}
programMode = MODE_TRAIN;
trk0 = NULL;
- MainRedraw(); //Make sure track is redrawn after switch thrown
- MapRedraw();
+ MainRedraw(); //CmdTrain: Make sure track is redrawn after switch thrown
} else {
trk0 = FindCar(&pos);
@@ -2704,6 +2751,14 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
}
xx = GetTrkExtraData(trainFuncCar);
+ if (xx->pencils) {
+ wMenuPushEnable(trainPopupMI[DO_PENCILS_OFF], TRUE);
+ wMenuPushEnable(trainPopupMI[DO_PENCILS_ON], FALSE);
+ } else {
+ wMenuPushEnable(trainPopupMI[DO_PENCILS_OFF], FALSE);
+ wMenuPushEnable(trainPopupMI[DO_PENCILS_ON], TRUE);
+ }
+
trk0 = FindMasterLoco(trainFuncCar,NULL);
dir = IsAligned(xx->trvTrk.angle, FindAngle(xx->trvTrk.pos,
trainFuncPos)) ? 0 : 1;
@@ -2761,8 +2816,7 @@ static STATUS_T CmdTrain(wAction_t action, coOrd pos)
wHide(curTrainDlg->win);
}
- MainRedraw();
- MapRedraw();
+ MainRedraw(); // CmdTrain: Exit
curTrainDlg->train = NULL;
return C_CONTINUE;
@@ -2844,8 +2898,6 @@ static void CmdTrainExit(void * junk)
{
Reset();
InfoSubstituteControls(NULL, NULL);
- MainRedraw();
- MapRedraw();
}
@@ -2879,6 +2931,14 @@ static void TrainFunc(
break;
+ case DO_PENCILS_ON:
+ xx->pencils = TRUE;
+ break;
+
+ case DO_PENCILS_OFF:
+ xx->pencils = FALSE;
+ break;
+
case DO_FLIPCAR:
temp0 = GetTrkEndTrk(trainFuncCar,0);
pos0 = GetTrkEndPos(trainFuncCar,0);
@@ -3019,16 +3079,15 @@ static void TrainFunc(
break;
}
- MainRedraw(); //Redraw if Train altered
- MapRedraw();
+ MainRedraw(); //TrainFunc: Redraw if Train altered
if (trainsState == TRAINS_PAUSE) {
RestartTrains();
} else {
- DrawAllCars();
}
}
+EXPORT wIndex_t trainCmdInx;
void InitCmdTrain(wMenu_p menu)
{
@@ -3036,8 +3095,8 @@ void InitCmdTrain(wMenu_p menu)
log_trainPlayback = LogFindIndex("trainPlayback");
trainPLs[I_ZERO].winLabel = (char*)wIconCreatePixMap(zero_xpm);
ParamRegister(&trainPG);
- AddMenuButton(menu, CmdTrain, "cmdTrain", _("Train"),
- wIconCreatePixMap(train_xpm), LEVEL0_50, IC_POPUP2|IC_LCLICK|IC_RCLICK, 0,
+ trainCmdInx = AddMenuButton(menu, CmdTrain, "cmdTrain", _("Train"),
+ wIconCreatePixMap(train_xpm), LEVEL0_50, IC_POPUP3|IC_LCLICK|IC_RCLICK, 0,
NULL);
stopI = wIconCreatePixMap(ballred);
goI = wIconCreatePixMap(ballgreen);
@@ -3053,6 +3112,10 @@ void InitCmdTrain(wMenu_p menu)
TrainFunc, (void*)DO_UNCOUPLE);
trainPopupMI[DO_FLIPCAR] = wMenuPushCreate(trainPopupM, "", _("Flip Car"), 0,
TrainFunc, (void*)DO_FLIPCAR);
+ trainPopupMI[DO_PENCILS_ON] = wMenuPushCreate(trainPopupM, "", _("Clearance Lines On"), 0,
+ TrainFunc, (void*)DO_PENCILS_ON);
+ trainPopupMI[DO_PENCILS_OFF] = wMenuPushCreate(trainPopupM, "", _("Clearance Lines Off"), 0,
+ TrainFunc, (void*)DO_PENCILS_OFF);
trainPopupMI[DO_FLIPTRAIN] = wMenuPushCreate(trainPopupM, "", _("Flip Train"),
0, TrainFunc, (void*)DO_FLIPTRAIN);
trainPopupMI[DO_MUMASTER] = wMenuPushCreate(trainPopupM, "", _("MU Master"),
diff --git a/app/bin/ctrain.h b/app/bin/ctrain.h
index daa083c..858860b 100644
--- a/app/bin/ctrain.h
+++ b/app/bin/ctrain.h
@@ -24,8 +24,11 @@
#define HAVE_CTRAIN_H
#include "common.h"
+#include "include/paramfile.h"
#include "track.h"
+extern wIndex_t trainCmdInx;
+
struct carItem_t;
typedef struct carItem_t carItem_t;
typedef carItem_t * carItem_p;
@@ -34,8 +37,8 @@ typedef struct {
ANGLE_T angle;
} vector_t;
-carItem_p currCarItemPtr;
-wControl_p newCarControls[2];
+extern carItem_p currCarItemPtr;
+extern wControl_p newCarControls[2];
void DoCarDlg( void );
BOOL_T CarItemRead( char * );
track_p NewCar( wIndex_t, carItem_p, coOrd, ANGLE_T );
@@ -44,7 +47,7 @@ void CarSetVisible( track_p );
void CarItemUpdate( carItem_p );
void CarItemLoadList( void * );
char * CarItemDescribe( carItem_p, long, long * );
-coOrd CarItemFindCouplerMountPoint( carItem_p, traverseTrack_t, int );
+void CarItemFindCouplerMountPoint( carItem_p, traverseTrack_t, coOrd[2] );
void CarItemSize( carItem_p, coOrd * );
char * CarItemNumber( carItem_p );
DIST_T CarItemCoupledLength( carItem_p );
@@ -53,9 +56,16 @@ BOOL_T CarItemIsLocoMaster( carItem_p );
void CarItemSetLocoMaster( carItem_p, BOOL_T );
void CarItemSetTrack( carItem_p, track_p );
void CarItemPlace( carItem_p, traverseTrack_p, DIST_T * );
-void CarItemDraw( drawCmd_p, carItem_p, wDrawColor, int, BOOL_T, vector_t * );
+void CarItemDraw( drawCmd_p, carItem_p, wDrawColor, int, BOOL_T, vector_t *, BOOL_T, track_p );
+BOOL_T StoreCarItem (carItem_p item, void **data,long *len);
+BOOL_T ReplayCarItem(carItem_p item, void *data,long len);
+enum paramFileState GetCarPartCompatibility(int paramFileIndex, SCALEINX_T scaleIndex);
+enum paramFileState GetCarProtoCompatibility(int paramFileIndex, SCALEINX_T scaleIndex);
int CarAvailableCount( void );
BOOL_T TraverseTrack2( traverseTrack_p, DIST_T );
void FlipTraverseTrack( traverseTrack_p );
+void CheckCarTraverse( track_p trk);
+void DeleteCarProto(int fileIndex);
+void DeleteCarPart(int fileIndex);
-#endif // !HAVE_CTRAIN_H \ No newline at end of file
+#endif // !HAVE_CTRAIN_H
diff --git a/app/bin/cturnout.c b/app/bin/cturnout.c
index eace782..150f381 100644
--- a/app/bin/cturnout.c
+++ b/app/bin/cturnout.c
@@ -27,6 +27,7 @@
#include "ccurve.h"
#include "tbezier.h"
+#include "tcornu.h"
#include "cjoin.h"
#include "compound.h"
#include "cstraigh.h"
@@ -37,7 +38,9 @@
#include "layout.h"
#include "messages.h"
#include "param.h"
+#include "include/paramfile.h"
#include "track.h"
+#include "trackx.h"
#include "utility.h"
EXPORT TRKTYP_T T_TURNOUT = -1;
@@ -50,9 +53,12 @@ EXPORT dynArr_t turnoutInfo_da;
EXPORT turnoutInfo_t * curTurnout = NULL;
EXPORT long curTurnoutEp = 0;
+static int curTurnoutInx = -1;
static int log_turnout = 0;
static int log_traverseTurnout = 0;
+static int log_suppressCheckPaths = 0;
+static int log_splitturnout = 0;
static wMenu_p turnoutPopupM;
@@ -71,6 +77,7 @@ static wIndex_t turnoutInx;
static long hideTurnoutWindow;
static void RedrawTurnout(void);
static void SelTurnoutEndPt( wIndex_t, coOrd );
+static void HilightEndPt( void );
static wPos_t turnoutListWidths[] = { 80, 80, 220 };
static const char * turnoutListTitles[] = { N_("Manufacturer"), N_("Part No"), N_("Description") };
@@ -111,6 +118,7 @@ EXPORT turnoutInfo_t * CreateNewTurnout(
PATHPTR_T paths,
EPINX_T endPtCnt,
trkEndPt_t * endPts,
+ DIST_T * radii,
wBool_t updateList )
{
turnoutInfo_t * to;
@@ -126,7 +134,14 @@ EXPORT turnoutInfo_t * CreateNewTurnout(
changes = CHANGE_PARAMS;
}
to->segCnt = segCnt;
- to->segs = (trkSeg_p)memdup( segData, (sizeof *segData) * segCnt );
+ trkSeg_p seg_p;
+ to->segs = (trkSeg_p)memdup( segData, (sizeof (*segData) * segCnt ));
+ seg_p = to->segs;
+ for (int i=0;i<segCnt;i++) {
+ seg_p[i].bezSegs.ptr = NULL;
+ seg_p[i].bezSegs.cnt = 0;
+ seg_p[i].bezSegs.max = 0;
+ }
CopyPoly(to->segs,segCnt);
FixUpBezierSegs(to->segs,to->segCnt);
GetSegBounds( zero, 0.0, segCnt, to->segs, &to->orig, &to->size );
@@ -137,7 +152,7 @@ EXPORT turnoutInfo_t * CreateNewTurnout(
to->paths = (PATHPTR_T)memdup( paths, (sizeof *to->paths) * to->pathLen );
to->paramFileIndex = curParamFileIndex;
if (curParamFileIndex == PARAM_CUSTOM)
- to->contentsLabel = "Custom Turnouts";
+ to->contentsLabel = MyStrdup("Custom Turnouts");
else
to->contentsLabel = curSubContents;
#ifdef TURNOUTCMD
@@ -150,11 +165,137 @@ EXPORT turnoutInfo_t * CreateNewTurnout(
to->barScale = curBarScale>0?curBarScale:-1;
to->special = TOnormal;
+ if (radii) {
+ to->special = TOcurved;
+ DYNARR_SET(DIST_T,to->u.curved.radii,to->endCnt);
+ for (int i=0;i<to->endCnt;i++) {
+ DYNARR_N(DIST_T,to->u.curved.radii,i) = radii[i];
+ }
+ }
if (updateList && changes)
DoChangeNotification( changes );
return to;
}
+/**
+ * Delete a turnout parameter from the list and free the related memory
+ *
+ * \param [IN] to turnout definition to be deleted
+ */
+
+BOOL_T
+DeleteTurnout(void *toInfo)
+{
+ turnoutInfo_t * to = (turnoutInfo_t *)toInfo;
+ MyFree(to->title);
+ MyFree(to->segs);
+ MyFree(to->endPt);
+ MyFree(to->paths);
+ if (to->special) {
+ DYNARR_FREE(DIST_T, to->u.curved.radii);
+ }
+
+ MyFree(to);
+ return(TRUE);
+}
+
+/**
+ * Delete all turnout definitions that came from a specific parameter file.
+ * Due to the way the definitions are loaded from file it is safe to
+ * assume that they form a contiguous block in the array.
+ *
+ * \param [IN] fileIndex parameter file
+ */
+
+void
+DeleteTurnoutParams(int fileIndex)
+{
+ int inx=0;
+ int startInx = -1;
+ int cnt = 0;
+
+ // go to the start of the block
+ while (inx < turnoutInfo_da.cnt &&
+ turnoutInfo(inx)->paramFileIndex != fileIndex) {
+ startInx = inx++;
+ }
+
+ // delete them
+ for (; inx < turnoutInfo_da.cnt &&
+ turnoutInfo(inx)->paramFileIndex == fileIndex; inx++) {
+ turnoutInfo_t * to = turnoutInfo(inx);
+ if (to->paramFileIndex == fileIndex) {
+ DeleteTurnout(to);
+ cnt++;
+ }
+ }
+
+ // copy down the rest of the list to fill the gap
+ startInx++;
+ while (inx < turnoutInfo_da.cnt) {
+ turnoutInfo(startInx++) = turnoutInfo(inx++);
+ }
+
+ // and reduce the actual number
+ turnoutInfo_da.cnt -= cnt;
+}
+
+/**
+ * Check to find out to what extent the contents of the parameter file can be used with
+ * the current layout scale / gauge.
+ *
+ * If parameter scale == layout and parameter gauge == layout we have an exact fit.
+ * If parameter gauge == layout we have compatible track.
+ * OO scale is special cased. If the layout is in OO scale track in HO is considered
+ * an exact fit in spite of scale differences.
+ *
+ * \param paramFileIndex
+ * \param scaleIndex
+ * \return
+ */
+
+enum paramFileState
+GetTrackCompatibility(int paramFileIndex, SCALEINX_T scaleIndex)
+{
+ int i;
+ enum paramFileState ret = PARAMFILE_NOTUSABLE;
+ DIST_T gauge = GetScaleTrackGauge(scaleIndex);
+
+ if (!IsParamValid(paramFileIndex)) {
+ return(PARAMFILE_UNLOADED);
+ }
+
+ // loop over all parameter entries or until a exact fit is found
+ for (i = 0; i < turnoutInfo_da.cnt && ret < PARAMFILE_FIT; i++) {
+ turnoutInfo_t *to = turnoutInfo( i );
+ if (to->paramFileIndex == paramFileIndex ) {
+ if (to->scaleInx == scaleIndex ) {
+ ret = PARAMFILE_FIT;
+ break;
+ } else {
+ if (GetScaleTrackGauge(to->scaleInx) == gauge &&
+ ret < PARAMFILE_COMPATIBLE) {
+ ret = PARAMFILE_COMPATIBLE;
+ // handle special cases
+ // if layout is OO scale, HO scale track is considered exact
+ char *layoutScaleName = GetScaleName(scaleIndex);
+ char *paramScaleName = GetScaleName(to->scaleInx);
+ if (!strcmp(layoutScaleName, "OO") &&
+ !strcmp(paramScaleName, "HO")) {
+ ret = PARAMFILE_FIT;
+ }
+ //if layout is in Japanese or British N scale, N scale is exact
+ if ((!strcmp(layoutScaleName, "N(UK)") ||
+ !strcmp(layoutScaleName, "N(JP)")) &&
+ !strcmp(paramScaleName, "N")) {
+ ret = PARAMFILE_FIT;
+ }
+ }
+ }
+ }
+ }
+ return(ret);
+}
EXPORT wIndex_t CheckPaths(
@@ -162,31 +303,59 @@ EXPORT wIndex_t CheckPaths(
trkSeg_p segs,
PATHPTR_T paths )
{
+ if ((segCnt == 0) || !segs) return -1;
int pc, ps;
PATHPTR_T pp = 0;
- int inx, inx1;
+ int inx;
static dynArr_t segMap_da;
int segInx[2], segEp[2];
int segTrkLast = -1;
- trkSeg_t tempSeg;
-#define segMap(N) DYNARR_N( trkSeg_p, segMap_da, N )
+ // Check that each track segment is on at least one path
+ int suppressCheckPaths = log_suppressCheckPaths > 0 ? logTable(log_suppressCheckPaths).level : 0;
+ if ( suppressCheckPaths == 0 ) {
+ char trkSegInx = 0;
+ for ( int inx = 0; inx<segCnt; inx++ ) {
+ if ( IsSegTrack( &segs[inx] ) ) {
+ trkSegInx++;
+ PATHPTR_T cp = paths;
+ while ( *cp ) {
+ // path is: 'N' 'A' 'M' 'E' 0 1 2 0 3 4 0 0
+ // skip name
+ for ( ; *cp; cp++ );
+ cp++;
+ // check each path component
+ for ( ; cp[0] || cp[1]; cp++ )
+ if ( abs(*cp) == trkSegInx )
+ break;
+ if ( *cp ) // we broke early
+ break;
+ cp += 2;; // Skip 2nd 0
+ }
+ if ( !*cp ) { // we looked and didn't find
+ InputError( "Track segment %d not on Path", FALSE, inx+1 );
+ return -1;;
+ }
+ }
+ }
+ }
- DYNARR_RESET( trkSeg_p, segMap_da );
+typedef struct {
+ trkSeg_p seg;
+ int indx;
+} segMap_t, * segMap_p;
+
+#define segMap(N) DYNARR_N( segMap_t, segMap_da, N )
+ segMap_p sg;
+ DYNARR_RESET( segMap_t, segMap_da );
+ // Don't reshuffle segs, but build an offset map instead just of the tracks
+ // Use the map to set up the paths to point at the correct segs in the Turnout
for ( inx=0; inx<segCnt; inx++ ) {
if ( IsSegTrack(&segs[inx]) ) {
- if ( segTrkLast != inx-1 ) {
- tempSeg = segs[inx];
- segTrkLast++;
- for ( inx1=inx; inx1>segTrkLast; inx1-- ) {
- segs[inx1] = segs[inx1-1];
- }
- segs[segTrkLast] = tempSeg;
- } else {
- segTrkLast = inx;
- }
- DYNARR_APPEND( trkSeg_p, segMap_da, 10 );
- segMap(segMap_da.cnt-1) = &segs[inx];
+ DYNARR_APPEND( segMap_t, segMap_da, 10 );
+ sg = &DYNARR_LAST(segMap_t,segMap_da);
+ sg->seg = &segs[inx];
+ sg->indx = inx;
}
}
@@ -203,8 +372,27 @@ EXPORT wIndex_t CheckPaths(
return -1;
}
#endif
-
+ //Rewrite the Path to point to the nth Track seg using the Map
+ int old_inx;
+ EPINX_T old_EP;
+ if (pp[0]!=0 && ps==0) { // First or only one
+ GetSegInxEP( pp[0], &old_inx, &old_EP );
+ if (old_inx<0 || old_inx>= segMap_da.cnt) {
+ InputError( _("Turnout path[%d] %d is not a valid track segment"),
+ FALSE, pc, ps );
+ return -1;
+ }
+ SetSegInxEP( &pp[0], DYNARR_N(segMap_t,segMap_da,old_inx).indx, old_EP);
+ }
if (pp[0]!=0 && pp[1]!=0 ) {
+ //Rewrite the Path to point to the nth Track seg using the Map
+ GetSegInxEP( pp[1], &old_inx, &old_EP );
+ if (old_inx<0 || old_inx>= segMap_da.cnt) {
+ InputError( _("Turnout path[%d] %d is not a valid track segment"),
+ FALSE, pc, ps );
+ return -1;
+ }
+ SetSegInxEP( &pp[1], DYNARR_N(segMap_t,segMap_da,old_inx).indx, old_EP);
/* check connectivity */
DIST_T d;
GetSegInxEP( pp[0], &segInx[0], &segEp[0] );
@@ -219,12 +407,12 @@ EXPORT wIndex_t CheckPaths(
FALSE, pc, pp[1] );
return -1;
}
- d = FindDistance(
- GetSegEndPt( &segs[segInx[0]], 1-segEp[0], FALSE, NULL ),
- GetSegEndPt( &segs[segInx[1]], segEp[1], FALSE, NULL ) );
+ coOrd p0 = GetSegEndPt( &segs[segInx[0]], 1-segEp[0], FALSE, NULL );
+ coOrd p1 = GetSegEndPt( &segs[segInx[1]], segEp[1], FALSE, NULL );
+ d = FindDistance(p0,p1);
if (d > MIN_TURNOUT_SEG_CONNECT_DIST) {
- InputError( _("Turnout path[%d] %d-%d not connected: %0.3f"),
- FALSE, pc, pp[0], pp[1], d );
+ InputError( _("Turnout path[%d] %d-%d not connected: %0.3f P0(%f,%f) P1(%f,%f)"),
+ FALSE, pc, pp[0], pp[1], d, p0.x, p0.y, p1.x, p1.y );
return -1;
}
}
@@ -246,27 +434,28 @@ static BOOL_T ReadTurnoutParam(
return FALSE;
DYNARR_RESET( trkEndPt_t, tempEndPts_da );
pathCnt = 0;
- if (ReadSegs()) {
- CheckPaths( tempSegs_da.cnt, &tempSegs(0), pathPtr );
- to = CreateNewTurnout( scale, title, tempSegs_da.cnt, &tempSegs(0),
- pathCnt, pathPtr, tempEndPts_da.cnt, &tempEndPts(0), FALSE );
- if (to == NULL)
+ if ( !ReadSegs() )
+ return FALSE;
+ CheckPaths( tempSegs_da.cnt, &tempSegs(0), pathPtr );
+ to = CreateNewTurnout( scale, title, tempSegs_da.cnt, &tempSegs(0),
+ pathCnt, pathPtr, tempEndPts_da.cnt, &tempEndPts(0), NULL, FALSE );
+ MyFree( title );
+ if (to == NULL)
+ return FALSE;
+ if (tempSpecial[0] != '\0') {
+ if (strncmp( tempSpecial, ADJUSTABLE, strlen(ADJUSTABLE) ) == 0) {
+ to->special = TOadjustable;
+ if ( !GetArgs( tempSpecial+strlen(ADJUSTABLE), "ff",
+ &to->u.adjustable.minD, &to->u.adjustable.maxD ) )
+ return FALSE;
+ } else {
+ InputError(_("Unknown special case"), TRUE);
return FALSE;
- if (tempSpecial[0] != '\0') {
- if (strncmp( tempSpecial, ADJUSTABLE, strlen(ADJUSTABLE) ) == 0) {
- to->special = TOadjustable;
- GetArgs( tempSpecial+strlen(ADJUSTABLE), "ff",
- &to->u.adjustable.minD, &to->u.adjustable.maxD );
-
- } else {
- InputError(_("Unknown special case"), TRUE);
- }
- }
- if (tempCustom[0] != '\0') {
- to->customInfo = MyStrdup( tempCustom );
}
}
- MyFree( title );
+ if (tempCustom[0] != '\0') {
+ to->customInfo = MyStrdup( tempCustom );
+ }
return TRUE;
}
@@ -275,6 +464,7 @@ EXPORT turnoutInfo_t * TurnoutAdd( long mode, SCALEINX_T scale, wList_p list, co
{
wIndex_t inx;
turnoutInfo_t * to, * to1 = NULL;
+ turnoutInx = 0;
for ( inx = 0; inx < turnoutInfo_da.cnt; inx++ ) {
to = turnoutInfo(inx);
if ( IsParamValid(to->paramFileIndex) &&
@@ -284,6 +474,10 @@ EXPORT turnoutInfo_t * TurnoutAdd( long mode, SCALEINX_T scale, wList_p list, co
( epCnt <= 0 || epCnt == to->endCnt ) ) {
if (to1==NULL)
to1 = to;
+ if ( to == curTurnout ) {
+ to1 = to;
+ turnoutInx = wListGetCount( list );
+ }
FormatCompoundTitle( mode, to->title );
if (message[0] != '\0') {
wListAddValue( list, message, NULL, to );
@@ -535,44 +729,10 @@ track_p NewHandLaidTurnout(
segs[1].color = wDrawColorBlack;
segs[1].u.l.pos[0] = zero;
segs[1].u.l.pos[1] = p2;
- trk = NewCompound( T_TURNOUT, 0, p0, a0, message, 3, &tempEndPts(0), 22, "Normal\0\1\0\0Reverse\0\2\0\0\0", 2, segs );
+ trk = NewCompound( T_TURNOUT, 0, p0, a0, message, 3, &tempEndPts(0), NULL, 22, "Normal\0\1\0\0Reverse\0\2\0\0\0", 2, segs );
xx = GetTrkExtraData(trk);
xx->handlaid = TRUE;
-#ifdef LATER
- trk = NewTrack( 0, T_TURNOUT, 3,
- sizeof (*xx) + (3-1)*sizeof curTurnout->segs[0] + 1);
- xx = GetTrkExtraData(trk);
- xx->orig = p0;
- xx->angle = a0;
- xx->handlaid = TRUE;
- xx->descriptionOff = zero;
- xx->descriptionSize = zero;
- sprintf( message, "\tHand Laid Turnout, Angle=%0.1f\t", frogA );
- xx->title = MyStrdup( message );
- xx->paths = xx->pathCurr = (PATHPTR_T)"Normal\0\1\0\0Reverse\0\2\0\0\0";
- xx->pathLen = 21;
- SetTrkEndPoint( trk, 0, p0, a0 );
- SetTrkEndPoint( trk, 1, p1, a1 );
- SetTrkEndPoint( trk, 2, p2, a2 );
- xx->segCnt = 2;
- Rotate( &p1, p0, -a0 );
- p1.x -= p0.x;
- p1.y -= p0.y;
- xx->segs[0].type = SEG_STRTRK;
- xx->segs[0].color = wDrawColorBlack;
- xx->segs[0].u.l.pos[0] = zero;
- xx->segs[0].u.l.pos[1] = p1;
- Rotate( &p2, p0, -a0 );
- p2.x -= p0.x;
- p2.y -= p0.y;
- xx->segs[1].type = SEG_STRTRK;
- xx->segs[1].color = wDrawColorBlack;
- xx->segs[1].u.l.pos[0] = zero;
- xx->segs[1].u.l.pos[1] = p2;
- ComputeBoundingBox( trk );
- SetDescriptionOrig( trk );
-#endif
return trk;
}
@@ -588,7 +748,6 @@ static coOrd MapPathPos(
EPINX_T ep )
{
trkSeg_p segPtr;
- wIndex_t inx;
coOrd pos;
if ( segInx < 0 ) {
@@ -596,15 +755,15 @@ static coOrd MapPathPos(
ep = 1-ep;
}
- for ( inx=0,segPtr=xx->segs; inx<xx->segCnt; inx++,segPtr++ ) {
- if ( !IsSegTrack(segPtr) ) continue;
- if ( --segInx > 0 ) continue;
- pos = GetSegEndPt( segPtr, ep, FALSE, NULL );
- REORIGIN1( pos, xx->angle, xx->orig );
- return pos;
+ segPtr=xx->segs+(segInx-1);
+ if (!IsSegTrack(segPtr)) {
+ fprintf( stderr, "mapPathPos: bad segInx: %d\n", segInx );
+ return zero;
}
- fprintf( stderr, "mapPathPos: bad segInx: %d\n", segInx );
- return zero;
+ pos = GetSegEndPt( segPtr, ep, FALSE, NULL );
+ REORIGIN1( pos, xx->angle, xx->orig );
+ return pos;
+
}
@@ -618,21 +777,16 @@ static void DrawTurnout(
long widthOptions = 0;
DIST_T scale2rail;
- if (GetTrkWidth(trk) == 2)
- widthOptions = DTS_THICK2;
- if (GetTrkWidth(trk) == 3)
- widthOptions = DTS_THICK3;
+ widthOptions = DTS_LEFT|DTS_RIGHT;
+
scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale;
- if ( tieDrawMode!=TIEDRAWMODE_NONE &&
- d!=&mapD &&
- (d->options&DC_TIES)!=0 &&
- d->scale<scale2rail/2 )
- DrawSegsO( d, trk, xx->orig, xx->angle, xx->segs, xx->segCnt, GetTrkGauge(trk), color, widthOptions|DTS_TIES );
DrawSegsO( d, trk, xx->orig, xx->angle, xx->segs, xx->segCnt, GetTrkGauge(trk), color, widthOptions | DTS_NOCENTER ); // no curve center for turnouts
+
+
for (i=0; i<GetTrkEndPtCnt(trk); i++) {
DrawEndPt( d, trk, i, color );
}
- if ( ((d->funcs->options&wDrawOptTemp)==0) &&
+ if ( (d->options & DC_SIMPLE) == 0 &&
(labelWhen == 2 || (labelWhen == 1 && (d->options&DC_PRINT))) &&
labelScale >= d->scale &&
( GetTrkBits( trk ) & TB_HIDEDESC ) == 0 ) {
@@ -648,11 +802,12 @@ static void DrawTurnout(
}
-static void ReadTurnout(
+static BOOL_T ReadTurnout(
char * line )
{
- ReadCompound( line+8, T_TURNOUT );
- CheckPaths( tempSegs_da.cnt, &tempSegs(0), pathPtr );
+ if ( !ReadCompound( line+8, T_TURNOUT ) )
+ return FALSE;
+ return TRUE;
}
@@ -668,12 +823,27 @@ static ANGLE_T GetAngleTurnout(
if ( ep0 && ep1 )
*ep0 = *ep1 = PickEndPoint( pos, trk );
- for ( segCnt=0; segCnt<xx->segCnt && IsSegTrack(&xx->segs[segCnt]); segCnt++ );
- pos.x -= xx->orig.x;
- pos.y -= xx->orig.y;
- Rotate( &pos, zero, -xx->angle );
- angle = GetAngleSegs( segCnt, xx->segs, &pos, &segInx, NULL, NULL, NULL, NULL );
- return NormalizeAngle( angle+xx->angle );
+ coOrd pos0=pos;
+ double dd = 10000.0;
+ int found = -1;
+ //Cope with tracks not being first
+ for (segCnt =0; segCnt<xx->segCnt ; segCnt++ ) {
+ if (IsSegTrack(&xx->segs[segCnt])) {
+ double d = DistanceSegs( xx->orig, xx->angle, 1, &xx->segs[segCnt], &pos0, NULL );
+ if (d<dd) {
+ dd = d;
+ found = segCnt;
+ }
+ }
+ pos0 = pos;
+ }
+ if (found>=0) {
+ pos.x -= xx->orig.x;
+ pos.y -= xx->orig.y;
+ Rotate( &pos, zero, -xx->angle );
+ angle = GetAngleSegs( 1, &xx->segs[found], &pos, &segInx, NULL, NULL, NULL, NULL );
+ return NormalizeAngle( angle+xx->angle );
+ } else return 0.0;
}
@@ -843,6 +1013,7 @@ static void SplitTurnoutCheckEndPt(
if ( dir < 0 ) segEP = 1-segEP;
pos = GetSegEndPt( &segs[segInx], segEP, FALSE, NULL );
dist = FindDistance( pos, epPos );
+ LOG( log_splitturnout, 1, ( " SPTChkEp P%d DIR:%d SegInx:%d SegEP:%d POS[%0.3f %0.3f] DIST:%0.3f\n", *path, dir, segInx, segEP, pos.x, pos.y, dist ) );
if ( dist>connectDistance )
return;
minDist = trackGauge;
@@ -851,6 +1022,7 @@ static void SplitTurnoutCheckEndPt(
if ( dir < 0 ) segEP = 1-segEP;
pos = splitPos;
dist = DistanceSegs( zero, 0.0, 1, &segs[segInx], &pos, NULL );
+ LOG( log_splitturnout, 1, ( " - P:%d SegInx:%d SegEP:%d DIST:%0.3f\n", path[0], segInx, segEP, dist ) );
if ( dist < minDist ) {
minDist = dist;
splitTurnoutPath = path;
@@ -861,15 +1033,17 @@ static void SplitTurnoutCheckEndPt(
}
}
-
-static BOOL_T SplitTurnout(
- track_p trk,
- coOrd pos,
- EPINX_T ep,
- track_p *leftover,
- EPINX_T * ep0,
- EPINX_T * ep1 )
-{
+EXPORT BOOL_T SplitTurnoutCheck(
+ track_p trk,
+ coOrd pos,
+ EPINX_T ep,
+ track_p *leftover,
+ EPINX_T * ep0,
+ EPINX_T * ep1,
+ BOOL_T check,
+ coOrd * outPos,
+ ANGLE_T * outAngle )
+ {
struct extraData * xx = GetTrkExtraData( trk );
wIndex_t segInx0, segInx, segCnt;
EPINX_T segEP, epCnt, ep2=0, epN;
@@ -891,7 +1065,8 @@ static BOOL_T SplitTurnout(
trkSeg_t newSeg;
if ( (MyGetKeyState()&WKEY_SHIFT) == 0 ) {
- ErrorMessage( MSG_CANT_SPLIT_TRK, _("Turnout") );
+ if (!check)
+ ErrorMessage( MSG_CANT_SPLIT_TRK, _("Turnout") );
return FALSE;
}
@@ -909,6 +1084,7 @@ static BOOL_T SplitTurnout(
epPos.y -= xx->orig.y;
splitTurnoutPath = NULL;
pp = xx->paths;
+ LOG( log_splitturnout, 1, ( "SplitTurnoutCheck T%d POS[%0.3f %0.3f] EP:%d CHK:%d EPPOS[%0.3f %0.3f]\n", trk?trk->index:0, pos.x, pos.y, ep, check, epPos.x, epPos.y ) );
while ( pp[0] ) {
pp += strlen((char *)pp)+1;
while ( pp[0] ) {
@@ -924,7 +1100,8 @@ static BOOL_T SplitTurnout(
}
pp++;
}
- ErrorMessage( _("splitTurnout: can't find segment") );
+ if (!check)
+ ErrorMessage( _("splitTurnout: can't find segment") );
return FALSE;
foundSeg:
@@ -932,6 +1109,7 @@ foundSeg:
* 2a. Check that all other paths thru found segment are the same
*/
GetSegInxEP( splitTurnoutPath[0], &segInx0, &segEP );
+ LOG( log_splitturnout, 1, (" Found Seg: %d SEG:%d EP:%d\n", *splitTurnoutPath, segInx0, segEP ) );
pp = xx->paths;
pathCnt = 0;
while ( pp[0] ) {
@@ -950,7 +1128,8 @@ foundSeg:
pp2 += dir;
}
if ( pp1[0]!='\0' || pp2[0]!='\0' ) {
- ErrorMessage( MSG_SPLIT_POS_BTW_MERGEPTS );
+ if (!check)
+ ErrorMessage( MSG_SPLIT_POS_BTW_MERGEPTS );
return FALSE;
}
}
@@ -965,10 +1144,21 @@ foundSeg:
* 2b. Check that all paths from ep pass thru segInx0
*/
if ( !SplitTurnoutCheckEP( segInx0, epPos, splitTurnoutRoot, -splitTurnoutDir, xx->paths, xx->segs ) ) {
- ErrorMessage( MSG_SPLIT_PATH_NOT_UNIQUE );
+ if (!check)
+ ErrorMessage( MSG_SPLIT_PATH_NOT_UNIQUE );
return FALSE;
}
+ if (check) {
+ segProcDataSplit.getAngle.pos = pos;
+ SegProc( SEGPROC_GETANGLE, xx->segs+segInx0, &segProcDataSplit );
+ *outAngle = NormalizeAngle(segProcDataSplit.getAngle.angle+xx->angle);
+ *outPos = segProcDataSplit.getAngle.pos;
+ (*outPos).x += xx->orig.x;
+ (*outPos).y += xx->orig.y;
+ Rotate( outPos, xx->orig, xx->angle );
+ return TRUE;
+ }
/*
* 3. Split the found segment.
@@ -994,10 +1184,6 @@ foundSeg:
epPos = GetSegEndPt( &segProcDataSplit.split.newSeg[s1], s0, FALSE, &epAngle );
epAngle += 180.0;
}
-#ifdef LATER
- if ( segProcDataSplit.split.length[s1] <= minLength && splitTurnoutPath[1] == '\0' )
- return FALSE;
-#endif
/*
* 4. Map the old segments to new
@@ -1027,6 +1213,7 @@ foundSeg:
} else {
tempSegs(segIndexMap(segInx)-1) = xx->segs[segInx];
}
+ posCnt++;
}
}
@@ -1084,6 +1271,7 @@ foundSeg:
/*
* 7. Convert trailing segments to new tracks
*/
+ int trks = 0;
path = splitTurnoutPath;
if ( segProcDataSplit.split.length[s1] < minLength )
path += splitTurnoutDir;
@@ -1108,6 +1296,7 @@ foundSeg:
trk2 = segProcDataNewTrack.newTrack.trk;
ep2 = 1-epN;
}
+ ++trks;
path += splitTurnoutDir;
}
@@ -1133,6 +1322,16 @@ foundSeg:
return TRUE;
}
+static BOOL_T SplitTurnout(
+ track_p trk,
+ coOrd pos,
+ EPINX_T ep,
+ track_p *leftover,
+ EPINX_T * ep0,
+ EPINX_T * ep1 )
+{
+ return SplitTurnoutCheck(trk,pos,ep,leftover,ep0,ep1,FALSE,NULL,NULL);
+}
static BOOL_T CheckTraverseTurnout(
track_p trk,
@@ -1332,11 +1531,16 @@ static STATUS_T ModifyTurnout( track_p trk, wAction_t action, coOrd pos )
{
struct extraData *xx;
static EPINX_T ep;
+ static wBool_t curved;
DIST_T d;
xx = GetTrkExtraData(trk);
if ( xx->special == TOadjustable ) {
switch ( action ) {
+ case C_START:
+ ep = -1;
+ curved = FALSE;
+ return C_CONTINUE;
case C_DOWN:
ep = PickUnconnectedEndPoint( pos, trk );
if (ep == -1)
@@ -1347,7 +1551,7 @@ static STATUS_T ModifyTurnout( track_p trk, wAction_t action, coOrd pos )
tempSegs(0).u.l.pos[0] = GetTrkEndPos( trk, 1-ep );
tempSegs_da.cnt = 1;
InfoMessage( _("Drag to change track length") );
-
+ return C_CONTINUE;
case C_MOVE:
d = FindDistance( tempSegs(0).u.l.pos[0], pos );
if ( d < xx->u.adjustable.minD )
@@ -1359,28 +1563,148 @@ static STATUS_T ModifyTurnout( track_p trk, wAction_t action, coOrd pos )
if (action == C_MOVE)
InfoMessage( _("Length=%s"), FormatDistance( d ) );
return C_CONTINUE;
-
case C_UP:
d = FindDistance( tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1] );
ChangeAdjustableEndPt( trk, ep, d );
return C_TERMINATE;
-
default:
- ;
+ return C_CONTINUE;
}
}
- return ExtendStraightFromOrig( trk, action, pos );
+
+ return ExtendTrackFromOrig(trk, action, pos);
}
static BOOL_T GetParamsTurnout( int inx, track_p trk, coOrd pos, trackParams_t * params )
{
-
-
- params->type = curveTypeStraight; //TODO should check if last segment is actually straight
- if (inx == PARAMS_CORNU || inx == PARAMS_BEZIER) {
+ struct extraData *xx;
+ xx = GetTrkExtraData(trk);
+ params->type = curveTypeStraight;
+ if (inx == PARAMS_TURNOUT) {
+ params->len = 0.0;
+ int epCnt = GetTrkEndPtCnt(trk);
+ if (epCnt < 3) {
+ double d = 10000.0;
+ params->centroid = zero;
+ //calculate path length from endPt (either to end or to other end)
+ segProcData_t segProcData;
+ trkSeg_p seg;
+ int segInx;
+ int segEP;
+ trkSeg_p segPtr;
+ PATHPTR_T path,pathCurr;
+ //Find starting seg on path (nearest to end Pt)
+ for ( path = xx->pathCurr+strlen((char*)xx->pathCurr)+1; path[0] || path[1]; path++ ) {
+ if ( path[0] == 0 )
+ continue;
+ GetSegInxEP( path[0], &segInx, &segEP );
+ segPtr = xx->segs+segInx;
+ segProcData.distance.pos1 = pos;
+ SegProc( SEGPROC_DISTANCE, segPtr, &segProcData );
+ if ( segProcData.distance.dd < d ) {
+ d = segProcData.distance.dd;
+ pathCurr = path;
+ }
+ }
+ GetSegInxEP( pathCurr[0], &segInx, &segEP );
+ seg = xx->segs+segInx;
+ d = 0.0;
+ //Loop through segs on path from endPt adding
+ while (pathCurr[0]) {
+ GetSegInxEP( pathCurr[0], &segInx, &segEP );
+ seg = xx->segs+segInx;
+ SegProc(SEGPROC_LENGTH, seg, &segProcData );
+ d += segProcData.length.length;
+ pathCurr += segEP?1:-1;
+ }
+ params->len = d;
+ } else {
+ double x, y;
+ x = 0; y = 0;
+ for (int i=0;i<epCnt; i++) {
+ coOrd cpos = GetTrkEndPos(trk,i);
+ x += cpos.x;
+ y += cpos.y;
+ }
+ params->centroid.x = x/epCnt;
+ params->centroid.y = y/epCnt;
+ params->len = FindDistance(params->centroid,pos)*2; //Times two because it will be halved by track.c
+ }
+ return TRUE;
+ }
+ if ((inx == PARAMS_CORNU) || (inx == PARAMS_EXTEND)) {
+ params->type = curveTypeStraight;
params->arcR = 0.0;
params->arcP = zero;
+ params->ep = PickEndPoint(pos, trk);
+ params->circleOrHelix = FALSE;
+ if (params->ep>=0) {
+ params->angle = GetTrkEndAngle(trk,params->ep);
+ params->track_angle = params->angle + params->ep?0:180;
+ } else {
+ params->angle = params-> track_angle = 0;
+ return FALSE;
+ }
+ /* Use end radii if we have them */
+ //if (xx->special == TOcurved) {
+ // params->type = curveTypeCurve;
+ // params->arcR = fabs(DYNARR_N(DIST_T,xx->u.curved.radii,params->ep));
+ // if (params->arcR != 0.0)
+ // Translate(&params->arcP,pos,params->track_angle-90.0,params->arcR);
+ // else
+ // params->type = curveTypeStraight;
+ // return TRUE;
+ //}
+ /* Find the path we are closest to */
+ PATHPTR_T pathCurr = 0;
+ int segInx, subSegInx;
+ trkSeg_p segPtr;
+ double d = 10000;
+ struct extraData * xx = GetTrkExtraData(trk);
+ /* Get parms from that seg */
+ wBool_t back,negative;
+ coOrd segPos = pos;
+ Rotate(&segPos,xx->orig,-xx->angle);
+ segPos.x -= xx->orig.x;
+ segPos.y -= xx->orig.y;
+
+ params->track_angle = GetAngleSegs( //Find correct subSegment
+ xx->segCnt,xx->segs,
+ &segPos, &segInx, &d , &back, &subSegInx, &negative );
+ if (segInx ==- 1) return FALSE;
+ segPtr = xx->segs+segInx;
+ switch (segPtr->type) {
+ case SEG_BEZTRK:
+ if ( negative != back ) params->track_angle = NormalizeAngle(params->track_angle+180); //Bezier is in reverse
+ segPtr = xx->segs + segInx;
+ trkSeg_p subSegPtr = (trkSeg_p)segPtr->bezSegs.ptr+subSegInx;
+ if (subSegPtr->type == SEG_CRVTRK) {
+ params->type = curveTypeCurve;
+ params->arcR = fabs(subSegPtr->u.c.radius);
+ params->arcP = subSegPtr->u.c.center;
+ params->arcP.x += xx->orig.x;
+ params->arcP.y += xx->orig.y;
+ Rotate(&params->arcP,xx->orig,xx->angle);
+ params->arcA0 = subSegPtr->u.c.a0;
+ params->arcA1 = subSegPtr->u.c.a1;
+ }
+ return TRUE;
+ break;
+ case SEG_CRVTRK:
+ params->type = curveTypeCurve;
+ params->arcR = fabs(segPtr->u.c.radius);
+ params->arcP = segPtr->u.c.center;
+ params->arcP.x += xx->orig.x;
+ params->arcP.y += xx->orig.y;
+ Rotate(&params->arcP,xx->orig,xx->angle);
+ params->arcA0 = segPtr->u.c.a0;
+ params->arcA1 = segPtr->u.c.a1;
+ return TRUE;
+ break;
+ }
+ params->arcR = 0.0;
+ params->arcP = zero;
params->ep = PickEndPoint(pos,trk); //Nearest
if (params->ep>=0) {
params->angle = GetTrkEndAngle(trk,params->ep);
@@ -1391,7 +1715,10 @@ static BOOL_T GetParamsTurnout( int inx, track_p trk, coOrd pos, trackParams_t *
}
return TRUE;
}
- params->ep = PickUnconnectedEndPointSilent( pos, trk );
+ if ((inx == PARAMS_1ST_JOIN) || (inx == PARAMS_2ND_JOIN))
+ params->ep = PickEndPoint(pos, trk);
+ else
+ params->ep = PickUnconnectedEndPointSilent( pos, trk );
if (params->ep == -1)
return FALSE;
params->lineOrig = GetTrkEndPos(trk,params->ep);
@@ -1441,15 +1768,11 @@ static BOOL_T QueryTurnout( track_p trk, int query )
case Q_NOT_PLACE_FROGPOINTS:
case Q_HAS_DESC:
case Q_MODIFY_REDRAW_DONT_UNDRAW_TRACK:
- case Q_CAN_EXTEND:
return TRUE;
case Q_MODIFY_CAN_SPLIT:
- if (GetTrkEndPtCnt(trk) <= 2) { // allow splitting of simple track und buffers
- return TRUE ;
- }
- else {
- return FALSE;
- }
+ return TRUE;
+ case Q_IS_TURNOUT:
+ return TRUE;
case Q_CAN_PARALLEL:
if( GetTrkEndPtCnt( trk ) == 2 && fabs( GetTrkEndAngle( trk, 0 ) - GetTrkEndAngle( trk, 1 )) == 180.0 )
return TRUE;
@@ -1485,7 +1808,7 @@ static void DrawTurnoutPositionIndicator(
pos0 = MapPathPos( xx, path[1], 0 );
} else if ( path[1] == 0 ) {
pos1 = MapPathPos( xx, path[0], 1 );
- DrawLine( &mainD, pos0, pos1, drawTurnoutPositionWidth, color );
+ DrawLine( &tempD, pos0, pos1, drawTurnoutPositionWidth, color );
}
}
}
@@ -1505,7 +1828,6 @@ EXPORT void AdvanceTurnoutPositionIndicator(
if ( GetTrkType(trk) != T_TURNOUT )
AbortProg( "nextTurnoutPosition" );
- DrawTurnoutPositionIndicator( trk, wDrawColorWhite );
path = xx->pathCurr;
path += strlen((char *)path)+1;
while ( path[0] || path[1] )
@@ -1514,7 +1836,6 @@ EXPORT void AdvanceTurnoutPositionIndicator(
if ( *path == 0 )
path = xx->paths;
xx->pathCurr = path;
- DrawTurnoutPositionIndicator( trk, selectedColor );
if ( angleR == NULL || posR == NULL )
return;
trvtrk.trk = trk;
@@ -1548,9 +1869,11 @@ static BOOL_T MakeParallelTurnout(
track_p trk,
coOrd pos,
DIST_T sep,
+ DIST_T factor,
track_p * newTrk,
coOrd * p0R,
- coOrd * p1R )
+ coOrd * p1R,
+ BOOL_T track)
{
ANGLE_T angle = GetTrkEndAngle(trk,1);
struct extraData *xx, *yy;
@@ -1578,42 +1901,61 @@ static BOOL_T MakeParallelTurnout(
*/
if( newTrk ) {
- endPt = MyMalloc( GetTrkEndPtCnt( trk ) * sizeof( trkEndPt_t ));
- endPt[ 0 ].pos = endPts[ 0 ];
- endPt[ 0 ].angle = GetTrkEndAngle( trk, 0 );
- endPt[ 1 ].pos = endPts[ 1 ];
- endPt[ 1 ].angle = GetTrkEndAngle( trk, 1 );
-
- yy = GetTrkExtraData(trk);
-
- *newTrk = NewCompound( T_TURNOUT, 0, endPt[ 0 ].pos, endPt[ 0 ].angle + 90.0, yy->title, 2, endPt, yy->pathLen, (char *)yy->paths, yy->segCnt, yy->segs );
- xx = GetTrkExtraData(*newTrk);
- xx->customInfo = yy->customInfo;
-
- /* if (connection((int)curTurnoutEp).trk) {
- CopyAttributes( connection((int)curTurnoutEp).trk, newTrk );
- SetTrkScale( newTrk, curScaleInx );
- } */
- xx->special = yy->special;
- xx->u = yy->u;
-
- SetDescriptionOrig( *newTrk );
- xx->descriptionOff = zero;
- xx->descriptionSize = zero;
-
- SetTrkElev(*newTrk, GetTrkElevMode(trk), GetTrkElev(trk));
- GetTrkEndElev( trk, 0, &option, &d );
- SetTrkEndElev( *newTrk, 0, option, d, NULL );
- GetTrkEndElev( trk, 1, &option, &d );
- SetTrkEndElev( *newTrk, 1, option, d, NULL );
-
- MyFree( endPt );
+ if (track) {
+ endPt = MyMalloc( GetTrkEndPtCnt( trk ) * sizeof( trkEndPt_t ));
+ endPt[ 0 ].pos = endPts[ 0 ];
+ endPt[ 0 ].angle = GetTrkEndAngle( trk, 0 );
+ endPt[ 1 ].pos = endPts[ 1 ];
+ endPt[ 1 ].angle = GetTrkEndAngle( trk, 1 );
+
+ yy = GetTrkExtraData(trk);
+
+ DIST_T * radii = NULL;
+ if (yy->special == TOcurved) {
+ radii = MyMalloc(GetTrkEndPtCnt(trk) * sizeof(DIST_T));
+ for (int i=0;i<GetTrkEndPtCnt( trk );i++) {
+ radii[i] = DYNARR_N(DIST_T,yy->u.curved.radii,i);
+ }
+ }
+
+ *newTrk = NewCompound( T_TURNOUT, 0, endPt[ 0 ].pos, endPt[ 0 ].angle + 90.0, yy->title, 2, endPt, radii, yy->pathLen, (char *)yy->paths, yy->segCnt, yy->segs );
+ xx = GetTrkExtraData(*newTrk);
+ xx->customInfo = yy->customInfo;
+
+ /* if (connection((int)curTurnoutEp).trk) {
+ CopyAttributes( connection((int)curTurnoutEp).trk, newTrk );
+ SetTrkScale( newTrk, curScaleInx );
+ } */
+ xx->special = yy->special;
+
+ xx->u = yy->u;
+
+ SetDescriptionOrig( *newTrk );
+ xx->descriptionOff = zero;
+ xx->descriptionSize = zero;
+
+ SetTrkElev(*newTrk, GetTrkElevMode(trk), GetTrkElev(trk));
+ GetTrkEndElev( trk, 0, &option, &d );
+ SetTrkEndElev( *newTrk, 0, option, d, NULL );
+ GetTrkEndElev( trk, 1, &option, &d );
+ SetTrkEndElev( *newTrk, 1, option, d, NULL );
+
+ MyFree( endPt );
+ } else {
+ tempSegs(0).color = wDrawColorBlack;
+ tempSegs(0).width = 0;
+ tempSegs_da.cnt = 1;
+ tempSegs(0).type = track?SEG_STRTRK:SEG_STRLIN;
+ tempSegs(0).u.l.pos[0] = endPts[ 0 ];
+ tempSegs(0).u.l.pos[1] = endPts[ 1 ];
+ *newTrk = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) );
+ }
} else {
/* draw some temporary track while command is in process */
tempSegs(0).color = wDrawColorBlack;
tempSegs(0).width = 0;
tempSegs_da.cnt = 1;
- tempSegs(0).type = SEG_STRTRK;
+ tempSegs(0).type = track?SEG_STRTRK:SEG_STRLIN;
tempSegs(0).u.l.pos[0] = endPts[ 0 ];
tempSegs(0).u.l.pos[1] = endPts[ 1 ];
}
@@ -1625,8 +1967,26 @@ static BOOL_T MakeParallelTurnout(
return TRUE;
}
+static wBool_t CompareTurnout( 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( "Handlaid", xx1, xx2, handlaid )
+ REGRESS_CHECK_INT( "Flipped", xx1, xx2, flipped )
+ REGRESS_CHECK_INT( "Ungrouped", xx1, xx2, ungrouped )
+ REGRESS_CHECK_INT( "Split", xx1, xx2, split )
+ /* desc orig is not stable
+ REGRESS_CHECK_POS( "DescOrig", xx1, xx2, descriptionOrig ) */
+ REGRESS_CHECK_POS( "DescOff", xx1, xx2, descriptionOff )
+ REGRESS_CHECK_POS( "DescSize", xx1, xx2, descriptionSize )
+ return CompareSegs( xx1->segs, xx1->segCnt, xx1->segs, xx1->segCnt );
+}
+
static trackCmd_t turnoutCmds = {
- N_("TURNOUT "),
+ "TURNOUT ",
DrawTurnout,
DistanceCompound,
DescribeCompound,
@@ -1654,7 +2014,13 @@ static trackCmd_t turnoutCmds = {
DrawTurnoutPositionIndicator,
AdvanceTurnoutPositionIndicator,
CheckTraverseTurnout,
- MakeParallelTurnout };
+ MakeParallelTurnout,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CompareTurnout };
#ifdef TURNOUTCMD
@@ -1702,7 +2068,7 @@ static void TurnoutChange( long changes )
(changes&CHANGE_PARAMS) == 0 ) )
return;
lastScaleName = curScaleName;
- curTurnout = NULL;
+ //curTurnout = NULL;
curTurnoutEp = 0;
wControlShow( (wControl_p)turnoutListL, FALSE );
wListClear( turnoutListL );
@@ -1710,7 +2076,7 @@ static void TurnoutChange( long changes )
if (turnoutInfo_da.cnt <= 0)
return;
curTurnout = TurnoutAdd( LABEL_TABBED|LABEL_MANUF|LABEL_PARTNO|LABEL_DESCR, GetLayoutCurScale(), turnoutListL, &maxTurnoutDim, -1 );
- wListSetIndex( turnoutListL, 0 );
+ wListSetIndex( turnoutListL, turnoutInx );
wControlShow( (wControl_p)turnoutListL, TRUE );
if (curTurnout == NULL) {
wDrawClear( turnoutD.d );
@@ -1727,7 +2093,6 @@ static void TurnoutChange( long changes )
static void RedrawTurnout()
{
- coOrd p, s;
RescaleTurnout();
LOG( log_turnout, 2, ( "SelTurnout(%s)\n", (curTurnout?curTurnout->title:"<NULL>") ) )
@@ -1740,10 +2105,7 @@ LOG( log_turnout, 2, ( "SelTurnout(%s)\n", (curTurnout?curTurnout->title:"<NULL>
DrawSegs( &turnoutD, zero, 0.0, curTurnout->segs, curTurnout->segCnt,
trackGauge, wDrawColorBlack );
curTurnoutEp = 0;
- p.x = curTurnout->endPt[0].pos.x - trackGauge;
- p.y = curTurnout->endPt[0].pos.y - trackGauge;
- s.x = s.y = trackGauge*2.0 /*+ turnoutD.minSize*/;
- DrawHilight( &turnoutD, p, s );
+ HilightEndPt();
}
@@ -1796,7 +2158,9 @@ static void HilightEndPt( void )
p.x = curTurnout->endPt[(int)curTurnoutEp].pos.x - trackGauge;
p.y = curTurnout->endPt[(int)curTurnoutEp].pos.y - trackGauge;
s.x = s.y = trackGauge*2.0 /*+ turnoutD.minSize*/;
- DrawHilight( &turnoutD, p, s );
+ wDrawSetTempMode( turnoutD.d, TRUE );
+ DrawHilight( &turnoutD, p, s, FALSE );
+ wDrawSetTempMode( turnoutD.d, FALSE );
}
@@ -1806,7 +2170,6 @@ static void SelTurnoutEndPt(
{
if (action != C_DOWN) return;
- HilightEndPt();
curTurnoutEp = TOpickEndPoint( pos, curTurnout );
HilightEndPt();
LOG( log_turnout, 3, (" selected (action=%d) %ld\n", action, curTurnoutEp ) )
@@ -1831,13 +2194,27 @@ static struct {
coOrd rot0, rot1;
} Dto;
+static dynArr_t vector_da;
+#define vector(N) DYNARR_N( vector_t, vector_da, N )
typedef struct {
DIST_T off;
ANGLE_T angle;
EPINX_T ep;
+ track_p trk;
} vector_t;
+/*
+ * PlaceTurnoutTrial
+ *
+ * OUT Track - the Track that the Turnout is closest to
+ * IN/OUT Pos - Position of the Turnout end
+ * OUT Angle1 - The angle on the Track at the position
+ * OUT Angle2 - The angle of the Turnout (can be reversed from Angle 2 if the point is to the left)
+ * OUT Count - The number of connections
+ * OUT Max - The maximum distance between the ends and the connection points
+ * OUT Vector - An array of end points positions and offsets
+ */
static void PlaceTurnoutTrial(
track_p *trkR,
coOrd *posR,
@@ -1856,23 +2233,30 @@ static void PlaceTurnoutTrial(
ANGLE_T epAngle;
int i, connCnt = 0;
DIST_T d, maxD = 0;
+ coOrd testP = pos;
- if ( (*trkR = trk = OnTrack( &pos, FALSE, TRUE )) != NULL &&
+ if (*trkR && (GetTrkDistance(*trkR,&testP)<trackGauge)) { //Have Track, stick with it unless outside bounds
+ trk = *trkR;
+ pos = testP;
+ } else *trkR = trk = OnTrack( &pos, FALSE, TRUE );
+ if ( (trk) != NULL &&
!QueryTrack(trk,Q_CANNOT_PLACE_TURNOUT) &&
(ep0 = PickEndPoint( pos, trk )) >= 0 &&
! ( GetTrkType(trk) == T_TURNOUT &&
(trk1=GetTrkEndTrk(trk,ep0)) &&
GetTrkType(trk1) == T_TURNOUT) &&
- ! GetLayerFrozen(GetTrkLayer(trk)) ) {
+ ! GetLayerFrozen(GetTrkLayer(trk)) &&
+ ! GetLayerModule(GetTrkLayer(trk))) {
epPos = GetTrkEndPos( trk, ep0 );
d = FindDistance( pos, epPos );
if (d <= minLength)
pos = epPos;
- if ( GetTrkType(trk) == T_TURNOUT ) {
+ if ( GetTrkType(trk) == T_TURNOUT ) { //Only on the end
ep0 = ep1 = PickEndPoint( pos, trk );
angle = GetTrkEndAngle( trk, ep0 );
} else {
angle = GetAngleAtPoint( trk, pos, &ep0, &ep1 );
+ if (ep0==1) angle = NormalizeAngle(angle+180); //Reverse if curve backwards
}
angle = NormalizeAngle( angle + 180.0 );
if ( NormalizeAngle( FindAngle( pos, *posR ) - angle ) < 180.0 && ep0 != ep1 )
@@ -1883,18 +2267,21 @@ static void PlaceTurnoutTrial(
Rotate( &epPos, zero, angle );
pos.x -= epPos.x;
pos.y -= epPos.y;
- *posR = pos;
+ *posR = pos; //The place the Turnout end sits
LOG( log_turnout, 3, ( "placeTurnout T%d (%0.3f %0.3f) A%0.3f\n",
GetTrkIndex(trk), pos.x, pos.y, angle ) )
/*InfoMessage( "Turnout(%d): Angle=%0.3f", GetTrkIndex(trk), angle );*/
-
+ track_p ctrk = NULL;
+ int ccnt = 0;
+ DIST_T clarge = 100000;
for (i=0;i<curTurnout->endCnt;i++) {
posI = curTurnout->endPt[i].pos;
epPos = AddCoOrd( pos, posI, angle );
epAngle = NormalizeAngle( curTurnout->endPt[i].angle + angle );
conPos = epPos;
if ((trk = OnTrack(&conPos, FALSE, TRUE)) != NULL &&
- !GetLayerFrozen(GetTrkLayer(trk))) {
+ !GetLayerFrozen(GetTrkLayer(trk)) &&
+ !GetLayerModule(GetTrkLayer(trk))) {
v->off = FindDistance( epPos, conPos );
v->angle = FindAngle( epPos, conPos );
if ( GetTrkType(trk) == T_TURNOUT ) {
@@ -1902,14 +2289,28 @@ LOG( log_turnout, 3, ( "placeTurnout T%d (%0.3f %0.3f) A%0.3f\n",
aa = GetTrkEndAngle( trk, ep0 );
} else {
aa = GetAngleAtPoint( trk, conPos, &ep0, &ep1 );
+ if (ep0) //Backwards - so reverse
+ aa = NormalizeAngle(aa+180);
}
v->ep = i;
- aa = NormalizeAngle( aa - epAngle + connectAngle/2.0 );
- if ( IsClose(v->off) &&
- ( aa<connectAngle || ( aa>180.0 && aa<180.0+connectAngle ) ) &&
- ! ( GetTrkType(trk) == T_TURNOUT &&
+ aa = fabs(DifferenceBetweenAngles( aa, epAngle ));
+ if (QueryTrack(trk,Q_IS_CORNU) ) { //Make sure only two conns to each Cornu
+ int k=0;
+ v->trk = trk;
+ for (int j=0; j<i;j++) {
+ if (vector(j).trk == trk) k++;
+ }
+ if (k<2) { //Already two conns to this track
+ connCnt++;
+ if (v->off > maxD)
+ maxD = v->off;
+ v++;
+
+ }
+ } else if (( IsClose(v->off) && (aa<connectAngle || aa>180-connectAngle) &&
+ !( GetTrkType(trk) == T_TURNOUT &&
(trk1=GetTrkEndTrk(trk,ep0)) &&
- GetTrkType(trk1) == T_TURNOUT ) ) {
+ GetTrkType(trk1) == T_TURNOUT )) ) {
if (v->off > maxD)
maxD = v->off;
connCnt++;
@@ -1927,7 +2328,7 @@ LOG( log_turnout, 3, ( "placeTurnout T%d (%0.3f %0.3f) A%0.3f\n",
static void PlaceTurnout(
- coOrd pos )
+ coOrd pos, track_p trk )
{
coOrd p, pos1, pos2;
track_p trk1, trk2;
@@ -1936,21 +2337,24 @@ static void PlaceTurnout(
DIST_T d, maxD1, maxD2, sina;
vector_t *V, * maxV;
- static dynArr_t vector_da;
-#define vector(N) DYNARR_N( vector_t, vector_da, N )
+
pos1 = Dto.place = Dto.pos = pos;
+LOG( log_turnout, 1, ( "Place Turnout @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) );
if (curTurnoutEp >= (long)curTurnout->endCnt)
curTurnoutEp = 0;
DYNARR_SET( vector_t, vector_da, curTurnout->endCnt );
+ if (trk) trk1 = trk;
+ else trk1 = NULL;
PlaceTurnoutTrial( &trk1, &pos1, &a1, &a2, &connCnt1, &maxD1, &vector(0) );
if (connCnt1 > 0) {
- Dto.pos = pos1;
- Dto.trk = trk1;
- Dto.angle = a1;
- if ( (MyGetKeyState()&WKEY_SHIFT)==0 && connCnt1 > 1 && maxD1 >= 0.001 ) {
+ Dto.pos = pos1; //First track pos
+LOG( log_turnout, 1, ( " trial 1 @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) );
+ Dto.trk = trk1; //Track
+ Dto.angle = a1; //Angle of track to put down
+ if ( ((MyGetKeyState()&WKEY_SHIFT)==0) && (connCnt1 > 1) && (maxD1 >= 0.001) ) { //Adjust if not Shift
maxV = &vector(0);
- for ( i=1; i<connCnt1; i++ ) {
+ for ( i=1; i<connCnt1; i++ ) { //Ignore first point
V = &vector(i);
if ( V->off > maxV->off ) {
maxV = V;
@@ -1964,9 +2368,11 @@ static void PlaceTurnout(
if (NormalizeAngle( maxV->angle - a3) > 180)
d = -d;
Translate( &pos2, pos, a2, d );
+ trk2 = trk1;
PlaceTurnoutTrial( &trk2, &pos2, &a2, &a, &connCnt2, &maxD2, &vector(0) );
if ( connCnt2 >= connCnt1 && maxD2 < maxD1 ) {
Dto.pos = pos2;
+LOG( log_turnout, 1, ( " trial 2 @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) );
Dto.trk = trk2;
Dto.angle = a2;
maxD1 = maxD2;
@@ -1987,6 +2393,7 @@ static void PlaceTurnout(
Rotate( &p, zero, Dto.angle );
Dto.pos.x = pos.x - p.x;
Dto.pos.y = pos.y - p.y;
+LOG( log_turnout, 1, ( " final @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) );
}
}
@@ -2010,6 +2417,7 @@ static void AddTurnout( void )
#define connection(N) DYNARR_N( junk_t, connection_da, N )
#define leftover(N) DYNARR_N( junk_t, leftover_da, N )
BOOL_T visible;
+ BOOL_T no_ties;
BOOL_T noConnections;
coOrd p0, p1;
@@ -2020,8 +2428,6 @@ static void AddTurnout( void )
AbortProg( "addTurnout: bad cnt" );
}
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlack );
UndoStart( _("Place New Turnout"), "addTurnout" );
titleLen = strlen( curTurnout->title );
@@ -2041,13 +2447,29 @@ static void AddTurnout( void )
for (i=0;i<curTurnout->endCnt;i++) {
AuditTracks( "addTurnout [%d]", i );
connection(i).trk = leftover(i).trk = NULL;
+ connection(i).ep = -1;
+ leftover(i).ep = -1;
/* connect each endPt ... */
epPos = tempEndPts(i).pos;
- if ((trk = OnTrack(&epPos, FALSE, TRUE)) != NULL &&
+ if ((trk = OnTrack(&epPos, FALSE, TRUE)) != NULL && //Adjust epPos onto existing track
(!GetLayerFrozen(GetTrkLayer(trk))) &&
+ (!GetLayerModule(GetTrkLayer(trk))) &&
(!QueryTrack(trk,Q_CANNOT_PLACE_TURNOUT)) ) {
LOG( log_turnout, 1, ( "ep[%d] on T%d @(%0.3f %0.3f)\n",
i, GetTrkIndex(trk), epPos.x, epPos.y ) )
+ DIST_T dd = 10000.0;
+ int nearest = -1;
+ for (int j=0;j<curTurnout->endCnt;j++) {
+ if (j<i && (connection(j).trk == trk)) {
+ nearest = -1;
+ goto nextEnd; //Track already chosen in use
+ }
+ if (dd>FindDistance(epPos,tempEndPts(j).pos)) {
+ dd = FindDistance(epPos,tempEndPts(j).pos);
+ nearest = j;
+ }
+ }
+ if (nearest != i) continue; //Not this one
d = FindDistance( tempEndPts(i).pos, epPos );
if ( GetTrkType(trk) == T_TURNOUT ) {
ep0 = ep1 = PickEndPoint( epPos, trk );
@@ -2055,15 +2477,14 @@ LOG( log_turnout, 1, ( "ep[%d] on T%d @(%0.3f %0.3f)\n",
} else {
a = GetAngleAtPoint( trk, epPos, &ep0, &ep1 );
}
- aa = NormalizeAngle( a - tempEndPts(i).angle + connectAngle/2.0 );
- if ( IsClose(d) &&
- ( (ep0!=ep1 && aa<connectAngle) ||
- ( aa>180.0 && aa<180.0+connectAngle ) ) &&
- ! ( GetTrkType(trk) == T_TURNOUT &&
- (trk1=GetTrkEndTrk(trk,ep0)) &&
- GetTrkType(trk1) == T_TURNOUT ) ) {
- /* ... if they are close to a track and line up */
- if (aa<connectAngle) {
+ aa = fabs(DifferenceBetweenAngles( a , tempEndPts(i).angle));
+ if ((QueryTrack(trk,Q_IS_CORNU) && (d<trackGauge*2)) ||
+ (( IsClose(d) && ( ((ep0!=ep1) && (aa<=connectAngle)) || ((aa<=connectAngle) || (aa>180-connectAngle)) ) &&
+ ! ( GetTrkType(trk) == T_TURNOUT &&
+ (trk1=GetTrkEndTrk(trk,ep0)) &&
+ GetTrkType(trk1) == T_TURNOUT )) ) ) {
+ /* ... if they are close enough to a track and line up */
+ if (aa<90) {
epx = ep1;
epy = ep0;
} else {
@@ -2071,9 +2492,9 @@ LOG( log_turnout, 1, ( "ep[%d] on T%d @(%0.3f %0.3f)\n",
epy = ep1;
}
LOG( log_turnout, 1, ( " Attach! epx=%d\n", epx ) )
- if ( epx != epy &&
- (d=FindDistance(GetTrkEndPos(trk,epy), epPos)) < minLength &&
- (trk1=GetTrkEndTrk(trk,epy)) != NULL ) {
+ if ( (epx != epy) &&
+ ((d=FindDistance(GetTrkEndPos(trk,epy), epPos)) < minLength) &&
+ ((trk1=GetTrkEndTrk(trk,epy)) != NULL) ) {
epx = GetEndPtConnectedToMe( trk1, trk );
trk = trk1;
}
@@ -2085,22 +2506,21 @@ LOG( log_turnout, 1, ( " Attach! epx=%d\n", epx ) )
connection(i).trk = trk;
connection(i).ep = epx;
if (leftover(i).trk != NULL) {
- leftover(i).ep = PickEndPoint( epPos, leftover(i).trk );
+ leftover(i).ep = 1-epx;
/* did we already split this track? */
for (j=0;j<i;j++) {
- if ( leftover(j).trk == leftover(i).trk ) {
- leftover(i).trk = NULL;
- break;
- }
- if ( leftover(j).trk == connection(i).trk ) {
- /* yes. Remove the leftover piece */
+ if ( connection(i).trk == leftover(j).trk ) {
+ /* yes. Remove the latest leftover piece */
LOG( log_turnout, 1, ( " deleting leftover T%d\n",
GetTrkIndex(leftover(i).trk) ) )
- leftover(j).trk = NULL;
AuditTracks( "addTurnout [%d] before delete", i );
+ UndrawNewTrack( leftover(i).trk );
DeleteTrack( leftover(i).trk, FALSE );
AuditTracks( "addTurnout [%d] before delete", i );
leftover(i).trk = NULL;
+ leftover(i).ep = -1;
+ leftover(j).trk = NULL; //Forget this leftover
+ leftover(j).ep = -1;
break;
}
}
@@ -2108,13 +2528,15 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n",
}
}
}
+nextEnd:;
}
AuditTracks( "addTurnout after loop" );
/*
* copy data */
- newTrk = NewCompound( T_TURNOUT, 0, Dto.pos, Dto.angle, curTurnout->title, tempEndPts_da.cnt, &tempEndPts(0), curTurnout->pathLen, (char *)curTurnout->paths, curTurnout->segCnt, curTurnout->segs );
+
+ newTrk = NewCompound( T_TURNOUT, 0, Dto.pos, Dto.angle, curTurnout->title, tempEndPts_da.cnt, &tempEndPts(0), NULL, curTurnout->pathLen, (char *)curTurnout->paths, curTurnout->segCnt, curTurnout->segs );
xx = GetTrkExtraData(newTrk);
xx->customInfo = curTurnout->customInfo;
if (connection((int)curTurnoutEp).trk) {
@@ -2122,28 +2544,50 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n",
SetTrkScale( newTrk, GetLayoutCurScale());
}
xx->special = curTurnout->special;
+ if (xx->special == TOcurved) {
+ DYNARR_SET(DIST_T,xx->u.curved.radii,curTurnout->endCnt);
+ for (int i=0;i<curTurnout->endCnt;i++) {
+ DYNARR_N(DIST_T,xx->u.curved.radii,i) = DYNARR_N(DIST_T,curTurnout->u.curved.radii,i);
+ }
+ }
xx->u = curTurnout->u;
/* Make the connections */
visible = FALSE;
+ no_ties = FALSE;
noConnections = TRUE;
AuditTracks( "addTurnout T%d before connection", GetTrkIndex(newTrk) );
for (i=0;i<curTurnout->endCnt;i++) {
if ( connection(i).trk != NULL ) {
+ if (GetTrkEndTrk(connection(i).trk,connection(i).ep)) continue;
p0 = GetTrkEndPos( newTrk, i );
p1 = GetTrkEndPos( connection(i).trk, connection(i).ep );
ANGLE_T a0 = GetTrkEndAngle( newTrk, i);
ANGLE_T a1 = GetTrkEndAngle( connection(i).trk, connection(i).ep );
- ANGLE_T a = NormalizeAngle(a1-a0+180);
+ ANGLE_T a = fabs(DifferenceBetweenAngles(a0+180,a1));
d = FindDistance( p0, p1 );
- if ( d < connectDistance ) {
+ if (QueryTrack(connection(i).trk,Q_IS_CORNU)) {
+ ANGLE_T a = DifferenceBetweenAngles(FindAngle(p0,p1),a0);
+ if (IsClose(d) || fabs(a)<=90.0) {
+ trk1 = connection(i).trk;
+ ep0 = connection(i).ep;
+ if (GetTrkEndTrk(trk1,ep0)) continue;
+ DrawEndPt( &mainD, trk1, ep0, wDrawColorWhite );
+ trackParams_t params;
+ GetTrackParams( PARAMS_EXTEND, newTrk, GetTrkEndPos(newTrk,i), &params);
+ SetCornuEndPt(trk1, ep0, GetTrkEndPos(newTrk,i), params.arcP, NormalizeAngle(params.angle+180.0), params.arcR);
+ ConnectTracks(newTrk,i,trk1,ep0);
+ DrawEndPt( &mainD, trk1, ep0, wDrawColorBlack );
+ }
+ } else if ( d < connectDistance && (a<=connectAngle)) {
noConnections = FALSE;
trk1 = connection(i).trk;
ep0 = connection(i).ep;
DrawEndPt( &mainD, trk1, ep0, wDrawColorWhite );
ConnectTracks( newTrk, i, trk1, ep0 );
visible |= GetTrkVisible(trk1);
+ no_ties |= GetTrkNoTies(trk1);
DrawEndPt( &mainD, trk1, ep0, wDrawColorBlack );
}
}
@@ -2151,10 +2595,8 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n",
if (noConnections)
visible = TRUE;
SetTrkVisible( newTrk, visible);
-#ifdef LATER
- SetTrkScale( newTrk, curScaleInx );
- ComputeCompoundBoundingBox( newTrk );
-#endif
+ SetTrkNoTies(newTrk, no_ties);
+ SetTrkBridge(newTrk, FALSE);
AuditTracks( "addTurnout T%d before dealing with leftovers", GetTrkIndex(newTrk) );
/* deal with the leftovers */
@@ -2165,20 +2607,59 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n",
coOrd off;
DIST_T maxX;
track_p lt = leftover(i).trk;
- EPINX_T ep, le = leftover(i).ep;
- coOrd pos;
+ if (QueryTrack(lt,Q_IS_CORNU)) {
+ UndrawNewTrack(lt);
+ DeleteTrack(lt,TRUE);
+ leftover(i).trk = NULL;
+ continue;
+ }
+ EPINX_T ep, le = leftover(i).ep, nearest_ep =-1;
+ coOrd pos, nearest_pos = zero;
+ ANGLE_T nearest_angle = 0.0;
+ DIST_T nearest_radius = 0.0;
+ coOrd nearest_center = zero;
+ trackParams_t params;
maxX = 0.0;
+ DIST_T dd = 10000.0;
a = NormalizeAngle( GetTrkEndAngle(lt,le) + 180.0 );
for (ep=0; ep<curTurnout->endCnt; ep++) {
FindPos( &off, NULL, GetTrkEndPos(newTrk,ep), GetTrkEndPos(lt,le), a, 100000.0 );
+ pos = GetTrkEndPos(newTrk,ep);
+ DIST_T d = GetTrkDistance(lt, &pos);
+ if ((d<dd) && ( d<trackGauge/2)) {
+ ANGLE_T a = GetTrkEndAngle( lt, le );
+ ANGLE_T a2 = fabs(DifferenceBetweenAngles(GetTrkEndAngle(newTrk,ep),a+180));
+ if (GetTrkEndTrk(newTrk,ep)==NULL) { //Not if joined already
+ if (a2<90 && QueryTrack(lt,Q_IS_CORNU)) { //And Cornu in the right direction
+ GetTrackParams( PARAMS_EXTEND, newTrk, GetTrkEndPos(newTrk,ep), &params);
+ nearest_pos = GetTrkEndPos(newTrk,ep);
+ nearest_angle = NormalizeAngle(params.angle+180.0);
+ nearest_radius = params.arcR;
+ nearest_center = params.arcP;
+ nearest_ep = ep;
+ }
+ dd = d;
+ }
+ }
if (off.x > maxX)
maxX = off.x;
}
maxX += trackGauge;
pos = Dto.pos;
+ if (QueryTrack(lt,Q_IS_CORNU)) {
+ if (nearest_ep >=0) {
+ SetCornuEndPt(lt, le, nearest_pos, nearest_center, nearest_angle, nearest_radius);
+ ConnectTracks(newTrk,nearest_ep,lt,le);
+ } else {
+ UndrawNewTrack(lt);
+ DeleteTrack(lt,TRUE);
+ }
+ } else {
AuditTracks( "addTurnout T%d[%d] before trimming L%d[%d]", GetTrkIndex(newTrk), i, GetTrkIndex(lt), le );
- TrimTrack( lt, le, maxX );
+ wBool_t rc = TrimTrack( lt, le, maxX, nearest_pos, nearest_angle, nearest_radius, nearest_center );
AuditTracks( "addTurnout T%d[%d] after trimming L%d[%d]", GetTrkIndex(newTrk), i, GetTrkIndex(lt), le );
+
+ }
}
}
@@ -2198,17 +2679,59 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n",
static void TurnoutRotate( void * pangle )
{
+ if (Dto.state == 0)
+ return;
ANGLE_T angle = (ANGLE_T)(long)pangle;
- if (Dto.state == 1)
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlack );
- else
- Dto.pos = cmdMenuPos;
+ angle /= 1000.0;
+ Dto.pos = cmdMenuPos;
Rotate( &Dto.pos, cmdMenuPos, angle );
Dto.angle += angle;
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlack );
- Dto.state = 1;
+ TempRedraw(); // TurnoutRotate
+}
+
+static dynArr_t anchors_da;
+#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N)
+
+void static CreateArrowAnchor(coOrd pos,ANGLE_T a,DIST_T len) {
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).width = 0;
+ anchors(i).u.l.pos[0] = pos;
+ Translate(&anchors(i).u.l.pos[1],pos,NormalizeAngle(a+135),len);
+ anchors(i).color = wDrawColorBlue;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).width = 0;
+ anchors(i).u.l.pos[0] = pos;
+ Translate(&anchors(i).u.l.pos[1],pos,NormalizeAngle(a-135),len);
+ anchors(i).color = wDrawColorBlue;
+}
+
+void static CreateRotateAnchor(coOrd pos) {
+ DIST_T d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_CRVLIN;
+ anchors(i).width = 0.5;
+ anchors(i).u.c.center = pos;
+ anchors(i).u.c.a0 = 180.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).u.c.radius = d*2;
+ anchors(i).color = wDrawColorAqua;
+ coOrd head; //Arrows
+ for (int j=0;j<3;j++) {
+ Translate(&head,pos,j*120,d*2);
+ CreateArrowAnchor(head,NormalizeAngle((j*120)+90),d);
+ }
+}
+
+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);
}
/**
@@ -2230,71 +2753,71 @@ EXPORT STATUS_T CmdTurnoutAction(
#ifdef NEWROTATE
static ANGLE_T origAngle;
#endif
+
switch (action & 0xFF) {
case C_START:
Dto.state = 0;
Dto.trk = NULL;
Dto.angle = 0.0;
+ DYNARR_RESET(trkSeg_t,anchors_da);
return C_CONTINUE;
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (Dto.state && (MyGetKeyState()&WKEY_CTRL)) {
+ CreateRotateAnchor(pos);
+ } else {
+ CreateMoveAnchor(pos);
+ }
+ return C_CONTINUE;
+ break;
case C_DOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curTurnout == NULL ) return C_CONTINUE;
- if (Dto.state == 1) {
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
- }
- PlaceTurnout( pos );
+ PlaceTurnout( pos, NULL );
Dto.state = 1;
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
+ CreateMoveAnchor(pos);
return C_CONTINUE;
case C_MOVE:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curTurnout == NULL ) return C_CONTINUE;
if ( curTurnoutEp >= (long)curTurnout->endCnt )
curTurnoutEp = 0;
- if (Dto.state == 1) {
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
- } else {
- Dto.state = 1;
- }
- PlaceTurnout( pos );
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
+ Dto.state = 1;
+ PlaceTurnout( pos, Dto.trk );
+ CreateMoveAnchor(pos);
return C_CONTINUE;
case C_UP:
- InfoMessage( _("Left drag to move, right drag to rotate, press Space or Return to fix track in place or Esc to cancel") );
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ CreateMoveAnchor(pos);
+ InfoMessage( _("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel") );
return C_CONTINUE;
case C_RDOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curTurnout == NULL ) return C_CONTINUE;
- if (Dto.state == 1)
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
- else
- Dto.pos = pos;
+ if (Dto.state == 0) {
+ Dto.pos = pos; // If first, use pos, otherwise use current
+LOG( log_turnout, 1, ( "RDOWN @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) );
+ }
Dto.rot0 = Dto.rot1 = pos;
- DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack );
- Dto.state = 1;
+ CreateRotateAnchor(pos);
+ Dto.state = 2;
origPos = Dto.pos;
#ifdef NEWROTATE
origAngle = Dto.angle;
#else
Rotate( &origPos, Dto.rot0, -(Dto.angle + curTurnout->endPt[(int)curTurnoutEp].angle) );
#endif
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
validAngle = FALSE;
return C_CONTINUE;
case C_RMOVE:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curTurnout == NULL ) return C_CONTINUE;
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
- DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack );
Dto.rot1 = pos;
if ( FindDistance(Dto.rot0, Dto.rot1) > 0.1*mainD.scale ) {
angle = FindAngle( Dto.rot0, Dto.rot1 );
@@ -2303,6 +2826,7 @@ EXPORT STATUS_T CmdTurnoutAction(
validAngle = TRUE;
}
Dto.pos = origPos;
+LOG( log_turnout, 1, ( "RMOVE pre @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) );
#ifdef NEWROTATE
angle -= baseAngle;
Dto.angle = NormalizeAngle( origAngle + angle );
@@ -2311,36 +2835,33 @@ EXPORT STATUS_T CmdTurnoutAction(
Dto.angle = angle - curTurnout->endPt[(int)curTurnoutEp].angle;
#endif
Rotate( &Dto.pos, Dto.rot0, angle );
+LOG( log_turnout, 1, ( "RMOVE post @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) );
}
FormatCompoundTitle( listLabels, curTurnout->title );
InfoMessage( _("Angle = %0.3f (%s)"), PutAngle( NormalizeAngle(Dto.angle + 90.0) ), message );
- DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack );
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
+ Dto.state = 2;
+ CreateRotateAnchor(Dto.rot0);
return C_CONTINUE;
case C_RUP:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curTurnout == NULL ) return C_CONTINUE;
- DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack );
- InfoMessage( _("Left drag to move, right drag to rotate, press Space or Return to fix track in place or Esc to cancel") );
+ Dto.state = 1;
+ CreateMoveAnchor(pos);
+ InfoMessage( _("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel") );
return C_CONTINUE;
case C_LCLICK:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( curTurnout == NULL ) return C_CONTINUE;
if ( MyGetKeyState() & WKEY_SHIFT ) {
- if (Dto.state == 1)
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
angle = curTurnout->endPt[(int)curTurnoutEp].angle;
curTurnoutEp++;
if (curTurnoutEp >= (long)curTurnout->endCnt)
curTurnoutEp = 0;
if (Dto.trk == NULL)
Dto.angle = NormalizeAngle( Dto.angle + (angle - curTurnout->endPt[(int)curTurnoutEp].angle ) );
- PlaceTurnout( Dto.place );
- if (Dto.state == 1)
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
+ PlaceTurnout( Dto.place, Dto.trk );
} else {
CmdTurnoutAction( C_DOWN, pos );
CmdTurnoutAction( C_UP, pos );
@@ -2348,15 +2869,19 @@ EXPORT STATUS_T CmdTurnoutAction(
return C_CONTINUE;
case C_REDRAW:
- if (Dto.state)
+ if (Dto.state) {
DrawSegs( &tempD, Dto.pos, Dto.angle,
curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
+ }
+ if (anchors_da.cnt>0) {
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ }
+ if (Dto.state == 2)
+ DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack );
return C_CONTINUE;
case C_CANCEL:
- if (Dto.state)
- DrawSegs( &tempD, Dto.pos, Dto.angle,
- curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue );
+ DYNARR_RESET(trkSeg_t,anchors_da);
Dto.state = 0;
Dto.trk = NULL;
/*wHide( newTurn.reg.win );*/
@@ -2365,11 +2890,16 @@ EXPORT STATUS_T CmdTurnoutAction(
case C_TEXT:
if ((action>>8) != ' ')
return C_CONTINUE;
+ /*no break*/
case C_OK:
+ DYNARR_RESET(trkSeg_t,anchors_da);
AddTurnout();
+ Dto.state=0;
+ Dto.trk = NULL;
return C_TERMINATE;
case C_FINISH:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if (Dto.state != 0 && Dto.trk != NULL)
CmdTurnoutAction( C_OK, pos );
else
@@ -2377,10 +2907,7 @@ EXPORT STATUS_T CmdTurnoutAction(
return C_TERMINATE;
case C_CMDMENU:
- if ( turnoutPopupM == NULL ) {
- turnoutPopupM = MenuRegister( "Turnout Rotate" );
- AddRotateMenu( turnoutPopupM, TurnoutRotate );
- }
+ menuPos = pos;
wMenuPopupShow( turnoutPopupM );
return C_CONTINUE;
@@ -2403,7 +2930,7 @@ static STATUS_T CmdTurnout(
case C_START:
if (turnoutW == NULL) {
/* turnoutW = ParamCreateDialog( &turnoutPG, MakeWindowTitle("Turnout"), "Ok", , (paramActionCancelProc)Reset, TRUE, NULL, F_RESIZE|F_RECALLSIZE, TurnoutDlgUpdate ); */
- turnoutW = ParamCreateDialog( &turnoutPG, MakeWindowTitle(_("Turnout")), _("Close"), (paramActionOkProc)TurnoutOk, NULL, TRUE, NULL, F_RESIZE|F_RECALLSIZE|PD_F_ALT_CANCELLABEL, TurnoutDlgUpdate );
+ turnoutW = ParamCreateDialog( &turnoutPG, MakeWindowTitle(_("Turnout")), _("Close"), (paramActionOkProc)TurnoutOk, wHide, TRUE, NULL, F_RESIZE|F_RECALLSIZE|PD_F_ALT_CANCELLABEL, TurnoutDlgUpdate );
InitNewTurn( turnoutNewM );
}
/* ParamDialogOkActive( &turnoutPG, FALSE ); */
@@ -2425,12 +2952,21 @@ static STATUS_T CmdTurnout(
ParamGroupRecord( &turnoutPG );
return CmdTurnoutAction( action, pos );
+ case wActionMove:
+ return CmdTurnoutAction( action, pos );
+
case C_DOWN:
case C_RDOWN:
ParamDialogOkActive( &turnoutPG, TRUE );
if (hideTurnoutWindow)
wHide( turnoutW );
+ if (((action&0xFF) == C_DOWN) && (MyGetKeyState()&WKEY_CTRL))
+ return CmdTurnoutAction(C_RDOWN, pos); //Convert CTRL into Right
+ /*no break*/
case C_MOVE:
+ if (MyGetKeyState()&WKEY_CTRL)
+ return CmdTurnoutAction (C_RMOVE, pos);
+ /*no break*/
case C_RMOVE:
return CmdTurnoutAction( action, pos );
@@ -2438,11 +2974,13 @@ static STATUS_T CmdTurnout(
case C_RUP:
if (hideTurnoutWindow)
wShow( turnoutW );
- InfoMessage( _("Left drag to move, right drag to rotate, press Space or Return to fix track in place or Esc to cancel") );
+
+ InfoMessage( _("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel") );
+ if (((action&0xFF) == C_UP) && (MyGetKeyState()&WKEY_CTRL))
+ return CmdTurnoutAction (C_RUP, pos);
return CmdTurnoutAction( action, pos );
case C_LCLICK:
- HilightEndPt();
CmdTurnoutAction( action, pos );
HilightEndPt();
return C_CONTINUE;
@@ -2487,7 +3025,7 @@ static char * CmdTurnoutHotBarProc(
case HB_SELECT: /* new element is selected */
CmdTurnoutAction( C_FINISH, zero ); /* finish current operation */
curTurnout = to;
- DoCommandB( (void*)(intptr_t)turnoutHotBarCmdInx ); /* continue with new turnut / structure */
+ DoCommandB( (void*)(intptr_t)turnoutHotBarCmdInx ); /* continue with new turnout / structure */
return NULL;
case HB_LISTTITLE:
FormatCompoundTitle( listLabels, to->title );
@@ -2517,7 +3055,7 @@ EXPORT void AddHotBarTurnouts( void )
to->segCnt > 0 &&
CompatibleScale( TRUE, to->scaleInx, GetLayoutCurScale()) ) )
continue;
- AddHotBarElement( to->contentsLabel, to->size, to->orig, TRUE, to->barScale, to, CmdTurnoutHotBarProc );
+ AddHotBarElement( to->contentsLabel, to->size, to->orig, TRUE, FALSE, to->barScale, to, CmdTurnoutHotBarProc );
}
}
@@ -2537,31 +3075,61 @@ static STATUS_T CmdTurnoutHotBar(
switch (action & 0xFF) {
case C_START:
- TurnoutChange( CHANGE_PARAMS|CHANGE_SCALE );
+ //TurnoutChange( CHANGE_PARAMS|CHANGE_SCALE );
if (curTurnout == NULL) {
NoticeMessage2( 0, MSG_TURNOUT_NO_TURNOUT, _("Ok"), NULL );
return C_TERMINATE;
}
FormatCompoundTitle( listLabels|LABEL_DESCR, curTurnout->title );
InfoMessage( _("Place %s and draw into position"), message );
- ParamLoadControls( &turnoutPG );
- ParamGroupRecord( &turnoutPG );
+ wIndex_t listIndex = FindListItemByContext( turnoutListL, curTurnout );
+ if ( listIndex > 0 )
+ turnoutInx = listIndex;
+ ParamLoadControls( &turnoutPG );
+ ParamGroupRecord( &turnoutPG );
+ return CmdTurnoutAction( action, pos );
+
+ case wActionMove:
+ return CmdTurnoutAction( action, pos );
+
+ case C_DOWN:
+ if (MyGetKeyState()&WKEY_CTRL) {
+ return CmdTurnoutAction( C_RDOWN, pos );
+ }
+ /*no break*/
+ case C_RDOWN:
+ return CmdTurnoutAction( action, pos );
+
+ case C_MOVE:
+ if (MyGetKeyState()&WKEY_CTRL) {
+ return CmdTurnoutAction( C_RMOVE, pos );
+ }
+ /*no break*/
+ case C_RMOVE:
return CmdTurnoutAction( action, pos );
case C_UP:
+ if (MyGetKeyState()&WKEY_CTRL) {
+ return CmdTurnoutAction( C_RUP, pos );
+ }
+ /*no break*/
case C_RUP:
- InfoMessage( _("Left drag to move, right drag to rotate, press Space or Return to fix track in place or Esc to cancel") );
+ InfoMessage( _("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel") );
return CmdTurnoutAction( action, pos );
+ case C_REDRAW:
+ return CmdTurnoutAction( action, pos );
case C_TEXT:
if ((action>>8) != ' ')
return C_CONTINUE;
+ /* no break*/
case C_OK:
CmdTurnoutAction( action, pos );
return C_CONTINUE;
case C_CANCEL:
HotBarCancel();
+ /*no break*/
default:
return CmdTurnoutAction( action, pos );
}
@@ -2573,12 +3141,18 @@ static STATUS_T CmdTurnoutHotBar(
EXPORT void InitCmdTurnout( wMenu_p menu )
{
- AddMenuButton( menu, CmdTurnout, "cmdTurnout", _("Turnout"), wIconCreatePixMap(turnout_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_CMDMENU|IC_POPUP2, ACCL_TURNOUT, NULL );
- turnoutHotBarCmdInx = AddMenuButton( menu, CmdTurnoutHotBar, "cmdTurnoutHotBar", "", NULL, LEVEL0_50, IC_STICKY|IC_LCLICK|IC_CMDMENU|IC_POPUP2, 0, NULL );
+ AddMenuButton( menu, CmdTurnout, "cmdTurnout", _("Predefined Track"), wIconCreatePixMap(turnout_xpm), LEVEL0_50, IC_WANT_MOVE|IC_STICKY|IC_LCLICK|IC_CMDMENU|IC_POPUP2, ACCL_TURNOUT, NULL );
+ turnoutHotBarCmdInx = AddMenuButton( menu, CmdTurnoutHotBar, "cmdTurnoutHotBar", "", NULL, LEVEL0_50, IC_WANT_MOVE|IC_STICKY|IC_LCLICK|IC_CMDMENU|IC_POPUP2, 0, NULL );
RegisterChangeNotification( TurnoutChange );
ParamRegister( &turnoutPG );
log_turnout = LogFindIndex( "turnout" );
log_traverseTurnout = LogFindIndex( "traverseTurnout" );
+ log_suppressCheckPaths = LogFindIndex( "suppresscheckpaths" );
+ log_splitturnout = LogFindIndex( "splitturnout" );
+ if ( turnoutPopupM == NULL ) {
+ turnoutPopupM = MenuRegister( "Turnout Rotate" );
+ AddRotateMenu( turnoutPopupM, TurnoutRotate );
+ }
}
#endif
@@ -2587,7 +3161,7 @@ EXPORT void InitTrkTurnout( void )
T_TURNOUT = InitObject( &turnoutCmds );
/*InitDebug( "Turnout", &debugTurnout );*/
- AddParam( N_("TURNOUT "), ReadTurnoutParam );
+ AddParam( "TURNOUT ", ReadTurnoutParam);
}
#ifdef TEST
diff --git a/app/bin/cturntbl.c b/app/bin/cturntbl.c
index 9264572..f15aeff 100644
--- a/app/bin/cturntbl.c
+++ b/app/bin/cturntbl.c
@@ -162,9 +162,19 @@ static ANGLE_T ConstrainTurntableAngle( track_p trk, coOrd pos )
static EPINX_T NewTurntableEndPt( track_p trk, ANGLE_T angle )
{
struct extraData *xx = GetTrkExtraData(trk);
- EPINX_T ep = GetTrkEndPtCnt(trk);
+ EPINX_T ep = -1;
+ /* Reuse an old empty ep if it exists */
+ for (int i =0;i< GetTrkEndPtCnt(trk)-1;i++) {
+ if (GetTrkEndTrk(trk,i) == NULL) {
+ ep = i;
+ break;
+ }
+ }
+ if (ep == -1) {
+ ep = GetTrkEndPtCnt(trk);
+ SetTrkEndPtCnt( trk, ep+1 );
+ }
coOrd pos;
- SetTrkEndPtCnt( trk, ep+1 );
PointOnCircle( &pos, xx->pos, xx->radius, angle );
SetTrkEndPoint( trk, ep, pos, angle );
return ep;
@@ -182,7 +192,8 @@ static void DrawTurntable( track_p t, drawCmd_p d, wDrawColor color )
struct extraData *xx = GetTrkExtraData(t);
coOrd p0, p1;
EPINX_T ep;
- long widthOptions = DTS_TIES;
+ long widthOptions = DTS_LEFT|DTS_RIGHT;
+
if ( !ValidateTurntablePosition(t) ) {
p0.y = p1.y = xx->pos.y;
@@ -194,17 +205,13 @@ static void DrawTurntable( track_p t, drawCmd_p d, wDrawColor color )
}
if (color == wDrawColorBlack)
color = normalColor;
- DrawArc( d, xx->pos, xx->radius, 0.0, 360.0, 0, 0, color );
- if ( programMode != MODE_DESIGN )
- return;
- if ( (d->options&DC_QUICK) == 0 ) {
- DrawStraightTrack( d, p0, p1, FindAngle(p0,p1), t, GetTrkGauge(t), color, widthOptions );
- for ( ep=0; ep<GetTrkEndPtCnt(t); ep++ ) {
- if (GetTrkEndTrk(t,ep) != NULL )
- DrawEndPt( d, t, ep, color );
- }
+ DrawArc( d, xx->pos, xx->radius, 0.0, 360.0, 0, (color == wDrawColorPreviewSelected || color == wDrawColorPreviewUnselected)?3:0, color );
+ DrawStraightTrack( d, p0, p1, FindAngle(p0,p1), t, color, widthOptions );
+ for ( ep=0; ep<GetTrkEndPtCnt(t); ep++ ) {
+ if (GetTrkEndTrk(t,ep) != NULL )
+ DrawEndPt( d, t, ep, color );
}
- if ( ((d->funcs->options&wDrawOptTemp)==0) &&
+ if ( ((d->options&DC_SIMPLE)==0) &&
(labelWhen == 2 || (labelWhen == 1 && (d->options&DC_PRINT))) &&
labelScale >= d->scale ) {
LabelLengths( d, t, color );
@@ -218,9 +225,7 @@ static DIST_T DistanceTurntable( track_p trk, coOrd * p )
ANGLE_T a;
coOrd pos0, pos1;
- d = FindDistance( xx->pos, *p ) - xx->radius;
- if (d < 0.0)
- d = 0.0;
+ d = FindDistance( xx->pos, *p ) - xx->radius; //OK to be negative
if ( programMode == MODE_DESIGN ) {
a = FindAngle( xx->pos, *p );
Translate( p, xx->pos, a, d+xx->radius );
@@ -310,11 +315,11 @@ static BOOL_T WriteTurntable( track_p t, FILE * f )
xx->pos.x, xx->pos.y, xx->radius, xx->currEp )>0;
for (ep=0; ep<GetTrkEndPtCnt(t); ep++)
rc &= WriteEndPt( f, t, ep );
- rc &= fprintf(f, "\tEND\n")>0;
+ rc &= fprintf(f, "\t%s\n", END_SEGS)>0;
return rc;
}
-static void ReadTurntable( char * line )
+static BOOL_T ReadTurntable( char * line )
{
track_p trk;
struct extraData *xx;
@@ -333,12 +338,17 @@ static void ReadTurntable( char * line )
paramVersion<10?"dL000sdpffX":
"dL000sdpffd",
&index, &layer, scale, &visible, &p, &elev, &r, &currEp ))
- return;
+ return FALSE;
+ if ( !ReadSegs() )
+ return FALSE;
trk = NewTrack( index, T_TURNTABLE, 0, sizeof *xx );
- ReadSegs();
SetEndPts( trk, 0 );
xx = GetTrkExtraData(trk);
- SetTrkVisible(trk, visible);
+ if ( paramVersion < 3 ) {
+ SetTrkVisible(trk, visible!=0);
+ } else {
+ SetTrkVisible(trk, visible&2);
+ }
SetTrkScale(trk, LookupScale( scale ) );
SetTrkLayer(trk, layer);
xx->pos = p;
@@ -346,6 +356,7 @@ static void ReadTurntable( char * line )
xx->currEp = currEp;
xx->reverse = 0;
ComputeTurntableBoundingBox( trk );
+ return TRUE;
}
static void MoveTurntable( track_p trk, coOrd orig )
@@ -590,22 +601,32 @@ static STATUS_T ModifyTurntable( track_p trk, wAction_t action, coOrd pos )
}
EXPORT BOOL_T ConnectTurntableTracks(
- track_p trk1,
- EPINX_T ep1,
+ track_p trk1, /*The turntable */
+ EPINX_T ep1, /*Ignored */
track_p trk2,
EPINX_T ep2 ) {
coOrd center, pos;
DIST_T radius;
+ DIST_T dist;
+ if (!QueryTrack(trk1,Q_CAN_ADD_ENDPOINTS)) return FALSE;
TurntableGetCenter( trk1, &center, &radius );
pos = GetTrkEndPos(trk2,ep2);
ANGLE_T angle = FindAngle(center, GetTrkEndPos(trk2,ep2));
- if (NormalizeAngle(GetTrkEndAngle(trk2,ep2) + 180 - angle) < connectAngle) {
- if (FindDistance(center,pos)-radius < connectDistance) {
+ if (fabs(DifferenceBetweenAngles(GetTrkEndAngle(trk2,ep2),angle+180)) <= connectAngle) {
+ dist = FindDistance(center,pos)-radius;
+ if (dist < connectDistance) {
+ UndoStart( _("Connect Turntable Tracks"), "TurnTracks(T%d[%d] T%d[%d] D%0.3f A%0.3F )",
+ GetTrkIndex(trk1), ep1, GetTrkIndex(trk2), ep2, dist, angle );
+ UndoModify(trk1);
EPINX_T ep = NewTurntableEndPt(trk1,angle);
- ConnectTracks( trk1, ep, trk2, ep2 );
+ if (ConnectTracks( trk1, ep, trk2, ep2 )) {
+ UndoUndo();
+ return FALSE;
+ }
return TRUE;
}
}
+ ErrorMessage( MSG_TOO_FAR_APART_DIVERGE );
return FALSE;
}
@@ -688,13 +709,12 @@ static BOOL_T QueryTurntable( track_p trk, int query )
switch ( query ) {
case Q_REFRESH_JOIN_PARAMS_ON_MOVE:
case Q_CANNOT_PLACE_TURNOUT:
- case Q_DONT_DRAW_ENDPOINT:
+ case Q_NODRAWENDPT:
case Q_CAN_NEXT_POSITION:
case Q_ISTRACK:
case Q_NOT_PLACE_FROGPOINTS:
case Q_MODIFY_REDRAW_DONT_UNDRAW_TRACK:
case Q_CAN_ADD_ENDPOINTS:
- case Q_CAN_EXTEND:
return TRUE;
case Q_MODIFY_CAN_SPLIT:
case Q_CORNU_CAN_MODIFY:
@@ -727,7 +747,19 @@ static void DrawTurntablePositionIndicator( track_p trk, wDrawColor color )
pos0 = GetTrkEndPos(trk,xx->currEp);
angle = FindAngle( xx->pos, pos0 );
PointOnCircle( &pos1, xx->pos, xx->radius, angle+180.0 );
- DrawLine( &mainD, pos0, pos1, 3, color );
+ DrawLine( &tempD, pos0, pos1, 3, color );
+}
+
+static wBool_t CompareTurntable( track_cp trk1, track_cp trk2 )
+{
+ struct extraData *xx1 = GetTrkExtraData( trk1 );
+ struct extraData *xx2 = GetTrkExtraData( trk2 );
+ char * cp = message + strlen(message);
+ REGRESS_CHECK_POS( "Pos", xx1, xx2, pos )
+ REGRESS_CHECK_DIST( "Radius", xx1, xx2, radius )
+ REGRESS_CHECK_INT( "CurrEp", xx1, xx2, currEp )
+ REGRESS_CHECK_INT( "Reverse", xx1, xx2, reverse )
+ return TRUE;
}
static void AdvanceTurntablePositionIndicator(
@@ -744,7 +776,6 @@ static void AdvanceTurntablePositionIndicator(
angle1 = FindAngle( xx->pos, pos );
if ( !FindTurntableEndPt( trk, &angle1, &ep, &reverse ) )
return;
- DrawTurntablePositionIndicator( trk, wDrawColorWhite );
angle0 = GetTrkEndAngle(trk,xx->currEp);
if ( ep == xx->currEp ) {
Rotate( posR, xx->pos, 180.0 );
@@ -762,7 +793,6 @@ static void AdvanceTurntablePositionIndicator(
}
*angleR = angle1;
xx->currEp = ep;
- DrawTurntablePositionIndicator( trk, selectedColor );
}
@@ -794,13 +824,21 @@ static trackCmd_t turntableCmds = {
FlipTurntable,
DrawTurntablePositionIndicator,
AdvanceTurntablePositionIndicator,
- CheckTraverseTurntable };
+ CheckTraverseTurntable,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CompareTurntable };
static STATUS_T CmdTurntable( wAction_t action, coOrd pos )
{
track_p t;
static coOrd pos0;
+ static int state = 0;
wControl_p controls[2];
char * labels[1];
@@ -819,6 +857,7 @@ static STATUS_T CmdTurntable( wAction_t action, coOrd pos )
labels[0] = N_("Diameter");
InfoSubstituteControls( controls, labels );
/*InfoMessage( "Place Turntable");*/
+ state = 0;
return C_CONTINUE;
case C_DOWN:
@@ -833,18 +872,15 @@ static STATUS_T CmdTurntable( wAction_t action, coOrd pos )
InfoSubstituteControls( controls, labels );
ParamLoadData( &turntablePG );
pos0 = pos;
- DrawArc( &tempD, pos0, turntableDiameter/2.0, 0.0, 360.0, 0, 0, wDrawColorBlack );
+ state = 1;
return C_CONTINUE;
case C_MOVE:
- DrawArc( &tempD, pos0, turntableDiameter/2.0, 0.0, 360.0, 0, 0, wDrawColorBlack );
SnapPos( &pos );
pos0 = pos;
- DrawArc( &tempD, pos0, turntableDiameter/2.0, 0.0, 360.0, 0, 0, wDrawColorBlack );
return C_CONTINUE;
case C_UP:
- DrawArc( &tempD, pos0, turntableDiameter/2.0, 0.0, 360.0, 0, 0, wDrawColorBlack );
SnapPos( &pos );
UndoStart( _("Create Turntable"), "NewTurntable" );
t = NewTurntable( pos, turntableDiameter/2.0 );
@@ -853,10 +889,13 @@ static STATUS_T CmdTurntable( wAction_t action, coOrd pos )
InfoSubstituteControls( NULL, NULL );
sprintf( message, "turntable-diameter-%s", curScaleName );
wPrefSetFloat( "misc", message, turntableDiameter );
+ state = 0;
return C_TERMINATE;
case C_REDRAW:
- DrawArc( &tempD, pos0, turntableDiameter/2.0, 0.0, 360.0, 0, 0, wDrawColorBlack );
+ if ( state > 0 ) {
+ DrawArc( &tempD, pos0, turntableDiameter/2.0, 0.0, 360.0, 0, 0, wDrawColorBlack );
+ }
return C_CONTINUE;
case C_CANCEL:
@@ -874,7 +913,7 @@ static STATUS_T CmdTurntable( wAction_t action, coOrd pos )
EXPORT void InitCmdTurntable( wMenu_p menu )
{
- AddMenuButton( menu, CmdTurntable, "cmdTurntable", _("Turntable"), wIconCreatePixMap(turntbl_xpm), LEVEL0_50, IC_STICKY, ACCL_TURNTABLE, NULL );
+ AddMenuButton( menu, CmdTurntable, "cmdTurntable", _("Custom Turntable"), wIconCreatePixMap(turntbl_xpm), LEVEL0_50, IC_STICKY|IC_INITNOTSTICKY, ACCL_TURNTABLE, NULL );
}
diff --git a/app/bin/custom.c b/app/bin/custom.c
index 618a8ac..68a996b 100644
--- a/app/bin/custom.c
+++ b/app/bin/custom.c
@@ -53,7 +53,6 @@
#define product "xtrkcad"
#define PRODUCT "XTRKCAD"
#define Version VERSION
-#define KEYCODE "x"
#define PARAMKEY (0)
@@ -68,15 +67,18 @@ char * sTurnoutDesignerW = NULL;
char * sAboutProd = NULL;
char * sCustomF = product ".cus";
-char * sCheckPointF = product ".ckp";
-char * sCheckPoint1F = product ".ck1";
+char * sCheckPointF = product Version ".ckp";
+char * sCheckPoint1F = product Version ".ck1";
+
char * sClipboardF = product ".clp";
-char * sParamQF = product "." KEYCODE "tq";
+char * sParamQF = product ".xtq";
char * sUndoF = product ".und";
char * sAuditF = product ".aud";
char * sTipF = product ".tip";
char * sSourceFilePattern = NULL;
+char * sSaveFilePattern = NULL;
+char * sImageFilePattern = NULL;
char * sImportFilePattern = NULL;
char * sDXFFilePattern = NULL;
char * sRecordFilePattern = NULL;
@@ -137,13 +139,14 @@ BOOL_T Initialize( void )
InitTrkStruct();
InitTrkText();
InitTrkDraw();
- InitTrkNote();
+
InitTrkBlock();
InitTrkSwitchMotor();
InitTrkSignal();
InitTrkControl();
InitTrkSensor();
InitCarDlg();
+ InitCmdNote();
memset( message, 0, sizeof message );
@@ -156,7 +159,7 @@ BOOL_T Initialize( void )
void InitCustom( void )
{
- char buf[STR_SHORT_SIZE];
+ char *buf = malloc(1024);
/* Initialize some localized strings */
if (sTurnoutDesignerW == NULL)
@@ -171,38 +174,60 @@ void InitCustom( void )
}
if (sSourceFilePattern == NULL)
{
- sprintf(buf, _("%s Files|*.xtc"), Product);
+ sprintf(buf, _("All %s Files (*.xtc,*.xtce)|*.xtc;*.xtce|"
+ "%s Trackplan (*.xtc)|*.xtc|"
+ "%s Extended Trackplan (*.xtce)|*.xtce|"
+ "All Files (*)|*"),
+ Product,
+ Product,
+ Product );
sSourceFilePattern = strdup(buf);
}
+ if (sSaveFilePattern == NULL)
+ {
+ sprintf(buf, _("%s Trackplan (*.xtc)|*.xtc|"
+ "%s Extended Trackplan (*.xtce)|*.xtce|"
+ "All Files (*)|*"),
+ Product,
+ Product );
+ sSaveFilePattern = strdup(buf);
+ }
+ if (sImageFilePattern == NULL)
+ {
+ sprintf(buf,_("All Files (*)|*"));
+ sImageFilePattern = strdup(buf);
+ }
if (sImportFilePattern == NULL)
{
- sprintf(buf, _("%s Import Files|*.%sti"), Product, KEYCODE);
+ sprintf(buf, _("%s Import Files (*.xti)|*.xti"), Product );
sImportFilePattern = strdup(buf);
}
if (sDXFFilePattern == NULL)
{
- sDXFFilePattern = strdup(_("Data Exchange Format Files|*.dxf"));
+ sDXFFilePattern = strdup(_("Data Exchange Format Files (*.dxf)|*.dxf"));
}
if (sRecordFilePattern == NULL)
{
- sprintf(buf, _("%s Record Files|*.%str"), Product, KEYCODE);
+ sprintf(buf, _("%s Record Files (*.xtr)|*.xtr"), Product);
sRecordFilePattern = strdup(buf);
}
if (sNoteFilePattern == NULL)
{
- sprintf(buf, _("%s Note Files|*.not"), Product);
+ sprintf(buf, _("%s Note Files (*.not)|*.not"), Product);
sNoteFilePattern = strdup(buf);
}
if (sLogFilePattern == NULL)
{
- sprintf(buf, _("%s Log Files|*.log"), Product);
+ sprintf(buf, _("%s Log Files (*.log)|*.log"), Product);
sLogFilePattern = strdup(buf);
}
if (sPartsListFilePattern == NULL)
{
- sprintf(buf, _("%s PartsList Files|*.txt"), Product);
+ sprintf(buf, _("%s PartsList Files (*.txt)|*.txt"), Product);
sPartsListFilePattern = strdup(buf);
}
+
+ free(buf);
}
diff --git a/app/bin/custom.h b/app/bin/custom.h
index a4d335a..1c4f7b6 100644
--- a/app/bin/custom.h
+++ b/app/bin/custom.h
@@ -45,6 +45,7 @@
#define BG_COUNT (13)
#define BG_FILE (14)
#define BG_CONTROL (15)
+#define BG_EXPORTIMPORT (16)
#define BG_BIGGAP (1<<8)
extern int cmdGroup;
@@ -67,6 +68,8 @@ extern char * sUndoF;
extern char * sAuditF;
extern char * sSourceFilePattern;
+extern char * sSaveFilePattern;
+extern char * sImageFilePattern;
extern char * sImportFilePattern;
extern char * sDXFFilePattern;
extern char * sRecordFilePattern;
@@ -89,7 +92,7 @@ void InitTrkBezier( void );
void InitTrkDraw( void );
void InitTrkEase( void );
void InitTrkCornu( void );
-void InitTrkNote( void );
+void InitTrkNote(wMenu_p menu);
void InitTrkStraight( void );
void InitTrkStruct( void );
void InitTrkText( void );
@@ -103,6 +106,7 @@ void InitTrkControl ( void );
void InitTrkSensor ( void );
void InitCmdCurve( wMenu_p menu );
+void InitCmdCornu( wMenu_p menu);
void InitCmdHelix( wMenu_p menu );
void InitCmdDraw( wMenu_p menu );
void InitCmdElevation( wMenu_p menu );
@@ -114,11 +118,15 @@ void InitCmdMove( wMenu_p menu );
void InitCmdMoveDescription( wMenu_p menu );
void InitCmdStraight( wMenu_p menu );
void InitCmdDescribe( wMenu_p menu );
+void InitCmdDescribe2( wMenu_p menu );
void InitCmdSelect( wMenu_p menu );
-void InitCmdPan( wMenu_p menu);
+void InitCmdSelect2( wMenu_p menu );
+void InitCmdPan( wMenu_p menu );
+void InitCmdPan2( wMenu_p menu );
void InitCmdDelete( void );
void InitCmdSplit( wMenu_p menu );
void InitCmdTunnel( void );
+void InitCmdBridge( void );
void InitCmdRuler( wMenu_p menu );
void InitCmdParallel( wMenu_p menu );
@@ -128,7 +136,7 @@ void InitCmdTrain( wMenu_p menu );
void InitCmdTurnout( wMenu_p menu );
void InitCmdHandLaidTurnout( wMenu_p menu );
void InitCmdTurntable( wMenu_p menu );
-void InitCmdNote( wMenu_p menu );
+void InitCmdNote();
void InitCmdUndo( void );
void InitCmdStruct( wMenu_p menu );
void InitCmdAboveBelow( void );
diff --git a/app/bin/dbench.c b/app/bin/dbench.c
index 7e44713..c8d944f 100644
--- a/app/bin/dbench.c
+++ b/app/bin/dbench.c
@@ -257,7 +257,7 @@ EXPORT void DrawBench(
Translate( &pp[1], p0, a-90, width );
Translate( &pp[2], p1, a-90, width );
Translate( &pp[3], p1, a+90, width );
- DrawFillPoly( d, 4, pp, color1 );
+ DrawPoly( d, 4, pp, NULL, color1, 0, 1, 0);
/* Draw Outline */
if ( /*color1 != color2 &&*/
( ( d->scale < ((d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale) ) || /* big enough scale */
diff --git a/app/bin/dbitmap.c b/app/bin/dbitmap.c
index 340bad1..c45c7d0 100644
--- a/app/bin/dbitmap.c
+++ b/app/bin/dbitmap.c
@@ -112,7 +112,7 @@ static int SaveBitmapFile(
(wPos_t)(-bitmap_d.orig.y/bitmap_d.scale*bitmap_d.dpi),
(wPos_t)(mapD.size.x/bitmap_d.scale*bitmap_d.dpi),
(wPos_t)(mapD.size.y/bitmap_d.scale*bitmap_d.dpi) );
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
InfoMessage( _("Drawing tracks to BitMap") );
DrawSnapGrid( &bitmap_d, mapD.size, TRUE );
if ( (outputBitMapTogglesV&4) )
@@ -126,7 +126,7 @@ static int SaveBitmapFile(
return FALSE;
}
InfoMessage( "" );
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
wBitMapDelete( bitmap_d.d );
return TRUE;
}
@@ -211,11 +211,11 @@ static void OutputBitMapOk( void * junk )
wHide( outputBitMapW );
if (bitmap_fs == NULL)
bitmap_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("Save Bitmap"),
-#ifdef WINDOWS
- _("Bitmap files|*.bmp"),
-#else
- _("Bitmap files|*.xpm"),
-#endif
+//#ifdef WINDOWS
+// _("Bitmap files (*.bmp)|*.bmp"),
+//#else
+ _("Bitmap files (*.png)|*.png"),
+//#endif
SaveBitmapFile, NULL );
wFilSelect( bitmap_fs, GetCurrentPath( BITMAPPATHKEY ));
}
diff --git a/app/bin/dcar.c b/app/bin/dcar.c
index 2e1a790..e067e2b 100644
--- a/app/bin/dcar.c
+++ b/app/bin/dcar.c
@@ -47,6 +47,7 @@ static int log_carDlgState;
static int log_carDlgList;
static paramFloatRange_t r0_99999 = { 0, 99999, 80 };
+static paramFloatRange_t r9999_9999 = {-99999, 99999, 80};
static paramIntegerRange_t i1_999999999 = { 1, 999999999, 80, PDO_NORANGECHECK_HIGH };
static paramIntegerRange_t i1_9999 = { 1, 9999, 50 };
static char * isLocoLabels[] = { "", 0 };
@@ -85,6 +86,7 @@ typedef struct {
DIST_T carLength;
DIST_T carWidth;
DIST_T truckCenter;
+ DIST_T truckCenterOffset;
DIST_T coupledLength;
} carDim_t;
typedef struct {
@@ -381,10 +383,10 @@ static void CarProtoDrawTruck(
memcpy( p, truckOutline, sizeof truckOutline );
RescalePts( sizeof truckOutline/sizeof truckOutline[0], p, 1.0, width/56.5 );
- RescalePts( sizeof wheelOutline/sizeof wheelOutline[0], p, ratio, ratio );
- RotatePts( sizeof wheelOutline/sizeof wheelOutline[0], p, zero, angle );
+ RescalePts( sizeof truckOutline/sizeof truckOutline[0], p, ratio, ratio );
+ RotatePts( sizeof truckOutline/sizeof truckOutline[0], p, zero, angle );
MovePts( sizeof truckOutline/sizeof truckOutline[0], p, pos );
- DrawFillPoly( d, sizeof truckOutline/sizeof truckOutline[0], p, color );
+ DrawPoly( d, sizeof truckOutline/sizeof truckOutline[0], p, NULL, color, 0, 1, 0);
pp.x = -70/2;
pp.y = 0;
memcpy( p, wheelOutline, sizeof wheelOutline );
@@ -393,7 +395,7 @@ static void CarProtoDrawTruck(
RescalePts( sizeof wheelOutline/sizeof wheelOutline[0], p, ratio, ratio );
RotatePts( sizeof wheelOutline/sizeof wheelOutline[0], p, zero, angle );
MovePts( sizeof wheelOutline/sizeof wheelOutline[0], p, pos );
- DrawFillPoly( d, sizeof wheelOutline/sizeof wheelOutline[0], p, color );
+ DrawPoly( d, sizeof wheelOutline/sizeof wheelOutline[0], p, NULL, color, 0, 1, 0);
pp.x = 70/2;
memcpy( p, wheelOutline, sizeof wheelOutline );
RescalePts( sizeof wheelOutline/sizeof wheelOutline[0], p, 1.0, width/56.5 );
@@ -401,7 +403,7 @@ static void CarProtoDrawTruck(
RescalePts( sizeof wheelOutline/sizeof wheelOutline[0], p, ratio, ratio );
RotatePts( sizeof wheelOutline/sizeof wheelOutline[0], p, zero, angle );
MovePts( sizeof wheelOutline/sizeof wheelOutline[0], p, pos );
- DrawFillPoly( d, sizeof wheelOutline/sizeof wheelOutline[0], p, color );
+ DrawPoly( d, sizeof wheelOutline/sizeof wheelOutline[0], p, NULL, color, 0, 1, 0 );
}
@@ -438,22 +440,11 @@ static void CarProtoDrawCoupler(
pp.x = length-12.0;
pp.y = 0;
/* TODO - if length > 6 then draw Sills */
-#ifdef FUTURE
- if ( angle == 270.0 ) {
- pos.x -= (length-12.0);
- for ( inx=0; inx<sizeof couplerOutline/sizeof couplerOutline[0]; inx++ ) {
- p[inx].x = -p[inx].x;
- p[inx].y = -p[inx].y;
- }
- } else {
- pos.x += (length-12.0);
- }
-#endif
MovePts( sizeof couplerOutline/sizeof couplerOutline[0], p, pp );
RescalePts( sizeof couplerOutline/sizeof couplerOutline[0], p, ratio, ratio );
RotatePts( sizeof couplerOutline/sizeof couplerOutline[0], p, zero, angle-90.0 );
MovePts( sizeof couplerOutline/sizeof couplerOutline[0], p, pos );
- DrawFillPoly( d, sizeof couplerOutline/sizeof couplerOutline[0], p, color );
+ DrawPoly( d, sizeof couplerOutline/sizeof couplerOutline[0], p, NULL, color, 0, 1 ,0 );
}
@@ -496,7 +487,7 @@ static trkSeg_p carProtoSegPtr;
static int carProtoSegCnt;
-static coOrd dummyOutlineSegPts[5];
+static pts_t dummyOutlineSegPts[5];
static trkSeg_t dummyOutlineSegs;
static void CarProtoDlgCreateDummyOutline(
int * segCntP,
@@ -507,7 +498,7 @@ static void CarProtoDlgCreateDummyOutline(
wDrawColor color )
{
trkSeg_p segPtr;
- coOrd * pts;
+ pts_t * pts;
DIST_T length2;
*segCntP = 1;
@@ -523,22 +514,27 @@ static void CarProtoDlgCreateDummyOutline(
segPtr->u.p.angle = 0;
length2 = length;
if ( isLoco ) {
- pts->x = length;
- pts->y = width/2.0;
+ pts->pt.x = length;
+ pts->pt.y = width/2.0;
+ pts->pt_type = 0;
pts++;
length2 -= width/2.0;
}
- pts->x = length2;
- pts->y = 0.0;
+ pts->pt.x = length2;
+ pts->pt.y = 0.0;
+ pts->pt_type = 0;
pts++;
- pts->x = 0.0;
- pts->y = 0.0;
+ pts->pt.x = 0.0;
+ pts->pt.y = 0.0;
+ pts->pt_type = 0;
pts++;
- pts->x = 0.0;
- pts->y = width;
+ pts->pt.x = 0.0;
+ pts->pt.y = width;
+ pts->pt_type = 0;
pts++;
- pts->x = length2;
- pts->y = width;
+ pts->pt.x = length2;
+ pts->pt.y = width;
+ pts->pt_type = 0;
}
@@ -605,6 +601,26 @@ static carProto_p CarProtoLookup(
return proto;
}
+enum paramFileState
+GetCarProtoCompatibility(int paramFileIndex, SCALEINX_T scaleIndex)
+{
+ int i;
+ enum paramFileState ret = PARAMFILE_NOTUSABLE;
+ DIST_T ratio = GetScaleRatio(scaleIndex);
+
+ if (!IsParamValid(paramFileIndex)) {
+ return(PARAMFILE_UNLOADED);
+ }
+
+ for (i = 0; i < carProto_da.cnt; i++) {
+ carProto_t *carProto = carProto(i);
+ if (carProto->paramFileIndex == paramFileIndex) {
+ ret = PARAMFILE_FIT;
+ break;
+ }
+ }
+ return(ret);
+}
static carProto_p CarProtoNew(
carProto_p proto,
@@ -617,7 +633,7 @@ static carProto_p CarProtoNew(
trkSeg_p segPtr )
{
if ( proto == NULL ) {
- proto = LookupListElem( &carProto_da, desc, CmpCarProto, sizeof *(carProto_p)0 );
+ proto = LookupListElem( &carProto_da, desc, CmpCarProto, sizeof *proto );
if ( proto->desc != NULL ) {
if ( proto->paramFileIndex == PARAM_CUSTOM &&
paramFileIndex != PARAM_CUSTOM )
@@ -656,6 +672,45 @@ static void CarProtoDelete(
}
+/**
+* Delete all car prototype definitions that came from a specific parameter file.
+* Due to the way the definitions are loaded from file it is safe to
+* assume that they form a contiguous block in the array.
+*
+* \param [IN] fileIndex parameter file
+*/
+
+void
+DeleteCarProto(int fileIndex)
+{
+ int inx = 0;
+ int startInx = -1;
+ int cnt = 0;
+
+ // go to the start of the block
+ while (inx < carProto_da.cnt && carProto(inx)->paramFileIndex != fileIndex) {
+ startInx = inx++;
+ }
+
+ // delete them
+ for (; inx < carProto_da.cnt && carProto(inx)->paramFileIndex == fileIndex; inx++) {
+ carProto_t * cp = carProto(inx);
+ if (cp->paramFileIndex == fileIndex) {
+ CarProtoDelete(cp);
+ cnt++;
+ }
+ }
+
+ // copy down the rest of the list to fill the gap
+ startInx++;
+ while (inx < carProto_da.cnt) {
+ carProto(startInx++) = carProto(inx++);
+ }
+
+ // and reduce the actual number
+ carProto_da.cnt -= cnt;
+}
+
static BOOL_T CarProtoRead(
char * line )
{
@@ -663,10 +718,12 @@ static BOOL_T CarProtoRead(
long options;
long type;
carDim_t dim;
+ long longCenterOffset;
- if ( !GetArgs( line+9, "qllff00ff",
- &desc, &options, &type, &dim.carLength, &dim.carWidth, &dim.truckCenter, &dim.coupledLength ) )
+ if ( !GetArgs( line+9, "qllff0lff",
+ &desc, &options, &type, &dim.carLength, &dim.carWidth, &longCenterOffset, &dim.truckCenter, &dim.coupledLength ) )
return FALSE;
+ dim.truckCenterOffset = longCenterOffset/1000.0;
if ( !ReadSegs() )
return FALSE;
CarProtoNew( NULL, curParamFileIndex, desc, options, type, &dim, tempSegs_da.cnt, &tempSegs(0) );
@@ -685,8 +742,10 @@ static BOOL_T CarProtoWrite(
oldLocale = SaveLocale("C");
- rc &= fprintf( f, "CARPROTO \"%s\" %ld %ld %0.3f %0.3f 0 0 %0.3f %0.3f\n",
- PutTitle(proto->desc), proto->options, proto->type, proto->dim.carLength, proto->dim.carWidth, proto->dim.truckCenter, proto->dim.coupledLength )>0;
+ long longCenterOffset = (long)(proto->dim.truckCenterOffset*1000);
+
+ rc &= fprintf( f, "CARPROTO \"%s\" %ld %ld %0.3f %0.3f 0 %ld %0.3f %0.3f\n",
+ PutTitle(proto->desc), proto->options, proto->type, proto->dim.carLength, proto->dim.carWidth, longCenterOffset, proto->dim.truckCenter, proto->dim.coupledLength )>0;
rc &= WriteSegs( f, proto->segCnt, proto->segPtr );
RestoreLocale(oldLocale);
@@ -850,7 +909,7 @@ static roadnameMap_p LoadRoadnameList(
cmp_key.name = roadnameTab->ptr;
cmp_key.len = roadnameTab->len;
- roadnameMapP = LookupListElem( &roadnameMap_da, &cmp_key, Cmp_roadnameMap, sizeof *(roadnameMap_p)0 );
+ roadnameMapP = LookupListElem( &roadnameMap_da, &cmp_key, Cmp_roadnameMap, sizeof roadnameMapP );
if ( roadnameMapP->roadname == NULL ) {
roadnameMapP->roadname = TabStringDup(roadnameTab);
roadnameMapP->repmark = TabStringDup(repmarkTab);
@@ -957,29 +1016,29 @@ static carPart_p CarPartNew(
carPart_t cmp_key;
tabString_t tabs[7];
- TabStringExtract( title, 7, tabs );
- if ( TabStringCmp( "Undecorated", &tabs[T_MANUF] ) == 0 ||
- TabStringCmp( "Custom", &tabs[T_MANUF] ) == 0 ||
- tabs[T_PART].len == 0 )
+ TabStringExtract(title, 7, tabs);
+ if (TabStringCmp("Undecorated", &tabs[T_MANUF]) == 0 ||
+ TabStringCmp("Custom", &tabs[T_MANUF]) == 0 ||
+ tabs[T_PART].len == 0)
return NULL;
- if ( tabs[T_PROTO].len == 0 )
+ if (tabs[T_PROTO].len == 0)
return NULL;
- if ( partP == NULL ) {
- partP = CarPartFind( tabs[T_MANUF].ptr, tabs[T_MANUF].len, tabs[T_PART].ptr, tabs[T_PART].len, scaleInx );
- if ( partP != NULL &&
- partP->paramFileIndex == PARAM_CUSTOM &&
- paramFileIndex != PARAM_CUSTOM )
+ if (partP == NULL) {
+ partP = CarPartFind(tabs[T_MANUF].ptr, tabs[T_MANUF].len, tabs[T_PART].ptr, tabs[T_PART].len, scaleInx);
+ if (partP != NULL &&
+ partP->paramFileIndex == PARAM_CUSTOM &&
+ paramFileIndex != PARAM_CUSTOM)
return partP;
-LOG( log_carList, 2, ( "new car part: %s (%d) at %d\n", title, paramFileIndex, lookupListIndex ) )
+ LOG(log_carList, 2, ("new car part: %s (%d) at %d\n", title, paramFileIndex, lookupListIndex))
}
- if ( partP != NULL ) {
- CarPartUnlink( partP );
- if ( partP->title != NULL )
- MyFree( partP->title );
-LOG( log_carList, 2, ( "upd car part: %s (%d)\n", title, paramFileIndex ) )
+ if (partP != NULL) {
+ CarPartUnlink(partP);
+ if (partP->title != NULL)
+ MyFree(partP->title);
+ LOG(log_carList, 2, ("upd car part: %s (%d)\n", title, paramFileIndex))
}
- LoadRoadnameList( &tabs[T_ROADNAME], &tabs[T_REPMARK] );
- parentP = CarPartParentNew( tabs[T_MANUF].ptr, tabs[T_MANUF].len, tabs[T_PROTO].ptr, tabs[T_PROTO].len, scaleInx );
+ LoadRoadnameList(&tabs[T_ROADNAME], &tabs[T_REPMARK]);
+ parentP = CarPartParentNew(tabs[T_MANUF].ptr, tabs[T_MANUF].len, tabs[T_PROTO].ptr, tabs[T_PROTO].len, scaleInx);
cmp_key.title = title;
cmp_key.parent = parentP;
cmp_key.paramFileIndex = paramFileIndex;
@@ -989,13 +1048,13 @@ LOG( log_carList, 2, ( "upd car part: %s (%d)\n", title, paramFileIndex ) )
cmp_key.color = color;
cmp_key.partnoP = tabs[T_PART].ptr;
cmp_key.partnoL = tabs[T_PART].len;
- partP = (carPart_p)LookupListElem( &parentP->parts_da, &cmp_key, Cmp_part, sizeof * partP );
- if ( partP->title != NULL )
- MyFree( partP->title );
+ partP = (carPart_p)LookupListElem(&parentP->parts_da, &cmp_key, Cmp_part, sizeof * partP);
+ if (partP->title != NULL)
+ MyFree(partP->title);
*partP = cmp_key;
- sprintf( message, "\t\t%s", tabs[2].ptr );
- partP->title = MyStrdup( message );
- partP->partnoP = partP->title + 2+tabs[2].len+1;;
+ sprintf(message, "\t\t%s", tabs[2].ptr);
+ partP->title = MyStrdup(message);
+ partP->partnoP = partP->title + 2 + tabs[2].len + 1;;
partP->partnoL = tabs[T_PART].len;
return partP;
}
@@ -1012,6 +1071,32 @@ static void CarPartDelete(
MyFree( partP );
}
+/**
+* Delete all car part definitions that came from a specific parameter file.
+* CarParts are stored in DYNARR for the specific car model. These DYNARRs
+* are linked from CarPartParents, again DYNARRs. Thes parents are created
+* from part definition and only contain manufacturer and type information.
+*
+* \param [IN] fileIndex parameter file
+*/
+
+void
+DeleteCarPart(int fileIndex)
+{
+ int inxParent = 0;
+ int inx;
+
+ while (inxParent < carPartParent_da.cnt) {
+ inx = 0;
+ while (inx < carPartParent(inxParent)->parts_da.cnt) {
+ carPart_p part = carPart(carPartParent(inxParent), inx++);
+ if (part->paramFileIndex == fileIndex) {
+ CarPartDelete(part);
+ }
+ }
+ inxParent++;
+ }
+}
static BOOL_T CarPartRead(
char * line )
@@ -1022,10 +1107,12 @@ static BOOL_T CarPartRead(
char * title;
carDim_t dim;
long rgb;
+ long longCenterOffset;
- if ( !GetArgs( line+8, "sqllff00ffl",
- scale, &title, &options, &type, &dim.carLength, &dim.carWidth, &dim.truckCenter, &dim.coupledLength, &rgb ) )
+ if ( !GetArgs( line+8, "sqllff0lffl",
+ scale, &title, &options, &type, &dim.carLength, &dim.carWidth, &longCenterOffset, &dim.truckCenter, &dim.coupledLength, &rgb ) )
return FALSE;
+ dim.truckCenterOffset = longCenterOffset/1000.0;
CarPartNew( NULL, curParamFileIndex, LookupScale(scale), title, options, type, &dim, wDrawFindColor(rgb) );
MyFree( title );
return TRUE;
@@ -1181,6 +1268,42 @@ static carItem_p CarItemNew(
return item;
}
+/**
+ * Check the whether the parameter file has CARPARTS that are compatible
+ * with the current state. For CARPARTS only the exactly identical scale
+ * is accepted as compatible
+ *
+ * \param paramFileIndex IN the parameter file
+ * \param scaleIndex IN the scale to check against
+ * \return the compatibility state of the the
+ */
+enum paramFileState
+GetCarPartCompatibility(int paramFileIndex, SCALEINX_T scaleIndex)
+{
+ int i;
+ enum paramFileState ret = PARAMFILE_NOTUSABLE;
+ DIST_T ratio = GetScaleRatio(scaleIndex);
+
+ if (!IsParamValid(paramFileIndex)) {
+ return(PARAMFILE_UNLOADED);
+ }
+
+ for (i = 0; i < carPartParent_da.cnt && ret != PARAMFILE_FIT; i++) {
+ carPartParent_t *carPartParent = carPartParent( i );
+
+ if(GetScaleRatio(carPartParent->scale) == ratio ){
+ for(int j = 0; j < carPartParent->parts_da.cnt; j++ ){
+ carPart_t *carPart = carPart( carPartParent, j );
+
+ if (carPart->paramFileIndex == paramFileIndex) {
+ ret = PARAMFILE_FIT;
+ break;
+ }
+ }
+ }
+ }
+ return(ret);
+}
EXPORT BOOL_T CarItemRead(
char * line )
@@ -1197,45 +1320,43 @@ EXPORT BOOL_T CarItemRead(
long condition = 0;
long purchDate = 0;
long serviceDate = 0;
- int len, siz;
- static dynArr_t buffer_da;
carItem_p item;
char * cp;
wIndex_t layer;
coOrd pos;
ANGLE_T angle;
wIndex_t index;
+ long longCenterOffset;
+ char * sNote = NULL;
- if ( !GetArgs( line+4, "lsqll" "ff00ffl" "fflll000000c",
+ if ( !GetArgs( line+4, "lsqll" "ff0lffl" "fflll000000c",
&itemIndex, scale, &title, &options, &type,
- &dim.carLength, &dim.carWidth, &dim.truckCenter, &dim.coupledLength, &rgb,
+ &dim.carLength, &dim.carWidth, &longCenterOffset, &dim.truckCenter, &dim.coupledLength, &rgb,
&purchPrice, &currPrice, &condition, &purchDate, &serviceDate, &cp ) )
return FALSE;
- if ( (options&CAR_ITEM_HASNOTES) ) {
- DYNARR_SET( char, buffer_da, 0 );
- while ( (line=GetNextLine()) && strncmp( line, " END", 7 ) != 0 ) {
- siz = buffer_da.cnt;
- len = strlen( line );
- DYNARR_SET( char, buffer_da, siz+len+1 );
- memcpy( &((char*)buffer_da.ptr)[siz], line, len );
- ((char*)buffer_da.ptr)[siz+len] = '\n';
+ dim.truckCenterOffset = longCenterOffset/1000.0;
+ if ( paramVersion < 12 ) {
+ if ( (options&CAR_ITEM_HASNOTES) ) {
+ sNote = ReadMultilineText();
}
- DYNARR_APPEND( char, buffer_da, 1 );
- ((char*)buffer_da.ptr)[buffer_da.cnt-1] = 0;
+ } else {
+ if ( !GetArgs( cp, "qc", &sNote, &cp ) )
+ return FALSE;
}
item = CarItemNew( NULL, curParamFileIndex, itemIndex, LookupScale(scale), title,
options&(CAR_DESC_BITS|CAR_ITEM_BITS), type, &dim, wDrawFindColor(rgb),
purchPrice, currPrice, condition, purchDate, serviceDate );
if ( (options&CAR_ITEM_HASNOTES) )
- item->data.notes = MyStrdup( (char*)buffer_da.ptr );
+ item->data.notes = sNote;
MyFree(title);
if ( (options&CAR_ITEM_ONLAYOUT) ) {
if ( !GetArgs( cp, "dLpf",
&index, &layer, &pos, &angle ) )
return FALSE;
+ if ( !ReadSegs() )
+ return FALSE;
item->car = NewCar( index, item, pos, angle );
SetTrkLayer( item->car, layer );
- ReadSegs();
SetEndPts( item->car, 2 );
ComputeBoundingBox( item->car );
}
@@ -1253,6 +1374,7 @@ static BOOL_T CarItemWrite(
ANGLE_T angle;
BOOL_T rc = TRUE;
char *oldLocale = NULL;
+ long longCenterOffset = (long)(item->dim.truckCenterOffset*1000);
oldLocale = SaveLocale("C");
@@ -1260,25 +1382,27 @@ static BOOL_T CarItemWrite(
options |= CAR_ITEM_HASNOTES;
if ( layout && item->car && !IsTrackDeleted(item->car) )
options |= CAR_ITEM_ONLAYOUT;
- rc &= fprintf( f, "CAR %ld %s \"%s\" %ld %ld %0.3f %0.3f 0 0 %0.3f %0.3f %ld %0.3f %0.3f %ld %ld %ld 0 0 0 0 0 0",
+ rc &= fprintf( f, "CAR %ld %s \"%s\" %ld %ld %0.3f %0.3f 0 %ld %0.3f %0.3f %ld %0.3f %0.3f %ld %ld %ld 0 0 0 0 0 0",
item->index, GetScaleName(item->scaleInx), PutTitle(item->title),
options, item->type,
- item->dim.carLength, item->dim.carWidth, item->dim.truckCenter, item->dim.coupledLength, wDrawGetRGB(item->color),
+ item->dim.carLength, item->dim.carWidth, longCenterOffset, item->dim.truckCenter, item->dim.coupledLength, wDrawGetRGB(item->color),
item->data.purchPrice, item->data.currPrice, item->data.condition, item->data.purchDate, item->data.serviceDate )>0;
+ if ( (options&CAR_ITEM_HASNOTES) ) {
+ char * sEscapedNote = ConvertToEscapedText( item->data.notes );
+ rc &= fprintf( f, " \"%s\"", sEscapedNote )>0;
+ MyFree( sEscapedNote );
+ } else {
+ rc &= fprintf( f, " \"\"" ) > 0;
+ }
if ( ( options&CAR_ITEM_ONLAYOUT) ) {
CarGetPos( item->car, &pos, &angle );
- rc &= fprintf( f, " %d %u %0.3f %0.3f %0.3f",
+ rc &= fprintf( f, " %d %u %0.3f %0.3f %0.3f\n",
GetTrkIndex(item->car), GetTrkLayer(item->car), pos.x, pos.y, angle )>0;
- }
- rc &= fprintf( f, "\n" )>0;
- if ( (options&CAR_ITEM_HASNOTES) ) {
- rc &= fprintf( f, "%s\n", item->data.notes )>0;
- rc &= fprintf( f, " END\n" )>0;
- }
- if ( (options&CAR_ITEM_ONLAYOUT) ) {
rc &= WriteEndPt( f, item->car, 0 );
rc &= WriteEndPt( f, item->car, 1 );
- rc &= fprintf( f, "\tEND\n" )>0;
+ rc &= fprintf( f, "\t%s\n", END_SEGS )>0;
+ } else {
+ rc &= fprintf( f, "\n" )>0;
}
RestoreLocale(oldLocale);
@@ -1658,33 +1782,76 @@ EXPORT void AddHotBarCarDesc( void )
orig = zero;
size.x = item1->dim.carLength;
size.y = item1->dim.carWidth;
- AddHotBarElement( FormatCarTitle( item1, carHotbarContents[carHotbarModeInx] ), size, orig, FALSE, (60.0*12.0/curScaleRatio), (void*)(intptr_t)inx, CarItemHotbarProc );
+ AddHotBarElement( FormatCarTitle( item1, carHotbarContents[carHotbarModeInx] ), size, orig, FALSE, FALSE, (60.0*12.0/curScaleRatio), (void*)(intptr_t)inx, CarItemHotbarProc );
}
item0 = item1;
}
}
-EXPORT coOrd CarItemFindCouplerMountPoint(
+EXPORT void CarItemFindCouplerMountPoint(
carItem_p item,
- traverseTrack_t trvTrk,
- int dir )
+ traverseTrack_t trvTrk0,
+ coOrd pos[2] )
{
- DIST_T couplerOffset;
- coOrd pos;
+ // We assume the coupler pivot is 'couplerLength' before the end of the car
+ DIST_T couplerLength = (item->dim.coupledLength - item->dim.carLength) / 2.0;
+ if ( IsClose(item->dim.truckCenter) ) {
+ // Single truck/bogie
+ DIST_T d = item->dim.carLength/2.0 - couplerLength;
+ Translate( &pos[0], trvTrk0.pos, trvTrk0.angle, d + item->dim.truckCenterOffset );
+ FlipTraverseTrack( &trvTrk0 );
+ Translate( &pos[1], trvTrk0.pos, trvTrk0.angle, d - item->dim.truckCenterOffset );
+ return;
+ }
+ // Find the pos of the 2 trucks
+ // Note this is a slight simplification, we should use the car center, not the on-track position
+ traverseTrack_t trvTrk1 = trvTrk0;
+ TraverseTrack2( &trvTrk0, item->dim.truckCenter/2.0 + item->dim.truckCenterOffset );
+ FlipTraverseTrack( & trvTrk1 );
+ TraverseTrack2( &trvTrk1, item->dim.truckCenter/2.0 - item->dim.truckCenterOffset );
+
+ // Get the angle to translate from the truck
+ ANGLE_T angle[2];
+ if ( trvTrk0.trk == NULL || (item->options&CAR_DESC_COUPLER_MODE_BODY)!=0 ) {
+ // Body mount couplers
+ // Angle is same as the car
+ angle[0] = FindAngle( trvTrk1.pos, trvTrk0.pos );
+ angle[1] = NormalizeAngle( angle[0]+180.0 );
+ } else {
+ // Truck mounted couplers
+ // Angle is same as the trucks
+ angle[0] = trvTrk0.angle;
+ angle[1] = trvTrk1.angle;
+ }
- if ( dir )
- FlipTraverseTrack( &trvTrk );
+ // Get the distance to translate
+ DIST_T d[2];
+ d[0] = item->dim.carLength/2.0 - couplerLength - ( item->dim.truckCenter/2.0 + item->dim.truckCenterOffset );
+ d[1] = item->dim.carLength/2.0 - couplerLength - ( item->dim.truckCenter/2.0 - item->dim.truckCenterOffset );
+
+ // And translate
+ Translate( &pos[0], trvTrk0.pos, angle[0], d[0] );
+ Translate( &pos[1], trvTrk1.pos, angle[1], d[1] );
+
+#ifdef LATER
if ( trvTrk.trk == NULL || (item->options&CAR_DESC_COUPLER_MODE_BODY)!=0 ) {
- couplerOffset = (item->dim.carLength-(item->dim.coupledLength-item->dim.carLength))/2.0;
+ couplerOffset = item->dim.coupledLength/2.0;
Translate( &pos, trvTrk.pos, trvTrk.angle, couplerOffset );
} else {
- TraverseTrack2( &trvTrk, item->dim.truckCenter/2.0 );
+ if (dir)
+ TraverseTrack2( &trvTrk, item->dim.truckCenter/2.0-item->dim.truckCenterOffset );
+ else
+ TraverseTrack2( &trvTrk, item->dim.truckCenter/2.0+item->dim.truckCenterOffset );
/*Translate( &pos1, trvTrk.pos, trvTrk.angle, item->dim.truckCenter/2.0 );*/
- couplerOffset = item->dim.carLength - (item->dim.truckCenter+item->dim.coupledLength)/2.0;
+ couplerOffset = (item->dim.coupledLength-item->dim.truckCenter)/2.0;
+ if (dir)
+ couplerOffset = couplerOffset + item->dim.truckCenterOffset;
+ else
+ couplerOffset = couplerOffset - item->dim.truckCenterOffset;
Translate( &pos, trvTrk.pos, trvTrk.angle, couplerOffset );
}
- return pos;
+#endif
}
@@ -1710,6 +1877,11 @@ static DIST_T CarItemTruckCenter(
return item->dim.truckCenter;
}
+static DIST_T CarItemTruckOffset(
+ carItem_p item ) {
+ return item->dim.truckCenterOffset;
+}
+
EXPORT DIST_T CarItemCoupledLength(
carItem_p item )
@@ -1759,6 +1931,22 @@ static DIST_T CarItemCouplerLength(
return item->dim.coupledLength-item->dim.carLength;
}
+EXPORT BOOL_T StoreCarItem (carItem_p item, void **data,long *len) {
+
+ *data = item;
+ *len = sizeof (carItem_t);
+ return TRUE;
+
+}
+
+EXPORT BOOL_T ReplayCarItem(carItem_p item, void *data,long len) {
+
+
+ item->pos = ((carItem_t *)data)->pos;
+ item->angle = ((carItem_t *)data)->angle;
+ return TRUE;
+
+}
EXPORT void CarItemPlace(
carItem_p item,
@@ -1766,18 +1954,37 @@ EXPORT void CarItemPlace(
DIST_T * dists )
{
DIST_T dist;
+ DIST_T offset;
traverseTrack_t trks[2];
dist = CarItemTruckCenter(item)/2.0;
+ offset = CarItemTruckOffset(item); //Offset is the amount the truck centers are displaced
trks[0] = trks[1] = *trvTrk;
- TraverseTrack2( &trks[0], dist );
- TraverseTrack2( &trks[1], -dist );
+ TraverseTrack2( &trks[0], dist+offset );
+ TraverseTrack2( &trks[1], -dist+offset );
+ item->angle = FindAngle( trks[1].pos, trks[0].pos );
item->pos.x = (trks[0].pos.x+trks[1].pos.x)/2.0;
item->pos.y = (trks[0].pos.y+trks[1].pos.y)/2.0;
- item->angle = FindAngle( trks[1].pos, trks[0].pos );
+ Translate(&item->pos,item->pos,item->angle, -offset); // Put truck center back along line by offset
dists[0] = dists[1] = CarItemCoupledLength(item)/2.0;
}
+static dynArr_t clearance;
+
+static void ClearClearancePoints(void) {
+ //DYNARR_RESET(trkSeg_t,clearance);
+}
+
+static void CreateClearancePoint(coOrd pos, int position) {
+ //DYNARR_APPEND(trkSeg_t,clearance,1);
+
+}
+
+static void DrawClearancePoints(void) {
+ //for (int i=0;i<clearance.cnt;i++) {
+ //DrawSegs();
+ //}
+}
static int drawCarTrucks = 0;
@@ -1787,14 +1994,16 @@ EXPORT void CarItemDraw(
wDrawColor color,
int direction,
BOOL_T locoIsMaster,
- vector_t *coupler )
+ vector_t *coupler,
+ BOOL_T pencils,
+ track_p traverse)
{
coOrd size, pos, pos2;
DIST_T length;
wFont_p fp;
wDrawWidth width;
trkSeg_t simpleSegs[1];
- coOrd simplePts[4];
+ pts_t simplePts[4];
int dir;
DIST_T rad;
static int couplerLineWidth = 3;
@@ -1802,10 +2011,14 @@ EXPORT void CarItemDraw(
CarItemSize( item, &size );
if ( d->scale >= ((d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale) ) {
- simplePts[0].x = simplePts[3].x = -size.x/2.0;
- simplePts[1].x = simplePts[2].x = size.x/2.0;
- simplePts[0].y = simplePts[1].y = -size.y/2.0;
- simplePts[2].y = simplePts[3].y = size.y/2.0;
+ simplePts[0].pt.x = simplePts[3].pt.x = -size.x/2.0;
+ simplePts[1].pt.x = simplePts[2].pt.x = size.x/2.0;
+ simplePts[0].pt.y = simplePts[1].pt.y = -size.y/2.0;
+ simplePts[2].pt.y = simplePts[3].pt.y = size.y/2.0;
+ simplePts[0].pt_type = 0;
+ simplePts[1].pt_type = 0;
+ simplePts[2].pt_type = 0;
+ simplePts[3].pt_type = 0;
simpleSegs[0].type = SEG_FILPOLY;
simpleSegs[0].color = item->color;
simpleSegs[0].width = 0;
@@ -1822,11 +2035,47 @@ EXPORT void CarItemDraw(
DrawSegs( d, pos, item->angle-90.0, item->segPtr, item->segCnt, 0.0, color );
}
+ if (pencils) {
+ ClearClearancePoints();
+ coOrd posm1,posm2;
+ Translate( &posm1, item->pos, item->angle-90, -size.y/2.0 );
+ Translate( &posm2, item->pos, item->angle+90, -size.y/2.0 );
+ coOrd posm1a = posm1;
+ coOrd posm2a = posm2;
+ if (GetTrkDistance(traverse, &posm1a)>GetTrkDistance(traverse, &posm2a))
+ CreateClearancePoint(posm1,1);
+ else
+ CreateClearancePoint(posm2,2);
+
+ coOrd pose1,pose2;
+ Translate( &pose1, item->pos, item->angle, size.x/2.0 );
+ Translate( &pose1, pose1, item->angle-90, -size.y/2.0 );
+ Translate( &pose2, pose1, item->angle+90, -size.y );
+
+ traverseTrack_t traverseTrk;
+ traverseTrk.trk = traverse;
+ traverseTrk.pos = item->pos;
+ traverseTrk.angle = item->angle;
+ TraverseTrack2(&traverseTrk,size.x/2.0);
+ coOrd pose1a = pose1;
+ coOrd pose2a = pose2;
+ if (GetTrkDistance(traverseTrk.trk, &pose1a)>GetTrkDistance(traverseTrk.trk, &pose2a))
+ CreateClearancePoint(pose1,3);
+ else
+ CreateClearancePoint(pose2,4);
+
+
+ DrawClearancePoints();
+
+ }
+
if ( drawCarTrucks ) {
+
length = item->dim.truckCenter/2.0;
- Translate( &pos, item->pos, item->angle, length );
+ double offset = CarItemTruckOffset(item);
+ Translate( &pos, item->pos, item->angle, length+(direction?offset:-offset) );
DrawArc( d, pos, trackGauge/2.0, 0.0, 360.0, FALSE, 0, color );
- Translate( &pos, item->pos, item->angle+180, length );
+ Translate( &pos, item->pos, item->angle+180, length+(direction?-offset:offset) );
DrawArc( d, pos, trackGauge/2.0, 0.0, 360.0, FALSE, 0, color );
}
@@ -1925,7 +2174,7 @@ static char *dispmodeLabels[] = { N_("Information"), N_("Customize"), NULL };
static drawCmd_t carDlgD = {
NULL,
&screenDrawFuncs,
- DC_NOCLIP,
+ 0,
1.0,
0.0,
{ 0, 0 }, { 0, 0 },
@@ -1984,16 +2233,18 @@ static paramData_t carDlgPLs[] = {
{ PD_FLOAT, &carDlgDim.carWidth, "carWidth", PDO_DIM|PDO_NOPREF|PDO_DLGWIDE|PDO_DLGHORZ, &r0_99999, N_("Width") },
#define I_CD_TRKCENTER (B+6)
{ PD_FLOAT, &carDlgDim.truckCenter, "trkCenter", PDO_DIM|PDO_NOPREF, &r0_99999, N_("Truck Centers") },
-#define I_CD_CPLRMNT (B+7)
- { PD_RADIO, &carDlgCouplerMount, "cplrMount", PDO_NOPREF|PDO_DLGHORZ|PDO_DLGWIDE, cplrModeLabels, N_("Coupler Mount"), BC_HORZ|BC_NOBORDER },
-#define I_CD_CPLDLEN (B+8)
+#define I_CD_TRKOFFSET (B+7)
+ { PD_FLOAT, &carDlgDim.truckCenterOffset, "trkCenterOffset", PDO_DIM|PDO_NOPREF|PDO_DLGHORZ|PDO_DLGWIDE, &r9999_9999, N_("Center Offset") },
+#define I_CD_CPLRMNT (B+8)
+ { PD_RADIO, &carDlgCouplerMount, "cplrMount", PDO_NOPREF, cplrModeLabels, N_("Coupler Mount"), BC_HORZ|BC_NOBORDER },
+#define I_CD_CPLDLEN (B+9)
{ PD_FLOAT, &carDlgDim.coupledLength, "cpldLen", PDO_DIM|PDO_NOPREF, &r0_99999, N_("Coupled Length") },
-#define I_CD_CPLRLEN (B+9)
- { PD_FLOAT, &carDlgCouplerLength, "cplrLen", PDO_DIM|PDO_NOPREF|PDO_DLGWIDE|PDO_DLGHORZ, &r0_99999, N_("Coupler Length") },
-#define I_CD_CANVAS (B+10)
+#define I_CD_CPLRLEN (B+10)
+ { PD_FLOAT, &carDlgCouplerLength, "cplrLen", PDO_DIM|PDO_NOPREF|PDO_DLGHORZ, &r0_99999, N_("Coupler Length") },
+#define I_CD_CANVAS (B+11)
{ PD_DRAW, NULL, "canvas", PDO_NOPSHUPD|PDO_DLGWIDE|PDO_DLGNOLABELALIGN|PDO_DLGRESETMARGIN|PDO_DLGBOXEND|PDO_DLGRESIZE, &carDlgDrawData, NULL, 0 },
-#define C (B+11)
+#define C (B+12)
#define I_CD_ITEMINDEX (C+0)
{ PD_LONG, &carDlgItemIndex, "index", PDO_NOPREF|PDO_DLGWIDE, &i1_999999999, N_("Index"), 0 },
#define I_CD_PURPRC (C+1)
@@ -2276,6 +2527,7 @@ static void CarDlgLoadDimsFromProto( carProto_p protoP )
carDlgDim.carLength = protoP->dim.carLength/ratio;
carDlgDim.carWidth = protoP->dim.carWidth/ratio;
carDlgDim.truckCenter = protoP->dim.truckCenter/ratio;
+ carDlgDim.truckCenterOffset = protoP->dim.truckCenterOffset/ratio;
carDlgDim.coupledLength = carDlgDim.carLength + carDlgCouplerLength*2;
/*carDlgCouplerLength = (carDlgDim.coupledLength-carDlgDim.carLength)/2.0;*/
carDlgIsLoco = (protoP->options&CAR_DESC_IS_LOCO)?1:0;
@@ -2354,9 +2606,9 @@ static void CarDlgRedraw( void )
pos.y = orig.y+carDlgDim.carWidth/2.0;
if ( carDlgDim.truckCenter > 0.0 ) {
- pos.x = orig.x+(carDlgDim.carLength-carDlgDim.truckCenter)/2.0;
+ pos.x = orig.x+(carDlgDim.carLength-carDlgDim.truckCenter)/2.0-carDlgDim.truckCenterOffset;
CarProtoDrawTruck( &carDlgD, trackGauge*curScaleRatio, ratio, pos, 0.0 );
- pos.x = orig.x+(carDlgDim.carLength+carDlgDim.truckCenter)/2.0;
+ pos.x = orig.x+(carDlgDim.carLength+carDlgDim.truckCenter)/2.0-carDlgDim.truckCenterOffset;
CarProtoDrawTruck( &carDlgD, trackGauge*curScaleRatio, ratio, pos, 0.0 );
}
if ( carDlgDim.coupledLength > carDlgDim.carLength ) {
@@ -2756,6 +3008,7 @@ static BOOL_T CarDlgLoadLists(
protoTmp.dim.carLength = carDlgDim.carLength*ratio;
protoTmp.dim.coupledLength = carDlgDim.coupledLength*ratio;
protoTmp.dim.truckCenter = carDlgDim.truckCenter*ratio;
+ protoTmp.dim.truckCenterOffset = carDlgDim.truckCenterOffset*ratio;
CarProtoDlgCreateDummyOutline( &carProtoSegCnt, &carProtoSegPtr, (BOOL_T)carDlgIsLoco, protoTmp.dim.carLength, protoTmp.dim.carWidth, drawColorBlue );
protoTmp.segCnt = carProtoSegCnt;
protoTmp.segPtr = carProtoSegPtr;
@@ -2798,6 +3051,7 @@ static void CarDlgShowControls( void )
ParamControlShow( &carDlgPG, I_CD_CARLENGTH, !( S_ITEM && carDlgDispMode==0 ) );
ParamControlShow( &carDlgPG, I_CD_CARWIDTH, !( S_ITEM && carDlgDispMode==0 ) );
ParamControlShow( &carDlgPG, I_CD_TRKCENTER, !( S_ITEM && carDlgDispMode==0 ) );
+ ParamControlShow( &carDlgPG, I_CD_TRKOFFSET, !( S_ITEM && carDlgDispMode==0 ) );
ParamControlShow( &carDlgPG, I_CD_CANVAS, !( S_ITEM && carDlgDispMode==0 ) );
ParamControlShow( &carDlgPG, I_CD_CPLRLEN, S_PART || ( S_ITEM && carDlgDispMode==1 ) );
ParamControlShow( &carDlgPG, I_CD_CPLDLEN, S_PART || ( S_ITEM && carDlgDispMode==1 ) );
@@ -2875,7 +3129,7 @@ static void CarDlgDoActions(
BOOL_T reload[sizeof carDlgPLs/sizeof carDlgPLs[0]];
#define RELOAD_DIMS \
reload[I_CD_CARLENGTH] = reload[I_CD_CARWIDTH] = reload[I_CD_CPLDLEN] = \
- reload[I_CD_TRKCENTER] = reload[I_CD_CPLRLEN] = TRUE
+ reload[I_CD_TRKCENTER] = reload[I_CD_TRKOFFSET] = reload[I_CD_CPLRLEN] = TRUE
#define RELOAD_PARTDATA \
RELOAD_DIMS; \
reload[I_CD_PARTNO_STR] = reload[I_CD_DESC_STR] = \
@@ -2999,6 +3253,7 @@ LOG( log_carDlgState, 2, ( "Action = %s\n", carDlgAction_s[*actions] ) )
carDlgDim.carWidth = 10*12/ratio;
carDlgDim.coupledLength = carDlgDim.carLength+carDlgCouplerLength*2;
carDlgDim.truckCenter = carDlgDim.carLength-59.0*2.0/ratio;
+
carDlgTypeInx = 0;
carDlgIsLoco = (typeListMap[0].value&1);
}
@@ -3012,6 +3267,7 @@ LOG( log_carDlgState, 2, ( "Action = %s\n", carDlgAction_s[*actions] ) )
carDlgCouplerLength = 16.0;
carDlgDim.coupledLength = carDlgDim.carLength + 2 * carDlgCouplerLength;
carDlgDim.truckCenter *= ratio;
+ carDlgDim.truckCenterOffset *= ratio;
RELOAD_DIMS;
break;
case A_Redraw:
@@ -3158,6 +3414,7 @@ LOG( log_carDlgState, 2, ( "Action = %s\n", carDlgAction_s[*actions] ) )
carDlgDim.coupledLength = carDlgDim.carLength+16.0*2.0;
carDlgCouplerLength = (carDlgDim.coupledLength-carDlgDim.carLength)/2.0;
carDlgDim.truckCenter = carDlgDim.carLength-59.0*2.0;
+ carDlgDim.truckCenterOffset = 0;
carDlgIsLoco = (typeListMap[carDlgTypeInx].value&1);
} else {
strcpy( carDlgProtoStr , carDlgUpdateProtoPtr->desc );
@@ -3238,7 +3495,8 @@ static void CarDlgUpdate(
cmp_key_t cmp_key;
coOrd orig, size, size2;
carPartParent_p parentP;
- static DIST_T carDlgTruckOffset;
+ static DIST_T carDlgTruckOffsetL;
+ static DIST_T carDlgTruckOffsetR;
static long carDlgClock;
static long carDlgCarLengthClock;
static long carDlgTruckCenterClock;
@@ -3252,10 +3510,15 @@ LOG( log_carDlgState, 3, ( "CarDlgUpdate( %d )\n", inx ) )
switch ( inx ) {
case -1:
- if ( carDlgDim.truckCenter > 0 && carDlgDim.carLength > carDlgDim.truckCenter )
- carDlgTruckOffset = carDlgDim.carLength - carDlgDim.truckCenter;
- else
- carDlgTruckOffset = 0;
+ if ( carDlgDim.truckCenter > 0 && carDlgDim.carLength > carDlgDim.truckCenter ) {
+ carDlgTruckOffsetL = (carDlgDim.carLength - carDlgDim.truckCenter)/2 - carDlgDim.truckCenterOffset;
+ carDlgTruckOffsetR = (carDlgDim.carLength - carDlgDim.truckCenter)/2 + carDlgDim.truckCenterOffset;
+ }
+ else {
+ carDlgTruckOffsetL = 0;
+ carDlgTruckOffsetR = 0;
+ }
+
carDlgCarLengthClock = carDlgCoupledLengthClock = carDlgTruckCenterClock = carDlgCouplerLengthClock = carDlgClock = 0;
redraw = TRUE;
break;
@@ -3448,16 +3711,36 @@ LOG( log_carDlgState, 3, ( "CarDlgUpdate( %d )\n", inx ) )
redraw = TRUE;
break;
+ case I_CD_TRKOFFSET:
+ carDlgChanged++;
+ if ( carDlgDim.truckCenterOffset == 0 ) {
+ carDlgTruckOffsetL = carDlgDim.truckCenter/2;
+ carDlgTruckOffsetR = carDlgTruckOffsetL;
+ } else if (carDlgDim.carLength - carDlgDim.truckCenter > 2*fabs(carDlgDim.truckCenterOffset)) {
+ carDlgTruckOffsetL = carDlgDim.truckCenter/2 - carDlgDim.truckCenterOffset;
+ carDlgTruckOffsetR = carDlgDim.truckCenter/2 + carDlgDim.truckCenterOffset;
+ } else {
+ carDlgTruckOffsetL = 0;
+ carDlgTruckOffsetR = 0;
+ }
+ redraw = TRUE;
+ break;
+
case I_CD_TRKCENTER:
carDlgChanged++;
if ( carDlgDim.truckCenter == 0 ) {
- carDlgTruckOffset = 0;
+ carDlgTruckOffsetL = 0;
+ carDlgTruckOffsetR = 0;
} else if ( carDlgDim.truckCenter < 100/ratio /*&& carDlgDim.carLength == 0.0*/ ) {
+ carDlgTruckOffsetL = 0;
+ carDlgTruckOffsetR = 0;
return;
- } else if ( carDlgDim.carLength > carDlgDim.truckCenter ) {
- carDlgTruckOffset = carDlgDim.carLength - carDlgDim.truckCenter;
+ } else if ( carDlgDim.carLength - carDlgDim.truckCenter > 2*fabs(carDlgDim.truckCenterOffset) ) {
+ carDlgTruckOffsetL = carDlgDim.truckCenter/2-carDlgDim.truckCenterOffset;
+ carDlgTruckOffsetR = carDlgDim.truckCenter/2+carDlgDim.truckCenterOffset;
} else {
- carDlgTruckOffset = 0;
+ carDlgTruckOffsetL = 0;
+ carDlgTruckOffsetR = 0;
}
redraw = TRUE;
break;
@@ -3551,16 +3834,19 @@ LOG( log_carDlgState, 3, ( "CarDlgUpdate( %d )\n", inx ) )
carDlgDim.coupledLength = carDlgDim.carLength + 32;
if ( carDlgDim.carLength > 120 ) {
carDlgDim.truckCenter = carDlgDim.carLength - 120;
- carDlgTruckOffset = carDlgDim.carLength - carDlgDim.truckCenter;
+ carDlgTruckOffsetL = (carDlgDim.carLength - carDlgDim.truckCenter)/2;
+ carDlgTruckOffsetR = (carDlgDim.carLength - carDlgDim.truckCenter)/2;
} else {
carDlgDim.truckCenter = 0;
- carDlgTruckOffset = 0;
+ carDlgTruckOffsetL = 0;
+ carDlgTruckOffsetR = 0;
}
carDlgFlipToggle = FALSE;
ParamLoadControl( &carDlgPG, I_CD_CARLENGTH );
ParamLoadControl( &carDlgPG, I_CD_CARWIDTH );
ParamLoadControl( &carDlgPG, I_CD_CPLRLEN );
ParamLoadControl( &carDlgPG, I_CD_TRKCENTER );
+ ParamLoadControl( &carDlgPG, I_CD_TRKOFFSET );
redraw = TRUE;
break;
@@ -3579,12 +3865,15 @@ LOG( log_carDlgState, 3, ( "CarDlgUpdate( %d )\n", inx ) )
}
if ( checkTruckCenter && carDlgDim.carLength > 0 ) {
- if ( carDlgTruckOffset > 0 ) {
- carDlgDim.truckCenter = carDlgDim.carLength - carDlgTruckOffset;
+ if ( carDlgTruckOffsetL > 0 || carDlgTruckOffsetR > 0 ) {
+ carDlgDim.truckCenter = carDlgTruckOffsetL + carDlgTruckOffsetR;
+ carDlgDim.truckCenterOffset = (carDlgTruckOffsetR - carDlgTruckOffsetL)/2;
} else {
carDlgDim.truckCenter = carDlgDim.carLength * 0.75;
+ carDlgDim.truckCenterOffset = 0;
}
ParamLoadControl( &carDlgPG, I_CD_TRKCENTER );
+ ParamLoadControl( &carDlgPG, I_CD_TRKOFFSET );
}
ok = FALSE;
@@ -3600,8 +3889,12 @@ LOG( log_carDlgState, 3, ( "CarDlgUpdate( %d )\n", inx ) )
ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter the Car Width") );
else if ( carDlgDim.truckCenter <= 0 )
ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter the Truck Centers") );
+ else if ( carDlgDim.truckCenterOffset < 0)
+ ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Truck Center Offset must be greater than 0 or 0") );
else if ( carDlgDim.truckCenter >= carDlgDim.carLength )
ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Truck Centers must be less than Car Length") );
+ else if ( 2*carDlgDim.truckCenterOffset > carDlgDim.carLength - carDlgDim.truckCenter)
+ ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Truck Center Offset plus Truck Centers must be less than Car Length") );
else if ( (!S_PROTO) && ( carDlgDim.coupledLength <= 0 || carDlgCouplerLength <= 0 ) )
ParamLoadMessage( &carDlgPG, I_CD_MSG, _("Enter the Coupled Length or Coupler Length") );
else if ( S_PROTO && carDlgDim.coupledLength <= 0 )
@@ -3720,6 +4013,7 @@ LOG( log_carDlgState, 3, ( "CarDlgOk()\n" ) )
if ( carDlgDim.carLength <= 0.0 ||
carDlgDim.carWidth <= 0.0 ||
carDlgDim.truckCenter <= 0.0 ||
+ carDlgDim.truckCenterOffset < 0.0 ||
carDlgDim.coupledLength <= 0.0 ) {
NoticeMessage( MSG_CARDESC_VALUE_ZERO, _("Ok"), NULL );
return;
@@ -3951,7 +4245,6 @@ static void CarDlgLayout(
case I_CD_NEWPROTO:
*yy = wControlGetPosY(carDlgPLs[I_CD_NEW].control);
break;
- case I_CD_CPLRMNT:
case I_CD_CPLRLEN:
case I_CD_CARWIDTH:
if ( col2pos == 0 )
@@ -3961,8 +4254,11 @@ static void CarDlgLayout(
case I_CD_DESC_STR:
*yy = wControlBelow(carDlgPLs[I_CD_PARTNO_STR].control) + 3;
break;
+ case I_CD_CPLRMNT:
+ *yy = wControlBelow(carDlgPLs[I_CD_TRKOFFSET].control) + 3;
+ break;
case I_CD_CPLDLEN:
- *yy = wControlBelow(carDlgPLs[I_CD_TRKCENTER].control) + 3;
+ *yy = wControlBelow(carDlgPLs[I_CD_CPLRMNT].control) + 3;
break;
case I_CD_CANVAS:
*yy = wControlBelow(carDlgPLs[I_CD_CPLDLEN].control)+5;
@@ -3985,7 +4281,7 @@ static void DoCarPartDlg( carDlgAction_e *actions )
int inx;
if ( carDlgPG.win == NULL ) {
- ParamCreateDialog( &carDlgPG, MakeWindowTitle(_("New Car Part")), _("Add"), CarDlgOk, CarDlgClose, TRUE, CarDlgLayout, F_BLOCK|PD_F_ALT_CANCELLABEL, CarDlgUpdate );
+ ParamCreateDialog( &carDlgPG, MakeWindowTitle(_("New Car Part")), _("Add"), CarDlgOk, CarDlgClose, TRUE, CarDlgLayout, F_BLOCK|F_RESIZE|F_RECALLSIZE|PD_F_ALT_CANCELLABEL, CarDlgUpdate );
if ( carDlgDim.carWidth==0 )
carDlgDim.carWidth = 12.0*10.0/curScaleRatio;
@@ -4021,18 +4317,6 @@ static void DoCarPartDlg( carDlgAction_e *actions )
CarDlgDoStateActions( actions );
- /*CarDlgShowControls();*/
-
-#ifdef LATER
-if ( logTable(log_carList).level >= 1 ) {
- int inx;
- carPart_p partP;
- for ( inx=0; inx<carPart_da.cnt; inx++ ) {
- partP = carPart(inx);
- LogPrintf( "%d %s %d\n", inx, partP->title, partP->paramFileIndex );
- }
-}
-#endif
wShow( carDlgPG.win );
}
@@ -4147,13 +4431,9 @@ static void CarInvDlgFind( void * junk )
if ( item == NULL || item->car == NULL || IsTrackDeleted(item->car) ) return;
CarGetPos( item->car, &pos, &angle );
CarSetVisible( item->car );
- //DrawMapBoundingBox( FALSE );
- mainCenter = pos;
- mainD.orig.x = pos.x-mainD.size.x/2;;
- mainD.orig.y = pos.y-mainD.size.y/2;;
- MainRedraw();
- MapRedraw();
- //DrawMapBoundingBox( TRUE );
+ panCenter = pos;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere( (void*)0 ); // CarInvDlgFind
}
@@ -4357,7 +4637,7 @@ static void CarInvDlgSaveText( void )
{
if ( carInvSaveText_fs == NULL )
carInvSaveText_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("List Cars"),
- "Text|*.txt", CarInvSaveText, NULL );
+ "Text (*.txt)|*.txt", CarInvSaveText, NULL );
wFilSelect( carInvSaveText_fs, GetCurrentPath(CARSPATHKEY));
}
@@ -4365,7 +4645,7 @@ static void CarInvDlgSaveText( void )
static char *carCsvColumnTitles[] = {
"Index", "Scale", "Manufacturer", "Type", "Partno", "Prototype",
"Description", "Roadname", "Repmark", "Number", "Options", "CarLength",
- "CarWidth", "CoupledLength", "TruckCenter", "Color", "PurchPrice",
+ "CarWidth", "CoupledLength", "TruckOffset", "TruckCenter", "Color", "PurchPrice",
"CurrPrice", "Condition", "PurchDate", "ServiceDate", "Notes" };
#define M_INDEX (0)
#define M_SCALE (1)
@@ -4381,14 +4661,16 @@ static char *carCsvColumnTitles[] = {
#define M_CARLENGTH (11)
#define M_CARWIDTH (12)
#define M_CPLDLENGTH (13)
-#define M_TRKCENTER (14)
-#define M_COLOR (15)
-#define M_PURCHPRICE (16)
-#define M_CURRPRICE (17)
-#define M_CONDITION (18)
-#define M_PURCHDATE (19)
-#define M_SRVDATE (20)
-#define M_NOTES (21)
+#define M_TRKOFFSET (14)
+#define M_TRKCENTER (15)
+#define M_COLOR (16)
+#define M_PURCHPRICE (17)
+#define M_CURRPRICE (18)
+#define M_CONDITION (19)
+#define M_PURCHDATE (20)
+#define M_SRVDATE (21)
+#define M_NOTES (22)
+
static int ParseCsvLine(
@@ -4564,6 +4846,7 @@ static int CarInvImportCsv(
dim.carWidth = TabGetFloat( &tabs[M_CARWIDTH] );
dim.coupledLength = TabGetFloat( &tabs[M_CPLDLENGTH] );
dim.truckCenter = TabGetFloat( &tabs[M_TRKCENTER] );
+ dim.truckCenterOffset = TabGetFloat( &tabs[M_TRKOFFSET] );
partP = NULL;
if ( tabs[M_MANUF].len > 0 && tabs[M_PARTNO].len > 0 )
partP = CarPartFind( tabs[M_MANUF].ptr, tabs[M_MANUF].len, tabs[M_PARTNO].ptr, tabs[M_PARTNO].len, scale );
@@ -4578,6 +4861,7 @@ static int CarInvImportCsv(
if ( dim.carWidth <= 0 ) dim.carWidth = partP->dim.carWidth;
if ( dim.coupledLength <= 0 ) dim.coupledLength = partP->dim.coupledLength;
if ( dim.truckCenter <= 0 ) dim.truckCenter = partP->dim.truckCenter;
+ if ( dim.truckCenterOffset < 0 ) dim.truckCenterOffset = partP->dim.truckCenterOffset;
}
cp = TabStringCpy( title, &tabs[M_MANUF] );
*cp++ = '\t';
@@ -4642,7 +4926,7 @@ static void CarInvDlgImportCsv( void )
{
if ( carInvImportCsv_fs == NULL )
carInvImportCsv_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Import Cars"),
- _("Comma-Separated-Values|*.csv"), CarInvImportCsv, NULL );
+ _("Comma-Separated-Values (*.csv)|*.csv"), CarInvImportCsv, NULL );
wFilSelect( carInvImportCsv_fs, GetCurrentPath(CARSPATHKEY));
}
@@ -4738,6 +5022,7 @@ static int CarInvExportCsv(
CsvFormatLong( f, item->options, "," );
CsvFormatFloat( f, item->dim.carLength, 3, "," );
CsvFormatFloat( f, item->dim.carWidth, 3, "," );
+ CsvFormatFloat( f, item->dim.truckCenterOffset, 3, ",");
CsvFormatFloat( f, item->dim.coupledLength, 3, "," );
CsvFormatFloat( f, item->dim.truckCenter, 3, "," );
CsvFormatLong( f, wDrawGetRGB(item->color), "," );
@@ -4764,7 +5049,7 @@ static void CarInvDlgExportCsv( void )
return;
if ( carInvExportCsv_fs == NULL )
carInvExportCsv_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("Export Cars"),
- _("Comma-Separated-Values|*.csv"), CarInvExportCsv, NULL );
+ _("Comma-Separated-Values (*.csv)|*.csv"), CarInvExportCsv, NULL );
wFilSelect( carInvExportCsv_fs, GetCurrentPath(CARSPATHKEY));
}
@@ -5042,7 +5327,7 @@ EXPORT void InitCarDlg( void )
ParamRegister( &carInvPG );
RegisterChangeNotification( CarDlgChange );
AddParam( "CARPROTO ", CarProtoRead );
- AddParam( "CARPART ", CarPartRead );
+ AddParam( "CARPART ", CarPartRead);
ParamRegister( &newCarPG );
ParamCreateControls( &newCarPG, CarItemHotbarUpdate );
newCarControls[0] = newCarPLs[0].control;
diff --git a/app/bin/dcmpnd.c b/app/bin/dcmpnd.c
index 13f7c56..93e73ac 100644
--- a/app/bin/dcmpnd.c
+++ b/app/bin/dcmpnd.c
@@ -30,6 +30,7 @@
#include "i18n.h"
#include "messages.h"
#include "param.h"
+#include "include/paramfile.h"
#include "shrtpath.h"
#include "track.h"
#include "utility.h"
@@ -290,6 +291,11 @@ static BOOL_T RefreshCompound1(
xx->segCnt = to->segCnt;
xx->segs = (trkSeg_p)MyMalloc( xx->segCnt * sizeof *(trkSeg_p)0 );
memcpy( xx->segs, to->segs, xx->segCnt * sizeof *(trkSeg_p)0 );
+ MyFree( xx->paths);
+ xx->paths = (signed char*)MyMalloc( to->pathLen * sizeof *xx->paths );
+ memcpy( xx->paths, to->paths, to->pathLen * sizeof *xx->paths );
+ xx->pathLen = to->pathLen;
+ xx->pathCurr = xx->paths;
if ( flip )
FlipSegs( xx->segCnt, xx->segs, zero, 90.0 );
ClrTrkBits( trk, TB_SELECTED );
@@ -594,3 +600,30 @@ EXPORT void CompoundCustMgmLoad( void )
}
}
}
+
+/*****************************************************************************
+ *
+ * Utitlies
+ *
+ */
+
+wIndex_t FindListItemByContext(
+ wList_p listP,
+ void * context )
+{
+ if ( listP == NULL )
+ return -1;
+ if ( context == NULL )
+ return -1;
+ for ( wIndex_t inx = 0; inx < wListGetCount( listP ); ++inx ) {
+ void * itemContext = wListGetItemContext( listP, inx );
+ if ( itemContext != NULL ) {
+ if ( itemContext == context ) {
+ return inx;
+ }
+ }
+ }
+ return -1;
+}
+
+
diff --git a/app/bin/dcontmgm.c b/app/bin/dcontmgm.c
index e9e929f..19abefa 100644
--- a/app/bin/dcontmgm.c
+++ b/app/bin/dcontmgm.c
@@ -281,8 +281,7 @@ static void ContMgmChange( long changes )
{
if (changes) {
if (changed) {
- changed = 1;
- checkPtMark = 1;
+ changed = checkPtMark = 1;
}
}
if ((changes&CHANGE_PARAMS) == 0 ||
@@ -297,7 +296,7 @@ static void ContMgmChange( long changes )
static void DoControlMgr( void * junk )
{
if (controlPG.win == NULL) {
- ParamCreateDialog( &controlPG, MakeWindowTitle(_("Manage Layout Control Elements")), _("Done"), ControlDone, NULL, TRUE, NULL, F_RESIZE|F_RECALLSIZE|F_BLOCK, ControlDlgUpdate );
+ ParamCreateDialog( &controlPG, MakeWindowTitle(_("Manage Layout Control Elements")), _("Done"), ControlDone, wHide, TRUE, NULL, F_RESIZE|F_RECALLSIZE|F_BLOCK, ControlDlgUpdate );
} else {
wListClear( controlSelL );
}
diff --git a/app/bin/dcustmgm.c b/app/bin/dcustmgm.c
index 8455958..39bd085 100644
--- a/app/bin/dcustmgm.c
+++ b/app/bin/dcustmgm.c
@@ -41,11 +41,20 @@
#include "paths.h"
#include "track.h"
#include "wlib.h"
+#include "include/paramfilelist.h"
+#ifdef WINDOWS
+#include "include/utf8convert.h"
+#endif
static void CustomEdit( void * action );
static void CustomDelete( void * action );
static void CustomExport( void * action );
static void CustomDone( void * action );
+static void CustomNewCar( void * action );
+
+static const char * customTypes[] = { "Car Part", "Car Prototype", NULL };
+static wIndex_t selectedType;
+
static wPos_t customListWidths[] = { 18, 100, 30, 80, 220 };
static const char * customListTitles[] = { "", N_("Manufacturer"),
N_("Scale"), N_("Part No"), N_("Description") };
@@ -53,17 +62,17 @@ static paramListData_t customListData = { 10, 400, 5, customListWidths, customLi
static paramData_t customPLs[] = {
#define I_CUSTOMLIST (0)
#define customSelL ((wList_p)customPLs[I_CUSTOMLIST].control)
- { PD_LIST, NULL, "inx", PDO_DLGRESETMARGIN|PDO_DLGRESIZE, &customListData, NULL, BL_MANY },
-#define I_CUSTOMEDIT (1)
+ { PD_LIST, NULL, "inx", PDO_DLGRESETMARGIN|PDO_DLGRESIZE|PDO_DLGBOXEND, &customListData, NULL, BL_MANY },
+#define I_CUSTOMNEWTYPE (1)
+ { PD_DROPLIST, &selectedType, "newtype", PDO_DLGRESETMARGIN | PDO_LISTINDEX, (void*)150, N_("Create a new ") },
+#define I_CUSTOMNEW (2)
+ { PD_BUTTON, (void *)CustomNewCar, "newcar", PDO_DLGHORZ| PDO_DLGBOXEND, NULL, N_("Go") },
+#define I_CUSTOMEDIT (3)
{ PD_BUTTON, (void*)CustomEdit, "edit", PDO_DLGCMDBUTTON, NULL, N_("Edit") },
-#define I_CUSTOMDEL (2)
+#define I_CUSTOMDEL (4)
{ PD_BUTTON, (void*)CustomDelete, "delete", 0, NULL, N_("Delete") },
-#define I_CUSTOMCOPYTO (3)
+#define I_CUSTOMCOPYTO (5)
{ PD_BUTTON, (void*)CustomExport, "export", 0, NULL, N_("Move To") },
-#define I_CUSTOMNEW (4)
- { PD_MENU, NULL, "new", PDO_DLGWIDE, NULL, N_("New") },
- { PD_MENUITEM, (void*)CarDlgAddDesc, "new-part-mi", 0, NULL, N_("Car Part") },
- { PD_MENUITEM, (void*)CarDlgAddProto, "new-proto-mi", 0, NULL, N_("Car Prototype") }
} ;
static paramGroup_t customPG = { "custmgm", 0, customPLs, sizeof customPLs/sizeof customPLs[0] };
@@ -84,6 +93,10 @@ static void CustomDlgUpdate(
wIndex_t selcnt = wListGetSelectedCount( (wList_p)customPLs[0].control );
wIndex_t linx, lcnt;
+ if ( inx == I_CUSTOMNEW ) {
+ lcnt = wListGetCount( (wList_p)pg->paramPtr[I_CUSTOMNEWTYPE].control );
+ }
+
if ( inx != I_CUSTOMLIST ) return;
if ( selcnt == 1 ) {
lcnt = wListGetCount( (wList_p)pg->paramPtr[inx].control );
@@ -129,6 +142,20 @@ static void CustomEdit( void * action )
#endif
}
+static void CustomNewCar( void * action )
+{
+
+ switch(selectedType) {
+ case 1: // car prototype
+ CarDlgAddProto();
+ break;
+ case 0: // car part
+ CarDlgAddDesc();
+ break;
+ default:
+ break;
+ }
+}
static void CustomDelete( void * action )
{
@@ -212,8 +239,17 @@ static int CustomDoExport(
oldLocale = SaveLocale("C");
- if ( rc == -1 )
- fprintf( customMgmF, "CONTENTS %s\n", custMgmContentsStr );
+ if (rc == -1)
+ {
+ #ifdef WINDOWS
+ char *contents = MyStrdup(custMgmContentsStr);
+ contents = Convert2UTF8(contents);
+ fprintf(customMgmF, "CONTENTS %s\n", contents);
+ MyFree(contents);
+ #else
+ fprintf(customMgmF, "CONTENTS %s\n", custMgmContentsStr);
+ #endif // WINDOWS
+ }
cnt = wListGetCount( (wList_p)customPLs[0].control );
for ( inx=0; inx<cnt; inx++ ) {
@@ -245,7 +281,7 @@ static void CustomExport( void * junk )
{
if ( customMgmExport_fs == NULL )
customMgmExport_fs = wFilSelCreate( mainW, FS_UPDATE, 0, _("Move To XTP"),
- _("Parameter File|*.xtp"), CustomDoExport, NULL );
+ _("Parameter File (*.xtp)|*.xtp"), CustomDoExport, NULL );
wFilSelect( customMgmExport_fs, GetCurrentPath(CUSTOMPATHKEY));
}
@@ -340,8 +376,7 @@ static void CustMgmChange( long changes )
{
if (changes) {
if (changed) {
- changed = 1;
- checkPtMark = 1;
+ changed = checkPtMark = 1;
}
}
if ((changes&CHANGE_PARAMS) == 0 ||
@@ -354,8 +389,16 @@ static void CustMgmChange( long changes )
static void DoCustomMgr( void * junk )
{
+ int i = 0;
+
if (customPG.win == NULL) {
- ParamCreateDialog( &customPG, MakeWindowTitle(_("Manage custom designed parts")), _("Done"), CustomDone, NULL, TRUE, NULL, F_RESIZE|F_RECALLSIZE|F_BLOCK, CustomDlgUpdate );
+ ParamCreateDialog( &customPG, MakeWindowTitle(_("Manage custom designed parts")), _("Done"), CustomDone, wHide, TRUE, NULL, F_RESIZE|F_RECALLSIZE|F_BLOCK, CustomDlgUpdate );
+ while(customTypes[ i ] != NULL) {
+ wListAddValue( ((wList_p)customPLs[I_CUSTOMNEWTYPE].control), customTypes[ i++ ], NULL, NULL );
+ }
+ selectedType = 0;
+ wListSetIndex( ((wList_p)customPLs[I_CUSTOMNEWTYPE].control), selectedType);
+
} else {
wListClear( customSelL );
}
@@ -369,7 +412,7 @@ static void DoCustomMgr( void * junk )
EXPORT addButtonCallBack_t CustomMgrInit( void )
{
- ParamRegister( &customPG );
+ ParamRegister( &customPG );
ParamRegister( &custMgmContentsPG );
RegisterChangeNotification( CustMgmChange );
return &DoCustomMgr;
diff --git a/app/bin/dease.c b/app/bin/dease.c
index 7841857..d01f0df 100644
--- a/app/bin/dease.c
+++ b/app/bin/dease.c
@@ -21,12 +21,14 @@
*/
#include <math.h>
+#include <string.h>
#include "ccurve.h"
#include "cjoin.h"
#include "cstraigh.h"
#include "custom.h"
#include "i18n.h"
+#include "fileio.h"
#include "param.h"
#include "track.h"
diff --git a/app/bin/directory.c b/app/bin/directory.c
new file mode 100644
index 0000000..265485b
--- /dev/null
+++ b/app/bin/directory.c
@@ -0,0 +1,162 @@
+/** \file directory.c
+ * Directory Management
+ */
+
+/* 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 <string.h>
+
+#ifdef WINDOWS
+ #include "include/dirent.h"
+ #include <direct.h>
+ #define unlink(a) _unlink((a))
+ #define rmdir(a) _rmdir((a))
+#else
+ #include <dirent.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+#endif
+
+#include <wlib.h>
+#include "directory.h"
+#include "dynstring.h"
+#include "i18n.h"
+#include "messages.h"
+#include "misc.h"
+
+/*****************************************************************************
+ * Safe Create Dir
+ * \param IN dir The directory path to create
+ *
+ * \return TRUE if ok
+ *
+ */
+
+BOOL_T SafeCreateDir(const char *dir)
+{
+ int err;
+
+#ifdef WINDOWS
+ err = _mkdir(dir);
+#else
+ err = mkdir(dir, 0755);
+#endif
+ if (err < 0) {
+ if (errno != EEXIST) {
+ NoticeMessage(MSG_DIR_CREATE_FAIL,
+ _("Continue"), NULL, dir, strerror(errno));
+ perror(dir);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/************************************************
+ * DeleteDirectory empties and removes a directory recursively
+ *
+ * \param IN dir_path The Directory to empty and remove
+ *
+ * \return TRUE if ok
+ *
+ */
+BOOL_T DeleteDirectory(const char *dir_path)
+{
+ size_t path_len;
+ char *full_path = NULL;
+ DIR *dir;
+ struct stat stat_path, stat_entry;
+ struct dirent *entry;
+ DynString path;
+
+ // stat for the path
+ int resp = stat(dir_path, &stat_path);
+
+ if (resp != 0 && errno == ENOENT) {
+ return TRUE; //Does not Exist
+ }
+
+ // if path is not dir - exit
+ if (!(S_ISDIR(stat_path.st_mode))) {
+ 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_DIR_OPEN_FAIL,
+ _("Continue"), NULL, dir_path);
+ return FALSE;
+ }
+
+ // the length of the path
+ path_len = strlen(dir_path) + 1;
+ DynStringMalloc(&path, path_len + 16); //guessing the total path length
+
+ // 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
+ DynStringReset(&path);
+ DynStringCatCStrs(&path, dir_path, FILE_SEP_CHAR, entry->d_name, NULL);
+ full_path = DynStringToCStr(&path);
+ // stat for the entry
+ stat(full_path, &stat_entry);
+
+ // recursively remove a nested directory
+ if (S_ISDIR(stat_entry.st_mode) != 0) {
+ DeleteDirectory(full_path);
+ continue;
+ }
+
+ // remove a file object
+ if (unlink(full_path)) {
+ NoticeMessage(MSG_UNLINK_FAIL, _("Continue"), NULL, full_path);
+ DynStringFree(&path);
+ closedir(dir);
+ return FALSE;
+ } else {
+#if DEBUG
+ printf("Removed a file: %s \n", full_path);
+#endif
+ }
+ }
+
+ closedir(dir);
+ DynStringFree(&path);
+
+ // remove the devastated directory and close the object of it
+ if (rmdir(dir_path)) {
+ NoticeMessage(MSG_RMDIR_FAIL, _("Continue"), NULL, dir_path);
+ return FALSE;
+ } else {
+#if DEBUG
+ printf("Removed a directory: %s \n", dir_path);
+#endif
+ }
+ return TRUE;
+}
diff --git a/app/bin/directory.h b/app/bin/directory.h
new file mode 100644
index 0000000..2ddfffd
--- /dev/null
+++ b/app/bin/directory.h
@@ -0,0 +1,6 @@
+#ifndef HAVE_DIRECTORY_H
+ #define HAVE_DIRECTORY_H
+ #include "common.h"
+ BOOL_T SafeCreateDir(const char *dir);
+ BOOL_T DeleteDirectory(const char *dir_path);
+#endif \ No newline at end of file
diff --git a/app/bin/dlayer.c b/app/bin/dlayer.c
index 70f613f..352dbe1 100644
--- a/app/bin/dlayer.c
+++ b/app/bin/dlayer.c
@@ -29,6 +29,7 @@
#include "dynstring.h"
#include "fileio.h"
#include "i18n.h"
+#include "layout.h"
#include "messages.h"
#include "param.h"
#include "track.h"
@@ -43,6 +44,7 @@
#define LAYERPREF_FROZEN (1)
#define LAYERPREF_ONMAP (2)
#define LAYERPREF_VISIBLE (4)
+#define LAYERPREF_MODULE (8)
#define LAYERPREF_SECTION ("Layers")
#define LAYERPREF_NAME "name"
#define LAYERPREF_COLOR "color"
@@ -66,9 +68,11 @@ static wList_p setLayerL;
typedef struct {
char name[STR_SHORT_SIZE]; /**< Layer name */
wDrawColor color; /**< layer color, is an index into a color table */
+ BOOL_T useColor; /**< Use Layer color */
BOOL_T frozen; /**< Frozen flag */
BOOL_T visible; /**< visible flag */
BOOL_T onMap; /**< is layer shown map */
+ BOOL_T module; /**< is layer a module (all or nothing) */
long objCount; /**< number of objects on layer */
} layer_t;
@@ -176,6 +180,22 @@ BOOL_T GetLayerOnMap(unsigned int layer)
}
}
+BOOL_T GetLayerModule(unsigned int layer)
+{
+ if (!IsLayerValid(layer)) {
+ return TRUE;
+ } else {
+ return layers[layer].module;
+ }
+}
+
+void SetLayerModule(unsigned int layer, BOOL_T module)
+{
+ if (IsLayerValid(layer)) {
+ layers[layer].module = module;
+ }
+}
+
char * GetLayerName(unsigned int layer)
{
@@ -186,11 +206,26 @@ char * GetLayerName(unsigned int layer)
}
}
+void SetLayerName(unsigned int layer, char* name) {
+ if (IsLayerValid(layer)) {
+ strcpy(layers[layer].name,name);
+ }
+}
+
+BOOL_T GetLayerUseColor(unsigned int layer) {
+ return layers[layer].useColor;
+}
+
wDrawColor GetLayerColor(unsigned int layer)
{
return layers[layer].color;
}
+static void RedrawLayer( unsigned int l, BOOL_T draw )
+{
+ DoRedraw(); // RedrawLayer
+}
+
static void FlipLayer(unsigned int layer)
{
@@ -218,7 +253,7 @@ static void FlipLayer(unsigned int layer)
RedrawLayer(layer, TRUE);
}
-static void SetCurrLayer(wIndex_t inx, const char * name, wIndex_t op,
+void SetCurrLayer(wIndex_t inx, const char * name, wIndex_t op,
void * listContext, void * arg)
{
unsigned int newLayer = (unsigned int)inx;
@@ -422,9 +457,11 @@ static wDrawColor layerColorTab[COUNT(layerRawColorTab)];
static wWin_p layerW;
static char layerName[STR_SHORT_SIZE];
static wDrawColor layerColor;
+static long layerUseColor = TRUE;
static long layerVisible = TRUE;
static long layerFrozen = FALSE;
static long layerOnMap = TRUE;
+static long layerModule = FALSE;
static void LayerOk(void *);
static BOOL_T layerRedrawMap = FALSE;
@@ -435,6 +472,8 @@ static BOOL_T layerRedrawMap = FALSE;
static char *visibleLabels[] = { "", NULL };
static char *frozenLabels[] = { "", NULL };
static char *onMapLabels[] = { "", NULL };
+static char *moduleLabels[] = { "", NULL };
+static char *layerColorLabels[] = { "", NULL };
static paramIntegerRange_t i0_20 = { 0, NUM_BUTTONS };
static paramData_t layerPLs[] = {
@@ -444,13 +483,17 @@ static paramData_t layerPLs[] = {
{ PD_STRING, layerName, "name", PDO_NOPREF|PDO_STRINGLIMITLENGTH, (void*)(250-54), N_("Name"), 0, 0, sizeof(layerName) },
#define I_COLOR (2)
{ PD_COLORLIST, &layerColor, "color", PDO_NOPREF, NULL, N_("Color") },
-#define I_VIS (3)
+#define I_USE_COLOR (3)
+ { PD_TOGGLE, &layerUseColor, "layercolor", PDO_NOPREF|PDO_DLGHORZ, layerColorLabels, N_("Use Color"), BC_HORZ|BC_NOBORDER },
+#define I_VIS (4)
{ PD_TOGGLE, &layerVisible, "visible", PDO_NOPREF, visibleLabels, N_("Visible"), BC_HORZ|BC_NOBORDER },
-#define I_FRZ (4)
+#define I_FRZ (5)
{ PD_TOGGLE, &layerFrozen, "frozen", PDO_NOPREF|PDO_DLGHORZ, frozenLabels, N_("Frozen"), BC_HORZ|BC_NOBORDER },
-#define I_MAP (5)
+#define I_MAP (6)
{ PD_TOGGLE, &layerOnMap, "onmap", PDO_NOPREF|PDO_DLGHORZ, onMapLabels, N_("On Map"), BC_HORZ|BC_NOBORDER },
-#define I_COUNT (6)
+#define I_MOD (7)
+ { PD_TOGGLE, &layerModule, "module", PDO_NOPREF|PDO_DLGHORZ, moduleLabels, N_("Module"), BC_HORZ|BC_NOBORDER },
+#define I_COUNT (8)
{ PD_STRING, NULL, "object-count", PDO_NOPREF|PDO_DLGBOXEND, (void*)(80), N_("Count"), BO_READONLY },
{ PD_MESSAGE, N_("Personal Preferences"), NULL, PDO_DLGRESETMARGIN, (void *)180 },
{ PD_BUTTON, (void*)DoLayerOp, "reset", PDO_DLGRESETMARGIN, 0, N_("Load"), 0, (void *)ENUMLAYER_RELOAD },
@@ -477,6 +520,7 @@ LayerSystemDefaults(void)
layers[inx].visible = TRUE;
layers[inx].frozen = FALSE;
layers[inx].onMap = TRUE;
+ layers[inx].module = FALSE;
layers[inx].objCount = 0;
SetLayerColor(inx, layerColorTab[inx%COUNT(layerColorTab)]);
}
@@ -547,7 +591,7 @@ static void DoLayerOp(void * data)
if (layoutLayerChanged) {
MainProc(mainW, wResize_e, NULL, NULL);
layoutLayerChanged = FALSE;
- changed = TRUE;
+ changed++;
SetWindowTitle();
}
}
@@ -566,7 +610,9 @@ UpdateLayerDlg()
layerVisible = layers[curLayer].visible;
layerFrozen = layers[curLayer].frozen;
layerOnMap = layers[curLayer].onMap;
+ layerModule = layers[curLayer].module;
layerColor = layers[curLayer].color;
+ layerUseColor = layers[curLayer].useColor;
strcpy(layerName, layers[curLayer].name);
layerCurrent = curLayer;
/* now re-load the layer list boxes */
@@ -588,6 +634,28 @@ UpdateLayerDlg()
}
/**
+ * Fill a layer dropbox with the current layer settings
+ *
+ * \param listLayers the dropbox
+ * \return
+ */
+
+void
+FillLayerList( wList_p listLayers)
+{
+ wListClear(listLayers); // Rebuild list on each invovation
+
+ for (int inx = 0; inx < NUM_LAYERS; inx++) {
+ char *layerFormattedName;
+ layerFormattedName = FormatLayerName(inx);
+ wListAddValue((wList_p)listLayers, layerFormattedName, NULL, (void*)(long)inx);
+ free(layerFormattedName);
+ }
+
+ /* set current layer to selected */
+ wListSetIndex(listLayers, curLayer);
+}
+/**
* Initialize the layer lists.
*
* \param IN pointer to function that actually initialize tha data structures
@@ -646,6 +714,10 @@ LayerPrefSave(void)
flags |= LAYERPREF_VISIBLE;
}
+ if (layers[inx].module) {
+ flags |= LAYERPREF_MODULE;
+ }
+
sprintf(buffer, LAYERPREF_FLAGS ".%0u", inx);
wPrefSetInteger(LAYERPREF_SECTION, buffer, flags);
@@ -710,6 +782,7 @@ LayerPrefLoad(void)
layers[inx].frozen = ((flags & LAYERPREF_FROZEN) != 0);
layers[inx].onMap = ((flags & LAYERPREF_ONMAP) != 0);
layers[inx].visible = ((flags & LAYERPREF_VISIBLE) != 0);
+ layers[inx].module = ((flags & LAYERPREF_MODULE) !=0);
prefString = strtok(NULL, ",");
}
}
@@ -761,6 +834,15 @@ void LayerSetCounts(void)
}
}
+int FindUnusedLayer(unsigned int start) {
+ int inx;
+ for (inx=start; inx<NUM_LAYERS; inx++) {
+ if (layers[inx].objCount == 0 && !layers[inx].frozen) return inx;
+ }
+ ErrorMessage( MSG_NO_EMPTY_LAYER );
+ return -1;
+}
+
/**
* Reset layer options to their default values. The default values are loaded
* from the preferences file.
@@ -805,12 +887,20 @@ static void LayerUpdate(void)
ParamLoadControl(&layerPG, I_VIS);
}
+ if (layerCurrent == curLayer && layerModule) {
+ NoticeMessage(MSG_LAYER_MODULE, _("Ok"), NULL);
+ layerModule = FALSE;
+ ParamLoadControl(&layerPG, I_MOD);
+ }
+
if (strcmp(layers[(int)layerCurrent].name, layerName) ||
layerColor != layers[(int)layerCurrent].color ||
+ layers[(int)layerCurrent].useColor != (BOOL_T)layerUseColor ||
layers[(int)layerCurrent].visible != (BOOL_T)layerVisible ||
layers[(int)layerCurrent].frozen != (BOOL_T)layerFrozen ||
- layers[(int)layerCurrent].onMap != (BOOL_T)layerOnMap) {
- changed = TRUE;
+ layers[(int)layerCurrent].onMap != (BOOL_T)layerOnMap ||
+ layers[(int)layerCurrent].module != (BOOL_T)layerModule) {
+ changed++;
SetWindowTitle();
}
@@ -837,6 +927,7 @@ static void LayerUpdate(void)
}
redraw = (layerColor != layers[(int)layerCurrent].color ||
+ layers[(int)layerCurrent].useColor != (BOOL_T)layerUseColor ||
(BOOL_T)layerVisible != layers[(int)layerCurrent].visible);
if ((!layerRedrawMap) && redraw) {
@@ -850,9 +941,11 @@ static void LayerUpdate(void)
wButtonSetBusy(layer_btns[(int)layerCurrent], layerVisible);
}
+ layers[(int)layerCurrent].useColor = (BOOL_T)layerUseColor;
layers[(int)layerCurrent].visible = (BOOL_T)layerVisible;
layers[(int)layerCurrent].frozen = (BOOL_T)layerFrozen;
layers[(int)layerCurrent].onMap = (BOOL_T)layerOnMap;
+ layers[(int)layerCurrent].module = (BOOL_T)layerModule;
if (layerRedrawMap) {
DoRedraw();
@@ -878,7 +971,9 @@ static void LayerSelect(
layerVisible = layers[inx].visible;
layerFrozen = layers[inx].frozen;
layerOnMap = layers[inx].onMap;
+ layerModule = layers[inx].module;
layerColor = layers[inx].color;
+ layerUseColor = layers[inx].useColor;
sprintf(message, "%ld", layers[inx].objCount);
ParamLoadMessage(&layerPG, I_COUNT, message);
ParamLoadControls(&layerPG);
@@ -893,6 +988,7 @@ void ResetLayers(void)
layers[inx].visible = TRUE;
layers[inx].frozen = FALSE;
layers[inx].onMap = TRUE;
+ layers[inx].module = FALSE;
layers[inx].objCount = 0;
SetLayerColor(inx, layerColorTab[inx%COUNT(layerColorTab)]);
@@ -911,7 +1007,9 @@ void ResetLayers(void)
layerVisible = TRUE;
layerFrozen = FALSE;
layerOnMap = TRUE;
+ layerModule = FALSE;
layerColor = layers[0].color;
+ layerUseColor = TRUE;
strcpy(layerName, layers[0].name);
LoadLayerLists();
@@ -1024,7 +1122,7 @@ static void DoLayer(void * junk)
{
if (layerW == NULL) {
layerW = ParamCreateDialog(&layerPG, MakeWindowTitle(_("Layers")), _("Done"),
- LayerOk, NULL, TRUE, NULL, 0, LayerDlgUpdate);
+ LayerOk, wHide, TRUE, NULL, 0, LayerDlgUpdate);
}
/* set the globals to the values for the current layer */
@@ -1038,7 +1136,7 @@ static void DoLayer(void * junk)
BOOL_T ReadLayers(char * line)
{
char * name;
- int inx, visible, frozen, color, onMap;
+ int inx, visible, frozen, color, onMap, module, dontUseColor, ColorFlags;
unsigned long rgb;
/* older files didn't support layers */
@@ -1069,7 +1167,7 @@ BOOL_T ReadLayers(char * line)
/* get the properties for a layer from the file and update the layer accordingly */
- if (!GetArgs(line, "ddddu0000q", &inx, &visible, &frozen, &onMap, &rgb,
+ if (!GetArgs(line, "dddduddd0q", &inx, &visible, &frozen, &onMap, &rgb, &module, &dontUseColor, &ColorFlags,
&name)) {
return FALSE;
}
@@ -1093,7 +1191,12 @@ BOOL_T ReadLayers(char * line)
layers[inx].visible = visible;
layers[inx].frozen = frozen;
layers[inx].onMap = onMap;
+ layers[inx].module = module;
layers[inx].color = color;
+ layers[inx].useColor = !dontUseColor;
+
+ colorTrack = ColorFlags&1; //Make sure globals are set
+ colorDraw = ColorFlags&2;
if (inx<NUM_BUTTONS) {
if (strlen(name) > 0) {
@@ -1117,12 +1220,13 @@ BOOL_T ReadLayers(char * line)
* \return TRUE if configured, FALSE if not
*/
-bool
+BOOL_T
IsLayerConfigured(unsigned int layerNumber)
{
return (!layers[layerNumber].visible ||
layers[layerNumber].frozen ||
!layers[layerNumber].onMap ||
+ layers[layerNumber].module ||
layers[layerNumber].color !=
layerColorTab[layerNumber % (COUNT(layerColorTab))] ||
layers[layerNumber].name[0] ||
@@ -1140,6 +1244,11 @@ BOOL_T WriteLayers(FILE * f)
{
unsigned int inx;
+ int ColorFlags = 0;
+
+ if (colorTrack) ColorFlags |= 1;
+ if (colorDraw) ColorFlags |= 2;
+
for (inx = 0; inx < NUM_LAYERS; inx++) {
if (IsLayerConfigured(inx)) {
fprintf(f, "LAYERS %u %d %d %d %ld %d %d %d %d \"%s\"\n",
@@ -1148,7 +1257,9 @@ BOOL_T WriteLayers(FILE * f)
layers[inx].frozen,
layers[inx].onMap,
wDrawGetRGB(layers[inx].color),
- 0, 0, 0, 0,
+ layers[inx].module,
+ layers[inx].useColor?0:1,
+ ColorFlags, 0,
PutTitle(layers[inx].name));
}
}
@@ -1157,6 +1268,7 @@ BOOL_T WriteLayers(FILE * f)
return TRUE;
}
+#include "bitmaps/background.xpm"
void InitLayers(void)
{
@@ -1173,6 +1285,7 @@ void InitLayers(void)
show_layer_bmps[i] = wIconCreateBitMap(l1_width, l1_height, show_layer_bits[i],
layerColorTab[i%(COUNT(layerColorTab))]);
layers[i].color = layerColorTab[i%(COUNT(layerColorTab))];
+ layers[i].useColor = TRUE;
}
/* layer list for toolbar */
@@ -1180,6 +1293,10 @@ void InitLayers(void)
SetCurrLayer, NULL);
wControlSetBalloonText((wControl_p)setLayerL, GetBalloonHelpStr("cmdLayerSet"));
AddToolbarControl((wControl_p)setLayerL, IC_MODETRAIN_TOO);
+
+ backgroundB = AddToolbarButton("cmdBackgroundShow", wIconCreatePixMap(background), 0,
+ (addButtonCallBack_t)BackgroundToggleShow, NULL);
+ wControlActive((wControl_p)backgroundB, FALSE);
for (i = 0; i<NUM_LAYERS; i++) {
char *layerName;
diff --git a/app/bin/doption.c b/app/bin/doption.c
index ae36d21..3b9ed02 100644
--- a/app/bin/doption.c
+++ b/app/bin/doption.c
@@ -35,6 +35,7 @@ static paramIntegerRange_t i1_64 = { 1, 64 };
static paramIntegerRange_t i1_100 = { 1, 100 };
static paramIntegerRange_t i1_256 = { 1, 256 };
static paramIntegerRange_t i0_10000 = { 0, 10000 };
+static paramIntegerRange_t i0_99 = { 0, 99};
static paramIntegerRange_t i1_1000 = { 1, 1000 };
static paramIntegerRange_t i10_1000 = { 10, 1000 };
static paramIntegerRange_t i10_100 = { 10, 100 };
@@ -45,11 +46,15 @@ static paramFloatRange_t r0_180 = { 0, 180 };
static void UpdatePrefD( void );
static void UpdateMeasureFmt(void);
+static void UpdateAutoSaveInterval(long);
+static void UpdateChkPtInterval(long);
static wIndex_t distanceFormatInx;
EXPORT long enableBalloonHelp = 1;
+EXPORT long showFlexTrack = 1;
+
long GetChanges( paramGroup_p pg )
{
long changes;
@@ -62,21 +67,18 @@ long GetChanges( paramGroup_p pg )
return changes;
}
+static paramGroup_t prefPG;
+
+
static void OptionDlgUpdate(
paramGroup_p pg,
int inx,
void * valueP )
{
- int quickMoveOld;
if ( inx < 0 ) return;
if ( pg->paramPtr[inx].valueP == &enableBalloonHelp ) {
wEnableBalloonHelp((wBool_t)*(long*)valueP);
- } else if ( pg->paramPtr[inx].valueP == &quickMove ) {
- quickMoveOld = (int)quickMove;
- quickMove = *(long*)valueP;
- UpdateQuickMove(NULL);
- quickMove = quickMoveOld;
} else {
if (pg->paramPtr[inx].valueP == &units) {
UpdatePrefD();
@@ -84,6 +86,28 @@ static void OptionDlgUpdate(
if (pg->paramPtr[inx].valueP == &distanceFormatInx) {
UpdateMeasureFmt();
}
+ if (pg->paramPtr[inx].valueP == &showFlexTrack) {
+ DoChangeNotification(CHANGE_PARAMS|CHANGE_TOOLBAR);
+ }
+ if (pg->paramPtr[inx].valueP == &checkPtInterval) {
+ checkPtInterval = *(long *)valueP;
+ if (checkPtInterval == 0 ) {
+ wControlSetBalloon( pg->paramPtr[inx].control, 0, -5, _("Turning off AutoSave") );
+ UpdateAutoSaveInterval(0);
+ } else {
+ wControlSetBalloon( pg->paramPtr[inx].control, 0, -5, NULL );
+ }
+ }
+ if (pg->paramPtr[inx].valueP == &autosaveChkPoints) {
+ autosaveChkPoints = *(long *)valueP;
+ if (checkPtInterval == 0 && autosaveChkPoints>0 ) {
+ wControlSetBalloon( pg->paramPtr[inx].control, 0, -5, _("Turning on CheckPointing") );
+ UpdateChkPtInterval(10);
+ } else {
+ wControlSetBalloon( pg->paramPtr[inx].control, 0, -5, NULL );
+ }
+
+ }
}
}
@@ -91,7 +115,6 @@ static void OptionDlgCancel(
wWin_p win )
{
wEnableBalloonHelp( (int)enableBalloonHelp );
- UpdateQuickMove(NULL);
wHide( win );
}
@@ -113,15 +136,19 @@ static char * drawCenterCircle[] = { N_("Off"), N_("On"), NULL };
static char * labelEnableLabels[] = { N_("Track Descriptions"), N_("Lengths"), N_("EndPt Elevations"), N_("Track Elevations"), N_("Cars"), NULL };
static char * hotBarLabelsLabels[] = { N_("Part No"), N_("Descr"), NULL };
static char * listLabelsLabels[] = { N_("Manuf"), N_("Part No"), N_("Descr"), NULL };
-static char * colorLayersLabels[] = { N_("Tracks"), N_("Other"), NULL };
+static char * colorTrackLabels[] = { N_("Object"), N_("Layer"), NULL };
+static char * colorDrawLabels[] = { N_("Object"), N_("Layer"), NULL };
static char * liveMapLabels[] = { N_("Live Map"), NULL };
static char * hideTrainsInTunnelsLabels[] = { N_("Hide Trains On Hidden Track"), NULL };
-static char * zoomCornerLabels[] = {N_("Zoom keeps lower corner in view"), NULL};
+static char * constrainMainLabels[] = {N_("Constrain Drawing Area to Room boundaries"), NULL};
extern long trainPause;
+
+
static paramData_t displayPLs[] = {
- { PD_TOGGLE, &colorLayers, "color-layers", PDO_NOPSHUPD|PDO_DRAW, colorLayersLabels, N_("Color Layers"), BC_HORZ, (void*)(CHANGE_MAIN) },
+ { PD_RADIO, &colorTrack, "color-track", PDO_NOPSHUPD|PDO_DRAW, colorTrackLabels, N_("Color Track"), BC_HORZ, (void*)(CHANGE_MAIN) },
+ { PD_RADIO, &colorDraw, "color-draw", PDO_NOPSHUPD|PDO_DRAW, colorDrawLabels, N_("Color Draw"), BC_HORZ, (void*)(CHANGE_MAIN) },
{ PD_RADIO, &drawTunnel, "tunnels", PDO_NOPSHUPD|PDO_DRAW, drawTunnelLabels, N_("Draw Tunnel"), BC_HORZ, (void*)(CHANGE_MAIN) },
{ PD_RADIO, &drawEndPtV, "endpt", PDO_NOPSHUPD|PDO_DRAW, drawEndPtLabels3, N_("Draw EndPts"), BC_HORZ, (void*)(CHANGE_MAIN) },
{ PD_RADIO, &drawUnconnectedEndPt, "unconnected-endpt", PDO_NOPSHUPD|PDO_DRAW, drawEndPtUnconnectedSize, N_("Draw Unconnected EndPts"), BC_HORZ, (void*)(CHANGE_MAIN) },
@@ -129,7 +156,7 @@ static paramData_t displayPLs[] = {
{ PD_RADIO, &centerDrawMode, "centerdraw", PDO_NOPSHUPD|PDO_DRAW, drawCenterCircle, N_("Draw Centers"), BC_HORZ, (void*)(CHANGE_MAIN | CHANGE_MAP) },
{ PD_LONG, &twoRailScale, "tworailscale", PDO_NOPSHUPD, &i1_64, N_("Two Rail Scale"), 0, (void*)(CHANGE_MAIN) },
{ PD_LONG, &mapScale, "mapscale", PDO_NOPSHUPD, &i1_256, N_("Map Scale"), 0, (void*)(CHANGE_MAP) },
- { PD_TOGGLE, &zoomCorner, "zoom-corner", PDO_NOPSHUPD, zoomCornerLabels, "", BC_HORZ },
+ { PD_TOGGLE, &constrainMain, "constrainmain", PDO_NOPSHUPD, constrainMainLabels, "", BC_HORZ },
{ PD_TOGGLE, &liveMap, "livemap", PDO_NOPSHUPD, liveMapLabels, "", BC_HORZ },
{ PD_TOGGLE, &autoPan, "autoPan", PDO_NOPSHUPD, autoPanLabels, "", BC_HORZ },
{ PD_TOGGLE, &labelEnable, "labelenable", PDO_NOPSHUPD, labelEnableLabels, N_("Label Enable"), 0, (void*)(CHANGE_MAIN) },
@@ -139,7 +166,7 @@ static paramData_t displayPLs[] = {
{ PD_TOGGLE, &layoutLabels, "layoutlabels", PDO_NOPSHUPD, listLabelsLabels, N_("Layout Labels"), BC_HORZ, (void*)(CHANGE_MAIN) },
{ PD_TOGGLE, &listLabels, "listlabels", PDO_NOPSHUPD, listLabelsLabels, N_("List Labels"), BC_HORZ, (void*)(CHANGE_PARAMS) },
/* ATTENTION: update the define below if you add entries above */
-#define I_HOTBARLABELS (17)
+#define I_HOTBARLABELS (18)
{ PD_DROPLIST, &carHotbarModeInx, "carhotbarlabels", PDO_NOPSHUPD|PDO_DLGUNDERCMDBUTT|PDO_LISTINDEX, (void*)250, N_("Car Labels"), 0, (void*)CHANGE_SCALE },
{ PD_LONG, &trainPause, "trainpause", PDO_NOPSHUPD, &i10_1000 , N_("Train Update Delay"), 0, 0 },
{ PD_TOGGLE, &hideTrainsInTunnels, "hideTrainsInTunnels", PDO_NOPSHUPD, hideTrainsInTunnelsLabels, "", BC_HORZ }
@@ -178,6 +205,7 @@ static void DoDisplay( void * junk )
wListAddValue( (wList_p)displayPLs[I_HOTBARLABELS].control, _("Manuf/Proto/Part Number"), NULL, (void*)0x0321 );
wListAddValue( (wList_p)displayPLs[I_HOTBARLABELS].control, _("Manuf/Proto/Partno/Item"), NULL, (void*)0x4321 );
}
+
ParamLoadControls( &displayPG );
wShow( displayW );
#ifdef LATER
@@ -204,13 +232,9 @@ EXPORT addButtonCallBack_t DisplayInit( void )
static wWin_p cmdoptW;
-static char * moveQlabels[] = {
- N_("Normal"),
- N_("Simple"),
- N_("End-Points"),
- NULL };
-
static char * preSelectLabels[] = { N_("Properties"), N_("Select"), NULL };
+static char * selectLabels[] = { N_("Single item selected, +Ctrl Add to selection"), N_("Add to selection, +Ctrl Single item selected"), NULL };
+static char * selectZeroLabels[] = { N_("Deselect all on select nothing"), NULL };
#ifdef HIDESELECTIONWINDOW
static char * hideSelectionWindowLabels[] = { N_("Hide"), NULL };
@@ -218,17 +242,16 @@ static char * hideSelectionWindowLabels[] = { N_("Hide"), NULL };
static char * rightClickLabels[] = {N_("Normal: Command List, Shift: Command Options"), N_("Normal: Command Options, Shift: Command List"), NULL };
EXPORT paramData_t cmdoptPLs[] = {
- { PD_RADIO, &quickMove, "move-quick", PDO_NOPSHUPD, moveQlabels, N_("Draw Moving Tracks"), BC_HORZ },
{ PD_RADIO, &preSelect, "preselect", PDO_NOPSHUPD, preSelectLabels, N_("Default Command"), BC_HORZ },
#ifdef HIDESELECTIONWINDOW
{ PD_TOGGLE, &hideSelectionWindow, PDO_NOPSHUPD, hideSelectionWindowLabels, N_("Hide Selection Window"), BC_HORZ },
#endif
- { PD_RADIO, &rightClickMode, "rightclickmode", PDO_NOPSHUPD, rightClickLabels, N_("Right Click"), 0 }
+ { PD_RADIO, &rightClickMode, "rightclickmode", PDO_NOPSHUPD, rightClickLabels, N_("Right Click"), 0 },
+ { PD_RADIO, &selectMode, "selectmode", PDO_NOPSHUPD, selectLabels, N_("Select Mode"), 0},
+ { PD_TOGGLE, &selectZero, "selectzero", PDO_NOPSHUPD, selectZeroLabels, "", 0 }
};
static paramGroup_t cmdoptPG = { "cmdopt", PGO_RECORD|PGO_PREFMISC, cmdoptPLs, sizeof cmdoptPLs/sizeof cmdoptPLs[0] };
-EXPORT paramData_p moveQuickPD = &cmdoptPLs[0];
-
static void CmdoptOk( void * junk )
{
long changes;
@@ -275,6 +298,7 @@ static long displayUnits;
static char * unitsLabels[] = { N_("English"), N_("Metric"), NULL };
static char * angleSystemLabels[] = { N_("Polar"), N_("Cartesian"), NULL };
static char * enableBalloonHelpLabels[] = { N_("Balloon Help"), NULL };
+static char * enableFlexTrackLabels[] = { N_("Show FlexTrack in HotBar"), NULL };
static char * startOptions[] = { N_("Load Last Layout"), N_("Start New Layout"), NULL };
static paramData_t prefPLs[] = {
@@ -288,10 +312,14 @@ static paramData_t prefPLs[] = {
{ PD_FLOAT, &turntableAngle, "turntable-angle", PDO_NOPSHUPD, &r0_180, N_("Turntable Angle") },
{ PD_LONG, &maxCouplingSpeed, "coupling-speed-max", PDO_NOPSHUPD, &i10_100, N_("Max Coupling Speed"), 0 },
{ PD_TOGGLE, &enableBalloonHelp, "balloonhelp", PDO_NOPSHUPD, enableBalloonHelpLabels, "", BC_HORZ },
+ { PD_TOGGLE, &showFlexTrack, "showflextrack", PDO_NOPSHUPD, enableFlexTrackLabels, "", BC_HORZ},
{ PD_LONG, &dragPixels, "dragpixels", PDO_NOPSHUPD|PDO_DRAW, &i1_1000, N_("Drag Distance") },
{ PD_LONG, &dragTimeout, "dragtimeout", PDO_NOPSHUPD|PDO_DRAW, &i1_1000, N_("Drag Timeout") },
{ PD_LONG, &minGridSpacing, "mingridspacing", PDO_NOPSHUPD|PDO_DRAW, &i1_100, N_("Min Grid Spacing"), 0, 0 },
- { PD_LONG, &checkPtInterval, "checkpoint", PDO_NOPSHUPD|PDO_FILE, &i0_10000, N_("Check Point") },
+#define I_CHKPT (13)
+ { PD_LONG, &checkPtInterval, "checkpoint", PDO_NOPSHUPD|PDO_FILE, &i0_10000, N_("Check Point Frequency") },
+#define I_AUTOSAVE (14)
+ { PD_LONG, &autosaveChkPoints, "autosave", PDO_NOPSHUPD|PDO_FILE, &i0_99, N_("Autosave Checkpoint Frequency") },
{ PD_RADIO, &onStartup, "onstartup", PDO_NOPSHUPD, startOptions, N_("On Program Startup"), 0, NULL }
};
static paramGroup_t prefPG = { "pref", PGO_RECORD|PGO_PREFMISC, prefPLs, sizeof prefPLs/sizeof prefPLs[0] };
@@ -302,6 +330,7 @@ typedef struct {
long fmt;
} dstFmts_t;
static dstFmts_t englishDstFmts[] = {
+ { N_("999.999"), DISTFMT_FMT_NONE|DISTFMT_FRACT_NUM|3 },
{ N_("999.999999"), DISTFMT_FMT_NONE|DISTFMT_FRACT_NUM|6 },
{ N_("999.99999"), DISTFMT_FMT_NONE|DISTFMT_FRACT_NUM|5 },
{ N_("999.9999"), DISTFMT_FMT_NONE|DISTFMT_FRACT_NUM|4 },
@@ -339,10 +368,23 @@ static dstFmts_t metricDstFmts[] = {
{ NULL, 0 },
{ NULL, 0 },
{ NULL, 0 },
- { NULL, 0 },
{ NULL, 0 } };
static dstFmts_t *dstFmts[] = { englishDstFmts, metricDstFmts };
+void UpdateAutoSaveInterval(long value)
+{
+ autosaveChkPoints = value;
+ ParamLoadControl(&prefPG, I_AUTOSAVE);
+ ParamLoadControl(&prefPG, I_CHKPT);
+}
+
+void UpdateChkPtInterval(long value)
+{
+ checkPtInterval = value;
+ ParamLoadControl(&prefPG, I_AUTOSAVE);
+ ParamLoadControl(&prefPG, I_CHKPT);
+}
+
/**
* Load the selection list for number formats with the appropriate list of variants.
*/
diff --git a/app/bin/dpricels.c b/app/bin/dpricels.c
index 87df88b..9d04d6d 100644
--- a/app/bin/dpricels.c
+++ b/app/bin/dpricels.c
@@ -151,7 +151,7 @@ static void PriceListDlgUpdate(
static void DoPriceList( void * junk )
{
if (priceListW == NULL)
- priceListW = ParamCreateDialog( &priceListPG, MakeWindowTitle(_("Price List")), _("Done"), PriceListOk, NULL, TRUE, NULL, 0, PriceListDlgUpdate );
+ priceListW = ParamCreateDialog( &priceListPG, MakeWindowTitle(_("Price List")), _("Done"), PriceListOk, wHide, TRUE, NULL, F_RESIZE, PriceListDlgUpdate );
wShow( priceListW );
PriceListChange( CHANGE_SCALE|CHANGE_PARAMS );
}
diff --git a/app/bin/dprmfile.c b/app/bin/dprmfile.c
index 24250e7..3bb249e 100644
--- a/app/bin/dprmfile.c
+++ b/app/bin/dprmfile.c
@@ -1,5 +1,5 @@
/** \file dprmfile.c
- * Param File Management
+ * Param File Dialog
*/
/* XTrkCad - Model Railroad CAD
@@ -21,535 +21,426 @@
*/
#include <assert.h>
+#include <stdbool.h>
#include <stdint.h>
#include <string.h>
-#include <time.h>
#include "custom.h"
+#include "dynstring.h"
#include "fileio.h"
#include "i18n.h"
#include "messages.h"
#include "param.h"
+#include "include/paramfile.h"
+#include "include/paramfilelist.h"
#include "paths.h"
#include "track.h"
-typedef struct {
- char * name;
- char * contents;
- int deleted;
- int deletedShadow;
- int valid;
- } paramFileInfo_t;
-typedef paramFileInfo_t * paramFileInfo_p;
-static dynArr_t paramFileInfo_da;
-#define paramFileInfo(N) DYNARR_N( paramFileInfo_t, paramFileInfo_da, N )
-
-EXPORT int curParamFileIndex = PARAM_DEMO;
-static char curParamDir[STR_LONG_SIZE];
static struct wFilSel_t * paramFile_fs;
-EXPORT wBool_t IsParamValid(
- int fileInx )
-{
- if (fileInx == PARAM_DEMO)
- return (curDemo>=0);
- else if (fileInx == PARAM_CUSTOM)
- return TRUE;
- else if (fileInx == PARAM_LAYOUT)
- return TRUE;
- else if (fileInx >= 0 && fileInx < paramFileInfo_da.cnt)
- return (!paramFileInfo(fileInx).deleted) && paramFileInfo(fileInx).valid;
- else
- return FALSE;
-}
-
-
-EXPORT char * GetParamFileName(
- int fileInx )
-{
- return paramFileInfo(fileInx).contents;
-}
-
-
-static BOOL_T UpdateParamFiles( void )
-{
- char fileName[STR_LONG_SIZE], *fileNameP;
- char * contents;
- const char * cp;
- FILE * updateF;
- FILE * paramF;
- long updateTime;
- long lastTime;
-
- MakeFullpath(&fileNameP, libDir, "xtrkcad.upd", NULL);
- updateF = fopen( fileNameP, "r" );
- free(fileNameP);
- if ( updateF == NULL )
- return FALSE;
- if ( fgets( message, sizeof message, updateF ) == NULL ) {
- NoticeMessage( "short file: xtrkcad.upd", _("Ok"), NULL );
- return FALSE;
- }
- wPrefGetInteger( "file", "updatetime", &lastTime, 0 );
- updateTime = atol( message );
- if ( lastTime >= updateTime )
- return FALSE;
-
- while ( ( fgets( fileName, STR_LONG_SIZE, updateF ) ) != NULL ) {
- Stripcr( fileName );
- InfoMessage( _("Updating %s"), fileName );
- MakeFullpath(&fileNameP, libDir, "params", fileName, NULL);
- paramF = fopen( fileNameP, "r" );
- if ( paramF == NULL ) {
- NoticeMessage( MSG_PRMFIL_OPEN_NEW, _("Ok"), NULL, fileNameP );
- free(fileNameP);
- continue;
- }
- contents = NULL;
- while ( ( fgets(message, sizeof message, paramF) ) != NULL ) {
- if (strncmp( message, "CONTENTS", 8 ) == 0) {
- Stripcr( message );
- contents = message+9;
- break;
- }
- }
- fclose( paramF );
- if (contents == NULL) {
- NoticeMessage( MSG_PRMFIL_NO_CONTENTS, _("Ok"), NULL, fileNameP );
- free(fileNameP);
- continue;
- }
- cp = wPrefGetString( "Parameter File Map", contents );
- wPrefSetString( "Parameter File Map", contents, fileNameP );
- if (cp!=NULL && *cp!='\0') {
- /* been there, done that */
- free(fileNameP);
- continue;
- }
-
- DYNARR_APPEND( paramFileInfo_t, paramFileInfo_da, 10 );
- curParamFileIndex = paramFileInfo_da.cnt-1;
- paramFileInfo(curParamFileIndex).name = MyStrdup( fileNameP );
- curContents = curSubContents = NULL;
- paramFileInfo(curParamFileIndex).deleted = FALSE;
- paramFileInfo(curParamFileIndex).valid = TRUE;
- paramFileInfo(curParamFileIndex).deletedShadow =
- paramFileInfo(curParamFileIndex).deleted = !ReadParams( 0, NULL, fileNameP );
- paramFileInfo(curParamFileIndex).contents = curContents;
-
- free(fileNameP);
- }
- wPrefSetInteger( "file", "updatetime", updateTime );
- return TRUE;
-}
-
-
-EXPORT void ReadParamFiles( void )
-{
- int fileNo;
- const char *fileName;
- const char * contents;
- BOOL_T updated = FALSE;
-
- updated = UpdateParamFiles();
-
- for ( fileNo=1; ; fileNo++ ) {
- sprintf( message, "File%d", fileNo );
- contents = wPrefGetString( "Parameter File Names", message );
- if (contents==NULL || *contents=='\0')
- break;
- InfoMessage( "Parameters for %s", contents );
- fileName = wPrefGetString( "Parameter File Map", contents );
- if (fileName==NULL || *fileName=='\0') {
- NoticeMessage( MSG_PRMFIL_NO_MAP, _("Ok"), NULL, contents );
- continue;
- }
- DYNARR_APPEND( paramFileInfo_t, paramFileInfo_da, 10 );
- curParamFileIndex = paramFileInfo_da.cnt-1;
- paramFileInfo(curParamFileIndex).name = MyStrdup( fileName );
- curContents = NULL;
- paramFileInfo(curParamFileIndex).deleted = FALSE;
- paramFileInfo(curParamFileIndex).valid = TRUE;
- paramFileInfo(curParamFileIndex).deletedShadow =
- paramFileInfo(curParamFileIndex).deleted = !ReadParams( 0, NULL, fileName );
- if (curContents == NULL)
- curContents = curSubContents = MyStrdup(contents);
- paramFileInfo(curParamFileIndex).contents = curContents;
- }
- curParamFileIndex = PARAM_CUSTOM;
- if (updated) {
- RememberParamFiles();
- }
-}
+#include "bitmaps/greendot.xpm"
+#include "bitmaps/greydot.xpm"
+#include "bitmaps/yellowdot.xpm"
+#include "bitmaps/reddot.xpm"
+#include "bitmaps/greenstar.xpm"
+#include "bitmaps/greystar.xpm"
+#include "bitmaps/yellowstar.xpm"
+#include "bitmaps/redstar.xpm"
+#define FAVORITE_PARAM 1
+#define STANDARD_PARAM 0
-EXPORT void RememberParamFiles( void )
-{
- int fileInx;
- int fileNo;
- char * contents, *cp;
-
- for (fileInx=0, fileNo=1; fileInx<paramFileInfo_da.cnt; fileInx++ ) {
- if (paramFileInfo(fileInx).valid && !paramFileInfo(fileInx).deleted) {
- sprintf( message, "File%d", fileNo++ );
- contents = paramFileInfo(fileInx).contents;
- for ( cp=contents; *cp; cp++ ) {
- if ( *cp == '=' || *cp == '\'' || *cp == '"' || *cp == ':' || *cp == '.' )
- *cp = ' ';
- }
- wPrefSetString( "Parameter File Names", message, contents );
- wPrefSetString("Parameter File Map", contents, paramFileInfo(fileInx).name);
- }
- }
- sprintf( message, "File%d", fileNo++ );
- wPrefSetString( "Parameter File Names", message, "" );
-}
+#define PARAMBUTTON_UNLOAD "Unload"
+#define PARAMBUTTON_REFRESH "Reload"
+#define PARAMFILE_UNLOAD (0)
+#define PARAMFILE_REFRESH (1)
-
-/****************************************************************************
- *
- * Param File Dialog
- *
- */
+static wIcon_p indicatorIcons[ 2 ][PARAMFILE_MAXSTATE];
static wWin_p paramFileW;
static long paramFileSel = 0;
-static wIcon_p mtbox_bm;
-static wIcon_p chkbox_bm;
-static void ParamFileAction( void * );
-static void ParamFileBrowse( void * );
-static void ParamFileSelectAll( void * );
+static void ParamFileFavorite(void * favorite);
+static void ParamRefreshSelectedFiles(void * action);
+static void ParamUnloadSelectedFiles(void *);
+static void ParamFileBrowse(void *);
+static void ParamFileSelectAll(void *);
-static paramListData_t paramFileListData = { 10, 370 };
+static paramListData_t paramFileListData = { 15, 370 };
static char * paramFileLabels[] = { N_("Show File Names"), NULL };
static paramData_t paramFilePLs[] = {
#define I_PRMFILLIST (0)
#define paramFileL ((wList_p)paramFilePLs[I_PRMFILLIST].control)
- { PD_LIST, NULL, "inx", 0, &paramFileListData, NULL, BL_DUP|BL_SETSTAY|BL_MANY },
+ { PD_LIST, NULL, "inx", PDO_NOPREF | PDO_DLGRESIZE, &paramFileListData, NULL, BL_DUP|BL_SETSTAY|BL_MANY },
#define I_PRMFILTOGGLE (1)
- { PD_TOGGLE, &paramFileSel, "mode", 0, paramFileLabels, NULL, BC_HORZ|BC_NOBORDER },
- { PD_BUTTON, (void *)ParamFileSelectAll, "selectall", PDO_DLGCMDBUTTON, NULL, N_("Select all") },
-#define I_PRMFILACTION (3)
-#define paramFileActionB ((wButton_p)paramFilePLs[I_PRMFILACTION].control)
- { PD_BUTTON, (void*)ParamFileAction, "action", PDO_DLGCMDBUTTON, NULL, N_("Unload"), 0L, FALSE },
- { PD_BUTTON, (void*)ParamFileBrowse, "browse", 0, NULL, N_("Browse ...") } };
+ { PD_TOGGLE, &paramFileSel, "mode", 0, paramFileLabels, NULL, BC_HORZ|BC_NOBORDER },
+#define I_MESSAGE (2)
+ { PD_MESSAGE, "", NULL, 0, (void *)370 },
+ { PD_BUTTON, (void *)ParamFileSelectAll, "selectall", PDO_DLGCMDBUTTON, NULL, N_("Select all") },
+#define I_PRMFILEFAVORITE (4)
+ { PD_BUTTON, (void *)ParamFileFavorite, "favorite", PDO_DLGCMDBUTTON, (void *)TRUE, N_("Favorite")},
+ { PD_BUTTON, (void*)ParamUnloadSelectedFiles, "unload", PDO_DLGCMDBUTTON, NULL, N_(PARAMBUTTON_UNLOAD), 0L, FALSE },
+ { PD_BUTTON, (void*)ParamRefreshSelectedFiles, "refresh", PDO_DLGCMDBUTTON, NULL, N_(PARAMBUTTON_REFRESH), 0L, FALSE },
+ { PD_BUTTON, (void*)DoSearchParams, "find", 0, NULL, N_("Search Library") },
+ { PD_BUTTON, (void*)ParamFileBrowse, "browse", 0, NULL, N_("Browse ...") },
+
+
+};
static paramGroup_t paramFilePG = { "prmfile", 0, paramFilePLs, sizeof paramFilePLs/sizeof paramFilePLs[0] };
+#define MESSAGETEXT ((wMessage_p)paramFilePLs[I_MESSAGE].control)
-static void ParamFileLoadList( void )
+static dynArr_t *sortFiles;
+
+/** Comparison function per C runtime conventions. Elements are ordered by compatibility
+ * state first and name of contents second.
+ *
+ * \param index1 IN first element
+ * \param index2 IN second element
+ * \return
+ */
+
+int
+CompareParameterFiles(const void *index1, const void *index2)
{
- int fileInx;
- wIndex_t listInx;
- wControlShow( (wControl_p)paramFileL, FALSE );
- listInx = wListGetIndex(paramFileL);
- wListClear( paramFileL );
- for ( fileInx = 0; fileInx < paramFileInfo_da.cnt; fileInx++ ) {
- if (paramFileInfo(fileInx).valid) {
- strcpy( message, ((!paramFileSel) && paramFileInfo(fileInx).contents)?
- paramFileInfo(fileInx).contents:
- paramFileInfo(fileInx).name );
- wListAddValue( paramFileL, message, (paramFileInfo(fileInx).deleted)?mtbox_bm:chkbox_bm, (void*)(intptr_t)fileInx );
- }
- }
- wListSetIndex( paramFileL, listInx );
- wControlShow( (wControl_p)paramFileL, TRUE );
+ paramFileInfo_t paramFile1 = DYNARR_N(paramFileInfo_t, (*sortFiles), *(int*)index1);
+ paramFileInfo_t paramFile2 = DYNARR_N(paramFileInfo_t, (*sortFiles), *(int*)index2);
+
+ if (paramFile2.trackState != paramFile1.trackState) {
+ return (paramFile2.trackState - paramFile1.trackState);
+ } else {
+ return (strcmp(paramFile1.contents, paramFile2.contents));
+ }
}
/**
- * Load the selected parameter files. This is a callback executed when the file selection dialog
- * is closed.
- * Steps:
- * - the parameters are read from file
- * - check is performed to see whether the content is already present, if yes the previously
- * loaded content is invalidated
- * - loaded parameter file is added to list of parameter files
- * - if a parameter file dialog exists the list is updated. It is either rewritten in
- * in case of an invalidated file or the new file is appended
- * - the settings are updated
- * These steps are repeated for every file in list
+ * Create a sorted list of indexes into the parameter file array. That way, the elements
+ * in the array will not be moved. Instead the list is used for the order in which the
+ * list box is populated.
*
- * \param files IN the number of filenames in the fileName array
- * \param fileName IN an array of fully qualified filenames
- * \param data IN ignored
- * \return TRUE on success, FALSE on error
+ * \param cnt IN number of parameter files
+ * \param files IN parameter file array
+ * \param list OUT the ordered list
*/
-EXPORT int LoadParamFile(
- int files,
- char ** fileName,
- void * data )
+void
+SortParamFileList(size_t cnt, dynArr_t *files, int *list)
{
- wIndex_t inx;
- int i = 0;
-
- wBool_t redrawList = FALSE;
-
- assert( fileName != NULL );
- assert( files > 0);
-
- for( i=0; i < files; i++ )
- {
- curContents = curSubContents = NULL;
- curParamFileIndex = paramFileInfo_da.cnt;
- if ( !ReadParams( 0, NULL, fileName[ i ] ) )
- return FALSE;
-
- assert( curContents != NULL );
- // in case the contents is already presented, make invalid
- for ( inx=0; inx<paramFileInfo_da.cnt; inx++ ) {
- if ( paramFileInfo(inx).valid &&
- strcmp( paramFileInfo(inx).contents, curContents ) == 0 ) {
- paramFileInfo(inx).valid = FALSE;
- redrawList = TRUE;
- break;
- }
- }
+ for (size_t i = 0; i < cnt; i++) {
+ list[i] = i;
+ }
- DYNARR_APPEND( paramFileInfo_t, paramFileInfo_da, 10 );
- paramFileInfo(curParamFileIndex).name = MyStrdup( fileName[ i ] );
- paramFileInfo(curParamFileIndex).valid = TRUE;
- paramFileInfo(curParamFileIndex).deletedShadow =
- paramFileInfo(curParamFileIndex).deleted = FALSE;
- paramFileInfo(curParamFileIndex).contents = curContents;
-
- if ( paramFilePG.win ) {
- if ( redrawList ) {
- ParamFileLoadList();
- } else {
- strcpy( message, ((!paramFileSel) && paramFileInfo(curParamFileIndex).contents)?
- paramFileInfo(curParamFileIndex).contents:
- paramFileInfo(curParamFileIndex).name );
- wListAddValue( paramFileL, message, chkbox_bm, (void*)(intptr_t)curParamFileIndex );
- wListSetIndex( paramFileL, wListGetCount(paramFileL)-1 );
- }
- }
+ sortFiles = files;
- wPrefSetString( "Parameter File Map", curContents,
- paramFileInfo(curParamFileIndex).name );
- }
- curParamFileIndex = PARAM_CUSTOM;
- DoChangeNotification( CHANGE_PARAMS );
- return TRUE;
+ qsort((void *)list, (size_t)cnt, sizeof(int), CompareParameterFiles);
+}
+
+
+/**
+ * Reload the listbox showing the current parameter files
+ */
+void ParamFileListLoad(int paramFileCnt, dynArr_t *paramFiles)
+{
+ DynString description;
+ DynStringMalloc(&description, STR_SHORT_SIZE);
+ int *sortedIndex = MyMalloc(sizeof(int)*paramFileCnt);
+ int log_params = LogFindIndex("params");
+
+ SortParamFileList(paramFileCnt, paramFiles, sortedIndex);
+
+ wControlShow((wControl_p)paramFileL, FALSE);
+ wListClear(paramFileL);
+
+ for (int i = 0; i < paramFileCnt; i++) {
+ paramFileInfo_t paramFileInfo = DYNARR_N(paramFileInfo_t, (*paramFiles),
+ sortedIndex[ i ]);
+ if (paramFileInfo.valid) {
+ DynStringClear(&description);
+ DynStringCatCStr(&description,
+ ((!paramFileSel) && paramFileInfo.contents) ?
+ paramFileInfo.contents :
+ paramFileInfo.name);
+
+ wListAddValue(paramFileL,
+ DynStringToCStr(&description),
+ indicatorIcons[ paramFileInfo.favorite ][paramFileInfo.trackState],
+ (void*)(intptr_t)sortedIndex[i]);
+
+ LOG1(log_params, ("ParamFileListLoad: = %s: %d\n", paramFileInfo.contents, paramFileInfo.trackState))
+ }
+ }
+ wControlShow((wControl_p)paramFileL, TRUE);
+ DynStringFree(&description);
+ MyFree(sortedIndex);
}
-static void ParamFileBrowse( void * junk )
+static void ParamFileBrowse(void * junk)
{
- wFilSelect( paramFile_fs, curParamDir );
- return;
+ wMessageSetValue(MESSAGETEXT, "");
+ wFilSelect(paramFile_fs, GetParamFileDir());
+ return;
}
/**
- * Update the action button. If at least one selected file is unloaded, the action button
- * is set to 'Reload'. If all selected files are loaded, the button will be set to 'Unload'.
+ * Update the action buttons.
+ *
+ * If at least one selected file is not a favorite, the favorite button is set to 'SetFavorite'
*
- * \param varname1 IN this is a variable
- * \return
*/
-static void UpdateParamFileButton(
- wIndex_t fileInx )
+static void UpdateParamFileButton(void)
{
- wIndex_t selcnt = wListGetSelectedCount( paramFileL );
- wIndex_t inx, cnt;
-
- // set the default
- wButtonSetLabel( paramFileActionB, _("Unload"));
- paramFilePLs[ I_PRMFILACTION ].context = FALSE;
-
- //nothing selected -> leave
- if( selcnt <= 0 )
- return;
-
- // get the number of items in list
- cnt = wListGetCount( paramFileL );
-
- // walk through the whole list box
- for ( inx=0; inx<cnt; inx++ )
- {
- if ( wListGetItemSelected( (wList_p)paramFileL, inx ))
- {
- // if item is selected, get status
- fileInx = (intptr_t)wListGetItemContext( paramFileL, inx );
-
- if (fileInx < 0 || fileInx >= paramFileInfo_da.cnt)
- return;
- if( paramFileInfo(fileInx).deleted ) {
- // if selected file was unloaded, set button to reload and finish loop
- wButtonSetLabel( paramFileActionB, _("Reload"));
- paramFilePLs[ I_PRMFILACTION ].context = (void *)TRUE;
- break;
- }
- }
- }
+ wIndex_t selcnt = wListGetSelectedCount(paramFileL);
+ wIndex_t inx, cnt;
+ wIndex_t fileInx;
+
+ //nothing selected -> leave
+ if (selcnt <= 0) {
+ return;
+ }
+
+ // set the default
+ paramFilePLs[I_PRMFILEFAVORITE].context = FALSE;
+
+ // get the number of items in list
+ cnt = wListGetCount(paramFileL);
+
+ // walk through the whole list box
+ for (inx=0; inx<cnt; inx++) {
+ if (wListGetItemSelected((wList_p)paramFileL, inx)) {
+ // if item is selected, get status
+ fileInx = (intptr_t)wListGetItemContext(paramFileL, inx);
+
+ if (fileInx < 0 || fileInx >= GetParamFileCount()) {
+ return;
+ }
+ if (!IsParamFileFavorite(fileInx)) {
+ paramFilePLs[I_PRMFILEFAVORITE].context = (void *)TRUE;
+ }
+ }
+ }
}
+/**
+ * Set the property for a parameter file in memory
+ *
+ * \param newState IN new value for property
+ */
+
+void
+UpdateParamFileProperties( bool newState)
+{
+ wIndex_t inx, cnt;
+ wIndex_t fileInx;
+
+ // get the number of items in list
+ cnt = wListGetCount(paramFileL);
+
+ // walk through the whole list box
+ for (inx = 0; inx < cnt; inx++) {
+ if (wListGetItemSelected((wList_p)paramFileL, inx)) {
+ fileInx = (intptr_t)wListGetItemContext(paramFileL, inx);
+ SetParamFileFavorite(fileInx, newState);
+ }
+ }
+ DoChangeNotification(CHANGE_PARAMS);
+}
/**
- * Unload selected files.
+ * Mark selected files as favorite
*
- * \param action IN FALSE = unload, TRUE = reload parameter files
+ * \param favorite IN FALSE = remove, TRUE = set favorite
* \return
*/
-static void ParamFileAction( void * action )
+static void ParamFileFavorite(void * setFavorite)
+{
+ wIndex_t selcnt = wListGetSelectedCount(paramFileL);
+ wMessageSetValue(MESSAGETEXT, "");
+ if (selcnt) {
+ UpdateParamFileProperties(setFavorite?TRUE:FALSE);
+ }
+}
+
+/**
+ * Parameter change selected files
+ *
+ * \param paramFileChange The parameter file change.
+ */
+
+static void
+ParamChangeSelectedFiles(unsigned paramFileChange)
{
- wIndex_t selcnt = wListGetSelectedCount( paramFileL );
wIndex_t inx, cnt;
wIndex_t fileInx;
- unsigned newDeletedState;
-
- if( action )
- newDeletedState = FALSE;
- else
- newDeletedState = TRUE;
-
- //nothing selected -> leave
- if( selcnt <= 0 )
- return;
// get the number of items in list
- cnt = wListGetCount( paramFileL );
-
- // walk through the whole list box
- for ( inx=0; inx<cnt; inx++ )
- {
- if ( wListGetItemSelected( (wList_p)paramFileL, inx ) )
- {
- fileInx = (intptr_t)wListGetItemContext( paramFileL, inx );
-
- // set the desired state
- paramFileInfo(fileInx).deleted = newDeletedState;
-
- strcpy( message, ((!paramFileSel) && paramFileInfo(fileInx).contents)?
- paramFileInfo(fileInx).contents:
- paramFileInfo(fileInx).name );
- wListSetValues( paramFileL, inx, message, (paramFileInfo(fileInx).deleted)?mtbox_bm:chkbox_bm, (void*)(intptr_t)fileInx );
+ cnt = wListGetCount(paramFileL);
+
+ for (inx = 0; inx < cnt; inx++) {
+ if (wListGetItemSelected((wList_p)paramFileL, inx)) {
+ fileInx = (intptr_t)wListGetItemContext(paramFileL, inx);
+
+ switch (paramFileChange) {
+ case PARAMFILE_UNLOAD:
+ if (IsParamFileFavorite(fileInx)) {
+ SetParamFileDeleted(fileInx, TRUE);
+ } else {
+ UnloadParamFile(fileInx);
+ }
+ break;
+ case PARAMFILE_REFRESH:
+ if (IsParamFileFavorite(fileInx) && IsParamFileDeleted(fileInx)) {
+ SetParamFileDeleted(fileInx, FALSE);
+ } else {
+ ReloadParamFile(fileInx);
+ }
+ break;
+ default:
+ AbortProg("Invalid change type %d in ParamChangeSelectedFiles", paramFileChange);
+ }
}
}
- DoChangeNotification( CHANGE_PARAMS );
- UpdateParamFileButton( fileInx );
+ ParamFileListLoad(paramFileInfo_da.cnt, &paramFileInfo_da);
+ DoChangeNotification(CHANGE_PARAMS);
}
/**
- * Select all files in the list and set action button
+ * Refresh selected files.
*
- * \param junk IN ignored
- * \return
+ * \param action IN FALSE = unload, TRUE = reload parameter files
+ * \return
*/
-static void ParamFileSelectAll( void *junk )
+static void ParamRefreshSelectedFiles(void * action)
{
- wListSelectAll( paramFileL );
- UpdateParamFileButton( 0 );
+ wIndex_t selcnt = wListGetSelectedCount(paramFileL);
+
+ //nothing selected -> leave
+ if (selcnt) {
+ DynString reloadMessage;
+ ParamChangeSelectedFiles(PARAMFILE_REFRESH);
+
+ DynStringMalloc(&reloadMessage, 16);
+ if (selcnt > 1) {
+ DynStringPrintf(&reloadMessage, _("%d parameter files reloaded."), selcnt);
+ } else {
+ DynStringCatCStr(&reloadMessage, _("One parameter file reloaded."));
+ }
+ wMessageSetValue(MESSAGETEXT, DynStringToCStr(&reloadMessage));
+ DynStringFree(&reloadMessage);
+ } else {
+ wBeep();
+ }
}
-static void ParamFileOk( void * junk )
+static void ParamUnloadSelectedFiles(void * action)
{
- wIndex_t fileInx;
- for ( fileInx = 0; fileInx < paramFileInfo_da.cnt; fileInx++ )
- paramFileInfo(fileInx).deletedShadow = paramFileInfo(fileInx).deleted;
- wHide( paramFileW );
+ wIndex_t selcnt = wListGetSelectedCount(paramFileL);
+ wMessageSetValue(MESSAGETEXT, "");
+ //nothing selected -> leave
+ if (selcnt) {
+ ParamChangeSelectedFiles(PARAMFILE_UNLOAD);
+ } else {
+ wBeep();
+ }
}
-static void ParamFileCancel( wWin_p junk )
+/**
+ * Select all files in the list and set action button
+ *
+ * \param junk IN ignored
+ * \return
+ */
+
+static void ParamFileSelectAll(void *junk)
{
- wIndex_t fileInx;
- for ( fileInx = 0; fileInx < paramFileInfo_da.cnt; fileInx++ )
- paramFileInfo(fileInx).deleted = paramFileInfo(fileInx).deletedShadow;
- wHide( paramFileW );
- DoChangeNotification( CHANGE_PARAMS );
+ wMessageSetValue(MESSAGETEXT, "");
+ wListSelectAll(paramFileL);
+ UpdateParamFileButton();
}
-
-static void ParamFilesChange( long changes )
+static void ParamFileOk(void * junk)
{
-#ifdef LATER
- int fileInx;
- wIndex_t listInx;
- if ((changes&CHANGE_PARAMS) == 0 ||
- paramFileW == NULL || !wWinIsVisible(paramFileW) )
- return;
- wControlShow( (wControl_p)paramFileL, FALSE );
- listInx = wListGetIndex(paramFileL);
- wListClear( paramFileL );
- for ( fileInx = 0; fileInx < paramFileInfo_da.cnt; fileInx++ ) {
- if (paramFileInfo(fileInx).valid) {
- strcpy( message, ((!paramFileSel) && paramFileInfo(fileInx).contents)?
- paramFileInfo(fileInx).contents:
- paramFileInfo(fileInx).name );
- wListAddValue( paramFileL, message, (paramFileInfo(fileInx).deleted)?mtbox_bm:chkbox_bm, (void*)fileInx );
- }
- }
- wListSetIndex( paramFileL, listInx );
- wControlShow( (wControl_p)paramFileL, TRUE );
-#endif
+ SearchUiOk(junk);
+
+ DoChangeNotification(CHANGE_PARAMS);
+ wHide(paramFileW);
}
static void ParamFileDlgUpdate(
- paramGroup_p pg,
- int inx,
- void * valueP )
+ paramGroup_p pg,
+ int inx,
+ void * valueP)
{
- switch (inx) {
- case I_PRMFILLIST:
- UpdateParamFileButton( (wIndex_t)(long)wListGetItemContext(paramFileL,wListGetIndex(paramFileL)) );
- break;
- case I_PRMFILTOGGLE:
- ParamFileLoadList();
- break;
- }
+ switch (inx) {
+ case I_PRMFILLIST:
+ UpdateParamFileButton();
+ break;
+ case I_PRMFILTOGGLE:
+ DoChangeNotification(CHANGE_PARAMS);
+ break;
+ }
}
-#include "bitmaps/mtbox.xbm"
-#include "bitmaps/chkbox.xbm"
-static void DoParamFiles( void * junk )
+void ParamFilesChange(long changes)
{
- wIndex_t listInx;
- void * data;
-
- if (paramFileW == NULL) {
- const char * dir;
- dir = wPrefGetString( "file", "paramdir" );
- if (dir != NULL)
- strcpy( curParamDir, dir );
- else {
- // in case there is no preference setting, use the installation's param directory as default
- char *str;
- MakeFullpath(&str, libDir, PARAM_SUBDIR, NULL);
- strcpy( curParamDir, str );
- free(str);
- }
- mtbox_bm = wIconCreateBitMap( mtbox_width, mtbox_height, mtbox_bits, drawColorBlack );
- chkbox_bm = wIconCreateBitMap( chkbox_width, chkbox_height, chkbox_bits, drawColorBlack );
- paramFileW = ParamCreateDialog( &paramFilePG, MakeWindowTitle(_("Parameter Files")), _("Ok"), ParamFileOk, ParamFileCancel, TRUE, NULL, 0, ParamFileDlgUpdate );
- paramFile_fs = wFilSelCreate( mainW, FS_LOAD, FS_MULTIPLEFILES, _("Load Parameters"), _("Parameter files|*.xtp"), LoadParamFile, NULL );
- ParamFileLoadList();
- }
- ParamLoadControls( &paramFilePG );
- ParamGroupRecord( &paramFilePG );
- if ((listInx = wListGetValues( paramFileL, NULL, 0, NULL, &data ))>=0)
- UpdateParamFileButton( (wIndex_t)(long)data );
- ParamFileLoadList();
- wShow( paramFileW );
+ if (changes & CHANGE_PARAMS || changes & CHANGE_SCALE) {
+ UpdateParamFileList();
+ if (paramFileW) {
+ ParamFileListLoad(paramFileInfo_da.cnt, &paramFileInfo_da);
+ }
+ }
}
+/**
+ * Create and open the parameter file dialog.
+ *
+ * \param junk
+ */
-EXPORT addButtonCallBack_t ParamFilesInit( void )
+void DoParamFiles(void * junk)
{
- BOOL_T initted = FALSE;
- if (!initted) {
- ParamRegister( &paramFilePG );
- RegisterChangeNotification( ParamFilesChange );
- initted = TRUE;
- }
- return &DoParamFiles;
+ void * data;
+
+ if (paramFileW == NULL) {
+ indicatorIcons[ STANDARD_PARAM ][ PARAMFILE_UNLOADED ] = wIconCreatePixMap(
+ greydot);
+ indicatorIcons[ STANDARD_PARAM ][ PARAMFILE_NOTUSABLE ] = wIconCreatePixMap(
+ reddot);
+ indicatorIcons[ STANDARD_PARAM ][ PARAMFILE_COMPATIBLE ] = wIconCreatePixMap(
+ yellowdot);
+ indicatorIcons[ STANDARD_PARAM ][ PARAMFILE_FIT] = wIconCreatePixMap(greendot);
+ indicatorIcons[ FAVORITE_PARAM ][ PARAMFILE_UNLOADED ] = wIconCreatePixMap(
+ greystar);
+ indicatorIcons[ FAVORITE_PARAM ][ PARAMFILE_NOTUSABLE ] = wIconCreatePixMap(
+ redstar);
+ indicatorIcons[ FAVORITE_PARAM ][ PARAMFILE_COMPATIBLE ] = wIconCreatePixMap(
+ yellowstar);
+ indicatorIcons[ FAVORITE_PARAM ][ PARAMFILE_FIT ] = wIconCreatePixMap(
+ greenstar);
+
+ ParamRegister(&paramFilePG);
+
+ paramFileW = ParamCreateDialog(&paramFilePG,
+ MakeWindowTitle(_("Parameter Files")), _("Ok"), ParamFileOk, NULL,
+ TRUE, NULL, F_RESIZE | F_RECALLSIZE, ParamFileDlgUpdate);
+ paramFile_fs = wFilSelCreate(mainW, FS_LOAD, FS_MULTIPLEFILES,
+ _("Load Parameters"), _("Parameter files (*.xtp)|*.xtp"), LoadParamFile, NULL);
+ }
+ ParamLoadControls(&paramFilePG);
+ ParamGroupRecord(&paramFilePG);
+ if ((wListGetValues(paramFileL, NULL, 0, NULL, &data))>=0) {
+ UpdateParamFileButton();
+ }
+
+ wShow(paramFileW);
}
diff --git a/app/bin/draw.c b/app/bin/draw.c
index 1a0a74f..343ae3f 100644
--- a/app/bin/draw.c
+++ b/app/bin/draw.c
@@ -50,18 +50,32 @@
#include "param.h"
#include "track.h"
#include "utility.h"
+#include "layout.h"
static void DrawRoomWalls( wBool_t );
-EXPORT void DrawMarkers( void );
-static void ConstraintOrig( coOrd *, coOrd );
+static void DrawMarkers( void );
+static void ConstraintOrig( coOrd *, coOrd, int, int );
+static void DoMouse( wAction_t action, coOrd pos );
+static void DDrawPoly(
+ drawCmd_p d,
+ int cnt,
+ coOrd * pts,
+ int * types,
+ wDrawColor color,
+ wDrawWidth width,
+ int fill,
+ int open );
+static void DrawMapBoundingBox( BOOL_T set );
+static void DrawTicks( drawCmd_p d, coOrd size );
-static int log_pan = 0;
+EXPORT int log_pan = 0;
static int log_zoom = 0;
static int log_mouse = 0;
+static int log_redraw = 0;
-static wFontSize_t drawMaxTextFontSize = 100;
+static BOOL_T hideBox = FALSE;
-extern long zoomCorner;
+static wFontSize_t drawMaxTextFontSize = 100;
/****************************************************************************
*
@@ -69,12 +83,6 @@ extern long zoomCorner;
*
*/
-#define INIT_MAIN_SCALE (8.0)
-#define INIT_MAP_SCALE (64.0)
-#define MAX_MAIN_SCALE (256.0)
-#define MIN_MAIN_SCALE (1.0)
-#define MIN_MAIN_MACRO (0.10)
-
// static char FAR message[STR_LONG_SIZE];
EXPORT wPos_t closePixels = 10;
@@ -83,14 +91,31 @@ EXPORT long drawCount;
EXPORT BOOL_T drawEnable = TRUE;
EXPORT long currRedraw = 0;
+EXPORT coOrd panCenter;
+EXPORT coOrd menuPos;
+
EXPORT wDrawColor drawColorBlack;
EXPORT wDrawColor drawColorWhite;
EXPORT wDrawColor drawColorRed;
EXPORT wDrawColor drawColorBlue;
EXPORT wDrawColor drawColorGreen;
EXPORT wDrawColor drawColorAqua;
+EXPORT wDrawColor drawColorPreviewSelected;
+EXPORT wDrawColor drawColorPreviewUnselected;
+EXPORT wDrawColor drawColorPowderedBlue;
EXPORT wDrawColor drawColorPurple;
EXPORT wDrawColor drawColorGold;
+EXPORT wDrawColor drawColorGrey10;
+EXPORT wDrawColor drawColorGrey20;
+EXPORT wDrawColor drawColorGrey30;
+EXPORT wDrawColor drawColorGrey40;
+EXPORT wDrawColor drawColorGrey50;
+EXPORT wDrawColor drawColorGrey60;
+EXPORT wDrawColor drawColorGrey70;
+EXPORT wDrawColor drawColorGrey80;
+EXPORT wDrawColor drawColorGrey90;
+
+
EXPORT DIST_T pixelBins = 80;
@@ -104,6 +129,7 @@ static wPos_t infoHeight;
static wPos_t textHeight;
EXPORT wWin_p mapW;
EXPORT BOOL_T mapVisible;
+EXPORT BOOL_T magneticSnap;
EXPORT wDrawColor markerColor;
EXPORT wDrawColor borderColor;
@@ -148,15 +174,17 @@ static int mousePositionx, mousePositiony; /**< position of mouse pointer */
static int delayUpdate = 1;
-static char xLabel[] = "X : ";
-static char yLabel[] = "Y : ";
-static char zoomLabel[] = "Zoom : ";
+static char xLabel[] = "X: ";
+static char yLabel[] = "Y: ";
+static char zoomLabel[] = "Zoom: ";
static struct {
char * name;
double value;
wMenuRadio_p pdRadio;
wMenuRadio_p btRadio;
+ wMenuRadio_p ctxRadio1;
+ wMenuRadio_p panRadio;
} zoomList[] = {
{ "1:10", 1.0 / 10.0 },
{ "1:9", 1.0 / 9.0 },
@@ -293,9 +321,26 @@ static void DDrawLine(
d->CoOrd2Pix(d,p0,&x0,&y0);
d->CoOrd2Pix(d,p1,&x1,&y1);
drawCount++;
+ wDrawLineType_e lineOpt = wDrawLineSolid;
+ unsigned long NotSolid = DC_NOTSOLIDLINE;
+ unsigned long opt = d->options&NotSolid;
+ if (opt == DC_DASH)
+ lineOpt = wDrawLineDash;
+ else if(opt == DC_DOT)
+ lineOpt = wDrawLineDot;
+ else if(opt == DC_DASHDOT)
+ lineOpt = wDrawLineDashDot;
+ else if (opt == DC_DASHDOTDOT)
+ lineOpt = wDrawLineDashDotDot;
+ else if(opt == DC_CENTER)
+ lineOpt = wDrawLineCenter;
+ else if (opt == DC_PHANTOM)
+ lineOpt = wDrawLinePhantom;
+
if (drawEnable) {
wDrawLine( d->d, x0, y0, x1, y1,
- width, ((d->options&DC_DASH)==0)?wDrawLineSolid:wDrawLineDash,
+ width,
+ lineOpt,
color, (wDrawOpts)d->funcs->options );
}
}
@@ -311,37 +356,78 @@ static void DDrawArc(
wDrawWidth width,
wDrawColor color )
{
- wPos_t x, y;
- ANGLE_T da;
- coOrd p0, p1;
- DIST_T rr;
- int i, cnt;
-
- if (d == &mapD && !mapVisible)
- return;
- rr = (r / d->scale) * d->dpi + 0.5;
- if (rr > wDrawGetMaxRadius(d->d)) {
- da = (maxArcSegStraightLen * 180) / (M_PI * rr);
- cnt = (int)(angle1/da) + 1;
- da = angle1 / cnt;
- PointOnCircle( &p0, p, r, angle0 );
- for ( i=1; i<=cnt; i++ ) {
- angle0 += da;
- PointOnCircle( &p1, p, r, angle0 );
- DrawLine( d, p0, p1, width, color );
- p0 = p1;
- }
- return;
- }
- if (d->angle!=0.0 && angle1 < 360.0)
- angle0 = NormalizeAngle( angle0-d->angle );
- d->CoOrd2Pix(d,p,&x,&y);
- drawCount++;
- if (drawEnable) {
- wDrawArc( d->d, x, y, (wPos_t)(rr), angle0, angle1, drawCenter,
- width, ((d->options&DC_DASH)==0)?wDrawLineSolid:wDrawLineDash,
- color, (wDrawOpts)d->funcs->options );
- }
+ wPos_t x, y;
+ ANGLE_T da;
+ coOrd p0, p1;
+ DIST_T rr;
+ int i, cnt;
+
+ if (d == &mapD && !mapVisible)
+ {
+ return;
+ }
+ rr = (r / d->scale) * d->dpi + 0.5;
+ if (rr > wDrawGetMaxRadius(d->d))
+ {
+ da = (maxArcSegStraightLen * 180) / (M_PI * rr);
+ cnt = (int)(angle1/da) + 1;
+ da = angle1 / cnt;
+ coOrd min,max;
+ min = d->orig;
+ max.x = min.x + d->size.x;
+ max.y = min.y + d->size.y;
+ PointOnCircle(&p0, p, r, angle0);
+ for (i=1; i<=cnt; i++) {
+ angle0 += da;
+ PointOnCircle(&p1, p, r, angle0);
+ if (d->angle == 0.0 &&
+ ((p0.x >= min.x &&
+ p0.x <= max.x &&
+ p0.y >= min.y &&
+ p0.y <= max.y) ||
+ (p1.x >= min.x &&
+ p1.x <= max.x &&
+ p1.y >= min.y &&
+ p1.y <= max.y))) {
+ DrawLine(d, p0, p1, width, color);
+ } else {
+ coOrd clip0 = p0, clip1 = p1;
+ if (ClipLine(&clip0, &clip1, d->orig, d->angle, d->size)) {
+ DrawLine(d, clip0, clip1, width, color);
+ }
+ }
+
+ p0 = p1;
+ }
+ return;
+ }
+ if (d->angle!=0.0 && angle1 < 360.0)
+ {
+ angle0 = NormalizeAngle(angle0-d->angle);
+ }
+ d->CoOrd2Pix(d,p,&x,&y);
+ drawCount++;
+ wDrawLineType_e lineOpt = wDrawLineSolid;
+ unsigned long NotSolid = DC_NOTSOLIDLINE;
+ unsigned long opt = d->options&NotSolid;
+ if (opt == DC_DASH)
+ lineOpt = wDrawLineDash;
+ else if(opt == DC_DOT)
+ lineOpt = wDrawLineDot;
+ else if(opt == DC_DASHDOT)
+ lineOpt = wDrawLineDashDot;
+ else if (opt == DC_DASHDOTDOT)
+ lineOpt = wDrawLineDashDotDot;
+ else if(opt == DC_CENTER)
+ lineOpt = wDrawLineCenter;
+ else if (opt == DC_PHANTOM)
+ lineOpt = wDrawLinePhantom;
+ if (drawEnable)
+ {
+ wDrawArc(d->d, x, y, (wPos_t)(rr), angle0, angle1, drawCenter,
+ width, lineOpt,
+ color, (wDrawOpts)d->funcs->options);
+ }
}
@@ -357,30 +443,76 @@ static void DDrawString(
wPos_t x, y;
if (d == &mapD && !mapVisible)
return;
- fontSize /= d->scale;
d->CoOrd2Pix(d,p,&x,&y);
- wDrawString( d->d, x, y, d->angle-a, s, fp, fontSize, color, (wDrawOpts)d->funcs->options );
+ if ( color == wDrawColorWhite ) {
+ wPos_t width, height, descent, ascent;
+ coOrd pos[4], size;
+ double scale = 1.0;
+ wDrawGetTextSize( &width, &height, &descent, &ascent, d->d, s, fp, fontSize );
+ pos[0] = p;
+ size.x = SCALEX(mainD,width)*scale;
+ size.y = SCALEY(mainD,height)*scale;
+ pos[1].x = p.x+size.x;
+ pos[1].y = p.y;
+ pos[2].x = p.x+size.x;
+ pos[2].y = p.y+size.y;
+ pos[3].x = p.x;
+ pos[3].y = p.y+size.y;
+ Rotate( &pos[1], pos[0], a );
+ Rotate( &pos[2], pos[0], a );
+ Rotate( &pos[3], pos[0], a );
+ DDrawPoly( d, 4, pos, NULL, color, 0, 1, 0 );
+ } else {
+ fontSize /= d->scale;
+ wDrawString( d->d, x, y, d->angle-a, s, fp, fontSize, color, (wDrawOpts)d->funcs->options );
+ }
}
-static void DDrawFillPoly(
+static void DDrawPoly(
drawCmd_p d,
int cnt,
coOrd * pts,
- wDrawColor color )
+ int * types,
+ wDrawColor color,
+ wDrawWidth width,
+ int fill,
+ int open )
{
typedef wPos_t wPos2[2];
static dynArr_t wpts_da;
+ static dynArr_t wpts_type_da;
int inx;
wPos_t x, y;
DYNARR_SET( wPos2, wpts_da, cnt * 2 );
+ DYNARR_SET( int, wpts_type_da, cnt);
#define wpts(N) DYNARR_N( wPos2, wpts_da, N )
+#define wtype(N) DYNARR_N( wPolyLine_e, wpts_type_da, N )
for ( inx=0; inx<cnt; inx++ ) {
d->CoOrd2Pix( d, pts[inx], &x, &y );
wpts(inx)[0] = x;
wpts(inx)[1] = y;
+ if (!types)
+ wtype(inx) = 0;
+ else
+ wtype(inx) = (wPolyLine_e)types[inx];
}
- wDrawFilledPolygon( d->d, &wpts(0), cnt, color, (wDrawOpts)d->funcs->options );
+ wDrawLineType_e lineOpt = wDrawLineSolid;
+ unsigned long NotSolid = DC_NOTSOLIDLINE;
+ unsigned long opt = d->options&NotSolid;
+ if (opt == DC_DASH)
+ lineOpt = wDrawLineDash;
+ else if(opt == DC_DOT)
+ lineOpt = wDrawLineDot;
+ else if(opt == DC_DASHDOT)
+ lineOpt = wDrawLineDashDot;
+ else if (opt == DC_DASHDOTDOT)
+ lineOpt = wDrawLineDashDotDot;
+ else if(opt == DC_CENTER)
+ lineOpt = wDrawLineCenter;
+ else if (opt == DC_PHANTOM)
+ lineOpt = wDrawLinePhantom;
+ wDrawPolygon( d->d, &wpts(0), &wtype(0), cnt, color, width, lineOpt, (wDrawOpts)d->funcs->options, fill, open );
}
@@ -420,24 +552,20 @@ static void DDrawFillCircle(
}
-EXPORT void DrawHilight( drawCmd_p d, coOrd p, coOrd s )
+EXPORT void DrawHilight( drawCmd_p d, coOrd p, coOrd s, BOOL_T add )
{
wPos_t x, y, w, h;
if (d == &mapD && !mapVisible)
return;
-#ifdef LATER
- if (d->options&DC_TEMPSEGS) {
- return;
- }
- if (d->options&DC_PRINT)
- return;
-#endif
w = (wPos_t)((s.x/d->scale)*d->dpi+0.5);
h = (wPos_t)((s.y/d->scale)*d->dpi+0.5);
d->CoOrd2Pix(d,p,&x,&y);
- wDrawFilledRectangle( d->d, x, y, w, h, wDrawColorBlack, wDrawOptTemp );
-}
+ if ( add )
+ wDrawFilledRectangle( d->d, x, y, w, h, drawColorPowderedBlue, wDrawOptTemp|wDrawOptTransparent );
+ else
+ wDrawFilledRectangle( d->d, x, y, w, h, selectedColor, wDrawOptTemp|wDrawOptTransparent );
+}
EXPORT void DrawHilightPolygon( drawCmd_p d, coOrd *p, int cnt )
{
@@ -454,7 +582,10 @@ EXPORT void DrawHilightPolygon( drawCmd_p d, coOrd *p, int cnt )
for (i=0; i<cnt; i++) {
d->CoOrd2Pix(d,p[i],&q[i][0],&q[i][1]);
}
- wDrawFilledPolygon( d->d, q, cnt, wDrawColorBlack, wDrawOptTemp );
+ static wDrawColor color = 0;
+ if ( color == 0 )
+ color = wDrawColorGray( 70 );
+ wDrawPolygon( d->d, q, NULL, cnt, color, 0, 0, wDrawOptTemp|wDrawOptTransparent, 1, 0 );
}
@@ -467,13 +598,14 @@ EXPORT void DrawMultiString(
wDrawColor color,
ANGLE_T a,
coOrd * lo,
- coOrd * hi)
+ coOrd * hi,
+ BOOL_T boxed)
{
char * cp;
char * cp1;
POS_T lineH, lineW;
coOrd size, textsize, posl, orig;
- POS_T descent;
+ POS_T descent, ascent;
char *line;
if (!text || !*text) {
@@ -481,9 +613,9 @@ EXPORT void DrawMultiString(
}
line = malloc(strlen(text) + 1);
- DrawTextSize2( &mainD, "Aqjlp", fp, fs, TRUE, &textsize, &descent);
- POS_T ascent = textsize.y-descent;
- lineH = ascent+descent*1.5;
+ DrawTextSize2( &mainD, "Aqjlp", fp, fs, TRUE, &textsize, &descent, &ascent);
+ //POS_T ascent = textsize.y-descent;
+ lineH = (ascent+descent)*1.0;
size.x = 0.0;
size.y = 0.0;
orig.x = pos.x;
@@ -494,7 +626,7 @@ EXPORT void DrawMultiString(
while (*text != '\0' && *text != '\n')
*cp++ = *text++;
*cp = '\0';
- DrawTextSize2( &mainD, cp1, fp, fs, TRUE, &textsize, &descent);
+ DrawTextSize2( &mainD, cp1, fp, fs, TRUE, &textsize, &descent, &ascent);
lineW = textsize.x;
if (lineW>size.x)
size.x = lineW;
@@ -515,7 +647,25 @@ EXPORT void DrawMultiString(
}
if (hi) {
hi->x = posl.x+size.x;
- hi->y = posl.y+ascent;
+ hi->y = orig.y+ascent;
+ }
+ if (boxed && (d != &mapD)) {
+ int bw=2, bh=2, br=1, bb=1;
+ size.x += bw*d->scale/d->dpi;
+ size.y = fabs(orig.y-posl.y)+bh*d->scale/d->dpi;
+ size.y += descent+ascent;
+ coOrd p[4];
+ p[0] = orig; p[0].x -= (bw-br)*d->scale/d->dpi; p[0].y += (bh-bb)*d->scale/d->dpi+ascent;
+ p[1] = p[0]; p[1].x += size.x;
+ p[2] = p[1]; p[2].y -= size.y;
+ p[3] = p[2]; p[3].x = p[0].x;
+ for (int i=0;i<4;i++) {
+ Rotate( &p[i], orig, a);
+ }
+ DrawLine( d, p[0], p[1], 0, color );
+ DrawLine( d, p[1], p[2], 0, color );
+ DrawLine( d, p[2], p[3], 0, color );
+ DrawLine( d, p[3], p[0], 0, color );
}
free(line);
@@ -532,24 +682,25 @@ EXPORT void DrawBoxedString(
ANGLE_T a )
{
coOrd size, p[4], p0=pos, p1, p2;
- static int bw=5, bh=4, br=2, bb=2;
+ static int bw=2, bh=2, br=1, bb=1;
static double arrowScale = 0.5;
- long options = d->options;
- POS_T descent;
+ unsigned long options = d->options;
+ POS_T descent, ascent;
/*DrawMultiString( d, pos, text, fp, fs, color, a, &lo, &hi );*/
if ( fs < 2*d->scale )
return;
#ifndef WINDOWS
if ( ( d->options & DC_PRINT) != 0 ) {
double scale = ((FLOAT_T)fs)/((FLOAT_T)drawMaxTextFontSize)/72.0;
- wPos_t w, h, d;
- wDrawGetTextSize( &w, &h, &d, mainD.d, text, fp, drawMaxTextFontSize );
+ wPos_t w, h, d, a;
+ wDrawGetTextSize( &w, &h, &d, &a, mainD.d, text, fp, drawMaxTextFontSize );
size.x = w*scale;
size.y = h*scale;
descent = d*scale;
+ ascent = a*scale;
} else
#endif
- DrawTextSize2( &mainD, text, fp, fs, TRUE, &size, &descent );
+ DrawTextSize2( &mainD, text, fp, fs, TRUE, &size, &descent, &ascent );
#ifdef WINDOWS
/*h -= 15;*/
#endif
@@ -561,10 +712,9 @@ EXPORT void DrawBoxedString(
}
size.x += bw*d->scale/d->dpi;
size.y += bh*d->scale/d->dpi;
- size.y += descent;
p[0] = p0;
p[0].x -= br*d->scale/d->dpi;
- p[0].y -= bb*d->scale/d->dpi+descent;
+ p[0].y -= (bb*d->scale/d->dpi+descent);
p[1].y = p[0].y;
p[2].y = p[3].y = p[0].y + size.y;
p[1].x = p[2].x = p[0].x + size.x;
@@ -589,12 +739,12 @@ EXPORT void DrawBoxedString(
DrawString( d, p0, 0.0, text, fp, fs, color );
break;
case BOX_INVERT:
- DrawFillPoly( d, 4, p, color );
+ DrawPoly( d, 4, p, NULL, color, 0, 1, 0);
if ( color != wDrawColorWhite )
- DrawString( d, p0, 0.0, text, fp, fs, wDrawColorWhite );
+ DrawString( d, p0, 0.0, text, fp, fs, wDrawColorGray( 94 ) );
break;
case BOX_BACKGROUND:
- DrawFillPoly( d, 4, p, wDrawColorWhite );
+ DrawPoly( d, 4, p, NULL, wDrawColorWhite, 0, 1, 0 );
DrawString( d, p0, 0.0, text, fp, fs, color );
break;
}
@@ -609,9 +759,10 @@ EXPORT void DrawTextSize2(
wFontSize_t fs,
BOOL_T relative,
coOrd * size,
- POS_T * descent )
+ POS_T * descent,
+ POS_T * ascent)
{
- wPos_t w, h, d;
+ wPos_t w, h, d, a;
FLOAT_T scale = 1.0;
if ( relative )
fs /= dp->scale;
@@ -619,14 +770,16 @@ EXPORT void DrawTextSize2(
scale = ((FLOAT_T)fs)/((FLOAT_T)drawMaxTextFontSize);
fs = drawMaxTextFontSize;
}
- wDrawGetTextSize( &w, &h, &d, dp->d, text, fp, fs );
+ wDrawGetTextSize( &w, &h, &d, &a, dp->d, text, fp, fs );
size->x = SCALEX(mainD,w)*scale;
size->y = SCALEY(mainD,h)*scale;
*descent = SCALEY(mainD,d)*scale;
+ *ascent = SCALEY(mainD,a)*scale;
if ( relative ) {
size->x *= dp->scale;
size->y *= dp->scale;
*descent *= dp->scale;
+ *ascent *=dp->scale;
}
/* printf( "DTS2(\"%s\",%0.3f,%d) = (w%d,h%d,d%d) *%0.3f x%0.3f y%0.3f %0.3f\n", text, fs, relative, w, h, d, scale, size->x, size->y, *descent );*/
}
@@ -639,8 +792,8 @@ EXPORT void DrawTextSize(
BOOL_T relative,
coOrd * size )
{
- POS_T descent;
- DrawTextSize2( dp, text, fp, fs, relative, size, &descent );
+ POS_T descent, ascent;
+ DrawTextSize2( dp, text, fp, fs, relative, size, &descent, &ascent );
}
EXPORT void DrawMultiLineTextSize(
@@ -652,15 +805,14 @@ EXPORT void DrawMultiLineTextSize(
coOrd * size,
coOrd * lastline )
{
- POS_T descent, lineW, lineH;
+ POS_T descent, ascent, lineW, lineH;
coOrd textsize, blocksize;
char *cp;
char *line = malloc(strlen(text) + 1);
- DrawTextSize2( &mainD, "Aqlip", fp, fs, TRUE, &textsize, &descent);
- POS_T ascent = textsize.y-descent;
- lineH = ascent+descent*1.5;
+ DrawTextSize2( &mainD, "Aqlip", fp, fs, TRUE, &textsize, &descent, &ascent);
+ lineH = (ascent+descent)*1.0;
blocksize.x = 0;
blocksize.y = 0;
lastline->x = 0;
@@ -671,17 +823,20 @@ EXPORT void DrawMultiLineTextSize(
*cp++ = *text++;
*cp = '\0';
blocksize.y += lineH;
- DrawTextSize2( &mainD, line, fp, fs, TRUE, &textsize, &descent);
+ DrawTextSize2( &mainD, line, fp, fs, TRUE, &textsize, &descent, &ascent);
lineW = textsize.x;
if (lineW>blocksize.x)
blocksize.x = lineW;
lastline->x = textsize.x;
if (*text =='\n') {
+ blocksize.y += lineH;
lastline->y -= lineH;
lastline->x = 0;
}
- if (*text == '\0')
+ if (*text == '\0') {
+ blocksize.y += textsize.y;
break;
+ }
text++;
}
size->x = blocksize.x;
@@ -760,6 +915,7 @@ static void TempSegString(
DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 );
tempSegs(tempSegs_da.cnt-1).type = SEG_TEXT;
tempSegs(tempSegs_da.cnt-1).color = color;
+ tempSegs(tempSegs_da.cnt-1).u.t.boxed = FALSE;
tempSegs(tempSegs_da.cnt-1).width = 0;
tempSegs(tempSegs_da.cnt-1).u.t.pos = p;
tempSegs(tempSegs_da.cnt-1).u.t.angle = a;
@@ -769,22 +925,33 @@ static void TempSegString(
}
-static void TempSegFillPoly(
+static void TempSegPoly(
drawCmd_p d,
int cnt,
coOrd * pts,
- wDrawColor color )
+ int * types,
+ wDrawColor color,
+ wDrawWidth width,
+ int fill,
+ int open )
{
-#ifdef LATER
- pts is not guaranteed to valid
- DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 );
- tempSegs(tempSegs_da.cnt-1).type = SEG_FILPOLY;
+ DYNARR_APPEND( trkSeg_t, tempSegs_da, 1);
+ tempSegs(tempSegs_da.cnt-1).type = fill?SEG_FILPOLY:SEG_POLY;
tempSegs(tempSegs_da.cnt-1).color = color;
- tempSegs(tempSegs_da.cnt-1).width = 0;
+ if (d->options&DC_SIMPLE)
+ tempSegs(tempSegs_da.cnt-1).width = 0;
+ else
+ tempSegs(tempSegs_da.cnt-1).width = width*d->scale/d->dpi;
+ tempSegs(tempSegs_da.cnt-1).u.p.polyType = open?POLYLINE:FREEFORM;
tempSegs(tempSegs_da.cnt-1).u.p.cnt = cnt;
- tempSegs(tempSegs_da.cnt-1).u.p.pts = pts;
-#endif
- return;
+ tempSegs(tempSegs_da.cnt-1).u.p.orig = zero;
+ tempSegs(tempSegs_da.cnt-1).u.p.angle = 0.0;
+ tempSegs(tempSegs_da.cnt-1).u.p.pts = (pts_t *)MyMalloc(cnt*sizeof(pts_t));
+ for (int i=0;i<=cnt-1;i++) {
+ tempSegs(tempSegs_da.cnt-1).u.p.pts[i].pt = pts[i];
+ tempSegs(tempSegs_da.cnt-1).u.p.pts[i].pt_type = (d->options&DC_SIMPLE)==0?types[i]:wPolyLineStraight;
+ }
+
}
@@ -817,7 +984,7 @@ EXPORT drawFuncs_t screenDrawFuncs = {
DDrawArc,
DDrawString,
DDrawBitMap,
- DDrawFillPoly,
+ DDrawPoly,
DDrawFillCircle };
EXPORT drawFuncs_t tempDrawFuncs = {
@@ -826,7 +993,7 @@ EXPORT drawFuncs_t tempDrawFuncs = {
DDrawArc,
DDrawString,
DDrawBitMap,
- DDrawFillPoly,
+ DDrawPoly,
DDrawFillCircle };
EXPORT drawFuncs_t printDrawFuncs = {
@@ -835,7 +1002,7 @@ EXPORT drawFuncs_t printDrawFuncs = {
DDrawArc,
DDrawString,
NoDrawBitMap,
- DDrawFillPoly,
+ DDrawPoly,
DDrawFillCircle };
EXPORT drawFuncs_t tempSegDrawFuncs = {
@@ -844,17 +1011,17 @@ EXPORT drawFuncs_t tempSegDrawFuncs = {
TempSegArc,
TempSegString,
NoDrawBitMap,
- TempSegFillPoly,
+ TempSegPoly,
TempSegFillCircle };
EXPORT drawCmd_t mainD = {
NULL, &screenDrawFuncs, DC_TICKS, INIT_MAIN_SCALE, 0.0, {0.0,0.0}, {0.0,0.0}, MainPix2CoOrd, MainCoOrd2Pix };
EXPORT drawCmd_t tempD = {
- NULL, &tempDrawFuncs, DC_TICKS|DC_SIMPLE, INIT_MAIN_SCALE, 0.0, {0.0,0.0}, {0.0,0.0}, MainPix2CoOrd, MainCoOrd2Pix };
+ NULL, &tempDrawFuncs, DC_TICKS, INIT_MAIN_SCALE, 0.0, {0.0,0.0}, {0.0,0.0}, MainPix2CoOrd, MainCoOrd2Pix };
EXPORT drawCmd_t mapD = {
- NULL, &screenDrawFuncs, 0, INIT_MAP_SCALE, 0.0, {0.0,0.0}, {96.0,48.0}, Pix2CoOrd, CoOrd2Pix };
+ NULL, &screenDrawFuncs, DC_SIMPLE, INIT_MAP_SCALE, 0.0, {0.0,0.0}, {96.0,48.0}, Pix2CoOrd, CoOrd2Pix };
/*****************************************************************************
@@ -919,7 +1086,7 @@ EXPORT void InitInfoBar( void )
{
wPos_t width, height, y, yb, ym, x, boxH;
wWinGetSize( mainW, &width, &height );
- infoHeight = 3 + wStatusGetHeight( COMBOBOX ) + 3;
+ infoHeight = 2 + wStatusGetHeight( COMBOBOX ) + 2 ;
textHeight = wStatusGetHeight(0L);
y = height - max(infoHeight,textHeight)-10;
@@ -927,8 +1094,8 @@ EXPORT void InitInfoBar( void )
y -= 19; /* Kludge for MSW */
#endif
- infoD.pos_w = GetInfoPosWidth() + 2;
- infoD.scale_w = wStatusGetWidth( "999:1" ) + wStatusGetWidth( zoomLabel ) + 6;
+ infoD.pos_w = GetInfoPosWidth();
+ infoD.scale_w = wStatusGetWidth( "999:1" ) + wStatusGetWidth( zoomLabel );
/* we do not use the count label for the moment */
infoD.count_w = 0;
infoD.info_w = width - 20 - infoD.pos_w*2 - infoD.scale_w - infoD.count_w - 45; // Allow Window to resize down
@@ -941,13 +1108,13 @@ EXPORT void InitInfoBar( void )
x = 2;
infoD.scale_b = wBoxCreate( mainW, x, yb, NULL, wBoxBelow, infoD.scale_w, boxH );
infoD.scale_m = wStatusCreate( mainW, x+info_xm_offset, ym, "infoBarScale", infoD.scale_w-six, zoomLabel);
- x += infoD.scale_w + 10;
+ x += infoD.scale_w + 2;
infoD.posX_b = wBoxCreate( mainW, x, yb, NULL, wBoxBelow, infoD.pos_w, boxH );
infoD.posX_m = wStatusCreate( mainW, x+info_xm_offset, ym, "infoBarPosX", infoD.pos_w-six, xLabel );
- x += infoD.pos_w + 5;
+ x += infoD.pos_w + 2;
infoD.posY_b = wBoxCreate( mainW, x, yb, NULL, wBoxBelow, infoD.pos_w, boxH );
infoD.posY_m = wStatusCreate( mainW, x+info_xm_offset, ym, "infoBarPosY", infoD.pos_w-six, yLabel );
- x += infoD.pos_w + 10;
+ x += infoD.pos_w + 2;
messageOrControlX = x+info_xm_offset; //Remember Position
messageOrControlY = ym;
infoD.info_b = wBoxCreate( mainW, x, yb, NULL, wBoxBelow, infoD.info_w, boxH );
@@ -966,10 +1133,10 @@ static void SetInfoBar( void )
y = height - max(infoHeight,textHeight)-10;
newDistanceFormat = GetDistanceFormat();
if ( newDistanceFormat != oldDistanceFormat ) {
- infoD.pos_w = GetInfoPosWidth() + 2;
- wBoxSetSize( infoD.posX_b, infoD.pos_w, infoHeight-5 );
+ infoD.pos_w = GetInfoPosWidth();
+ wBoxSetSize( infoD.posX_b, infoD.pos_w, infoHeight-3 );
wStatusSetWidth( infoD.posX_m, infoD.pos_w-six );
- wBoxSetSize( infoD.posY_b, infoD.pos_w, infoHeight-5 );
+ wBoxSetSize( infoD.posY_b, infoD.pos_w, infoHeight-3 );
wStatusSetWidth( infoD.posY_m, infoD.pos_w-six );
}
infoD.info_w = width - 20 - infoD.pos_w*2 - infoD.scale_w - infoD.count_w - 40 + 4;
@@ -1028,13 +1195,12 @@ EXPORT void InfoCount( wIndex_t count )
EXPORT void InfoPos( coOrd pos )
{
- DrawMarkers();
sprintf( message, "%s%s", xLabel, FormatDistance(pos.x) );
wStatusSetValue( infoD.posX_m, message );
sprintf( message, "%s%s", yLabel, FormatDistance(pos.y) );
wStatusSetValue( infoD.posY_m, message );
+
oldMarker = pos;
- DrawMarkers();
}
static wControl_p deferSubstituteControls[NUM_INFOCTL+1];
@@ -1071,7 +1237,11 @@ EXPORT void InfoSubstituteControls(
for ( inx=0; controls[inx]; inx++ ) {
curInfoLabelWidth[inx] = wLabelWidth(_(labels[inx]));
x += curInfoLabelWidth[inx];
- int y_this = y + (textHeight/2) - (wControlGetHeight( controls[inx] )/2);
+#ifdef WINDOWS
+ int y_this = y + (infoHeight/2) - (textHeight / 2 );
+#else
+ int y_this = y + (infoHeight / 2) - (wControlGetHeight(controls[inx]) / 2) - 2;
+#endif
wControlSetPos( controls[inx], x, y_this );
x += wControlGetWidth( controls[inx] );
wControlSetLabel( controls[inx], _(labels[inx]) );
@@ -1090,39 +1260,23 @@ EXPORT void SetMessage( char * msg )
}
-static void ChangeMapScale( void )
+static void ChangeMapScale( BOOL_T reset )
{
wPos_t w, h;
wPos_t dw, dh;
FLOAT_T fw, fh;
- wGetDisplaySize( &dw, &dh );
- dw /= 2;
- dh /= 2;
- fw = ((mapD.size.x/mapD.scale)*mapD.dpi + 0.5)+2;
- fh = ((mapD.size.y/mapD.scale)*mapD.dpi + 0.5)+2;
- if (fw > dw || fh > dh) {
- if (fw/dw > fh/dh) {
- mapD.scale = ceil(mapD.size.x*mapD.dpi/dw);
- } else {
- mapD.scale = ceil(mapD.size.y*mapD.dpi/dh);
- }
- mapScale = (long)mapD.scale;
- fw = ((mapD.size.x/mapD.scale)*mapD.dpi + 0.5)+2;
- fh = ((mapD.size.y/mapD.scale)*mapD.dpi + 0.5)+2;
- } else if ( fw < 100.0 && fh < 100.0 ) {
- if (fw > fh) {
- mapD.scale = ceil(mapD.size.x*mapD.dpi/100);
- } else {
- mapD.scale = ceil(mapD.size.y*mapD.dpi/100);
- }
- mapScale = (long)mapD.scale;
- fw = ((mapD.size.x/mapD.scale)*mapD.dpi + 0.5)+2;
- fh = ((mapD.size.y/mapD.scale)*mapD.dpi + 0.5)+2;
- }
+
+ fw = (((mapD.size.x/mapD.scale)*mapD.dpi) + 0.5)+2;
+ fh = (((mapD.size.y/mapD.scale)*mapD.dpi) + 0.5)+2;
+
w = (wPos_t)fw;
h = (wPos_t)fh;
- wWinSetSize( mapW, w+DlgSepLeft+DlgSepRight, h+DlgSepTop+DlgSepBottom );
+ if (reset) {
+ wGetDisplaySize( &dw, &dh );
+ wSetGeometry(mapW, 50, dw, 50, dh, -1, -1, mapD.size.x/mapD.size.y);
+ wWinSetSize( mapW, w+DlgSepLeft+DlgSepRight, h+DlgSepTop+DlgSepBottom);
+ }
wDrawSetSize( mapD.d, w, h, NULL );
}
@@ -1137,12 +1291,10 @@ EXPORT BOOL_T SetRoomSize( coOrd size )
mapD.size.y == size.y )
return TRUE;
mapD.size = size;
+ SetLayoutRoomSize(size);
if ( mapW == NULL)
return TRUE;
- ChangeMapScale();
- ConstraintOrig( &mainD.orig, mainD.size );
- tempD.orig = mainD.orig;
- /*MainRedraw();*/
+ ChangeMapScale(TRUE);
wPrefSetFloat( "draw", "roomsizeX", mapD.size.x );
wPrefSetFloat( "draw", "roomsizeY", mapD.size.y );
return TRUE;
@@ -1155,23 +1307,21 @@ EXPORT void GetRoomSize( coOrd * froomSize )
}
-EXPORT void MapRedraw( void )
+static void MapRedraw()
{
if (inPlaybackQuit)
return;
-#ifdef VERBOSE
-lprintf("MapRedraw\n");
-#endif
+ static int cMR = 0;
+ LOG( log_redraw, 2, ( "MapRedraw: %d\n", cMR++ ) );
if (!mapVisible)
return;
-
if (delayUpdate)
wDrawDelayUpdate( mapD.d, TRUE );
- wSetCursor( wCursorWait );
+ //wSetCursor( mapD.d, wCursorWait );
wDrawClear( mapD.d );
DrawTracks( &mapD, mapD.scale, mapD.orig, mapD.size );
DrawMapBoundingBox( TRUE );
- wSetCursor( wCursorNormal );
+ //wSetCursor( mapD.d, defaultCursor );
wDrawDelayUpdate( mapD.d, FALSE );
}
@@ -1179,7 +1329,7 @@ lprintf("MapRedraw\n");
static void MapResize( void )
{
mapD.scale = mapScale;
- ChangeMapScale();
+ ChangeMapScale(TRUE);
MapRedraw();
}
@@ -1222,25 +1372,107 @@ EXPORT void SetMainSize( void )
tempD.size = mainD.size;
}
+// Hack to switch between TempRedraw and MainRedraw
+extern wBool_t wDrawDoTempDraw;
+/* Update temp_surface after executing a command
+ */
+EXPORT void TempRedraw( void ) {
+
+ static int cTR = 0;
+ LOG( log_redraw, 2, ( "TempRedraw: %d\n", cTR++ ) );
+if (wDrawDoTempDraw == FALSE) {
+ // Remove this after windows supports GTK
+ MainRedraw(); // TempRedraw - windows
+} else {
+ wDrawDelayUpdate( tempD.d, TRUE );
+ wDrawSetTempMode( tempD.d, TRUE );
+ DrawMarkers();
+ DoCurCommand( C_REDRAW, zero );
+ RulerRedraw( FALSE );
+ RedrawPlaybackCursor(); //If in playback
+ wDrawSetTempMode( tempD.d, FALSE );
+ wDrawDelayUpdate( tempD.d, FALSE );
+}
+}
+
+/*
+* Redraw contents on main window
+*/
EXPORT void MainRedraw( void )
{
+ coOrd orig, size;
+
+ static int cMR = 0;
+ LOG( log_redraw, 1, ( "MainRedraw: %d\n", cMR++ ) );
+ if (delayUpdate)
+ wDrawDelayUpdate( mainD.d, TRUE );
+
+ wDrawClear( mainD.d );
+
+ //mainD.d->option = 0;
+ //mainD.options = 0;
+ mainD.funcs->options = 0; //Force MainD back from Temp
+
+ orig = mainD.orig;
+ size = mainD.size;
+ orig.x -= LBORDER/mainD.dpi*mainD.scale;
+ orig.y -= BBORDER/mainD.dpi*mainD.scale;
+ wPos_t back_x,back_y;
+ coOrd back_pos = GetLayoutBackGroundPos();
+ back_x = (wPos_t)((back_pos.x-orig.x)/mainD.scale*mainD.dpi);
+ back_y = (wPos_t)((back_pos.y-orig.y)/mainD.scale*mainD.dpi);
+ wPos_t back_width = (wPos_t)(GetLayoutBackGroundSize()/mainD.scale*mainD.dpi);
+
+ DrawRoomWalls( TRUE );
+ if (GetLayoutBackGroundScreen() < 100.0 && GetLayoutBackGroundVisible()) {
+ wDrawShowBackground( mainD.d, back_x, back_y, back_width, GetLayoutBackGroundAngle(), GetLayoutBackGroundScreen());
+ }
+ orig = mainD.orig;
+ size = mainD.size;
+ orig.x -= RBORDER/mainD.dpi*mainD.scale;
+ orig.y -= BBORDER/mainD.dpi*mainD.scale;
+ size.x += (RBORDER+LBORDER)/mainD.dpi*mainD.scale;
+ size.y += (BBORDER+TBORDER)/mainD.dpi*mainD.scale;
+ DrawTracks( &mainD, mainD.scale, orig, size );
+
+ DrawRoomWalls( FALSE );
+ currRedraw++;
+ DrawSnapGrid( &mainD, mapD.size, TRUE );
+
+ //wSetCursor( mainD.d, defaultCursor );
+ InfoScale();
+ // The remainder is from TempRedraw
+ wDrawSetTempMode( tempD.d, TRUE );
+ DrawMarkers();
+ DoCurCommand( C_REDRAW, zero );
+ RulerRedraw( FALSE );
+ RedrawPlaybackCursor(); //If in playback
+ wDrawSetTempMode( tempD.d, FALSE );
+ wDrawDelayUpdate( mainD.d, FALSE );
+}
+
+/*
+* Layout main window in response to Pan/Zoom
+*
+* \param bRedraw Redraw mainD
+* \param bNoBorder Don't allow mainD.orig to go negative
+*/
+EXPORT void MainLayout(
+ wBool_t bRedraw,
+ wBool_t bNoBorder )
+{
#ifdef LATER
wPos_t ww, hh;
DIST_T w, h;
#endif
- coOrd orig, size;
DIST_T t1;
if (inPlaybackQuit)
return;
-#ifdef VERBOSE
-lprintf("mainRedraw\n");
-#endif
+ static int cML = 0;
+ LOG( log_redraw, 1, ( "MainLayout: %d\n", cML++ ) );
- wSetCursor( wCursorWait );
- if (delayUpdate)
- wDrawDelayUpdate( mainD.d, TRUE );
#ifdef LATER
wDrawGetSize( mainD.d, &ww, &hh );
w = ww/mainD.dpi;
@@ -1269,25 +1501,32 @@ lprintf("mainRedraw\n");
pixelBins /= 2.0;
}
}
- ConstraintOrig( &mainD.orig, mainD.size );
+ ConstraintOrig( &mainD.orig, mainD.size, bNoBorder, FALSE );
tempD.orig = mainD.orig;
- wDrawClear( mainD.d );
- currRedraw++;
- DrawSnapGrid( &tempD, mapD.size, TRUE );
- DrawRoomWalls( TRUE );
- orig = mainD.orig;
- size = mainD.size;
- orig.x -= RBORDER/mainD.dpi*mainD.scale;
- orig.y -= BBORDER/mainD.dpi*mainD.scale;
- size.x += (RBORDER+LBORDER)/mainD.dpi*mainD.scale;
- size.y += (BBORDER+TBORDER)/mainD.dpi*mainD.scale;
- DrawTracks( &mainD, mainD.scale, orig, size );
- RulerRedraw( FALSE );
- DoCurCommand( C_REDRAW, zero );
- DrawMarkers();
- wSetCursor( wCursorNormal );
- InfoScale();
- wDrawDelayUpdate( mainD.d, FALSE );
+ tempD.size = mainD.size;
+ mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
+ mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
+ DrawMapBoundingBox( TRUE );
+
+ if ( bRedraw )
+ MainRedraw();
+
+ if ( bRedraw && wDrawDoTempDraw ) { // Temporary until mswlib supports TempDraw
+ wAction_t action = wActionMove;
+ coOrd pos;
+ if ( mouseState == mouseLeft )
+ action = wActionLDrag;
+ if ( mouseState == mouseRight )
+ action = wActionRDrag;
+ mainD.Pix2CoOrd( &mainD, mousePositionx, mousePositiony, &pos );
+ // Prevent recursion if curCommand calls MainLayout when action if a Move or Drag
+ // ie CmdPan
+ static int iRecursion = 0;
+ iRecursion++;
+ if ( iRecursion == 1 )
+ DoMouse( action, pos );
+ iRecursion--;
+ }
}
/**
@@ -1305,7 +1544,6 @@ void MainProc( wWin_p win, winProcEvent e, void * refresh, void * data )
case wResize_e:
if (mainD.d == NULL)
return;
- if (refresh) DrawMapBoundingBox( FALSE );
wWinGetSize( mainW, &width, &height );
LayoutToolBar(refresh);
height -= (toolbarHeight+max(infoHeight,textHeight)+10);
@@ -1313,13 +1551,11 @@ void MainProc( wWin_p win, winProcEvent e, void * refresh, void * data )
wDrawSetSize( mainD.d, width-20, height, refresh );
wControlSetPos( (wControl_p)mainD.d, 0, toolbarHeight );
SetMainSize();
- ConstraintOrig( &mainD.orig, mainD.size );
- tempD.orig = mainD.orig;
SetInfoBar();
- if (!refresh) {
- MainRedraw();
- MapRedraw();
- } else DrawMapBoundingBox( TRUE );
+ panCenter.x = mainD.orig.x + mainD.size.x/2.0;
+ panCenter.y = mainD.orig.y + mainD.size.y/2.0;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ MainLayout( !refresh, TRUE ); // MainProc: wResize_e event
wPrefSetInteger( "draw", "mainwidth", width );
wPrefSetInteger( "draw", "mainheight", height );
} else DrawMapBoundingBox( TRUE );
@@ -1363,7 +1599,7 @@ EXPORT void DoRedraw( void )
#endif
#endif
MapRedraw();
- MainRedraw();
+ MainRedraw(); // DoRedraw
#ifdef WINDOWS
#ifndef WIN32
if (profRedraw)
@@ -1381,31 +1617,54 @@ EXPORT void DoRedraw( void )
*/
-static void DrawRoomWalls( wBool_t t )
+static void DrawRoomWalls( wBool_t drawBackground )
{
- coOrd p01, p11, p10;
+ coOrd p00, p01, p11, p10;
+ int p0,p1,p2,p3;
if (mainD.d == NULL)
return;
- DrawTicks( &mainD, mapD.size );
+ if (drawBackground) {
+ mainD.CoOrd2Pix(&mainD,mainD.orig,&p0,&p1);
+ coOrd end;
+ end.x = mainD.orig.x + mainD.size.x;
+ end.y = mainD.orig.y + mainD.size.y;
+ mainD.CoOrd2Pix(&mainD,end,&p2,&p3);
+ p2 -= p0;
+ p3 -= p1;
+ wDrawFilledRectangle( mainD.d, p0, p1, p2, p3, drawColorGrey80, 0 );
+
+ mainD.CoOrd2Pix(&mainD,zero,&p0,&p1);
+ mainD.CoOrd2Pix(&mainD,mapD.size,&p2,&p3);
+ p2 -= p0;
+ p3 -= p1;
+ wDrawFilledRectangle( mainD.d, p0, p1, p2, p3, drawColorWhite, 0 );
+
+ } else {
+
+ DrawTicks( &mainD, mapD.size );
- p01.x = p10.y = 0.0;
- p11.x = p10.x = mapD.size.x;
- p01.y = p11.y = mapD.size.y;
- DrawLine( &mainD, p01, p11, 3, t?borderColor:wDrawColorWhite );
- DrawLine( &mainD, p11, p10, 3, t?borderColor:wDrawColorWhite );
+ p00.x = 0.0; p00.y = 0.0;
+ p01.x = p10.y = 0.0;
+ p11.x = p10.x = mapD.size.x;
+ p01.y = p11.y = mapD.size.y;
+ DrawLine( &mainD, p01, p11, 3, borderColor );
+ DrawLine( &mainD, p11, p10, 3, borderColor );
+ DrawLine( &mainD, p00, p01, 3, borderColor );
+ DrawLine( &mainD, p00, p10, 3, borderColor );
+ }
}
-EXPORT void DrawMarkers( void )
+static void DrawMarkers( void )
{
wPos_t x, y;
mainD.CoOrd2Pix(&mainD,oldMarker,&x,&y);
- wDrawLine( mainD.d, 0, y, (wPos_t)LBORDER, y,
+ wDrawLine( tempD.d, 0, y, (wPos_t)LBORDER, y,
0, wDrawLineSolid, markerColor, wDrawOptTemp );
- wDrawLine( mainD.d, x, 0, x, (wPos_t)BBORDER,
+ wDrawLine( tempD.d, x, 0, x, (wPos_t)BBORDER,
0, wDrawLineSolid, markerColor, wDrawOptTemp );
}
@@ -1433,9 +1692,9 @@ EXPORT void DrawRuler(
wFontSize_t fs;
long mm, mm0, mm1, power;
wPos_t x0, y0, x1, y1;
- long dxn, dyn;
- static int lengths[8] = {
- 0, 2, 4, 2, 6, 2, 4, 2 };
+
+ static double lengths[16] = {
+ 0, 2.0, 4.0, 2.0, 6.0, 2.0, 4.0, 2.0, 8.0, 2.0, 4.0, 2.0, 6.0, 2.0, 4.0, 2.0 };
int fraction, incr, firstFraction, lastFraction;
int majorLength;
coOrd p0, p1;
@@ -1445,17 +1704,8 @@ EXPORT void DrawRuler(
Translate( &pos0, pos0, a, offset );
Translate( &pos1, pos1, a, offset );
aa = NormalizeAngle(a+(tickSide==0?+90:-90));
- if (aa > 90.0 && aa < 270.0) {
-#ifdef WINDOWS
- dyn = -17;
-#else
- dyn = -12;
-#endif
- } else {
- dyn = +3;
- }
sin_aa = sin(D2R(aa));
- dxn = (long)floor(10.0*sin_aa);
+
end = FindDistance( pos0, pos1 );
if (end < 0.1)
return;
@@ -1479,7 +1729,7 @@ EXPORT void DrawRuler(
if (units == UNITS_METRIC) {
mm0 = (int)ceil(start*25.4-0.5);
mm1 = (int)floor(end*25.4+0.5);
- len = 2;
+ len = 5;
if (d->scale <= 1) {
power = 1;
} else if (d->scale <= 8) {
@@ -1501,7 +1751,7 @@ EXPORT void DrawRuler(
wDrawLine( d->d, x0, y0, x1, y1,
0, wDrawLineSolid, color, (wDrawOpts)d->funcs->options );
- if (!number)
+ if (!number || (d->scale>40 && mm != 0.0))
continue;
if ( (power>=1000) ||
(d->scale<=8 && power>=100) ||
@@ -1509,15 +1759,21 @@ EXPORT void DrawRuler(
if (mm%100 != 0) {
sprintf(message, "%ld", mm/10%10 );
fs = rulerFontSize*2/3;
- p0.x = p1.x+4*dxn/10*d->scale/mainD.dpi;
- p0.y = p1.y+dyn*d->scale/mainD.dpi;
+ Translate( &p0, p0, aa, (fs/2.0+len)*d->scale/mainD.dpi );
+ Translate( &p0, p0, 225, fs*d->scale/mainD.dpi );
+ //p0.x = p1.x+4*dxn/10*d->scale/mainD.dpi;
+ //p0.y = p1.y+dyn*d->scale/mainD.dpi;
} else {
sprintf(message, "%0.1f", mm/1000.0 );
fs = rulerFontSize;
- p0.x = p0.x+((-(LBORDER-2)/2)+((LBORDER-2)/2+2)*sin_aa)*d->scale/mainD.dpi;
- p0.y = p1.y+dyn*d->scale/mainD.dpi;
+ Translate( &p0, p0, aa, (fs/2.0+len)*d->scale/mainD.dpi );
+ Translate( &p0, p0, 225, 1.5*fs*d->scale/mainD.dpi );
+ //p0.x = p0.x+((-(LBORDER-2)/2)+((LBORDER-2)/2+2)*sin_aa)*d->scale/mainD.dpi;
+ //p0.y = p1.y+dyn*d->scale/mainD.dpi;
}
d->CoOrd2Pix( d, p0, &x0, &y0 );
+ if (x0<0) x0 = 0;
+ if (y0<0) y0 = 0;
wDrawString( d->d, x0, y0, d->angle, message, rulerFp,
fs, color, (wDrawOpts)d->funcs->options );
}
@@ -1526,41 +1782,50 @@ EXPORT void DrawRuler(
}
} else {
if (d->scale <= 1)
- incr = 1;
- else if (d->scale <= 2)
- incr = 2;
- else if (d->scale <= 4)
- incr = 4;
+ incr = 1; //16ths
+ else if (d->scale <= 3)
+ incr = 2; //8ths
+ else if (d->scale <= 5)
+ incr = 4; //4ths
+ else if (d->scale <= 7)
+ incr = 8; //1/2ths
+ else if (d->scale <= 48)
+ incr = 32;
else
- incr = 8;
+ incr = 16; //Inches
lastInch = (int)floor(end);
- lastFraction = 7;
+ lastFraction = 16;
inch = (int)ceil(start);
- firstFraction = (((int)((inch-start)*8/*+1*/)) / incr) * incr;
+ firstFraction = (((int)((inch-start)*16/*+1*/)) / incr) * incr;
if (firstFraction > 0) {
inch--;
- firstFraction = 8 - firstFraction;
+ firstFraction = 16 - firstFraction;
}
for ( ; inch<=lastInch; inch++){
if (inch % 12 == 0) {
- lengths[0] = 10;
+ lengths[0] = 12;
majorLength = 16;
digit = (int)(inch/12);
fs = rulerFontSize;
quote = '\'';
} else if (d->scale <= 8) {
- lengths[0] = 8;
- majorLength = 13;
+ lengths[0] = 12;
+ majorLength = 16;
digit = (int)(inch%12);
fs = rulerFontSize*(2.0/3.0);
quote = '"';
+ } else if (d->scale <= 16){
+ lengths[0] = 10;
+ majorLength = 12;
+ digit = (int)(inch%12);
+ fs = rulerFontSize*(1.0/2.0);
} else {
continue;
}
if (inch == lastInch)
- lastFraction = (((int)((end - lastInch)*8)) / incr) * incr;
+ lastFraction = (((int)((end - lastInch)*16)) / incr) * incr;
for ( fraction = firstFraction; fraction<=lastFraction; fraction += incr ) {
- Translate( &p0, orig, a, inch+fraction/8.0 );
+ Translate( &p0, orig, a, inch+fraction/16.0 );
Translate( &p1, p0, aa, lengths[fraction]*d->scale/72.0 );
d->CoOrd2Pix( d, p0, &x0, &y0 );
d->CoOrd2Pix( d, p1, &x1, &y1 );
@@ -1571,13 +1836,17 @@ EXPORT void DrawRuler(
/* KLUDGE: can't draw invertable strings on windows */
if ( (opts&DO_TEMP) == 0)
#endif
- if ( fraction == 0 && number == TRUE) {
- if (inch % 12 == 0 || d->scale <= 2) {
- Translate( &p0, p0, aa, majorLength*d->scale/72.0 );
- Translate( &p0, p0, 225, 11*d->scale/72.0 );
- sprintf(message, "%d%c", digit, quote );
- d->CoOrd2Pix( d, p0, &x0, &y0 );
- wDrawString( d->d, x0, y0, d->angle, message, rulerFp, fs, color, (wDrawOpts)d->funcs->options );
+ if (fraction == 0) {
+ if ( (number == TRUE && d->scale<40) || (digit==0)) {
+ if (inch % 12 == 0 || d->scale <= 2) {
+ Translate( &p0, p0, aa, majorLength*d->scale/mainD.dpi );
+ Translate( &p0, p0, 225, fs*d->scale/mainD.dpi );
+ sprintf(message, "%d%c", digit, quote );
+ d->CoOrd2Pix( d, p0, &x0, &y0 );
+ if (x0<0) x0 = 0;
+ if (y0<0) y0 = 0;
+ wDrawString( d->d, x0, y0, d->angle, message, rulerFp, fs, color, (wDrawOpts)d->funcs->options );
+ }
}
}
firstFraction = 0;
@@ -1587,28 +1856,49 @@ EXPORT void DrawRuler(
}
-EXPORT void DrawTicks( drawCmd_p d, coOrd size )
+static void DrawTicks( drawCmd_p d, coOrd size )
{
coOrd p0, p1;
DIST_T offset;
offset = 0.0;
- if ( d->orig.x<0.0 )
- offset = d->orig.x;
- p0.x = 0.0/*d->orig.x*/; p1.x = size.x;
- p0.y = p1.y = /*max(d->orig.y,0.0)*/ d->orig.y;
+ double blank_zone = 40*d->scale/72.0;
+
+ if ( d->orig.x<0.0-blank_zone ) {
+ p0.y = 0.0; p1.y = mapD.size.y;
+ p0.x = p1.x = 0.0;
+ DrawRuler( d, p0, p1, offset, FALSE, TRUE, borderColor );
+ }
+ if (d->orig.x+d->size.x>mapD.size.x+blank_zone) {
+ p0.y = 0.0; p1.y = mapD.size.y;
+ p0.x = p1.x = mapD.size.x;
+ DrawRuler( d, p0, p1, offset, FALSE, FALSE, borderColor );
+ }
+ p0.x = 0.0; p1.x = d->size.x;
+ offset = d->orig.x;
+ p0.y = p1.y = d->orig.y;
DrawRuler( d, p0, p1, offset, TRUE, FALSE, borderColor );
- p0.y = p1.y = min(d->orig.y + d->size.y, size.y);
+ p0.y = p1.y = d->size.y+d->orig.y;
DrawRuler( d, p0, p1, offset, FALSE, TRUE, borderColor );
+
offset = 0.0;
- if ( d->orig.y<0.0 )
- offset = d->orig.y;
- p0.y = 0.0/*d->orig.y*/; p1.y = max(size.y,0.0);
+ if ( d->orig.y<0.0-blank_zone) {
+ p0.x = 0.0; p1.x = mapD.size.x;
+ p0.y = p1.y = 0.0;
+ DrawRuler( d, p0, p1, offset, FALSE, FALSE, borderColor );
+ }
+ if (d->orig.y+d->size.y>mapD.size.y+blank_zone) {
+ p0.x = 0.0; p1.x = mapD.size.x;
+ p0.y = p1.y = mapD.size.y;
+ DrawRuler( d, p0, p1, offset, FALSE, TRUE, borderColor );
+ }
+ p0.y = 0.0; p1.y = d->size.y;
+ offset = d->orig.y;
p0.x = p1.x = d->orig.x;
DrawRuler( d, p0, p1, offset, TRUE, TRUE, borderColor );
- p0.x = p1.x = min(d->orig.x + d->size.x, size.x);
+ p0.x = p1.x = d->size.x+d->orig.x;
DrawRuler( d, p0, p1, offset, FALSE, FALSE, borderColor );
}
@@ -1621,54 +1911,74 @@ EXPORT void DrawTicks( drawCmd_p d, coOrd size )
EXPORT coOrd mainCenter;
-EXPORT void DrawMapBoundingBox( BOOL_T set )
+static void DrawMapBoundingBox( BOOL_T set )
{
if (mainD.d == NULL || mapD.d == NULL)
return;
- DrawHilight( &mapD, mainD.orig, mainD.size );
+ wDrawSetTempMode( mapD.d, TRUE );
+ DrawHilight( &mapD, mainD.orig, mainD.size, TRUE );
+ wDrawSetTempMode( mapD.d, FALSE );
}
-static void ConstraintOrig( coOrd * orig, coOrd size )
+static void ConstraintOrig( coOrd * orig, coOrd size, wBool_t bNoBorder, wBool_t round )
{
LOG( log_pan, 2, ( "ConstraintOrig [ %0.3f, %0.3f ] RoomSize(%0.3f %0.3f), WxH=%0.3fx%0.3f",
orig->x, orig->y, mapD.size.x, mapD.size.y,
size.x, size.y ) )
- if (orig->x+size.x > mapD.size.x ) {
- orig->x = mapD.size.x-size.x;
- orig->x += (units==UNITS_ENGLISH?1.0:(1.0/2.54));
+ coOrd bound = zero;
+
+ if ( !bNoBorder ) {
+ bound.x = size.x/2;
+ bound.y = size.y/2;
}
- if (orig->x < 0)
- orig->x = 0;
- if (orig->y+size.y > mapD.size.y ) {
- orig->y = mapD.size.y-size.y;
- orig->y += (units==UNITS_ENGLISH?1.0:1.0/2.54);
+
+
+ if (orig->x > 0.0) {
+ if ((orig->x+size.x) > (mapD.size.x+bound.x)) {
+ orig->x = mapD.size.x-size.x+bound.x;
+ //orig->x += (units==UNITS_ENGLISH?1.0:(1.0/2.54));
+ }
}
- if (orig->y < 0)
- orig->y = 0;
- if (mainD.scale >= 1.0) {
- if (units == UNITS_ENGLISH) {
- orig->x = floor(orig->x*4)/4; //>1:1 = 1/4 inch
- orig->y = floor(orig->y*4)/4;
- } else {
- orig->x = floor(orig->x*2.54*2)/(2.54*2); //>1:1 = 0.5 cm
- orig->y = floor(orig->y*2.54*2)/(2.54*2);
+ if (orig->x < (0-bound.x))
+ orig->x = 0-bound.x;
+
+ if (orig->y > 0.0) {
+ if ((orig->y+size.y) > (mapD.size.y+bound.y) ) {
+ orig->y = mapD.size.y-size.y+bound.y;
+ //orig->y += (units==UNITS_ENGLISH?1.0:1.0/2.54);
+
}
- } else {
- if (units == UNITS_ENGLISH) {
- orig->x = floor(orig->x*64)/64; //<1:1 = 1/64 inch
- orig->y = floor(orig->y*64)/64;
+ }
+
+ if (orig->y < (0-bound.y))
+ orig->y = 0-bound.y;
+
+ if (round) {
+ if (mainD.scale >= 1.0) {
+ if (units == UNITS_ENGLISH) {
+ orig->x = floor(orig->x*4)/4; //>1:1 = 1/4 inch
+ orig->y = floor(orig->y*4)/4;
+ } else {
+ orig->x = floor(orig->x*2.54*2)/(2.54*2); //>1:1 = 0.5 cm
+ orig->y = floor(orig->y*2.54*2)/(2.54*2);
+ }
} else {
- orig->x = floor(orig->x*25.4*2)/(25.4*2); //>1:1 = 0.5 mm
- orig->y = floor(orig->y*25.4*2)/(25.4*2);
+ if (units == UNITS_ENGLISH) {
+ orig->x = floor(orig->x*64)/64; //<1:1 = 1/64 inch
+ orig->y = floor(orig->y*64)/64;
+ } else {
+ orig->x = floor(orig->x*25.4*2)/(25.4*2); //>1:1 = 0.5 mm
+ orig->y = floor(orig->y*25.4*2)/(25.4*2);
+ }
}
}
- orig->x = (long)(orig->x*pixelBins+0.5)/pixelBins;
- orig->y = (long)(orig->y*pixelBins+0.5)/pixelBins;
-LOG( log_pan, 2, ( " = [ %0.3f %0.3f ]\n", orig->y, orig->y ) )
+ //orig->x = (long)(orig->x*pixelBins+0.5)/pixelBins;
+ //orig->y = (long)(orig->y*pixelBins+0.5)/pixelBins;
+ LOG( log_pan, 2, ( " = [ %0.3f %0.3f ]\n", orig->y, orig->y ) )
}
/**
@@ -1676,18 +1986,29 @@ LOG( log_pan, 2, ( " = [ %0.3f %0.3f ]\n", orig->y, orig->y ) )
*
* \param IN zoomM Menu to which radio button is added
* \param IN zoomSubM Second menu to which radio button is added, ignored if NULL
+ * \param IN ctxMenu1
+ * \param IN ctxMenu2
*
*/
-EXPORT void InitCmdZoom( wMenu_p zoomM, wMenu_p zoomSubM )
+EXPORT void InitCmdZoom( wMenu_p zoomM, wMenu_p zoomSubM, wMenu_p ctxMenu1, wMenu_p panMenu )
{
int inx;
for ( inx=0; inx<sizeof zoomList/sizeof zoomList[0]; inx++ ) {
- if( zoomList[ inx ].value >= 1.0 ) {
- zoomList[inx].btRadio = wMenuRadioCreate( zoomM, "cmdZoom", zoomList[inx].name, 0, (wMenuCallBack_p)DoZoom, (void *)(&(zoomList[inx].value)));
+ if( (zoomList[ inx ].value >= 1.0 && zoomList[ inx ].value<=10 ) ||
+ (ceil(log2(zoomList[ inx ].value)) == floor(log2(zoomList[ inx ].value))))
+ {
+ if (zoomM)
+ zoomList[inx].btRadio = wMenuRadioCreate( zoomM, "cmdZoom", zoomList[inx].name, 0, (wMenuCallBack_p)DoZoom, (void *)(&(zoomList[inx].value)));
if( zoomSubM )
zoomList[inx].pdRadio = wMenuRadioCreate( zoomSubM, "cmdZoom", zoomList[inx].name, 0, (wMenuCallBack_p)DoZoom, (void *)(&(zoomList[inx].value)));
+ if (panMenu)
+ zoomList[inx].panRadio = wMenuRadioCreate( panMenu, "cmdZoom", zoomList[inx].name, 0, (wMenuCallBack_p)DoZoom, (void *)(&(zoomList[inx].value)));
+ }
+ if ((zoomList[inx].value >=1.0 && zoomList[inx].value <= 10.0) || (ceil(log2(zoomList[ inx ].value)) == floor(log2(zoomList[ inx ].value)))) {
+ if (ctxMenu1)
+ zoomList[inx].ctxRadio1 = wMenuRadioCreate( ctxMenu1, "cmdZoom", zoomList[inx].name, 0, (wMenuCallBack_p)DoZoom, (void *)(&(zoomList[inx].value)));
}
}
}
@@ -1706,11 +2027,14 @@ static void SetZoomRadio( DIST_T scale )
for ( inx=0; inx<sizeof zoomList/sizeof zoomList[0]; inx++ ) {
if( curScale == zoomList[inx].value ) {
-
- wMenuRadioSetActive( zoomList[inx].btRadio );
+ if (zoomList[inx].btRadio)
+ wMenuRadioSetActive( zoomList[inx].btRadio );
if( zoomList[inx].pdRadio )
wMenuRadioSetActive( zoomList[inx].pdRadio );
-
+ if (zoomList[inx].ctxRadio1)
+ wMenuRadioSetActive( zoomList[inx].ctxRadio1 );
+ if (zoomList[inx].panRadio)
+ wMenuRadioSetActive( zoomList[inx].panRadio );
/* activate / deactivate zoom buttons when appropriate */
wControlLinkedActive( (wControl_p)zoomUpB, ( inx != 0 ) );
wControlLinkedActive( (wControl_p)zoomDownB, ( inx < (sizeof zoomList/sizeof zoomList[0] - 1)));
@@ -1768,7 +2092,6 @@ static void DoNewScale( DIST_T scale )
if (scale > MAX_MAIN_SCALE)
scale = MAX_MAIN_SCALE;
- DrawHilight( &mapD, mainD.orig, mainD.size );
tempD.scale = mainD.scale = scale;
mainD.dpi = wDrawGetDPI( mainD.d );
if ( mainD.dpi == 75 ) {
@@ -1781,21 +2104,10 @@ static void DoNewScale( DIST_T scale )
SetZoomRadio( scale );
InfoScale();
SetMainSize();
- if (zoomCorner) {
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- } else {
- mainD.orig.x = mainCenter.x - mainD.size.x/2.0;
- mainD.orig.y = mainCenter.y - mainD.size.y/2.0;
- }
- ConstraintOrig( &mainD.orig, mainD.size );
- MainRedraw();
- tempD.orig = mainD.orig;
+ PanHere( (void*)1 );
LOG( log_zoom, 1, ( "center = [%0.3f %0.3f]\n", mainCenter.x, mainCenter.y ) )
- /*SetFont(0);*/
sprintf( tmp, "%0.3f", mainD.scale );
wPrefSetString( "draw", "zoom", tmp );
- DrawHilight( &mapD, mainD.orig, mainD.size );
if (recordF) {
fprintf( recordF, "ORIG %0.3f %0.3f %0.3f\n",
mainD.scale, mainD.orig.x, mainD.orig.y );
@@ -1814,6 +2126,7 @@ EXPORT void DoZoomUp( void * mode )
long newScale;
int i;
+ LOG( log_zoom, 2, ( "DoZoomUp KS:%x\n", MyGetKeyState() ) );
if ( mode != NULL || (MyGetKeyState()&WKEY_SHIFT) == 0) {
i = ScaleInx( mainD.scale );
if (i < 0) i = NearestScaleInx(mainD.scale, TRUE);
@@ -1826,12 +2139,12 @@ EXPORT void DoZoomUp( void * mode )
if (mainD.scale <=1.0)
InfoMessage(_("Macro Zoom Mode"));
else
- InfoMessage(_("Use Shift+PageDwn to jump to preset Zoom In"));
+ InfoMessage("");
DoNewScale( zoomList[ i - 1 ].value );
- } else InfoMessage("Min Macro Zoom");
+ } else InfoMessage("Minimum Macro Zoom");
} else {
- InfoMessage(_("Scale 1:1 - Use Ctrl+PageDwn to go to Macro Zoom Mode"));
+ InfoMessage(_("Scale 1:1 - Use Ctrl+ to go to Macro Zoom Mode"));
}
} else if ( (MyGetKeyState()&WKEY_CTRL) == 0 ) {
wPrefGetInteger( "misc", "zoomin", &newScale, 4 );
@@ -1843,6 +2156,22 @@ EXPORT void DoZoomUp( void * mode )
}
}
+EXPORT void DoZoomExtents( void * mode) {
+
+ DIST_T scale_x, scale_y;
+ scale_x = mapD.size.x/(mainD.size.x/mainD.scale);
+ scale_y = mapD.size.y/(mainD.size.y/mainD.scale);
+ if (scale_x<scale_y)
+ scale_x = scale_y;
+ scale_x = ceil(scale_x);
+ if (scale_x < 1) scale_x = 1;
+ if (scale_x > MAX_MAIN_SCALE) scale_x = MAX_MAIN_SCALE;
+ mainD.orig = zero;
+ DoNewScale(scale_x);
+ MainLayout(TRUE,TRUE);
+
+}
+
/**
* User selected zoom out, via mouse wheel, button or pulldown.
@@ -1855,11 +2184,12 @@ EXPORT void DoZoomDown( void * mode)
long newScale;
int i;
+ LOG( log_zoom, 2, ( "DoZoomDown KS:%x\n", MyGetKeyState() ) );
if ( mode != NULL || (MyGetKeyState()&WKEY_SHIFT) == 0 ) {
i = ScaleInx( mainD.scale );
if (i < 0) i = NearestScaleInx(mainD.scale, TRUE);
if( i>= 0 && i < ( sizeof zoomList/sizeof zoomList[0] - 1 )) {
- InfoMessage(_("Use Shift+PageUp to jump to preset Zoom Out"));
+ InfoMessage("");
DoNewScale( zoomList[ i + 1 ].value );
} else
InfoMessage(_("At Maximum Zoom Out"));
@@ -1913,11 +2243,102 @@ EXPORT void CoOrd2Pix(
*y = (wPos_t)((pos.y-d->orig.y)/d->scale*d->dpi);
}
+/*
+* Position mainD based on panCenter
+* \param mode control effect of constrainMain and CTRL key
+*
+* mode:
+* - 0: constrain if constrainMain==1 or CTRL is pressed
+* - 1: same as 0, but ignore CTRL
+* - 2: same as 0, plus liveMap
+* - 3: Take position from menuPos
+*/
+EXPORT void PanHere(void * mode) {
+ if ( 3 == (long)mode) {
+ panCenter = menuPos;
+ LOG( log_pan, 2, ( "MCenter:Mod-%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ }
+ mainD.orig.x = panCenter.x - mainD.size.x/2.0;
+ mainD.orig.y = panCenter.y - mainD.size.y/2.0;
+ wBool_t bNoBorder = (constrainMain != 0);
+ if ( 1 != (long)mode )
+ if ( (MyGetKeyState()&WKEY_CTRL)!= 0 )
+ bNoBorder = !bNoBorder;
+ wBool_t bLiveMap = TRUE;
+ if ( 2 == (long)mode )
+ bLiveMap = liveMap;
+
+ MainLayout( bLiveMap, bNoBorder ); // PanHere
+}
+
+
+static void DoPanKeyAction( wAction_t action )
+{
+ switch ((wAccelKey_e)(action>>8)) {
+ case wAccelKey_Del:
+ SelectDelete();
+ return;
+#ifndef WINDOWS
+ case wAccelKey_Pgdn:
+ DoZoomUp(NULL);
+ break;
+ case wAccelKey_Pgup:
+ DoZoomDown(NULL);
+ break;
+#endif
+ case wAccelKey_Right:
+ panCenter.x = mainD.orig.x + mainD.size.x/2;
+ panCenter.y = mainD.orig.y + mainD.size.y/2;
+ if ((MyGetKeyState() & WKEY_SHIFT) != 0)
+ panCenter.x += 0.25*mainD.scale; //~1cm in 1::1, 1ft in 30:1, 1mm in 10:1
+ else
+ panCenter.x += mainD.size.x/2;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)0);
+ break;
+
+ case wAccelKey_Left:
+ panCenter.x = mainD.orig.x + mainD.size.x/2;
+ panCenter.y = mainD.orig.y + mainD.size.y/2;
+ if ((MyGetKeyState() & WKEY_SHIFT) != 0)
+ panCenter.x -= 0.25*mainD.scale;
+ else
+ panCenter.x -= mainD.size.x/2;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)0);
+ break;
+
+ case wAccelKey_Up:
+ panCenter.x = mainD.orig.x + mainD.size.x/2;
+ panCenter.y = mainD.orig.y + mainD.size.y/2;
+ if ((MyGetKeyState() & WKEY_SHIFT) != 0)
+ panCenter.y += 0.25*mainD.scale;
+ else
+ panCenter.y += mainD.size.y/2;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)0);
+ break;
+
+ case wAccelKey_Down:
+ panCenter.x = mainD.orig.x + mainD.size.x/2;
+ panCenter.y = mainD.orig.y + mainD.size.y/2;
+ if ((MyGetKeyState() & WKEY_SHIFT) != 0)
+ panCenter.y -= 0.25*mainD.scale;
+ else
+ panCenter.y -= mainD.size.y/2;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)0);
+ break;
+
+ default:
+ return;
+ }
+}
+
static void DoMapPan( wAction_t action, coOrd pos )
{
static coOrd mapOrig;
- static coOrd oldOrig, newOrig;
static coOrd size;
static DIST_T xscale, yscale;
static enum { noPan, movePan, resizePan } mode = noPan;
@@ -1930,34 +2351,21 @@ static void DoMapPan( wAction_t action, coOrd pos )
mode = movePan;
else
break;
- mapOrig = pos;
- size = mainD.size;
- newOrig = oldOrig = mainD.orig;
-LOG( log_pan, 1, ( "ORIG = [ %0.3f, %0.3f ]\n", mapOrig.x, mapOrig.y ) )
- break;
case C_MOVE:
if ( mode != movePan )
break;
- DrawHilight( &mapD, newOrig, size );
-LOG( log_pan, 2, ( "NEW = [ %0.3f, %0.3f ] \n", pos.x, pos.y ) )
- newOrig.x = oldOrig.x + pos.x-mapOrig.x;
- newOrig.y = oldOrig.y + pos.y-mapOrig.y;
- ConstraintOrig( &newOrig, mainD.size );
- if (liveMap) {
- tempD.orig = mainD.orig = newOrig;
- MainRedraw();
- }
- DrawHilight( &mapD, newOrig, size );
+// mainD.orig.x = pos.x - mainD.size.x/2.0;
+// mainD.orig.y = pos.y - mainD.size.y/2.0;
+ panCenter = pos;
+LOG( log_pan, 1, ( "%s = [ %0.3f, %0.3f ]\n", action == C_DOWN? "START":"MOVE", mainD.orig.x, mainD.orig.y ) )
+ PanHere( (void*)2 );
break;
case C_UP:
if ( mode != movePan )
break;
- tempD.orig = mainD.orig = newOrig;
- mainCenter.x = newOrig.x + mainD.size.x/2.0;
- mainCenter.y = newOrig.y + mainD.size.y/2.0;
- if (!liveMap)
- MainRedraw();
-LOG( log_pan, 1, ( "FINAL = [ %0.3f, %0.3f ]\n", pos.x, pos.y ) )
+ panCenter = pos;
+ PanHere( (void*)0 );
+LOG( log_pan, 1, ( "FINAL = [ %0.3f, %0.3f ]\n", mainD.orig.x, mainD.orig.y ) )
mode = noPan;
break;
@@ -1966,21 +2374,17 @@ LOG( log_pan, 1, ( "FINAL = [ %0.3f, %0.3f ]\n", pos.x, pos.y ) )
mode = resizePan;
else
break;
- DrawHilight( &mapD, mainD.orig, mainD.size );
- newOrig = pos;
- oldOrig = newOrig;
- xscale = 1;
- size.x = mainD.size.x/mainD.scale;
+ mapOrig = pos;
+ size.x = mainD.size.x/mainD.scale; //How big screen?
size.y = mainD.size.y/mainD.scale;
- newOrig.x -= size.x/2.0;
- newOrig.y -= size.y/2.0;
- DrawHilight( &mapD, newOrig, size );
+ xscale = mainD.scale; //start at current
+ panCenter = pos;
+LOG( log_pan, 1, ( "START %0.3fx%0.3f %0.3f+%0.3f\n", mapOrig.x, mapOrig.y, size.x, size.y ) )
break;
case C_RMOVE:
if ( mode != resizePan )
break;
- DrawHilight( &mapD, newOrig, size );
if (pos.x < 0)
pos.x = 0;
if (pos.x > mapD.size.x)
@@ -1989,103 +2393,42 @@ LOG( log_pan, 1, ( "FINAL = [ %0.3f, %0.3f ]\n", pos.x, pos.y ) )
pos.y = 0;
if (pos.y > mapD.size.y)
pos.y = mapD.size.y;
- size.x = (pos.x - oldOrig.x)*2.0;
- size.y = (pos.y - oldOrig.y)*2.0;
- if (size.x < 0) {
- size.x = - size.x;
- }
- if (size.y < 0) {
- size.y = - size.y;
- }
- xscale = size.x / (mainD.size.x/mainD.scale);
- yscale = size.y / (mainD.size.y/mainD.scale);
+
+ xscale = fabs((pos.x-mapOrig.x)*2.0/size.x);
+ yscale = fabs((pos.y-mapOrig.y)*2.0/size.y);
if (xscale < yscale)
xscale = yscale;
xscale = ceil( xscale );
- if (xscale < 1)
- xscale = 1;
+
+ if (xscale < 0.01)
+ xscale = 0.01;
if (xscale > 64)
xscale = 64;
- size.x = (mainD.size.x/mainD.scale) * xscale;
- size.y = (mainD.size.y/mainD.scale) * xscale;
- newOrig = oldOrig;
- newOrig.x -= size.x/2.0;
- newOrig.y -= size.y/2.0;
- DrawHilight( &mapD, newOrig, size );
- break;
+
+ mainD.size.x = size.x * xscale;
+ mainD.size.y = size.y * xscale;
+ mainD.orig.x = mapOrig.x - mainD.size.x / 2.0;
+ mainD.orig.y = mapOrig.y - mainD.size.y / 2.0;
+ tempD.scale = mainD.scale = xscale;
+ PanHere( (void*)2 );
+LOG( log_pan, 1, ( "MOVE SCL:%0.3f %0.3fx%0.3f %0.3f+%0.3f\n", xscale, mainD.orig.x, mainD.orig.y, mainD.size.x, mainD.size.y ) )
+ InfoScale();
+ break;
case C_RUP:
if ( mode != resizePan )
break;
- tempD.size = mainD.size = size;
- tempD.orig = mainD.orig = newOrig;
- mainCenter.x = newOrig.x + mainD.size.x/2.0;
- mainCenter.y = newOrig.y + mainD.size.y/2.0;
DoNewScale( xscale );
mode = noPan;
break;
- case wActionExtKey:
- mainD.CoOrd2Pix(&mainD,pos,&x,&y);
- switch ((wAccelKey_e)(action>>8)) {
-#ifndef WINDOWS
- case wAccelKey_Pgdn:
- DoZoomUp(NULL);
- return;
- case wAccelKey_Pgup:
- DoZoomDown(NULL);
- return;
- case wAccelKey_F5:
- MainRedraw();
- MapRedraw();
- return;
-#endif
- case wAccelKey_Right:
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- mainD.orig.x += mainD.size.x/2;
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MainRedraw();
- MapRedraw();
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- break;
- case wAccelKey_Left:
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- mainD.orig.x -= mainD.size.x/2;
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MainRedraw();
- MapRedraw();
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- break;
- case wAccelKey_Up:
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- mainD.orig.y += mainD.size.y/2;
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MainRedraw();
- MapRedraw();
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- break;
- case wAccelKey_Down:
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- mainD.orig.y -= mainD.size.y/2;
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MainRedraw();
- MapRedraw();
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- break;
- default:
- return;
- }
- mainD.Pix2CoOrd( &mainD, x, y, &pos );
- InfoPos( pos );
- return;
+ case wActionExtKey:
+ mainD.CoOrd2Pix(&mainD,pos,&x,&y);
+ DoPanKeyAction( action );
+ mainD.Pix2CoOrd( &mainD, x, y, &pos );
+ InfoPos( pos );
+ return;
+
default:
return;
}
@@ -2106,7 +2449,7 @@ EXPORT BOOL_T IsClose(
*
*/
-static int ignoreMoves = 1;
+static int ignoreMoves = 0;
EXPORT void ResetMouseState( void )
{
@@ -2136,6 +2479,31 @@ GetMousePosition( int *x, int *y )
}
}
+coOrd minIncrementSizes() {
+ double x,y;
+ if (mainD.scale >= 1.0) {
+ if (units == UNITS_ENGLISH) {
+ x = 0.25; //>1:1 = 1/4 inch
+ y = 0.25;
+ } else {
+ x = 1/(2.54*2); //>1:1 = 0.5 cm
+ y = 1/(2.54*2);
+ }
+ } else {
+ if (units == UNITS_ENGLISH) {
+ x = 1/64; //<1:1 = 1/64 inch
+ y = 1/64;
+ } else {
+ x = 1/(25.4*2); //>1:1 = 0.5 mm
+ y = 1/(25.4*2);
+ }
+ }
+ coOrd ret;
+ ret.x = x*1.5;
+ ret.y = y*1.5;
+ return ret;
+}
+
static void DoMouse( wAction_t action, coOrd pos )
{
@@ -2149,6 +2517,8 @@ static void DoMouse( wAction_t action, coOrd pos )
RecordMouse( "MOUSE", action, pos.x, pos.y );
}
+
+
switch (action&0xFF) {
case C_UP:
if (mouseState != mouseLeft)
@@ -2196,6 +2566,12 @@ static void DoMouse( wAction_t action, coOrd pos )
if ( deferSubstituteControls[0] )
InfoSubstituteControls( deferSubstituteControls, deferSubstituteLabels );
+// panCenter.y = mainD.orig.y + mainD.size.y/2;
+// panCenter.x = mainD.orig.x + mainD.size.x/2;
+//printf( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y );
+
+ coOrd min = minIncrementSizes();
+
switch ( action&0xFF ) {
case C_DOWN:
case C_RDOWN:
@@ -2209,80 +2585,17 @@ static void DoMouse( wAction_t action, coOrd pos )
case wActionExtKey:
mainD.CoOrd2Pix(&mainD,pos,&x,&y);
if ((MyGetKeyState() &
- (WKEY_SHIFT | WKEY_CTRL)) == (WKEY_SHIFT | WKEY_CTRL)) break; //Allow SHIFT+CTRL for Move
+ (WKEY_SHIFT | WKEY_CTRL)) == (WKEY_SHIFT | WKEY_CTRL) &&
+ ( action>>8 == wAccelKey_Up ||
+ action>>8 == wAccelKey_Down ||
+ action>>8 == wAccelKey_Left ||
+ action>>8 == wAccelKey_Right ))
+ break; //Allow SHIFT+CTRL for Move
if (((action>>8)&0xFF) == wAccelKey_LineFeed) {
action = C_TEXT+((int)(0x0A<<8));
break;
}
- switch ((wAccelKey_e)(action>>8)) {
- case wAccelKey_Del:
- SelectDelete();
- return;
-#ifndef WINDOWS
- case wAccelKey_Pgdn:
- DoZoomUp(NULL);
- break;
- case wAccelKey_Pgup:
- DoZoomDown(NULL);
- break;
-#endif
- case wAccelKey_Right:
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- if ((MyGetKeyState() & WKEY_SHIFT) != 0)
- mainD.orig.x += 0.25*mainD.scale; //~1cm in 1::1, 1ft in 30:1, 1mm in 10:1
- else
- mainD.orig.x += mainD.size.x/2;
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MainRedraw();
- MapRedraw();
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- break;
- case wAccelKey_Left:
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- if ((MyGetKeyState() & WKEY_SHIFT) != 0)
- mainD.orig.x -= 0.25*mainD.scale;
- else
- mainD.orig.x -= mainD.size.x/2;
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MainRedraw();
- MapRedraw();
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- break;
- case wAccelKey_Up:
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- if ((MyGetKeyState() & WKEY_SHIFT) != 0)
- mainD.orig.y += 0.25*mainD.scale;
- else
- mainD.orig.y += mainD.size.y/2;
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MainRedraw();
- MapRedraw();
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- break;
- case wAccelKey_Down:
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- if ((MyGetKeyState() & WKEY_SHIFT) != 0)
- mainD.orig.y -= 0.25*mainD.scale;
- else
- mainD.orig.y -= mainD.size.y/2;
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MainRedraw();
- MapRedraw();
- //DrawHilight( &mapD, mainD.orig, mainD.size );
- break;
- default:
- return;
- }
- mainD.Pix2CoOrd( &mainD, x, y, &pos );
- InfoPos( pos );
+ DoPanKeyAction( action );
return;
case C_TEXT:
if ((action>>8) == 0x0D) {
@@ -2291,10 +2604,12 @@ static void DoMouse( wAction_t action, coOrd pos )
ConfirmReset( TRUE );
return;
}
+ case C_MODKEY:
case C_MOVE:
case C_UP:
case C_RMOVE:
case C_RUP:
+ case C_LDOUBLE:
InfoPos( pos );
/*DrawTempTrack();*/
break;
@@ -2304,6 +2619,26 @@ static void DoMouse( wAction_t action, coOrd pos )
case C_WDOWN:
DoZoomDown((void *)1L);
break;
+ case C_SCROLLUP:
+ panCenter.y = panCenter.y + ((mainD.size.y/20>min.y)?mainD.size.y/20:min.y);
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)1);
+ break;
+ case C_SCROLLDOWN:
+ panCenter.y = panCenter.y - ((mainD.size.y/20>min.y)?mainD.size.y/20:min.y);
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)1);
+ break;
+ case C_SCROLLLEFT:
+ panCenter.x = panCenter.x - ((mainD.size.x/20>min.x)?mainD.size.x/20:min.x);
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)1);
+ break;
+ case C_SCROLLRIGHT:
+ panCenter.x = panCenter.x + ((mainD.size.x/20>min.x)?mainD.size.x/20:min.x);
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere((void*)1);
+ break;
default:
NoticeMessage( MSG_DOMOUSE_BAD_OP, _("Ok"), NULL, action&0xFF );
break;
@@ -2382,16 +2717,13 @@ static void DoMousew( wDraw_p d, void * context, wAction_t action, wPos_t x, wPo
}
}
}
- ConstraintOrig( &orig, mainD.size );
- if ( orig.x != mainD.orig.x || orig.y != mainD.orig.y ) {
- //DrawMapBoundingBox( FALSE );
- mainD.orig = orig;
- MainRedraw();
- MapRedraw();
- /*DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );*/
- //DrawMapBoundingBox( TRUE );
- wFlush();
- }
+ mainD.orig = orig;
+ panCenter.x = mainD.orig.x + mainD.size.x/2.0;
+ panCenter.y = mainD.orig.y + mainD.size.y/2.0;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ MainLayout( TRUE, TRUE ); // DoMouseW: autopan
+ tempD.orig = mainD.orig;
+ wFlush();
}
}
lastX = x;
@@ -2399,8 +2731,21 @@ static void DoMousew( wDraw_p d, void * context, wAction_t action, wPos_t x, wPo
}
}
mainD.Pix2CoOrd( &mainD, x, y, &pos );
- mousePositionx = x;
- mousePositiony = y;
+ switch (action & 0xFF) {
+ case wActionMove:
+ case wActionLDown:
+ case wActionLDrag:
+ case wActionLUp:
+ case wActionRDown:
+ case wActionRDrag:
+ case wActionRUp:
+ case wActionLDownDouble:
+ mousePositionx = x;
+ mousePositiony = y;
+ break;
+ default:
+ break;
+ }
DoMouse( action, pos );
}
@@ -2413,6 +2758,7 @@ static wBool_t PlaybackMain( char * line )
char *oldLocale = NULL;
oldLocale = SaveLocale("C");
+
rc=sscanf( line, "%d " SCANF_FLOAT_FORMAT SCANF_FLOAT_FORMAT, &action, &pos.x, &pos.y);
RestoreLocale(oldLocale);
@@ -2423,6 +2769,27 @@ static wBool_t PlaybackMain( char * line )
}
return TRUE;
}
+
+static wBool_t PlaybackKey( char * line )
+{
+ int rc;
+ int action = C_TEXT;
+ coOrd pos;
+ char *oldLocale = NULL;
+ int c;
+
+ oldLocale = SaveLocale("C");
+ rc=sscanf( line, "%d " SCANF_FLOAT_FORMAT SCANF_FLOAT_FORMAT, &c, &pos.x, &pos.y );
+ RestoreLocale(oldLocale);
+
+ if (rc != 3) {
+ SyntaxError( "MOUSE", rc, 3 );
+ } else {
+ action = action||c<<8;
+ PlaybackMouse( DoMouse, &mainD, (wAction_t)action, pos, wDrawColorBlack );
+ }
+ return TRUE;
+}
/*****************************************************************************
*
@@ -2440,8 +2807,40 @@ static void MapDlgUpdate(
int inx,
void * valueP )
{
- if ( inx == -1 ) {
- MapWindowShow( FALSE );
+ int width,height;
+ switch(inx) {
+ case wResize_e:
+ if (mapD.d == NULL)
+ return;
+ wWinGetSize( mapW, &width, &height );
+ if (height >= 100) {
+ wControlSetPos( (wControl_p)mapD.d, 0, 0 );
+ double scaleX = (mapD.size.x/((width-DlgSepLeft-DlgSepRight-10)/mapD.dpi));
+ double scaleY = (mapD.size.y/((height-DlgSepTop-DlgSepBottom-10)/mapD.dpi));
+ double scale;
+
+ if (scaleX<scaleY) scale = scaleX;
+ else scale = scaleY;
+
+ if (scale > 256.0) scale = 256.0;
+ if (scale < 0.01) scale = 0.01;
+
+ mapScale = (long)scale;
+
+ mapD.scale = mapScale;
+ ChangeMapScale(FALSE);
+
+ if (mapVisible) {
+ MapRedraw();
+ }
+ wPrefSetInteger( "draw", "mapscale", (long)mapD.scale );
+ }
+ break;
+ case -1:
+ MapWindowShow( FALSE );
+ break;
+ default:
+ break;
}
}
@@ -2449,8 +2848,7 @@ static void MapDlgUpdate(
static void DrawChange( long changes )
{
if (changes & CHANGE_MAIN) {
- MainRedraw();
- MapRedraw();
+ MainLayout( TRUE, FALSE ); // DrawChange: CHANGE_MAIN
}
if (changes &CHANGE_UNITS)
SetInfoBar();
@@ -2459,6 +2857,13 @@ static void DrawChange( long changes )
}
+static void MainLayoutCB(
+ wDraw_p bd, void * pContex, wPos_t px, wPos_t py )
+{
+ MainLayout( TRUE, FALSE );
+}
+
+
EXPORT void DrawInit( int initialZoom )
{
wPos_t w, h;
@@ -2469,9 +2874,9 @@ EXPORT void DrawInit( int initialZoom )
h = h - (toolbarHeight+max(textHeight,infoHeight)+10);
if ( w <= 0 ) w = 1;
if ( h <= 0 ) h = 1;
- tempD.d = mainD.d = wDrawCreate( mainW, 0, toolbarHeight, "", BD_TICKS,
+ tempD.d = mainD.d = wDrawCreate( mainW, 0, toolbarHeight, "", BD_TICKS|BD_MODKEYS,
w, h, &mainD,
- (wDrawRedrawCallBack_p)MainRedraw, DoMousew );
+ (wDrawRedrawCallBack_p)MainLayoutCB, DoMousew );
if (initialZoom == 0) {
WDOUBLE_T tmpR;
@@ -2497,17 +2902,21 @@ EXPORT void DrawInit( int initialZoom )
tempD.dpi = mainD.dpi;
SetMainSize();
+ panCenter.x = mainD.size.x/2 +mainD.orig.x;
+ panCenter.y = mainD.size.y/2 +mainD.orig.y;
mapD.scale = mapScale;
/*w = (wPos_t)((mapD.size.x/mapD.scale)*mainD.dpi + 0.5)+2;*/
/*h = (wPos_t)((mapD.size.y/mapD.scale)*mainD.dpi + 0.5)+2;*/
ParamRegister( &mapPG );
- mapW = ParamCreateDialog( &mapPG, MakeWindowTitle(_("Map")), NULL, NULL, NULL, FALSE, NULL, 0, MapDlgUpdate );
- ChangeMapScale();
+ mapW = ParamCreateDialog( &mapPG, MakeWindowTitle(_("Map")), NULL, NULL, NULL, FALSE, NULL, F_RESIZE, MapDlgUpdate );
+ ChangeMapScale(TRUE);
log_pan = LogFindIndex( "pan" );
log_zoom = LogFindIndex( "zoom" );
log_mouse = LogFindIndex( "mouse" );
+ log_redraw = LogFindIndex( "redraw" );
AddPlaybackProc( "MOUSE ", (playbackProc_p)PlaybackMain, NULL );
+ AddPlaybackProc( "KEY ", (playbackProc_p)PlaybackKey, NULL );
rulerFp = wStandardFont( F_HELV, FALSE, FALSE );
@@ -2524,6 +2933,8 @@ EXPORT void DrawInit( int initialZoom )
#include "bitmaps/pan.xpm"
+EXPORT static wMenu_p panPopupM;
+
static STATUS_T CmdPan(
wAction_t action,
coOrd pos )
@@ -2544,19 +2955,23 @@ static STATUS_T CmdPan(
switch (action&0xFF) {
case C_START:
start_pos = zero;
- panmode = NONE; InfoMessage(_("Left Drag to Pan, Right Drag to Zoom, 0 to set Origin to 0,0, 1-9 to Zoom#, e to set to Extent"));
+ panmode = NONE;
+ InfoMessage(_("Left-Drag to pan, Ctrl+Left-Drag to zoom, 0 to set origin to zero, 1-9 to zoom#, e to set to extents"));
+ wSetCursor(mainD.d,wCursorSizeAll);
break;
case C_DOWN:
- panmode = PAN;
- start_pos = pos;
- InfoMessage(_("Pan Mode - drag point to new position"));
- break;
- case C_RDOWN:
- panmode = ZOOM;
- start_pos = pos;
- base = pos;
- size = zero;
- InfoMessage(_("Zoom Mode - drag Area to Zoom"));
+ if ((MyGetKeyState()&WKEY_CTRL) == 0) {
+ panmode = PAN;
+ start_pos = pos;
+ InfoMessage(_("Pan Mode - drag point to new position"));
+ break;
+ } else {
+ panmode = ZOOM;
+ start_pos = pos;
+ base = pos;
+ size = zero;
+ InfoMessage(_("Zoom Mode - drag area to zoom"));
+ }
break;
case C_MOVE:
if (panmode == PAN) {
@@ -2575,20 +2990,18 @@ static STATUS_T CmdPan(
}
}
if ((fabs(pos.x-start_pos.x) > min_inc) || (fabs(pos.y-start_pos.y) > min_inc)) {
- DrawMapBoundingBox( TRUE );
+ coOrd oldOrig = mainD.orig;
mainD.orig.x -= (pos.x - start_pos.x);
mainD.orig.y -= (pos.y - start_pos.y);
- ConstraintOrig( &mainD.orig, mainD.size );
- tempD.orig = mainD.orig;
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- DrawMapBoundingBox( TRUE );
+ if ((MyGetKeyState()&WKEY_SHIFT) != 0)
+ ConstraintOrig(&mainD.orig,mainD.size,TRUE,FALSE);
+ if ((oldOrig.x == mainD.orig.x) && (oldOrig.y == mainD.orig.y))
+ InfoMessage(_("Can't move any further in that direction"));
+ else
+ InfoMessage(_("Left click to pan, right click to zoom, 'o' for origin, 'e' for extents"));
}
}
- MainRedraw();
- break;
- case C_RMOVE:
- if (panmode == ZOOM) {
+ else if (panmode == ZOOM) {
base = start_pos;
size.x = pos.x - base.x;
if (size.x < 0) {
@@ -2601,90 +3014,125 @@ static STATUS_T CmdPan(
base.y = pos.y;
}
}
- MainRedraw();
+ panCenter.x = mainD.orig.x + mainD.size.x/2.0;
+ panCenter.y = mainD.orig.y + mainD.size.y/2.0;
+ PanHere( (void*)0 );
break;
- case C_RUP:
+ case C_UP:
+ if (panmode == ZOOM) {
+ scale_x = size.x/mainD.size.x*mainD.scale;
+ scale_y = size.y/mainD.size.y*mainD.scale;
- scale_x = size.x/mainD.size.x*mainD.scale;
- scale_y = size.y/mainD.size.y*mainD.scale;
+ DIST_T oldScale = mainD.scale;
- if (scale_x<scale_y)
- scale_x = scale_y;
- if (scale_x>1) scale_x = ceil( scale_x );
- else scale_x = 1/(ceil(1/scale_x));
+ if (scale_x<scale_y)
+ scale_x = scale_y;
+ if (scale_x>1) scale_x = ceil( scale_x );
+ else scale_x = 1/(ceil(1/scale_x));
- if (scale_x > MAX_MAIN_SCALE) scale_x = MAX_MAIN_SCALE;
- if (scale_x < MIN_MAIN_MACRO) scale_x = MIN_MAIN_MACRO;
+ if (scale_x > MAX_MAIN_SCALE) scale_x = MAX_MAIN_SCALE;
+ if (scale_x < MIN_MAIN_MACRO) scale_x = MIN_MAIN_MACRO;
- mainCenter.x = base.x + size.x/2.0; //Put center for scale in center of square
- mainCenter.y = base.y + size.y/2.0;
- mainD.orig.x = base.x;
- mainD.orig.y = base.y;
+ mainD.orig.x = base.x;
+ mainD.orig.y = base.y;
- panmode = NONE;
- DoNewScale(scale_x);
- MapRedraw();
- break;
- case C_UP:
- panmode = NONE;
+ panmode = NONE;
+ InfoMessage(_("Left Drag to Pan, +CTRL to Zoom, 0 to set Origin to 0,0, 1-9 to Zoom#, e to set to Extent"));
+ DoNewScale(scale_x);
+ break;
+ } else if (panmode == PAN) {
+ panCenter.x = mainD.orig.x + mainD.size.x/2.0;
+ panCenter.y = mainD.orig.y + mainD.size.y/2.0;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ panmode = NONE;
+ }
break;
case C_REDRAW:
if (panmode == ZOOM) {
if (base.x && base.y && size.x && size.y)
- DrawHilight( &mainD, base, size );
+ DrawHilight( &tempD, base, size, TRUE );
}
break;
case C_CANCEL:
base = zero;
+ wSetCursor(mainD.d,defaultCursor);
return C_TERMINATE;
case C_TEXT:
panmode = NONE;
- if ((action>>8) == 0x65) { //"e"
- scale_x = mapD.size.x/(mainD.size.x/mainD.scale);
- scale_y = mapD.size.y/(mainD.size.y/mainD.scale);
- if (scale_x<scale_y)
- scale_x = scale_y;
- scale_x = ceil(scale_x);
- if (scale_x < 1) scale_x = 1;
- if (scale_x > MAX_MAIN_SCALE) scale_x = MAX_MAIN_SCALE;
- mainD.orig = zero;
- mainCenter.x = mainD.orig.x + mapD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mapD.size.y/2.0;
- DoNewScale(scale_x);
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MapRedraw();
- MainRedraw();
- }
- if ((action>>8) == 0x30) { //"0"
+
+ if ((action>>8) == 'e') { //"e"
+ DoZoomExtents(0);
+ } else if (((action>>8) == '0') || ((action>>8) == 'o')) { //"0" or "o"
mainD.orig = zero;
- ConstraintOrig( &mainD.orig, mainD.size );
- mainCenter.x = mainD.orig.x + mainD.size.x/2.0;
- mainCenter.y = mainD.orig.y + mainD.size.y/2.0;
- MapRedraw();
- MainRedraw();
- }
- if ((action>>8) >= 0x31 && (action>>8) <= 0x39) { //"1" to "9"
+ panCenter.x = mainD.size.x/2.0;
+ panCenter.y = mainD.size.y/2.0;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ MainLayout( TRUE, TRUE ); // CmdPan C_TEXT '0' 'o'
+ } else if ((action>>8) >= '1' && (action>>8) <= '9') { //"1" to "9"
scale_x = (action>>8)&0x0F;
DoNewScale(scale_x);
- MapRedraw();
- MainRedraw();
+ } else if ((action>>8) == 'c') { // "c"
+ panCenter = pos;
+ LOG( log_pan, 2, ( "PanCenter:%d %0.3f %0.3f\n", __LINE__, panCenter.x, panCenter.y ) );
+ PanHere( (void*)0 ); // CmdPan C_TEXT 'c'
}
+
if ((action>>8) == 0x0D) {
+ wSetCursor(mainD.d,defaultCursor);
return C_TERMINATE;
- }
- else if ((action>>8) == 0x1B) {
+ } else if ((action>>8) == 0x1B) {
+ wSetCursor(mainD.d,defaultCursor);
return C_TERMINATE;
}
break;
+ case C_CMDMENU:
+ menuPos = pos;
+ wMenuPopupShow( panPopupM );
+ return C_CONTINUE;
+ break;
}
return C_CONTINUE;
}
+static wMenuPush_p zoomExtents,panOrig,panHere;
+static wMenuPush_p zoomLvl1,zoomLvl2,zoomLvl3,zoomLvl4,zoomLvl5,zoomLvl6,zoomLvl7,zoomLvl8,zoomLvl9;
+
+EXPORT void PanMenuEnter(int key) {
+ int action;
+ action = C_TEXT;
+ action |= key<<8;
+ CmdPan(action,zero);
+}
+
+extern wIndex_t selectCmdInx;
+extern wIndex_t describeCmdInx;
+extern wIndex_t joinCmdInx;
+extern wIndex_t modifyCmdInx;
EXPORT void InitCmdPan( wMenu_p menu )
{
panCmdInx = AddMenuButton( menu, CmdPan, "cmdPan", _("Pan/Zoom"), wIconCreatePixMap(pan_xpm),
- LEVEL0, IC_CANCEL|IC_POPUP|IC_LCLICK|IC_RCLICK|IC_CMDMENU, ACCL_PAN, NULL );
+ LEVEL0, IC_CANCEL|IC_POPUP|IC_LCLICK|IC_CMDMENU, ACCL_PAN, NULL );
+}
+EXPORT void InitCmdPan2( wMenu_p menu )
+{
+ panPopupM = MenuRegister( "Pan Options" );
+ wMenuPushCreate(panPopupM, "cmdSelectMode", GetBalloonHelpStr("cmdSelectMode"), 0, DoCommandB, (void*) (intptr_t) selectCmdInx);
+ wMenuPushCreate(panPopupM, "cmdDescribeMode", GetBalloonHelpStr("cmdDescribeMode"), 0, DoCommandB, (void*) (intptr_t) describeCmdInx);
+ wMenuPushCreate(panPopupM, "cmdModifyMode", GetBalloonHelpStr("cmdModifyMode"), 0, DoCommandB, (void*) (intptr_t) modifyCmdInx);
+ wMenuSeparatorCreate(panPopupM);
+ zoomExtents = wMenuPushCreate( panPopupM, "", _("Zoom to extents - 'e'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) 'e');
+ zoomLvl1 = wMenuPushCreate( panPopupM, "", _("Zoom to 1:1 - '1'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) '1');
+ zoomLvl2 = wMenuPushCreate( panPopupM, "", _("Zoom to 1:2 - '2'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) '2');
+ zoomLvl3 = wMenuPushCreate( panPopupM, "", _("Zoom to 1:3 - '3'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) '3');
+ zoomLvl4 = wMenuPushCreate( panPopupM, "", _("Zoom to 1:4 - '4'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) '4');
+ zoomLvl5 = wMenuPushCreate( panPopupM, "", _("Zoom to 1:5 - '5'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) '5');
+ zoomLvl6 = wMenuPushCreate( panPopupM, "", _("Zoom to 1:6 - '6'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) '6');
+ zoomLvl7 = wMenuPushCreate( panPopupM, "", _("Zoom to 1:7 - '7'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) '7');
+ zoomLvl8 = wMenuPushCreate( panPopupM, "", _("Zoom to 1:8 - '8'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) '8');
+ zoomLvl9 = wMenuPushCreate( panPopupM, "", _("Zoom to 1:9 - '9'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) '9');
+ panOrig = wMenuPushCreate( panPopupM, "", _("Pan to Origin - 'o'/'0'"), 0, (wMenuCallBack_p)PanMenuEnter, (void*) 'o');
+ wMenu_p zoomPanM = wMenuMenuCreate(panPopupM, "", _("&Zoom"));
+ InitCmdZoom(NULL, NULL, NULL, zoomPanM);
+ panHere = wMenuPushCreate( panPopupM, "", _("Pan center here - 'c'"), 0, (wMenuCallBack_p)PanHere, (void*) 3);
}
diff --git a/app/bin/draw.h b/app/bin/draw.h
index 66a1571..dc01695 100644
--- a/app/bin/draw.h
+++ b/app/bin/draw.h
@@ -26,70 +26,89 @@
#include "common.h"
#include "wlib.h"
-#define DC_TICKS (1<<1)
+// drawCmd_t.options
+//
+// SIMPLE: draw simplified objects.
+// No endpts, descriptions, wide lines and arcs, ties, centerlines, special color
+// Draw simple lines for: wide lines and arcs, dimlines, benchwork, tableedge, filled poly andcircle
+#define DC_SIMPLE (1<<0)
+// SEGTRACK: draw tracks as segments (SEG_*TRK) instead of lines and arcs
+#define DC_SEGTRACK (1<<1)
+// PRINT: we're printing
#define DC_PRINT (1<<2)
#define DC_NOCLIP (1<<3)
-#define DC_QUICK (1<<4)
-#define DC_DASH (1<<5)
-#define DC_SIMPLE (1<<6)
-#define DC_GROUP (1<<7)
-#define DC_CENTERLINE (1<<8)
-#define DC_SEGTRACK (1<<9)
-#define DC_TIES (1<<10)
+// CENTERLINE: draw centerlines (for bitmaps)
+#define DC_CENTERLINE (1<<4)
+// TICKS: draw rulers on edges
+#define DC_TICKS (1<<5)
+// Line styles
+#define DC_THICK (1<<7)
+#define DC_DASH (1<<12)
+#define DC_DOT (1<<13)
+#define DC_DASHDOT (1<<14)
+#define DC_DASHDOTDOT (1<<15)
+#define DC_CENTER (1<<16)
+#define DC_PHANTOM (1<<17)
+
+#define DC_NOTSOLIDLINE (DC_DASH|DC_DOT|DC_DASHDOT|DC_DASHDOTDOT|DC_CENTER|DC_PHANTOM)
+
+#define INIT_MAIN_SCALE (8.0)
+#define INIT_MAP_SCALE (64.0)
+#define MAX_MAIN_SCALE (256.0)
+#define MIN_MAIN_SCALE (1.0)
+#define MIN_MAIN_MACRO (0.10)
typedef struct drawCmd_t * drawCmd_p;
typedef struct {
- long options;
- void (*drawLine)( drawCmd_p, coOrd, coOrd, wDrawWidth, wDrawColor );
- void (*drawArc)( drawCmd_p, coOrd, DIST_T, ANGLE_T, ANGLE_T, BOOL_T, wDrawWidth, wDrawColor );
- void (*drawString)( drawCmd_p, coOrd, ANGLE_T, char *, wFont_p, FONTSIZE_T, wDrawColor );
- void (*drawBitMap)( drawCmd_p, coOrd, wDrawBitMap_p, wDrawColor );
- void (*drawFillPoly) (drawCmd_p, int, coOrd *, wDrawColor );
- void (*drawFillCircle) (drawCmd_p, coOrd, DIST_T, wDrawColor );
- } drawFuncs_t;
-
-typedef void (*drawConvertPix2CoOrd)( drawCmd_p, wPos_t, wPos_t, coOrd * );
-typedef void (*drawConvertCoOrd2Pix)( drawCmd_p, coOrd, wPos_t *, wPos_t * );
+ long options;
+ void (*drawLine)(drawCmd_p, coOrd, coOrd, wDrawWidth, wDrawColor);
+ void (*drawArc)(drawCmd_p, coOrd, DIST_T, ANGLE_T, ANGLE_T, BOOL_T, wDrawWidth,
+ wDrawColor);
+ void (*drawString)(drawCmd_p, coOrd, ANGLE_T, char *, wFont_p, FONTSIZE_T,
+ wDrawColor);
+ void (*drawBitMap)(drawCmd_p, coOrd, wDrawBitMap_p, wDrawColor);
+ void (*drawPoly)(drawCmd_p, int, coOrd *, int *, wDrawColor, wDrawWidth, int,
+ int);
+ void (*drawFillCircle)(drawCmd_p, coOrd, DIST_T, wDrawColor);
+} drawFuncs_t;
+
+typedef void (*drawConvertPix2CoOrd)(drawCmd_p, wPos_t, wPos_t, coOrd *);
+typedef void (*drawConvertCoOrd2Pix)(drawCmd_p, coOrd, wPos_t *, wPos_t *);
typedef struct drawCmd_t {
- wDraw_p d;
- drawFuncs_t * funcs;
- long options;
- DIST_T scale;
- ANGLE_T angle;
- coOrd orig;
- coOrd size;
- drawConvertPix2CoOrd Pix2CoOrd;
- drawConvertCoOrd2Pix CoOrd2Pix;
- FLOAT_T dpi;
- } drawCmd_t;
+ wDraw_p d;
+ drawFuncs_t * funcs;
+ unsigned long options;
+ DIST_T scale;
+ ANGLE_T angle;
+ coOrd orig;
+ coOrd size;
+ drawConvertPix2CoOrd Pix2CoOrd;
+ drawConvertCoOrd2Pix CoOrd2Pix;
+ FLOAT_T dpi;
+} drawCmd_t;
#define SCALEX(D,X) ((X)/(D).dpi)
#define SCALEY(D,Y) ((Y)/(D).dpi)
#ifdef WINDOWS
-#define LBORDER (33)
-#define BBORDER (32)
+ #define LBORDER (33)
+ #define BBORDER (32)
#else
-#define LBORDER (26)
-#define BBORDER (27)
+ #define LBORDER (26)
+ #define BBORDER (27)
#endif
#define RBORDER (9)
#define TBORDER (8)
-#ifdef LATER
-#define Pix2CoOrd( D, pos, X, Y ) { \
- pos.x = ((long)(((POS_T)((X)-LBORDER)*pixelBins)/D.dpi))/pixelBins * D.scale + D.orig.x; \
- pos.y = ((long)(((POS_T)((Y)-BBORDER)*pixelBins)/D.dpi))/pixelBins * D.scale + D.orig.y; \
- }
-#endif
-void Pix2CoOrd( drawCmd_p, wPos_t, wPos_t, coOrd * );
-void CoOrd2Pix( drawCmd_p, coOrd, wPos_t *, wPos_t * );
+void Pix2CoOrd(drawCmd_p, wPos_t, wPos_t, coOrd *);
+void CoOrd2Pix(drawCmd_p, coOrd, wPos_t *, wPos_t *);
extern BOOL_T inError;
extern DIST_T pixelBins;
extern wWin_p mapW;
extern BOOL_T mapVisible;
+extern BOOL_T magneticSnap;
extern drawCmd_t mainD;
extern coOrd mainCenter;
extern drawCmd_t mapD;
@@ -106,6 +125,11 @@ extern long drawCount;
extern BOOL_T drawEnable;
extern long currRedraw;
+extern coOrd panCenter;
+extern coOrd menuPos;
+
+extern int log_pan;
+
extern wDrawColor drawColorBlack;
extern wDrawColor drawColorWhite;
@@ -113,12 +137,39 @@ extern wDrawColor drawColorRed;
extern wDrawColor drawColorBlue;
extern wDrawColor drawColorGreen;
extern wDrawColor drawColorAqua;
+extern wDrawColor drawColorPowderedBlue;
extern wDrawColor drawColorPurple;
extern wDrawColor drawColorGold;
+extern wDrawColor drawColorGrey10;
+extern wDrawColor drawColorGrey20;
+extern wDrawColor drawColorGrey30;
+extern wDrawColor drawColorGrey40;
+extern wDrawColor drawColorGrey50;
+extern wDrawColor drawColorGrey60;
+extern wDrawColor drawColorGrey70;
+extern wDrawColor drawColorGrey80;
+extern wDrawColor drawColorGrey90;
+// Special colors
+extern wDrawColor drawColorPreviewSelected;
+extern wDrawColor drawColorPreviewUnselected;
+
#define wDrawColorBlack drawColorBlack
#define wDrawColorWhite drawColorWhite
#define wDrawColorBlue drawColorBlue
+#define wDrawColorPowderedBlue drawColorPowderedBlue
+#define wDrawColorAqua drawColorAqua
#define wDrawColorRed drawColorRed
+#define wDrawColorGrey10 drawColorGrey10
+#define wDrawColorGrey20 drawColorGrey20
+#define wDrawColorGrey30 drawColorGrey30
+#define wDrawColorGrey40 drawColorGrey40
+#define wDrawColorGrey50 drawColorGrey50
+#define wDrawColorGrey60 drawColorGrey60
+#define wDrawColorGrey70 drawColorGrey70
+#define wDrawColorGrey80 drawColorGrey80
+#define wDrawColorGrey90 drawColorGrey90
+#define wDrawColorPreviewSelected drawColorPreviewSelected
+#define wDrawColorPreviewUnselected drawColorPreviewUnselected
extern wDrawColor markerColor;
extern wDrawColor borderColor;
@@ -128,88 +179,97 @@ extern wDrawColor snapGridColor;
extern wDrawColor selectedColor;
extern wDrawColor profilePathColor;
-BOOL_T IsClose( DIST_T );
+BOOL_T IsClose(DIST_T);
-drawFuncs_t screenDrawFuncs;
-drawFuncs_t tempDrawFuncs;
-drawFuncs_t tempSegDrawFuncs;
-drawFuncs_t printDrawFuncs;
+extern drawFuncs_t screenDrawFuncs;
+extern drawFuncs_t tempDrawFuncs;
+extern drawFuncs_t tempSegDrawFuncs;
+extern drawFuncs_t printDrawFuncs;
#define DrawLine( D, P0, P1, W, C ) (D)->funcs->drawLine( D, P0, P1, W, C )
#define DrawArc( D, P, R, A0, A1, F, W, C ) (D)->funcs->drawArc( D, P, R, A0, A1, F, W, C )
#define DrawString( D, P, A, S, FP, FS, C ) (D)->funcs->drawString( D, P, A, S, FP, FS, C )
#define DrawBitMap( D, P, B, C ) (D)->funcs->drawBitMap( D, P, B, C )
-#define DrawFillPoly( D, N, P, C ) (D)->funcs->drawFillPoly( D, N, P, C );
+#define DrawPoly( D, N, P, T, C, W, F, O ) (D)->funcs->drawPoly( D, N, P, T, C, W, F, O );
#define DrawFillCircle( D, P, R, C ) (D)->funcs->drawFillCircle( D, P, R, C );
#define REORIGIN( Q, P, A, O ) { \
- (Q) = (P); \
- REORIGIN1( Q, A, O ) \
- }
+ (Q) = (P); \
+ REORIGIN1( Q, A, O ) \
+ }
#define REORIGIN1( Q, A, O ) { \
- if ( (A) != 0.0 ) \
- Rotate( &(Q), zero, (A) ); \
- (Q).x += (O).x; \
- (Q).y += (O).y; \
- }
+ if ( (A) != 0.0 ) \
+ Rotate( &(Q), zero, (A) ); \
+ (Q).x += (O).x; \
+ (Q).y += (O).y; \
+ }
#define OFF_D( ORIG, SIZE, LO, HI ) \
- ( (HI).x < (ORIG).x || \
- (LO).x > (ORIG).x+(SIZE).x || \
- (HI).y < (ORIG).y || \
- (LO).y > (ORIG).y+(SIZE).y )
+ ( (HI).x < (ORIG).x || \
+ (LO).x > (ORIG).x+(SIZE).x || \
+ (HI).y < (ORIG).y || \
+ (LO).y > (ORIG).y+(SIZE).y )
#define OFF_MAIND( LO, HI ) \
- OFF_D( mainD.orig, mainD.size, LO, HI )
+ OFF_D( mainD.orig, mainD.size, LO, HI )
-void DrawHilight( drawCmd_p, coOrd, coOrd );
-void DrawHilightPolygon( drawCmd_p, coOrd *, int );
+void DrawHilight(drawCmd_p, coOrd, coOrd, BOOL_T add);
+void DrawHilightPolygon(drawCmd_p, coOrd *, int);
#define BOX_NONE (0)
#define BOX_UNDERLINE (1)
#define BOX_BOX (2)
#define BOX_INVERT (3)
#define BOX_ARROW (4)
#define BOX_BACKGROUND (5)
-void DrawBoxedString( int, drawCmd_p, coOrd, char *, wFont_p, wFontSize_t, wDrawColor, ANGLE_T );
-void DrawMultiLineTextSize(drawCmd_p dp, char * text, wFont_p fp, wFontSize_t fs, BOOL_T relative, coOrd * size, coOrd * lastline );
-void DrawTextSize2( drawCmd_p, char *, wFont_p, wFontSize_t, BOOL_T, coOrd *, POS_T *);
-void DrawTextSize( drawCmd_p, char *, wFont_p, wFontSize_t, BOOL_T, coOrd * );
-void DrawMultiString(drawCmd_p d, coOrd pos, char * text, wFont_p fp, wFontSize_t fs, wDrawColor color, ANGLE_T a, coOrd * lo, coOrd * hi);
-BOOL_T SetRoomSize( coOrd );
-void GetRoomSize( coOrd * );
-void DoRedraw( void );
-void SetMainSize( void );
-void MainRedraw( void );
-void MapRedraw( void );
-void DrawMarkers( void );
-void DrawMapBoundingBox( BOOL_T );
-void DrawTicks( drawCmd_p, coOrd );
-void DrawRuler( drawCmd_p, coOrd, coOrd, DIST_T, int, int, wDrawColor );
-void MainProc( wWin_p, winProcEvent, void *, void * );
-void InitInfoBar( void );
-void DrawInit( int );
-void DoZoomUp( void * );
-void DoZoomDown( void * );
-void DoZoom( DIST_T * );
-
-void InitCmdZoom( wMenu_p, wMenu_p );
-
-void InfoPos( coOrd );
-void InfoCount( wIndex_t );
-void SetMessage( char * );
+void DrawBoxedString(int, drawCmd_p, coOrd, char *, wFont_p, wFontSize_t,
+ wDrawColor, ANGLE_T);
+void DrawMultiLineTextSize(drawCmd_p dp, char * text, wFont_p fp,
+ wFontSize_t fs, BOOL_T relative, coOrd * size, coOrd * lastline);
+void DrawTextSize2(drawCmd_p, char *, wFont_p, wFontSize_t, BOOL_T, coOrd *,
+ POS_T *, POS_T *);
+void DrawTextSize(drawCmd_p, char *, wFont_p, wFontSize_t, BOOL_T, coOrd *);
+void DrawMultiString(drawCmd_p d, coOrd pos, char * text, wFont_p fp,
+ wFontSize_t fs, wDrawColor color, ANGLE_T a, coOrd * lo, coOrd * hi,
+ BOOL_T boxed);
+BOOL_T SetRoomSize(coOrd);
+void GetRoomSize(coOrd *);
+void DoRedraw(void);
+void SetMainSize(void);
+void MainRedraw(void);
+void MainLayout(wBool_t, wBool_t);
+void TempRedraw(void);
+void DrawRuler(drawCmd_p, coOrd, coOrd, DIST_T, int, int, wDrawColor);
+void MainProc(wWin_p, winProcEvent, void *, void *);
+void InitInfoBar(void);
+void DrawInit(int);
+void DoZoomUp(void *);
+void DoZoomDown(void *);
+void DoZoomExtents( void *);
+void DoZoom(DIST_T *);
+void PanHere(void *);
+void PanMenuEnter(int);
+
+void InitCmdZoom(wMenu_p, wMenu_p, wMenu_p, wMenu_p);
+
+void InfoPos(coOrd);
+void InfoCount(wIndex_t);
+void SetMessage(char *);
wIndex_t panCmdInx;
-void InfoSubstituteControls( wControl_p *, char * * );
+void InfoSubstituteControls(wControl_p *, char * *);
-void MapGrid( coOrd, coOrd, ANGLE_T, coOrd, ANGLE_T, POS_T, POS_T, int *, int *, int *, int * );
-void DrawGrid( drawCmd_p, coOrd *, POS_T, POS_T, long, long, coOrd, ANGLE_T, wDrawColor, BOOL_T );
-STATUS_T GridAction( wAction_t, coOrd, coOrd *, DIST_T * );
+void MapGrid(coOrd, coOrd, ANGLE_T, coOrd, ANGLE_T, POS_T, POS_T, int *, int *,
+ int *, int *);
+void DrawGrid(drawCmd_p, coOrd *, POS_T, POS_T, long, long, coOrd, ANGLE_T,
+ wDrawColor, BOOL_T);
+STATUS_T GridAction(wAction_t, coOrd, coOrd *, DIST_T *);
-void ResetMouseState( void );
-void FakeDownMouseState( void );
-void GetMousePosition( int *x, int *y );
-void RecordMouse( char *, wAction_t, POS_T, POS_T );
+void ResetMouseState(void);
+void FakeDownMouseState(void);
+void GetMousePosition(int *x, int *y);
+void RecordMouse(char *, wAction_t, POS_T, POS_T);
extern long playbackDelay;
-void MovePlaybackCursor( drawCmd_p, wPos_t, wPos_t );
-typedef void (*playbackProc)( wAction_t, coOrd );
-void PlaybackMouse( playbackProc, drawCmd_p, wAction_t, coOrd, wDrawColor );
+void MovePlaybackCursor(drawCmd_p, wPos_t, wPos_t, wBool_t, wControl_p);
+typedef void (*playbackProc)(wAction_t, coOrd);
+void PlaybackMouse(playbackProc, drawCmd_p, wAction_t, coOrd, wDrawColor);
+void RedrawPlaybackCursor();
#endif
diff --git a/app/bin/drawgeom.c b/app/bin/drawgeom.c
index 2342599..d23031f 100644
--- a/app/bin/drawgeom.c
+++ b/app/bin/drawgeom.c
@@ -37,46 +37,42 @@ static long drawGeomCurveMode;
#define contextSegs(N) DYNARR_N( trkSeg_t, context->Segs_da, N )
-
-
static dynArr_t points_da;
-#define points(N) DYNARR_N( coOrd, points_da, N )
+static dynArr_t anchors_da;
+static dynArr_t select_da;
+
+#define points(N) DYNARR_N( pts_t, points_da, N )
+#define point_selected(N) DYNARR_N( wBool_t, select_da, N)
+#define anchors(N) DYNARR_N( trkSeg_t, anchors_da, N)
-static void EndPoly( drawContext_t * context, int cnt )
+static void EndPoly( drawContext_t * context, int cnt, wBool_t open)
{
trkSeg_p segPtr;
track_p trk;
- long oldOptions;
- coOrd * pts;
+ pts_t * pts;
int inx;
if (context->State==0 || cnt == 0)
return;
- oldOptions = context->D->funcs->options;
- context->D->funcs->options |= wDrawOptTemp;
- DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- context->D->funcs->options = oldOptions;
-
- if (IsClose(FindDistance(tempSegs(0).u.l.pos[0], tempSegs(cnt-1).u.l.pos[1] )))
- cnt--;
- if ( cnt < 2 ) {
+ if ( cnt < 3 ) {
tempSegs_da.cnt = 0;
ErrorMessage( MSG_POLY_SHAPES_3_SIDES );
return;
}
- pts = (coOrd*)MyMalloc( (cnt+1) * sizeof (coOrd) );
- for ( inx=0; inx<cnt; inx++ )
- pts[inx] = tempSegs(inx).u.l.pos[0];
- pts[cnt] = tempSegs(cnt-1).u.l.pos[1];
+ pts = (pts_t*)MyMalloc( (cnt) * sizeof (pts_t) );
+ for ( inx=0; inx<cnt; inx++ ) {
+ pts[inx].pt = tempSegs(inx).u.l.pos[0];
+ pts[inx].pt_type = wPolyLineStraight;
+ }
DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
segPtr = &tempSegs(0);
- segPtr->type = ( context->Op == OP_POLY ? SEG_POLY: SEG_FILPOLY );
- segPtr->u.p.cnt = cnt+1;
+ segPtr->type = ( (context->Op == OP_POLY || context->Op == OP_POLYLINE )? SEG_POLY:SEG_FILPOLY );
+ segPtr->u.p.cnt = cnt;
segPtr->u.p.pts = pts;
segPtr->u.p.angle = 0.0;
segPtr->u.p.orig = zero;
- segPtr->u.p.polyType = FREEFORM;
+ segPtr->u.p.polyType = open?POLYLINE:FREEFORM;
UndoStart( _("Create Lines"), "newDraw" );
trk = MakeDrawFromSeg( zero, 0.0, segPtr );
DrawNewTrack( trk );
@@ -100,6 +96,80 @@ static void DrawGeomOk( void )
tempSegs_da.cnt = 0;
}
+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 CreateLineAnchor(coOrd p, coOrd p0) {
+ DIST_T d = tempD.scale*0.15;
+ coOrd p1;
+ ANGLE_T a = FindAngle(p0,p);
+ Translate(&p1,p,a,d*5);
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = SEG_STRLIN;
+ anchors(i).color = wDrawColorBlue;
+ anchors(i).u.l.pos[0] = p;
+ anchors(i).u.l.pos[1] = p0;
+ anchors(i).width = 0;
+}
+
+static void CreateSquareAnchor(coOrd p) {
+ DIST_T d = tempD.scale*0.15;
+ 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;
+}
+
+BOOL_T FindTempNear(drawContext_t *context, coOrd *p) {
+ if (context->State == 2) {
+ if (context->Op >= OP_CURVE1 && context->Op <= OP_CURVE4) {
+ if (context->ArcData.type == curveTypeCurve) {
+ ANGLE_T a = FindAngle(context->ArcData.curvePos,*p);
+ if (IsClose(FindDistance(context->ArcData.curvePos,*p)-context->ArcData.curveRadius) &&
+ (a>=context->ArcData.a0) && (a<=context->ArcData.a0+context->ArcData.a1)) {
+ Translate(p,context->ArcData.curvePos,a,context->ArcData.curveRadius);
+ return TRUE;
+ }
+ } else {
+ if (IsClose(LineDistance(p,tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1])))
+ return TRUE;
+ }
+ } else if ( context->Op >=OP_LINE && context->Op <= OP_BENCH) {
+ if (IsClose(LineDistance(p,tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1])))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
/**
* Create and draw a graphics primitive (lines, arc, circle). The complete handling of mouse
* movements and clicks during the editing process is done here.
@@ -108,63 +178,195 @@ static void DrawGeomOk( void )
* \param pos IN position of mouse pointer
* \param context IN/OUT parameters for drawing op
* \return next command state
+ *
+ * Note - Poly supports both clicking points and/or dragging sides. Close is space or enter.
+ * Note - This routine will be recalled to C_UPDATE the last action if the State is 2 and the user updates the dialog
+ *
*/
STATUS_T DrawGeomMouse(
wAction_t action,
coOrd pos,
- drawContext_t *context )
+ drawContext_t *context)
{
static int lastValid = FALSE;
+ static wBool_t lock;
static coOrd pos0, pos0x, pos1, lastPos;
trkSeg_p segPtr;
- coOrd *pts;
+ pts_t *pts;
int inx;
DIST_T width;
static int segCnt;
DIST_T d;
+ ANGLE_T a1,a2;
+ static ANGLE_T line_angle;
BOOL_T createTrack;
- long oldOptions;
- width = context->Width/context->D->dpi;
+ width = context->line_Width/context->D->dpi;
switch (action&0xFF) {
+ case C_UPDATE:
+ if (context->State == 0 ) return C_TERMINATE;
+ if (context->Op != OP_POLY && context->Op != OP_FILLPOLY && context->Op != OP_POLYLINE && context->State == 1) return C_TERMINATE;
+ switch (context->Op) {
+ case OP_CIRCLE1:
+ case OP_CIRCLE2:
+ case OP_CIRCLE3:
+ case OP_FILLCIRCLE1:
+ case OP_FILLCIRCLE2:
+ case OP_FILLCIRCLE3:
+ tempSegs(0).u.c.radius = context->radius;
+ break;
+ case OP_CURVE1:
+ case OP_CURVE2:
+ case OP_CURVE3:
+ case OP_CURVE4:
+ if (context->ArcData.type == curveTypeCurve) {
+ if (tempSegs(0).u.c.radius != context->radius) {
+ coOrd end;
+ Translate(&end,context->ArcData.curvePos,context->ArcData.a0,context->ArcData.curveRadius);
+ tempSegs(0).u.c.radius = context->radius;
+ Translate(&tempSegs(0).u.c.center,end,context->ArcData.a0+180,context->radius);
+ context->ArcData.curvePos = tempSegs(0).u.c.center;
+ context->ArcData.curveRadius = tempSegs(0).u.c.radius;
+ }
+ tempSegs(0).u.c.a1 = context->angle;
+ context->ArcData.a1 = tempSegs(0).u.c.a1;
+ Translate(&context->ArcData.pos1,context->ArcData.curvePos,context->ArcData.a0,context->ArcData.curveRadius);
+ Translate(&context->ArcData.pos2,context->ArcData.curvePos,context->ArcData.a0+context->ArcData.a1,context->ArcData.curveRadius);
+ } else
+ Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->angle,context->length);
+ break;
+ case OP_LINE:
+ case OP_BENCH:
+ case OP_TBLEDGE:
+ a1 = FindAngle(pos0,pos1);
+ Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->angle,context->length);
+ lastPos = pos1 = tempSegs(0).u.l.pos[1];
+ tempSegs_da.cnt = 1;
+ context->angle = NormalizeAngle(context->angle);
+ break;
+ case OP_BOX:
+ case OP_FILLBOX:
+ pts = tempSegs(0).u.p.pts;
+ a1 = FindAngle(pts[0].pt,pts[1].pt);
+ Translate(&pts[1].pt,pts[0].pt,a1,context->length);
+ a2 = FindAngle(pts[0].pt,pts[3].pt);
+ Translate(&pts[2].pt,pts[1].pt,a2,context->width);
+ Translate(&pts[3].pt,pts[0].pt,a2,context->width);
+ tempSegs_da.cnt = 1;
+ break;
+ case OP_POLY:
+ case OP_FILLPOLY:
+ case OP_POLYLINE:
+ tempSegs_da.cnt = segCnt;
+ if (segCnt>1) {
+ ANGLE_T an = FindAngle(tempSegs(segCnt-2).u.l.pos[0],tempSegs(segCnt-2).u.l.pos[1]);
+ an = an+context->angle;
+ Translate(&tempSegs(segCnt-1).u.l.pos[1],tempSegs(segCnt-1).u.l.pos[0],an,context->length);
+ } else {
+ Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->angle,context->length);
+ }
+ pos1 = lastPos = tempSegs(segCnt-1).u.l.pos[1];
+ context->angle = fabs(context->angle);
+ if (context->angle >180) context->angle = context->angle - 180.0;
+ break;
+ default:
+ break;
+ }
+ MainRedraw();
+ anchors_da.cnt = 0;
+ return C_CONTINUE;
+
case C_START:
context->State = 0;
context->Changed = FALSE;
segCnt = 0;
+ CleanSegs(&tempSegs_da);
DYNARR_RESET( trkSeg_t, tempSegs_da );
+ DYNARR_RESET( trkSeg_t, anchors_da );
+ lock = FALSE;
+ if (!magneticSnap)
+ InfoMessage(_("+Shift to lock to nearby objects"));
+ else
+ InfoMessage(_("+Shift to not lock to nearby objects"));
return C_CONTINUE;
case wActionMove:
- return C_CONTINUE;
-
- case wActionLDown:
- context->Started = TRUE;
- if (context->State == 0) { //First Down only
- switch (context->Op) { //Snap pos to nearest line end point if this is end and just shift is depressed for lines and some curves
- case OP_LINE:
+ if (context->State == 0 || context->State ==2 ) {
+ DYNARR_RESET( trkSeg_t, anchors_da );
+ switch (context->Op) { //Snap pos to nearest line if this is end and just shift is depressed for lines and some curves
case OP_CURVE1:
- if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_SHIFT ) {
+ case OP_CURVE2:
+ case OP_CURVE3:
+ case OP_CURVE4:
+ case OP_LINE:
+ case OP_DIMLINE:
+ case OP_BENCH:
+ case OP_POLY:
+ case OP_FILLPOLY:
+ case OP_POLYLINE:
+ if (((MyGetKeyState() & WKEY_ALT) == 0) == magneticSnap ) {
coOrd p = pos;
track_p t;
- if ((t=OnTrack(&p,FALSE,FALSE))) {
- if (GetClosestEndPt(t,&p)) {
- pos = p;
+ if ((t=OnTrack(&p,FALSE,FALSE))!=NULL) {
+ if (context->Op == OP_DIMLINE ) {
+ CreateEndAnchor(p,FALSE);
+ } else if (!IsTrack(t)) CreateEndAnchor(p,FALSE);
+ } else {
+ p = pos;
+ if (FindTempNear(context,&p)) {
+ CreateEndAnchor(p,FALSE);
}
}
- };
+ }
break;
default:
;
}
}
+ return C_CONTINUE;
+
+ case wActionLDown:
+ DYNARR_RESET( trkSeg_t, anchors_da );
+ if (context->State == 2) {
+ tempSegs_da.cnt = segCnt;
+ if ((context->Op == OP_POLY || context->Op == OP_FILLPOLY || context->Op == OP_POLYLINE)) {
+ EndPoly(context, segCnt, context->Op==OP_POLYLINE);
+ } else {
+ DrawGeomOk();
+ }
+ segCnt = 0;
+ anchors_da.cnt = 0;
+ context->State = 0;
+ }
+ context->Started = TRUE;
+ line_angle = 90.0;
+ if ((context->Op == OP_CURVE1 && context->State != 2) ||
+ (context->Op == OP_CURVE2 && context->State == 0) ||
+ (context->Op == OP_CURVE3 && context->State != 0) ||
+ (context->Op == OP_CURVE4 && context->State != 2) ||
+ (context->Op == OP_LINE) || (context->Op == OP_DIMLINE) ||
+ (context->Op == OP_BENCH) ) {
+ BOOL_T found = FALSE;
+ if (((MyGetKeyState() & WKEY_ALT) ==0) == magneticSnap ) {
+ coOrd p = pos;
+ track_p t;
+ if ((t=OnTrack(&p,FALSE,FALSE))!=NULL) {
+ if (!IsTrack(t)) {
+ EPINX_T ep1,ep2;
+ line_angle = GetAngleAtPoint(t,pos,&ep1,&ep2);
+ pos = p;
+ found = TRUE;
+ }
+ }
+ }
+ if (!found) SnapPos( &pos );
+ }
if ((context->Op == OP_CURVE1 || context->Op == OP_CURVE2 || context->Op == OP_CURVE3 || context->Op == OP_CURVE4) && context->State == 1) {
- ;
+ ;
} else {
- if ( (MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) // Control snaps to nearest track (not necessarily the end)
- OnTrack( &pos, FALSE, FALSE );
pos0 = pos;
pos1 = pos;
}
@@ -173,9 +375,6 @@ STATUS_T DrawGeomMouse(
case OP_LINE:
case OP_DIMLINE:
case OP_BENCH:
- if ( lastValid && ( MyGetKeyState() & WKEY_CTRL ) ) {
- pos = pos0 = lastPos;
- }
DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
switch (context->Op) {
case OP_LINE: tempSegs(0).type = SEG_STRLIN; break;
@@ -191,12 +390,9 @@ STATUS_T DrawGeomMouse(
tempSegs(0).u.l.option = 0;
}
tempSegs_da.cnt = 0;
- context->message( _("Drag to place next end point") );
+ context->message( _("Drag to next point, +Shift to lock to object, +Ctrl to lock to 90deg") );
break;
case OP_TBLEDGE:
- if ( lastValid && ( MyGetKeyState() & WKEY_CTRL ) ) {
- pos = pos0 = lastPos;
- }
OnTableEdgeEndPt( NULL, &pos );
DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
tempSegs(0).type = SEG_TBLEDGE;
@@ -214,9 +410,8 @@ STATUS_T DrawGeomMouse(
case OP_CURVE3: drawGeomCurveMode = crvCmdFromCenter; break;
case OP_CURVE4: drawGeomCurveMode = crvCmdFromChord; break;
}
- CreateCurve( C_DOWN, pos, FALSE, context->Color, width, drawGeomCurveMode, context->message );
- } else {
- tempSegs_da.cnt = segCnt;
+ CreateCurve( C_START, pos, FALSE, context->Color, width, drawGeomCurveMode, &anchors_da, context->message );
+ CreateCurve( C_DOWN, pos, FALSE, context->Color, width, drawGeomCurveMode, &anchors_da, context->message );
}
break;
case OP_CIRCLE1:
@@ -240,6 +435,7 @@ STATUS_T DrawGeomMouse(
break;
case OP_FILLBOX:
width = 0;
+ /* no break */
case OP_BOX:
DYNARR_SET( trkSeg_t, tempSegs_da, 4 );
for ( inx=0; inx<4; inx++ ) {
@@ -248,75 +444,172 @@ STATUS_T DrawGeomMouse(
tempSegs(inx).width = width;
tempSegs(inx).u.l.pos[0] = tempSegs(inx).u.l.pos[1] = pos;
}
- tempSegs_da.cnt = 0;
context->message( _("Drag set box size") );
break;
case OP_POLY:
case OP_FILLPOLY:
+ case OP_POLYLINE:
tempSegs_da.cnt = segCnt;
- DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 );
+ wBool_t first_spot = FALSE;
+ if (segCnt == 1 && tempSegs(0).type == SEG_CRVLIN) {
+ coOrd start;
+ start = tempSegs(0).u.c.center;
+ tempSegs(0).type = SEG_STRLIN;
+ tempSegs(0).u.l.pos[0] = start;
+ first_spot=TRUE;
+ } else {
+ DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 );
+ }
segPtr = &tempSegs(tempSegs_da.cnt-1);
segPtr->type = SEG_STRLIN;
segPtr->color = context->Color;
segPtr->width = (context->Op==OP_POLY?width:0);
- if ( tempSegs_da.cnt == 1 ) {
- segPtr->u.l.pos[0] = pos;
- } else {
- segPtr->u.l.pos[0] = segPtr[-1].u.l.pos[1];
+ //End if over start
+ if ( segCnt>2 && IsClose(FindDistance(tempSegs(0).u.l.pos[0], pos ))) {
+ segPtr->u.l.pos[0] = tempSegs(segCnt-1).u.l.pos[1];
+ segPtr->u.l.pos[1] = tempSegs(0).u.l.pos[0];
+ EndPoly(context, tempSegs_da.cnt, context->Op==OP_POLYLINE);
+ DYNARR_RESET(pts_t, points_da);
+ DYNARR_RESET(trkSeg_t,tempSegs_da);
+ context->State = 0;
+ segCnt = 0;
+ return C_TERMINATE;
+ }
+ if (!first_spot) {
+ if ( tempSegs_da.cnt == 1) {
+ segPtr->u.l.pos[0] = pos;
+ } else {
+ segPtr->u.l.pos[0] = segPtr[-1].u.l.pos[1];
+ }
}
segPtr->u.l.pos[1] = pos;
context->State = 1;
- oldOptions = context->D->funcs->options;
- context->D->funcs->options |= wDrawOptTemp;
- DrawSegs( context->D, zero, 0.0, &tempSegs(tempSegs_da.cnt-1), 1, trackGauge, wDrawColorBlack );
- context->D->funcs->options = oldOptions;
+ segCnt = tempSegs_da.cnt;
+ context->message(_("+Shift - lock to close object, +Ctrl - lock to 90 deg"));
break;
}
return C_CONTINUE;
case wActionLDrag:
- oldOptions = context->D->funcs->options;
- context->D->funcs->options |= wDrawOptTemp;
- if (context->Op == OP_POLY || context->Op == OP_FILLPOLY)
- DrawSegs( context->D, zero, 0.0, &tempSegs(tempSegs_da.cnt-1), 1, trackGauge, wDrawColorBlack );
- else
- DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- if ( (MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL )
- OnTrack( &pos, FALSE, FALSE );
+ DYNARR_RESET(trkSeg_t, anchors_da );
+ if ((context->Op == OP_CURVE1 && context->State == 1) ||
+ (context->Op == OP_CURVE2 && context->State == 0) ||
+ (context->Op == OP_CURVE4 && context->State != 2) ||
+ (context->Op == OP_LINE) ||
+ (context->Op == OP_BENCH) ) {
+ if (( (MyGetKeyState() & WKEY_ALT)==0) == magneticSnap) {
+ if (OnTrack( &pos, FALSE, FALSE )!=NULL)
+ CreateEndAnchor(pos,TRUE);
+ }
+ } else if (context->Op == OP_DIMLINE) {
+ if (OnTrack( &pos, FALSE, FALSE )!=NULL) CreateEndAnchor(pos,TRUE);
+ }
+
pos1 = pos;
+
switch (context->Op) {
case OP_TBLEDGE:
OnTableEdgeEndPt( NULL, &pos1 );
+ /* no break */
case OP_LINE:
case OP_DIMLINE:
case OP_BENCH:
+ if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) {
+ //Snap to Right-Angle from previous or from 0
+ DIST_T l = FindDistance(pos0, pos);
+ ANGLE_T angle2 = NormalizeAngle(FindAngle(pos0, pos)-line_angle);
+ int quad = (int)((angle2 + 45.0) / 90.0);
+ if (tempSegs_da.cnt != 1 && (quad == 2)) {
+ pos1 = pos0;
+ } else if (quad == 1 || quad == 3) {
+ if (tempSegs_da.cnt != 1)
+ l = fabs(l*cos(D2R(((quad==1)?line_angle+90.0:line_angle-90.0)-FindAngle(pos,pos0))));
+ Translate( &pos1, pos0, NormalizeAngle(quad==1?line_angle+90.0:line_angle-90.0), l );
+ } else {
+ if (tempSegs_da.cnt != 1)
+ l = fabs(l*cos(D2R(((quad==0||quad==4)?line_angle:line_angle+180.0)-FindAngle(pos,pos0))));
+ Translate( &pos1, pos0, NormalizeAngle((quad==0||quad==4)?line_angle:line_angle+180.0), l );
+ }
+ CreateLineAnchor(pos1,pos0);
+ }
tempSegs(0).u.l.pos[1] = pos1;
context->message( _("Length = %s, Angle = %0.2f"),
FormatDistance(FindDistance( pos0, pos1 )),
PutAngle(FindAngle( pos0, pos1 )) );
tempSegs_da.cnt = 1;
+ if (anchors_da.cnt == 0) CreateEndAnchor(pos, FALSE);
break;
case OP_POLY:
case OP_FILLPOLY:
+ case OP_POLYLINE:
+ if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) {
+ coOrd last_point = zero;
+ ANGLE_T last_angle, initial_angle;
+ if (tempSegs_da.cnt == 1) {
+ last_angle = 90.0;
+ last_point = tempSegs(0).u.l.pos[0];
+ initial_angle = 90.0;
+ } else {
+ last_point = tempSegs(tempSegs_da.cnt-2).u.l.pos[1];
+ last_angle = FindAngle(tempSegs(tempSegs_da.cnt-2).u.l.pos[0],tempSegs(tempSegs_da.cnt-2).u.l.pos[1]);
+ initial_angle = FindAngle(tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1]);
+ }
+ //Snap to Right-Angle from previous or from 0
+ DIST_T l = FindDistance(tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos);
+ ANGLE_T angle2 = NormalizeAngle(FindAngle(tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos)-last_angle);
+ int quad = (int)((angle2+45.0)/90.0);
+ if (tempSegs_da.cnt != 1 && (quad == 2)) {
+ pos = tempSegs(tempSegs_da.cnt-1).u.l.pos[0];
+ } else if (quad == 1 || quad == 3) {
+ if (tempSegs_da.cnt != 1)
+ l = fabs(l*cos(D2R(((quad==1)?last_angle+90.0:last_angle-90.0)-FindAngle(pos,last_point))));
+ Translate( &pos, tempSegs(tempSegs_da.cnt-1).u.l.pos[0], NormalizeAngle(quad==1?last_angle+90.0:last_angle-90.0), l );
+ } else {
+ if (tempSegs_da.cnt != 1)
+ l = fabs(l*cos(D2R(((quad==0||quad==4)?last_angle:last_angle+180.0)-FindAngle(pos,last_point))));
+ Translate( &pos, tempSegs(tempSegs_da.cnt-1).u.l.pos[0], NormalizeAngle((quad==0||quad==4)?last_angle:last_angle+180.0), l );
+ }
+ CreateEndAnchor(pos,TRUE);
+ if (FindDistance(pos,last_point)>0.0) CreateLineAnchor(pos,last_point);
+ }
+ //If there is any point on this line that will give a 90 degree return to the first point, show it
+ if (tempSegs_da.cnt > 1) {
+ coOrd intersect;
+ ANGLE_T an_this = FindAngle(tempSegs(tempSegs_da.cnt-2).u.l.pos[1],pos);
+ if (FindIntersection(&intersect,tempSegs(0).u.l.pos[0],an_this+90.0,tempSegs(tempSegs_da.cnt-2).u.l.pos[1],an_this)) {
+ ANGLE_T an_inter = FindAngle(tempSegs(tempSegs_da.cnt-2).u.l.pos[1],intersect);
+ if (fabs(DifferenceBetweenAngles(an_inter,an_this))<90.0) {
+ CreateSquareAnchor(intersect);
+ d = FindDistance(intersect,pos);
+ if (IsClose(d)) {
+ pos = intersect;
+ }
+ }
+ }
+ }
tempSegs(tempSegs_da.cnt-1).type = SEG_STRLIN;
tempSegs(tempSegs_da.cnt-1).u.l.pos[1] = pos;
context->message( _("Length = %s, Angle = %0.2f"),
FormatDistance(FindDistance( tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos )),
PutAngle(FindAngle( tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos )) );
+ segCnt = tempSegs_da.cnt;
break;
case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4:
if (context->State == 0) {
- CreateCurve( C_MOVE, pos, FALSE, context->Color, width, drawGeomCurveMode, context->message );
pos0x = pos;
+ CreateCurve( C_MOVE, pos, FALSE, context->Color, width, drawGeomCurveMode, &anchors_da, context->message );
} else {
PlotCurve( drawGeomCurveMode, pos0, pos0x, pos1, &context->ArcData, FALSE );
tempSegs(0).color = context->Color;
tempSegs(0).width = width;
+ DYNARR_SET(trkSeg_t,tempSegs_da,1);
if (context->ArcData.type == curveTypeStraight) {
tempSegs(0).type = SEG_STRLIN;
tempSegs(0).u.l.pos[0] = pos0;
tempSegs(0).u.l.pos[1] = context->ArcData.pos1;
tempSegs_da.cnt = 1;
+ CreateEndAnchor(pos0, FALSE);
+ CreateEndAnchor(context->ArcData.pos1, FALSE);
context->message( _("Straight Line: Length=%s Angle=%0.3f"),
FormatDistance(FindDistance( pos0, context->ArcData.pos1 )),
PutAngle(FindAngle( pos0, context->ArcData.pos1 )) );
@@ -337,14 +630,21 @@ STATUS_T DrawGeomMouse(
ErrorMessage( MSG_CURVE_TOO_LARGE );
tempSegs_da.cnt = 0;
context->ArcData.type = curveTypeNone;
- context->D->funcs->options = oldOptions;
return C_CONTINUE;
}
context->message( _("Curved Line: Radius=%s Angle=%0.3f Length=%s"),
FormatDistance(context->ArcData.curveRadius), context->ArcData.a1,
FormatDistance(context->ArcData.curveRadius*d) );
+ if (context->Op == OP_CURVE1 || context->Op == OP_CURVE4 )
+ DrawArrowHeadsArray(&anchors_da,pos,FindAngle(context->ArcData.curvePos,pos),TRUE,wDrawColorRed);
+ else if (context->Op == OP_CURVE2 || context->Op == OP_CURVE3 ) {
+ CreateEndAnchor(context->ArcData.pos2,FALSE);
+ DrawArrowHeadsArray(&anchors_da,context->ArcData.pos2,FindAngle(context->ArcData.curvePos,context->ArcData.pos2)+90,TRUE,wDrawColorRed);
+ }
+ CreateEndAnchor(context->ArcData.curvePos,TRUE);
}
}
+ if (anchors_da.cnt == 0) CreateEndAnchor(pos, FALSE);
break;
case OP_CIRCLE1:
case OP_FILLCIRCLE1:
@@ -352,6 +652,7 @@ STATUS_T DrawGeomMouse(
case OP_CIRCLE2:
case OP_FILLCIRCLE2:
tempSegs(0).u.c.center = pos1;
+ /* no break */
case OP_CIRCLE3:
case OP_FILLCIRCLE3:
tempSegs(0).u.c.radius = FindDistance( pos0, pos1 );
@@ -369,58 +670,48 @@ STATUS_T DrawGeomMouse(
FormatDistance(fabs(pos1.x - pos0.x)), FormatDistance(fabs(pos1.y - pos0.y)) );
break;
}
- if (context->Op == OP_POLY || context->Op == OP_FILLPOLY)
- DrawSegs( context->D, zero, 0.0, &tempSegs(tempSegs_da.cnt-1), 1, trackGauge, wDrawColorBlack );
- else
- DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- context->D->funcs->options = oldOptions;
- if (context->Op == OP_DIMLINE) MainRedraw(); //Wipe Out Text
return C_CONTINUE;
case wActionLUp:
- oldOptions = context->D->funcs->options;
- context->D->funcs->options |= wDrawOptTemp;
- if (context->Op != OP_POLY && context->Op != OP_FILLPOLY)
- DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
lastValid = FALSE;
createTrack = FALSE;
- if ((context->State == 0 && (context->Op == OP_LINE )) || //first point release for line,
- (context->State == 1 && context->Op == OP_CURVE1)) { //second point for curve from end
- switch (context->Op) { //Snap pos to nearest line end point if this is on a line and just shift is depressed for lines and some curves
- case OP_CURVE1:
- case OP_LINE:
- if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_SHIFT ) {
- coOrd p = pos1;
- track_p t;
- if ((t=OnTrack(&p,FALSE,FALSE))) {
- if (GetClosestEndPt(t,&p)) {
- pos1 = p;
- if (context->Op == OP_LINE) {
- tempSegs(0).u.l.pos[1] = p;
- } else {
- PlotCurve( drawGeomCurveMode, pos0, pos0x, pos1, &context->ArcData, FALSE );
- if (context->ArcData.type == curveTypeStraight) {
- tempSegs(0).type = SEG_STRLIN;
- tempSegs(0).u.l.pos[0] = pos0;
- tempSegs(0).u.l.pos[1] = context->ArcData.pos1;
- tempSegs_da.cnt = 1;
- } else if (context->ArcData.type == curveTypeNone) {
- tempSegs_da.cnt = 0;
- } else if (context->ArcData.type == curveTypeCurve) {
- tempSegs(0).type = SEG_CRVLIN;
- tempSegs(0).u.c.center = context->ArcData.curvePos;
- tempSegs(0).u.c.radius = context->ArcData.curveRadius;
- tempSegs(0).u.c.a0 = context->ArcData.a0;
- tempSegs(0).u.c.a1 = context->ArcData.a1;
- tempSegs_da.cnt = 1;
- }
- }
- }
+ if ((context->Op == OP_CURVE1 && context->State == 1) ||
+ (context->Op == OP_CURVE2 && context->State == 0) ||
+ (context->Op == OP_CURVE3 && context->State != 0) ||
+ (context->Op == OP_CURVE4 && context->State != 2) ||
+ (context->Op == OP_LINE) || (context->Op == OP_DIMLINE) ||
+ (context->Op == OP_BENCH) ) {
+ if (((MyGetKeyState() & WKEY_ALT)==0) == magneticSnap ) {
+ coOrd p = pos1;
+ track_p t;
+ if ((t=OnTrack(&p,FALSE,FALSE))) {
+ pos1 = p;
+ if (context->Op == OP_LINE || context->Op == OP_DIMLINE || context->Op == OP_BENCH) {
+ tempSegs(0).u.l.pos[1] = p;
+ } else {
+ PlotCurve( drawGeomCurveMode, pos0, pos0x, pos1, &context->ArcData, FALSE );
+ if (context->ArcData.type == curveTypeStraight) {
+ DYNARR_RESET(trkSeg_t,tempSegs_da);
+ DYNARR_APPEND(trkSeg_t,tempSegs_da,1);
+ tempSegs(0).type = SEG_STRLIN;
+ tempSegs(0).u.l.pos[0] = pos0;
+ tempSegs(0).u.l.pos[1] = context->ArcData.pos1;
+ tempSegs_da.cnt = 1;
+ } else if (context->ArcData.type == curveTypeNone) {
+ DYNARR_RESET(trkSeg_t,tempSegs_da);
+ } else if (context->ArcData.type == curveTypeCurve) {
+ DYNARR_RESET(trkSeg_t,tempSegs_da);
+ DYNARR_APPEND(trkSeg_t,tempSegs_da,1);
+ tempSegs(0).type = SEG_CRVLIN;
+ tempSegs(0).u.c.center = context->ArcData.curvePos;
+ tempSegs(0).u.c.radius = context->ArcData.curveRadius;
+ tempSegs(0).u.c.a0 = context->ArcData.a0;
+ tempSegs(0).u.c.a1 = context->ArcData.a1;
+ tempSegs_da.cnt = 1;
}
- };
- break;
- default:
- ;
+ }
+
+ }
}
}
switch ( context->Op ) {
@@ -430,22 +721,22 @@ STATUS_T DrawGeomMouse(
case OP_TBLEDGE:
lastValid = TRUE;
lastPos = pos1;
+ context->length = FindDistance(pos1,pos0);
+ context->angle = FindAngle(pos0,pos1);
+ context->State = 2;
+ segCnt = tempSegs_da.cnt;
break;
case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4:
if (context->State == 0) {
context->State = 1;
context->ArcAngle = FindAngle( pos0, pos1 );
pos0x = pos1;
- CreateCurve( C_UP, pos, FALSE, context->Color, width, drawGeomCurveMode, context->message );
- DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- segCnt = tempSegs_da.cnt;
+ CreateCurve( C_UP, pos, FALSE, context->Color, width, drawGeomCurveMode, &anchors_da, context->message );
context->message( _("Drag on Red arrows to adjust curve") );
- context->D->funcs->options = oldOptions;
return C_CONTINUE;
} else {
- tempSegs_da.cnt = 0;
+ DYNARR_SET(trkSeg_t,tempSegs_da,1);
if (context->ArcData.type == curveTypeCurve) {
- tempSegs_da.cnt = 1;
segPtr = &tempSegs(0);
segPtr->type = SEG_CRVLIN;
segPtr->color = context->Color;
@@ -454,20 +745,22 @@ STATUS_T DrawGeomMouse(
segPtr->u.c.radius = context->ArcData.curveRadius;
segPtr->u.c.a0 = context->ArcData.a0;
segPtr->u.c.a1 = context->ArcData.a1;
+ context->radius = context->ArcData.curveRadius;
+ context->angle = context->ArcData.a1;
} else if (context->ArcData.type == curveTypeStraight) {
- tempSegs_da.cnt = 1;
segPtr = &tempSegs(0);
segPtr->type = SEG_STRLIN;
segPtr->color = context->Color;
segPtr->width = width;
segPtr->u.l.pos[0] = pos0;
segPtr->u.l.pos[1] = pos1;
- } else {
- tempSegs_da.cnt = 0;
+ context->radius = 0;
+ context->length = FindDistance(pos0,pos1);
+ context->angle = FindAngle(pos0,pos1);
}
- context->State = 0;
lastValid = TRUE;
lastPos = pos1;
+ context->State = 2;
/*drawContext = context;
DrawGeomOp( (void*)context->Op );*/
}
@@ -480,14 +773,17 @@ STATUS_T DrawGeomMouse(
case OP_FILLCIRCLE3:
if ( context->Op>=OP_FILLCIRCLE1 && context->Op<=OP_FILLCIRCLE3 )
tempSegs(0).type = SEG_FILCRCL;
- /*drawContext = context;
- DrawGeomOp( (void*)context->Op );*/
+ tempSegs_da.cnt = 1;
+ context->State = 2;
+ context->radius = tempSegs(0).u.c.radius;
break;
case OP_BOX:
case OP_FILLBOX:
- pts = (coOrd*)MyMalloc( 4 * sizeof (coOrd) );
- for ( inx=0; inx<4; inx++ )
- pts[inx] = tempSegs(inx).u.l.pos[0];
+ pts = (pts_t*)MyMalloc( 4 * sizeof (pts_t) );
+ for ( inx=0; inx<4; inx++ ) {
+ pts[inx].pt = tempSegs(inx).u.l.pos[0];
+ pts[inx].pt_type = wPolyLineStraight;
+ }
tempSegs(0).type = (context->Op == OP_FILLBOX)?SEG_FILPOLY:SEG_POLY;
tempSegs(0).u.p.cnt = 4;
tempSegs(0).u.p.pts = pts;
@@ -497,188 +793,1259 @@ STATUS_T DrawGeomMouse(
tempSegs_da.cnt = 1;
/*drawContext = context;
DrawGeomOp( (void*)context->Op );*/
+ context->length = FindDistance(pts[0].pt,pts[1].pt);
+ context->width = FindDistance(pts[3].pt,pts[0].pt);
+ context->State = 2;
+ segCnt = tempSegs_da.cnt;
break;
case OP_POLY:
case OP_FILLPOLY:
+ case OP_POLYLINE:
+ tempSegs_da.cnt = segCnt;
+ anchors_da.cnt=0;
+ //End if close to start
+ if ( segCnt>2 && IsClose(FindDistance(tempSegs(0).u.l.pos[0], pos))) {
+ EndPoly(context, tempSegs_da.cnt, context->Op==OP_POLYLINE);
+ DYNARR_RESET(pts_t, points_da);
+ CleanSegs(&tempSegs_da);
+ context->State = 0;
+ segCnt = 0;
+ return C_TERMINATE;
+ }
+ //If too short, remove last segment
+ if (IsClose(FindDistance(tempSegs(segCnt-1).u.l.pos[0],pos))) {
+ if (tempSegs_da.cnt>1) {
+ --tempSegs_da.cnt;
+ segCnt = tempSegs_da.cnt;
+ wBeep();
+ } else { //First spot only
+ tempSegs(0).color = wDrawColorRed;
+ tempSegs(0).type = SEG_CRVLIN;
+ tempSegs(0).u.c.a1 = 360;
+ tempSegs(0).u.c.radius = tempD.scale*0.15/2;
+ tempSegs(0).u.c.center = pos;
+ segCnt = tempSegs_da.cnt;
+ }
+ return C_CONTINUE;
+ }
+ int text_inx = tempSegs_da.cnt-1;
+ //tempSegs(tempSegs_da.cnt-1).u.l.pos[1] = pos;
+ context->length = FindDistance(tempSegs(text_inx).u.l.pos[0],tempSegs(text_inx).u.l.pos[1]);
+ if (text_inx>1) {
+ ANGLE_T an = FindAngle(tempSegs(text_inx-1).u.l.pos[0],tempSegs(text_inx-1).u.l.pos[1]);
+ context->angle = NormalizeAngle(FindAngle(tempSegs(text_inx).u.l.pos[0],tempSegs(text_inx).u.l.pos[1])-an);
+ } else
+ context->angle = FindAngle(tempSegs(1).u.l.pos[0],tempSegs(1).u.l.pos[1]);
+ context->State = 1;
+ context->index = text_inx;
segCnt = tempSegs_da.cnt;
- context->D->funcs->options = oldOptions;
return C_CONTINUE;
}
context->Started = FALSE;
- context->Changed = TRUE;
+ context->Changed = TRUE; //Update screen shown
/*CheckOk();*/
- context->D->funcs->options = oldOptions;
+ if (context->State == 2 && IsCurCommandSticky()) {
+ segCnt = tempSegs_da.cnt;
+ return C_CONTINUE;
+ }
DrawGeomOk();
+ context->State = 0;
+ context->Changed = FALSE;
+ context->message("");
return C_TERMINATE;
case wActionText:
-
+ DYNARR_RESET(trkSeg_t, anchors_da );
if ( ((action>>8)&0xFF) == 0x0D ||
((action>>8)&0xFF) == ' ' ) {
- EndPoly(context, segCnt);
- context->State = 0;
+ if ((context->Op == OP_POLY) || (context->Op == OP_FILLPOLY) || (context->Op == OP_POLYLINE)) {
+ tempSegs_da.cnt = segCnt;
+ //If last segment wasn't just a point, add another starting on its end
+ if (!IsClose(FindDistance(tempSegs(segCnt-1).u.l.pos[0],tempSegs(segCnt-1).u.l.pos[1]))) {
+ DYNARR_APPEND(trkSeg_t,tempSegs_da,1);
+ segPtr = &tempSegs(tempSegs_da.cnt-1);
+ segPtr->type = SEG_STRLIN;
+ segPtr->u.l.pos[0] = segPtr[-1].u.l.pos[1];
+ segPtr->u.l.pos[1] = tempSegs(0).u.l.pos[0];
+ }
+ EndPoly(context, tempSegs_da.cnt, context->Op == OP_POLYLINE);
+ DYNARR_RESET(pts_t, points_da);
+ DYNARR_RESET(trkSeg_t,tempSegs_da);
+ } else {
+ if (context->State == 2)
+ tempSegs_da.cnt = segCnt;
+ DrawGeomOk();
+ }
}
+ context->State = 0;
+ segCnt = 0;
return C_TERMINATE;
case C_CANCEL:
-
- oldOptions = context->D->funcs->options;
- context->D->funcs->options |= wDrawOptTemp;
- DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- context->D->funcs->options = oldOptions;
+ if (context->Changed) { //If the update values were shown
+ if (context->State == 2) {
+ tempSegs_da.cnt = segCnt;
+ DrawGeomOk();
+ }
+ }
+ DYNARR_RESET(trkSeg_t, anchors_da );
tempSegs_da.cnt = 0;
context->message( "" );
context->Changed = FALSE;
+ context->State = 0;
+ segCnt = 0;
lastValid = FALSE;
return C_TERMINATE;
case C_REDRAW:
- oldOptions = context->D->funcs->options;
- context->D->funcs->options |= wDrawOptTemp;
- DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
- context->D->funcs->options = oldOptions;
+ DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
+ if (anchors_da.cnt > 0) {
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, 0.0, wDrawColorBlack );
+ }
return C_CONTINUE;
+ case C_CMDMENU:
+
+ return C_CONTINUE;
+
default:
return C_CONTINUE;
}
}
+static int polyInx;
+static int lineInx;
+static int curveInx;
+
+typedef enum {POLY_NONE, POLY_SELECTED, POLYPOINT_SELECTED} PolyState_e;
+static PolyState_e polyState = POLY_NONE;
+static coOrd rotate_origin;
+static ANGLE_T rotate_angle;
+static dynArr_t origin_da;
+
+
+void static CreateCircleAnchor(wBool_t selected,coOrd center, DIST_T rad, ANGLE_T angle) {
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ double d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,anchors_da,2);
+ anchors(0).type = (selected)?SEG_FILCRCL:SEG_CRVLIN;
+ anchors(0).u.c.a1 = 360.0;
+ anchors(0).color = wDrawColorBlue;
+ anchors(0).u.c.radius = d/2;
+ PointOnCircle(&anchors(0).u.c.center,center,rad,angle);
+}
+void static CreateLineAnchors(int index, coOrd p0, coOrd p1) {
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ double d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,anchors_da,2);
+ anchors(0).type = (index ==0)?SEG_FILCRCL:SEG_CRVLIN;
+ anchors(0).u.c.a1 = 360.0;
+ anchors(0).color = wDrawColorBlue;
+ anchors(0).u.c.radius = d/2;
+ anchors(0).u.c.center = p0;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ anchors(1).type = (index ==1)?SEG_FILCRCL:SEG_CRVLIN;
+ anchors(1).u.c.a1 = 360.0;
+ anchors(1).color = wDrawColorBlue;
+ anchors(1).u.c.radius = d/2;
+ anchors(1).u.c.center = p1;
+}
+void static CreateBoxAnchors(int index, pts_t pt[4]) {
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ double d = tempD.scale*0.15;
+ ANGLE_T a = FindAngle(pt[0].pt,pt[1].pt);
+ ANGLE_T diag = FindAngle(pt[0].pt,pt[2].pt);
+ for (int i=0;i<4;i++) {
+ DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5);
+ DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pt[i].pt,(diag>a?45.0:-45.0)+a+(90.0*(i)),TRUE,i==index?wDrawColorRed:wDrawColorBlue);
+ }
+ coOrd pp;
+ for (int i=0;i<4;i++) {
+ pp.x = (i==3?((((pt[0].pt.x - pt[i].pt.x)/2))+pt[i].pt.x):((pt[i+1].pt.x - pt[i].pt.x)/2)+pt[i].pt.x);
+ pp.y = (i==3?((((pt[0].pt.y - pt[i].pt.y)/2))+pt[i].pt.y):((pt[i+1].pt.y - pt[i].pt.y)/2)+pt[i].pt.y);
+ DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5);
+ DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pp,90.0*(i-1)+a,TRUE,i==index+5?wDrawColorRed:wDrawColorBlue);
+ }
+}
+
+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;
+}
+
+void static CreateCurveAnchors(int index, coOrd pm, coOrd pc, coOrd p0, coOrd p1) {
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ double d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,anchors_da,9);
+ anchors(0).type = (index ==0)?SEG_FILCRCL:SEG_CRVLIN;
+ anchors(0).u.c.a1 = 360.0;
+ anchors(0).color = wDrawColorBlue;
+ anchors(0).u.c.radius = d/2;
+ anchors(0).u.c.center = p0;
+ anchors(0).width = 0;
+ DYNARR_APPEND(trkSeg_t,anchors_da,8);
+ anchors(1).type = (index ==1)?SEG_FILCRCL:SEG_CRVLIN;
+ anchors(1).u.c.a1 = 360.0;
+ anchors(1).color = wDrawColorBlue;
+ anchors(1).u.c.radius = d/2;
+ anchors(1).u.c.center = p1;
+ anchors(1).width = 0;
+ DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5);
+ DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pm,FindAngle(pm,pc),TRUE,index==2?wDrawColorAqua:wDrawColorBlue);
+}
+
+void static CreatePolyAnchors(int index) {
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ double d = tempD.scale*0.15;
+ for ( int inx=0; inx<points_da.cnt; inx++ ) {
+ DYNARR_APPEND(trkSeg_t,anchors_da,3);
+
+ anchors(inx).type = point_selected(inx)?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/2;
+ anchors(inx).u.c.center = points(inx).pt;
+ }
+ if (index>=0) {
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int inx = anchors_da.cnt-1;
+ anchors(inx).type = SEG_STRLIN;
+ anchors(inx).u.l.pos[0] = points(index==0?points_da.cnt-1:index-1).pt;
+ anchors(inx).u.l.pos[1] = points(index).pt;
+ anchors(inx).color = wDrawColorBlue;
+ anchors(inx).width = 0;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ inx = anchors_da.cnt-1;
+ int index0 = index==0?points_da.cnt-1:index-1;
+ ANGLE_T an0 = FindAngle(points(index0).pt, points(index).pt);
+ ANGLE_T an1 = FindAngle(points(index0==0?points_da.cnt-1:index0-1).pt, points(index0).pt);
+ anchors(inx).type = SEG_CRVLIN;
+ if (DifferenceBetweenAngles(an0,an1)<=0) {
+ anchors(inx).u.c.a1 = DifferenceBetweenAngles(an0,an1)-180;
+ anchors(inx).u.c.a0 = an0;
+ } else {
+ anchors(inx).u.c.a1 = 180-DifferenceBetweenAngles(an0,an1);
+ anchors(inx).u.c.a0 = NormalizeAngle(180+an1);
+ }
+ anchors(inx).color = wDrawColorBlue;
+ anchors(inx).u.c.radius = d;
+ anchors(inx).u.c.center = points(index0).pt;
+ }
+}
+
+void CreateMovingAnchor(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;
+}
+
+/*
+ * Modify Polygons. Polygons have a variable number of nodes.
+ *
+ * Each point has an anchor and selecting the node allows it to be moved
+ * Selecting a point between nodes adds a node ready for dragging
+ * The last selected node can be deleted
+ *
+ */
+STATUS_T DrawGeomPolyModify(
+ wAction_t action,
+ coOrd pos,
+ drawModContext_t *context) {
+ double d;
+ static int selected_count;
+ static int segInx;
+ static int prev_inx;
+ static wDrawColor save_color;
+ static wBool_t drawnAngle;
+ static double currentAngle;
+ static double baseAngle;
+ static BOOL_T lock;
+
+ switch ( action&0xFF ) {
+ case C_START:
+ lock = FALSE;
+ DistanceSegs( context->orig, context->angle, context->segCnt, context->segPtr, &pos, &segInx );
+ if (segInx == -1)
+ return C_ERROR;
+ if (context->type != SEG_POLY && context->type != SEG_FILPOLY)
+ return C_ERROR;
+ prev_inx = -1;
+ polyState = POLY_SELECTED;
+ polyInx = -1;
+ //Copy points
+ DYNARR_RESET( pts_t, points_da);
+ DYNARR_RESET( wBool_t, select_da);
+ for (int inx=0;inx<context->segPtr->u.p.cnt;inx++) {
+ DYNARR_APPEND(pts_t, points_da,3);
+ DYNARR_APPEND(wBool_t,select_da,3);
+ REORIGIN( points(inx).pt, context->segPtr[segInx].u.p.pts[inx].pt, context->angle, context->orig );
+ points(inx).pt_type = context->segPtr[segInx].u.p.pts[inx].pt_type;
+ point_selected(inx) = FALSE;
+ }
+ context->prev_inx = -1;
+ context->max_inx = points_da.cnt-1;
+ selected_count=0;
+ rotate_origin = context->orig;
+ rotate_angle = context->angle;
+ context->p0 = points(0).pt;
+ context->p1 = points(1).pt;
+ //Show points
+ tempSegs_da.cnt = 1;
+ tempSegs(0).width = context->segPtr->width;
+ save_color = context->segPtr->color;
+ tempSegs(0).color = wDrawColorRed;
+ tempSegs(0).type = context->type;
+ tempSegs(0).u.p.cnt = context->segPtr[segInx].u.p.cnt;
+ tempSegs(0).u.p.angle = 0.0;
+ tempSegs(0).u.p.orig = zero;
+ tempSegs(0).u.p.polyType = context->segPtr[segInx].u.p.polyType;
+ tempSegs(0).u.p.pts = &points(0);
+ CreatePolyAnchors( -1);
+ InfoMessage(_("Select points or use context menu"));
+ ClrAllTrkBitsRedraw( TB_UNDRAWN, TRUE );
+ UndrawNewTrack( context->trk );
+ return C_CONTINUE;
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ CreatePolyAnchors(context->prev_inx);
+ for (int i = 0; i<points_da.cnt; i++) {
+ if (IsClose(FindDistance(pos,points(i).pt))) {
+ CreateMovingAnchor(points(i).pt,TRUE);
+ return C_CONTINUE;
+ }
+ }
+ int pInx=0;
+ coOrd pm0,pm1;
+ DIST_T dm = 10000.0;
+ for ( int inx=0; inx<points_da.cnt; inx++ ) {
+ pm0 = pos;
+ DIST_T ddm = LineDistance( &pm0, points( inx==0?points_da.cnt-1:inx-1).pt, points(inx).pt );
+ if ( dm > ddm ) {
+ dm = ddm;
+ pm1 = pm0;
+ pInx = inx;
+ }
+ }
+ if (!IsClose(dm)) return C_CONTINUE;
+ int inxm = pInx==0?points_da.cnt-1:pInx-1;
+ dm = FindDistance( points(inxm).pt, pm1 );
+ DIST_T ddm = FindDistance( points(inxm).pt, points(pInx).pt );
+ if ( (dm > 0.25*ddm) && (dm < 0.75*ddm)) {
+ CreateMovingAnchor(pm1,FALSE);
+ } else {
+ if (dm < FindDistance( points(pInx).pt, pm1 ))
+ CreateMovingAnchor(points(inxm).pt,TRUE);
+ else
+ CreateMovingAnchor(points(pInx).pt,TRUE);
+ }
+ return C_CONTINUE;
+ break;
+ case C_DOWN:
+ d = 10000.0;
+ polyInx = -1;
+ coOrd p0;
+ double dd;
+ int inx;
+ if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) != WKEY_SHIFT) {
+ if (selected_count <2 ) {
+ //Wipe out selection(s) if we don't have multiple already (i,e. move with >1 selected)
+ for (int i=0;i<points_da.cnt;i++) {
+ point_selected(i) = FALSE;
+ }
+ selected_count = 0;
+ } else {
+ for (int i=0;i<points_da.cnt;i++) {
+ if (IsClose(FindDistance(pos,points(i).pt)) && point_selected(i)==TRUE) {
+ point_selected(i) = FALSE;
+ selected_count--;
+ }
+ }
+ }
+ }
+ //Select Point (polyInx)
+ for ( int inx=0; inx<points_da.cnt; inx++ ) {
+ p0 = pos;
+ dd = LineDistance( &p0, points( inx==0?points_da.cnt-1:inx-1).pt, points(inx).pt );
+ if ( d > dd ) {
+ d = dd;
+ polyInx = inx;
+ }
+ }
+ if (!IsClose(d)) { //Not on/near object - de-select all points
+ for (int i=0;i<points_da.cnt;i++) {
+ point_selected(i) = FALSE;
+ }
+ polyInx = -1;
+ selected_count = 0;
+ CreatePolyAnchors( -1);
+ context->prev_inx = -1;
+ return C_CONTINUE; //Not close to any line
+ }
+ polyState = POLYPOINT_SELECTED;
+ inx = polyInx==0?points_da.cnt-1:polyInx-1;
+ //Find if the point is to be added
+ d = FindDistance( points(inx).pt, pos );
+ dd = FindDistance( points(inx).pt, points(polyInx).pt );
+ if ( d < 0.25*dd ) {
+ polyInx = inx;
+ } else if ( d > 0.75*dd ) {
+ ;
+ } else {
+ if (selected_count == 0) { //Only add a new point if no points are already selected!
+ DYNARR_APPEND(wBool_t,select_da,1);
+ for (int i=0;i<select_da.cnt;i++) {
+ if (i == polyInx) point_selected(i) = TRUE;
+ else point_selected(i) = FALSE;
+ }
+ selected_count=1;
+ DYNARR_APPEND(pts_t,points_da,1);
+ tempSegs(0).u.p.pts = &points(0);
+ for (inx=points_da.cnt-1; inx>polyInx; inx-- ) {
+ points(inx) = points(inx-1);
+ }
+ points(polyInx).pt_type = wPolyLineStraight;
+ tempSegs(0).u.p.cnt = points_da.cnt;
+ context->max_inx = points_da.cnt-1;
+ }
+ }
+ //If already selected (multiple points), not using shift (to add) select, and on object move to first point
+ if (selected_count>0 && ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) != WKEY_SHIFT)) {
+ for (int i=0; i<points_da.cnt;i++) {
+ if (IsClose(FindDistance(pos,points(i).pt))) {
+
+ point_selected(i) = FALSE;
+
+ }
+ if (point_selected(i) == TRUE) {
+ polyInx = i;
+ }
+ }
+ }
+ pos = points(polyInx).pt; //Move to point
+ if (point_selected(polyInx)) { //Already selected
+ } else {
+ point_selected(polyInx) = TRUE;
+ ++selected_count;
+ }
+ //Work out before and after point
+ int first_inx = -1;
+ if (selected_count >0 && selected_count < points_da.cnt-2) {
+ for (int i=0; i<points_da.cnt;i++) {
+ if (point_selected(i)) {
+ first_inx = i;
+ break;
+ }
+ }
+ }
+ int last_inx = -1, next_inx = -1;
+ ANGLE_T an1, an0;
+ if (first_inx >=0) {
+ if (first_inx == 0) {
+ last_inx = points_da.cnt-1;
+ } else {
+ last_inx = first_inx-1;
+ }
+ if (first_inx == points_da.cnt-1) {
+ next_inx = 0;
+ } else {
+ next_inx = first_inx+1;
+ }
+ context->length = FindDistance(points(last_inx).pt,points(first_inx).pt);
+ an1 = FindAngle(points(last_inx).pt,points(first_inx).pt);
+ an0 = FindAngle(points(last_inx==0?(points_da.cnt-1):(last_inx-1)).pt,points(last_inx).pt);
+ if (DifferenceBetweenAngles(an0,an1)<=0) {
+ context->rel_angle = 180+DifferenceBetweenAngles(an0,an1);
+ } else {
+ context->rel_angle = 180-DifferenceBetweenAngles(an0,an1);
+ }
+ } else {
+
+ }
+ context->prev_inx = first_inx;
+ context->p0 = points(0).pt;
+ context->p1 = points(1).pt;
+ //Show three anchors only
+ CreatePolyAnchors(first_inx);
+ return C_CONTINUE;
+ case C_LDOUBLE:
+ return C_CONTINUE;
+ case C_MOVE:
+ tempSegs_da.cnt = 1;
+ if (polyState != POLYPOINT_SELECTED) {
+ return C_CONTINUE;
+ }
+ //Moving with Point Selected
+ if (polyInx<0) return C_ERROR;
+ first_inx = -1;
+ if (selected_count >0 && selected_count < points_da.cnt-2) {
+ for (int i=0; i<points_da.cnt;i++) {
+ if (point_selected(i)) {
+ first_inx = i;
+ break;
+ }
+ }
+ }
+ last_inx = -1;
+ next_inx = -1;
+ coOrd intersect;
+ wBool_t show_intersect = FALSE;
+ if (first_inx >=0) {
+ if (first_inx == 0) {
+ last_inx = points_da.cnt-1;
+ } else {
+ last_inx = first_inx-1;
+ }
+ if (first_inx == points_da.cnt-1) {
+ next_inx = 0;
+ } else {
+ next_inx = first_inx+1;
+ }
+ //Lock to 90 degrees first/last point
+ if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_SHIFT ) {
+ ANGLE_T last_angle,next_angle;
+ coOrd last_point,next_point;
+ if (first_inx == 0) {
+ last_point = points(points_da.cnt-1).pt;
+ last_angle = FindAngle(points(points_da.cnt-2).pt,last_point);
+ } else if (first_inx == 1) {
+ last_point = points(0).pt;
+ last_angle = FindAngle(points(points_da.cnt-1).pt,last_point);
+ } else {
+ last_point = points(first_inx-1).pt;
+ last_angle = FindAngle(points(first_inx-2).pt,last_point);
+ }
+ if (first_inx == points_da.cnt-1) {
+ next_point = points(0).pt;
+ next_angle = FindAngle(next_point,points(1).pt);
+ } else if (first_inx == points_da.cnt-2){
+ next_point = points(points_da.cnt-1).pt;
+ next_angle = FindAngle(next_point,points(0).pt);
+ } else {
+ next_point = points(first_inx+1).pt;
+ next_angle = FindAngle(next_point,points(first_inx+2).pt);
+ }
+ coOrd diff;
+ diff.x = pos.x - points(polyInx).pt.x;
+ diff.y = pos.y - points(polyInx).pt.y;
+ coOrd pos_lock = points(first_inx).pt;
+ pos_lock.x += diff.x;
+ pos_lock.y += diff.y;
+ //Snap to Right-Angle from previous or from 0
+ DIST_T l = FindDistance(last_point, pos_lock);
+ ANGLE_T angle2 = NormalizeAngle(FindAngle(last_point, pos_lock)-last_angle);
+ int quad = (int)((angle2+45.0)/90.0);
+ if (tempSegs_da.cnt != 1 && (quad == 2)) {
+ pos_lock = last_point;
+ } else if (quad == 1 || quad == 3) {
+ l = fabs(l*cos(D2R(((quad==1)?last_angle+90.0:last_angle-90.0)-FindAngle(pos_lock,last_point))));
+ Translate( &pos_lock, last_point, NormalizeAngle((quad==1)?last_angle+90.0:last_angle-90.0), l );
+ } else {
+ l = fabs(l*cos(D2R(((quad==0||quad==4)?last_angle:last_angle+180.0)-FindAngle(pos_lock,last_point))));
+ Translate( &pos_lock, last_point, NormalizeAngle((quad==0||quad==4)?last_angle:last_angle+180.0), l );
+ }
+ diff.x = pos_lock.x - points(first_inx).pt.x;
+ diff.y = pos_lock.y - points(first_inx).pt.y;
+ pos.x = points(polyInx).pt.x+diff.x;
+ pos.y = points(polyInx).pt.y+diff.y;
+ if (selected_count<2) {
+ if (FindIntersection(&intersect,last_point,last_angle+90.0,next_point,last_angle+180.0)) {
+ show_intersect = TRUE;
+ }
+ }
+ d = FindDistance(intersect,pos_lock);
+ if (IsClose(d)) {
+ pos = intersect;
+ }
+ InfoMessage( _("Length = %s, Last angle = %0.2f"),
+ FormatDistance(FindDistance(pos_lock,last_point)),
+ PutAngle(FindAngle(pos_lock,last_point)));
+
+ }
+ }
+ context->prev_inx = first_inx;
+ coOrd diff;
+ diff.x = pos.x - points(polyInx).pt.x;
+ diff.y = pos.y - points(polyInx).pt.y;
+ //points(polyInx) = pos;
+ for (int i=0;i<points_da.cnt;i++) {
+ if (point_selected(i)) {
+ points(i).pt.x = points(i).pt.x + diff.x;
+ points(i).pt.y = points(i).pt.y + diff.y;
+ }
+ }
+ if (first_inx>=0) {
+ context->length = FindDistance(points(first_inx).pt,points(last_inx).pt);
+ an1 = FindAngle(points(last_inx).pt,points(first_inx).pt);
+ an0 = FindAngle(points(first_inx==0?(points_da.cnt-1):(first_inx-1)).pt,points(first_inx).pt);
+ context->rel_angle = NormalizeAngle(180-(an1-an0));
+ }
+ CreatePolyAnchors(first_inx);
+ if (show_intersect)
+ CreateSquareAnchor(intersect);
+ context->p0 = points(0).pt;
+ context->p1 = points(1).pt;
+ return C_CONTINUE;
+ case C_UP:
+ context->prev_inx = -1;
+ if (segInx == -1 || polyState != POLYPOINT_SELECTED)
+ return C_CONTINUE; //Didn't get a point selected/added
+ polyState = POLY_SELECTED; //Return to base state
+ anchors_da.cnt = 0;
+ CreatePolyAnchors(polyInx); //Show last selection
+ prev_inx = polyInx;
+ for (int i=0;i<points_da.cnt;i++) {
+ if (point_selected(i)) {
+ first_inx = i;
+ break;
+ }
+ }
+ last_inx = first_inx==0?(points_da.cnt-1):(first_inx-1);
+ if (first_inx>=0) {
+ context->length = FindDistance(points(first_inx).pt,points(last_inx).pt);
+ an1 = FindAngle(points(last_inx).pt,points(first_inx).pt);
+ an0 = FindAngle(points(last_inx==0?(points_da.cnt-1):(last_inx-1)).pt,points(last_inx).pt);
+ if (DifferenceBetweenAngles(an0,an1)<=0) {
+ context->rel_angle = 180+DifferenceBetweenAngles(an0,an1);
+ } else {
+ context->rel_angle = 180-DifferenceBetweenAngles(an0,an1);
+ }
+ }
+ context->prev_inx = first_inx;
+ context->p0 = points(0).pt;
+ context->p1 = points(1).pt;
+ polyInx = -1;
+ return C_CONTINUE;
+ case C_UPDATE:
+ if (context->prev_inx>=0) {
+ int last_index = context->prev_inx==0?(points_da.cnt-1):(context->prev_inx-1);
+ an0 = FindAngle(points(last_index==0?(points_da.cnt-1):(last_index-1)).pt,points(last_index).pt);
+ an1 = FindAngle(points(last_index).pt,points(context->prev_inx).pt);
+ if (DifferenceBetweenAngles(an0,an1)<=0) {
+ an1 = NormalizeAngle(an0-(180-context->rel_angle));
+ } else {
+ an1 = NormalizeAngle((180-context->rel_angle)+an0);
+ }
+ Translate(&points(prev_inx).pt,points(last_index).pt,an1,context->length);
+ }
+ context->rel_angle = fabs(context->rel_angle);
+ if (context->rel_angle >180) context->rel_angle = context->rel_angle - 180.0;
+ CreatePolyAnchors(prev_inx);
+ context->p0 = points(0).pt;
+ context->p1 = points(1).pt;
+ break;
+ case C_TEXT:
+ if (action>>8 == 'o') { //"o" -> origin mode
+ MenuMode(1);
+ InfoMessage("Move Origin Mode: Place Origin, p for Points, Enter or Esc");
+ return C_CONTINUE;
+ }
+ if (((prev_inx>=0 && tempSegs(0).u.p.polyType != POLYLINE) || (prev_inx>=1 && prev_inx<=points_da.cnt-2)) &&
+ ((action>>8 == 's') || (action>>8 == 'v') || (action>>8 == 'r'))) {
+ switch(action>>8) {
+ case 's':
+ points(context->prev_inx).pt_type = wPolyLineSmooth;
+ break;
+ case 'v':
+ points(context->prev_inx).pt_type = wPolyLineStraight;
+ break;
+ case 'r':
+ points(context->prev_inx).pt_type = wPolyLineRound;
+ break;
+ default:
+ return C_CONTINUE;
+ }
+ }
+ if ((action>>8 == 'g') && (tempSegs(0).type == SEG_POLY) && (tempSegs(0).u.p.polyType == POLYLINE) ) {
+ tempSegs(0).u.p.polyType = FREEFORM;
+ context->subtype=FREEFORM;
+ context->open = FALSE;
+ CreatePolyAnchors( -1);
+ return C_CONTINUE;
+ }
+ if ((action>>8 == 'l') && (tempSegs(0).type == SEG_POLY) && (tempSegs(0).u.p.polyType == FREEFORM)) {
+ tempSegs(0).u.p.polyType = POLYLINE;
+ context->subtype=POLYLINE;
+ context->open = TRUE;
+ CreatePolyAnchors( -1);
+ return C_CONTINUE;
+ }
+ if ((action>>8 == 'f') && (tempSegs(0).type == SEG_POLY) && (tempSegs(0).u.p.polyType != POLYLINE )) {
+ tempSegs(0).type = SEG_FILPOLY;
+ context->type = SEG_FILPOLY;
+ context->filled = TRUE;
+ CreatePolyAnchors( -1);
+ return C_CONTINUE;
+ }
+ if ((action>>8 == 'u') && (tempSegs(0).type == SEG_FILPOLY) ) {
+ tempSegs(0).type = SEG_POLY;
+ context->type = SEG_POLY;
+ context->filled = FALSE;
+ CreatePolyAnchors( -1);
+ return C_CONTINUE;
+ }
+ //Delete or backspace deletes last selected index
+ if (action>>8 == 127 || action>>8 == 8) {
+ if (polyState == POLY_SELECTED && prev_inx >=0) {
+ if (selected_count >1) {
+ ErrorMessage( MSG_POLY_MULTIPLE_SELECTED );
+ return C_CONTINUE;
+ }
+ if (points_da.cnt <= 3) {
+ ErrorMessage( MSG_POLY_SHAPES_3_SIDES );
+ return C_CONTINUE;
+ }
+ for (int i=0;i<points_da.cnt;i++) {
+ point_selected(i) = FALSE;
+ if (i>=prev_inx && i<points_da.cnt-1)
+ points(i) = points(i+1);
+ }
+ points_da.cnt--;
+ select_da.cnt--;
+ selected_count=0;
+ tempSegs(0).u.p.cnt = points_da.cnt;
+ context->max_inx = points_da.cnt-1;
+ }
+ prev_inx = -1;
+ context->prev_inx = -1;
+ polyInx = -1;
+ polyState = POLY_SELECTED;
+ CreatePolyAnchors( -1);
+ InfoMessage(_("Point Deleted"));
+ return C_CONTINUE;
+ }
+ if (action>>8 != 32 && action>>8 != 13) return C_CONTINUE;
+ /* no break */
+ case C_FINISH:
+ //copy changes back into track
+ if (polyState != POLY_SELECTED) return C_TERMINATE;
+ pts_t * oldPts = context->segPtr[segInx].u.p.pts;
+ void * newPts = (pts_t*)MyMalloc( points_da.cnt * sizeof (pts_t) );
+ context->segPtr[segInx].u.p.pts = newPts;
+ context->segPtr->u.p.cnt = points_da.cnt;
+ context->orig = rotate_origin;
+ context->angle = rotate_angle;
+ for (int i=0; i<points_da.cnt; i++) {
+ pos = points(i).pt;
+ pos.x -= context->orig.x;
+ pos.y -= context->orig.y;
+ Rotate( &pos, zero, -context->angle );
+ context->segPtr[segInx].u.p.pts[i].pt = pos;
+ context->segPtr[segInx].u.p.pts[i].pt_type = points(i).pt_type;
+ }
+ MyFree(oldPts);
+ oldPts = NULL;
+ polyState = POLY_NONE;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ DYNARR_RESET(trkSeg_t,tempSegs_da);
+ DrawNewTrack( context->trk );
+ return C_TERMINATE;
+ case C_REDRAW:
+ if (polyState == POLY_NONE) return C_CONTINUE;
+ DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt,trackGauge, wDrawColorBlack);
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ break;
+ default:
+ ;
+ }
+ return C_CONTINUE;
+}
+
+void BuildCircleContext(drawModContext_t * context,int segInx) {
+ context->radius = fabs(context->segPtr[segInx].u.c.radius);
+ REORIGIN( context->pc, context->segPtr[segInx].u.c.center, context->angle, context->orig );
+ PointOnCircle( &context->p0, context->segPtr[segInx].u.c.center, fabs(context->segPtr[segInx].u.c.radius), context->segPtr[segInx].u.c.a0 );
+ REORIGIN( context->p0, context->p0, context->angle, context->orig );
+ PointOnCircle( &context->p1, context->segPtr[segInx].u.c.center, fabs(context->segPtr[segInx].u.c.radius), context->segPtr[segInx].u.c.a0 + context->segPtr[segInx].u.c.a1);
+ REORIGIN( context->p1, context->p1, context->angle, context->orig );
+ if (context->segPtr[segInx].u.c.a1<360) {
+ context->arc_angle = context->segPtr[segInx].u.c.a1;
+ PointOnCircle( &context->pm, context->segPtr[segInx].u.c.center, fabs(context->segPtr[segInx].u.c.radius), context->segPtr[segInx].u.c.a0 + (context->segPtr[segInx].u.c.a1/2));
+ REORIGIN( context->pm, context->pm, context->angle, context->orig );
+ coOrd cm;
+ cm = context->pm;
+ ANGLE_T a = FindAngle(context->p1,context->p0);
+ Rotate(&cm,context->p1,-a );
+ context->disp = cm.x-context->p1.x;
+ } else {
+ context->pm = context->p0;
+ context->disp = 0;
+ context->arc_angle = 360.0;
+ }
+}
+
+void CreateSelectedAnchor(coOrd pos) {
+ double d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int inx = anchors_da.cnt-1;
+ anchors(inx).type = SEG_FILCRCL;
+ anchors(inx).u.c.a0 = 0.0;
+ anchors(inx).u.c.a1 = 360.0;
+ anchors(inx).color = wDrawColorBlue;
+ anchors(inx).u.c.radius = d/2;
+ anchors(inx).u.c.center = pos;
+}
+
+/*
+ * Rotate Object Dialogs.
+ *
+ * Each Draw object has a rotation origin which all the points are offset from.
+ * Formerly this has been set to the origin, but it doesn't have to be. By setting
+ * to a point on the shape this allows assembly by aligning parts to a common point on a base object.
+ * The angle is always set to zero when the Modify finishes but can be altered via Describe.
+ *
+ * First locate the origin, and then place a rotation arm which is (optionally) rotated about the origin.
+ * Also supports whole object translate using translate anchor.
+ **/
+
+STATUS_T DrawGeomOriginMove(
+ wAction_t action,
+ coOrd pos,
+ drawModContext_t * context) {
+
+ switch ( action&0xFF ) {
+ case C_START:
+ context->state = MOD_ORIGIN;
+ context->rotate_state = TRUE;
+ context->rot_moved = TRUE;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ CreateOriginAnchor(context->rot_center,FALSE);
+ if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) {
+ CreateSelectedAnchor(points(context->prev_inx).pt);
+ }
+ InfoMessage("Move Origin Mode: Place Origin, 0-4, c or l, Enter or Esc");
+ return C_CONTINUE;
+ break;
+ case wActionMove:
+ CreateOriginAnchor(context->rot_center, TRUE);
+ if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) {
+ CreateSelectedAnchor(points(context->prev_inx).pt);
+ }
+ return C_CONTINUE;
+ break;
+ case C_DOWN:
+ if (context->state == MOD_ORIGIN || context->state == MOD_AFTER_ORIG) {
+ context->state = MOD_ORIGIN;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (IsClose(FindDistance(pos,context->rot_center))) {
+ pos = context->rot_center;
+ } else {
+ context->rot_center = pos;
+ }
+ CreateOriginAnchor(context->rot_center, TRUE);
+ if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) {
+ CreateSelectedAnchor(points(context->prev_inx).pt);
+ }
+ }
+ return C_CONTINUE;
+ break;
+ case C_MOVE:
+ if (context->state == MOD_ORIGIN || context->state == MOD_AFTER_ORIG){
+ context->rot_center = pos;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ CreateOriginAnchor(context->rot_center, TRUE);
+ if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) {
+ CreateSelectedAnchor(points(context->prev_inx).pt);
+ }
+ }
+ return C_CONTINUE;
+ break;
+ case C_UP:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (context->state == MOD_ORIGIN) {
+ context->state = MOD_AFTER_ORIG;
+ }
+ CreateOriginAnchor(context->rot_center,FALSE);
+ if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) {
+ CreateSelectedAnchor(points(context->prev_inx).pt);
+ }
+ return C_CONTINUE;
+ break;
+ case C_UPDATE:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (context->state == MOD_AFTER_ORIG) {
+ if (context->rot_center.x != context->rel_center.x &&
+ context->rot_center.y != context->rel_center.y ) {
+ context->rel_center = context->rot_center;
+ CreateOriginAnchor(context->rot_center, FALSE);
+ if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) {
+ CreateSelectedAnchor(points(context->prev_inx).pt);
+ }
+ }
+ }
+ return C_CONTINUE;
+ break;
+ case C_TEXT:
+ if ((context->state == MOD_ORIGIN || context->state == MOD_AFTER_ORIG) &&
+ ((action>>8 >= '0' && action>>8 <= '1') || action>>8 == 'l' || action>>8 == 'm' || action>>8 == 'p')) {
+ // 0,1,2,3,4 -> reset rot center
+ if (action>>8 == '0') {
+ context->rot_center = zero;
+ } else if (action>>8 == '1') {
+ context->rot_center = context->p0;
+ } else if (action>>8 == '2') {
+ context->rot_center = context->p1;
+ } else if (tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) {
+ if (action>>8 == '3' || action>>8 == '4') {
+ context->rot_center = action>>8 == '3'?points(2).pt:points(3).pt;
+ } else if (action>>8 == 'l') { //"l" - last selected
+ if (context->prev_inx !=-1) {
+ context->rot_center = points(context->prev_inx).pt;
+ }
+ } else if (action>>8 == 'm') {
+ context->rot_center = FindCentroid(points_da.cnt,&points(0));
+ }
+ }
+ if (action>>8 == 'p') { //"p" - points mode
+ MenuMode(0);
+ return C_CONTINUE;
+ }
+ context->rel_center = context->rot_center;
+ context->rot_angle = 0;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ context->state = MOD_AFTER_ORIG;
+ CreateOriginAnchor(context->rot_center, FALSE);
+ if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) {
+ CreateSelectedAnchor(points(context->prev_inx).pt);
+ }
+ return C_CONTINUE;
+ }
+ break;
+ case C_FINISH:
+ context->rotate_state = FALSE;
+ context->state = MOD_STARTED;
+ return C_CONTINUE;
+ break;
+ default:
+ break;
+ }
+ return C_CONTINUE;
+
+
+}
+
+/*
+ * Base Modify function for Draw objects.
+ */
STATUS_T DrawGeomModify(
- coOrd orig,
- ANGLE_T angle,
- wIndex_t segCnt,
- trkSeg_p segPtr,
wAction_t action,
coOrd pos,
- wBool_t selected)
+ drawModContext_t * context)
{
ANGLE_T a;
- coOrd p0, p1, pc;
+ coOrd p0, p1, pc, pm;
static coOrd start_pos;
static wIndex_t segInx;
static EPINX_T segEp;
static ANGLE_T segA1;
- static int polyInx, inx_other, inx_line, inx_origin;
+ static int inx_other, inx_line, inx_origin;
static BOOL_T corner_mode;
+ static BOOL_T polyMode;
+ static ANGLE_T original_angle;
int inx, inx1, inx2;
DIST_T d, d1, d2, dd;
coOrd * newPts = NULL;
- int mergePoints;
tempSegs_da.cnt = 1;
- switch ( action ) {
- case C_DOWN:
+ switch ( action&0xFF ) {
+ case C_START:
+ if (!context->rotate_state && !context->rot_moved) {
+ context->rot_center.x = context->orig.x;
+ context->rot_center.y = context->orig.y;
+ }
+ context->state = MOD_STARTED;
+ context->rotate_state = FALSE;
+ context->last_inx=-1;
+ lineInx = -1;
+ curveInx = -1;
segInx = -1;
- corner_mode = FALSE;
- DistanceSegs( orig, angle, segCnt, segPtr, &pos, &segInx );
+ polyMode = FALSE;
+ DistanceSegs( context->orig, context->angle, context->segCnt, context->segPtr, &pos, &segInx );
if (segInx == -1)
return C_ERROR;
- tempSegs(0).width = segPtr[segInx].width;
- tempSegs(0).color = segPtr[segInx].color;
- switch ( segPtr[segInx].type ) {
+ context->type = context->segPtr[segInx].type;
+ switch(context->type) {
+ case SEG_TBLEDGE:
+ case SEG_STRLIN:
+ case SEG_DIMLIN:
+ case SEG_BENCH:
+ REORIGIN( p0, context->segPtr[segInx].u.l.pos[0], context->angle, context->orig );
+ REORIGIN( p1, context->segPtr[segInx].u.l.pos[1], context->angle, context->orig );
+ tempSegs(0).type = SEG_STRLIN;
+ tempSegs(0).color = wDrawColorRed;
+ tempSegs(0).u.l.pos[0] = p0;
+ tempSegs(0).u.l.pos[1] = p1;
+ tempSegs(0).width = 0;
+ tempSegs_da.cnt = 1;
+ context->p0 = p0;
+ context->p1 = p1;
+ CreateLineAnchors(-1,p0,p1);
+ break;
+ case SEG_CRVLIN:
+ case SEG_FILCRCL:
+ BuildCircleContext(context,segInx);
+ tempSegs(0).type = SEG_CRVLIN;
+ tempSegs(0).color = wDrawColorRed;
+ tempSegs(0).u.c.center = context->pc;
+ tempSegs(0).u.c.radius = context->radius;
+ tempSegs(0).u.c.a0 = context->segPtr[segInx].u.c.a0;
+ tempSegs(0).u.c.a1 = context->segPtr[segInx].u.c.a1;
+ tempSegs(0).width = 0;
+ tempSegs_da.cnt = 1;
+ if (tempSegs(0).u.c.a1<360.0) {
+ CreateCurveAnchors(-1,context->pm,context->pc,context->p0,context->p1);
+ } else
+ CreateCircleAnchor(FALSE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,FindAngle(tempSegs(0).u.c.center,pos));
+ context->last_inx = 2;
+ break;
+ case SEG_POLY:
+ case SEG_FILPOLY:
+ if (context->segPtr[segInx].u.p.polyType !=RECTANGLE) {
+ polyMode = TRUE;
+ return DrawGeomPolyModify(action,pos,context);
+ } else {
+ tempSegs(0).type = SEG_POLY;
+ tempSegs(0).color = wDrawColorRed;
+ DYNARR_RESET( pts_t, points_da);
+ for (int inx=0;inx<context->segPtr->u.p.cnt;inx++) {
+ DYNARR_APPEND(pts_t, points_da,3);
+ REORIGIN( points(inx).pt, context->segPtr[segInx].u.p.pts[inx].pt, context->angle, context->orig );
+ }
+ tempSegs(0).u.p.pts = &points(0);
+ tempSegs(0).u.p.cnt = points_da.cnt;
+ tempSegs(0).width = 0;
+ tempSegs_da.cnt = 1;
+ context->p0 = points(0).pt;
+ CreateBoxAnchors(-1,&context->segPtr[segInx].u.p.pts[0]);
+ context->p0 = points(0).pt;
+ context->p1 = points(1).pt;
+ }
+ break;
+ case SEG_TEXT:
+ InfoMessage("Text can only be modified with Describe");
+ wBeep();
+ return C_ERROR;
+ default:
+ ;
+ }
+ InfoMessage("Points Mode - Select and drag Anchor Point");
+ return C_CONTINUE;
+ break;
+ case wActionMove:
+ if (context->rotate_state) return DrawGeomOriginMove(action,pos,context);
+ if (polyMode) return DrawGeomPolyModify(action,pos,context);
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ switch( context->type) {
case SEG_TBLEDGE:
-
case SEG_STRLIN:
case SEG_DIMLIN:
case SEG_BENCH:
- REORIGIN( p0, segPtr[segInx].u.l.pos[0], angle, orig );
- REORIGIN( p1, segPtr[segInx].u.l.pos[1], angle, orig );
- tempSegs(0).type = segPtr[segInx].type;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ CreateLineAnchors(lineInx,context->p0,context->p1);
+ dd = FindDistance( context->p0, pos );
+ if ( IsClose(dd)) {
+ CreateMovingAnchor(context->p0,TRUE);
+ } else {
+ dd = FindDistance( context->p1, pos );
+ if ( IsClose(dd)) {
+ CreateMovingAnchor(context->p1,TRUE);
+ }
+ }
+ break;
+ case SEG_CRVLIN:
+ case SEG_FILCRCL:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (tempSegs(0).u.c.a1 < 360.0)
+ CreateCurveAnchors(curveInx,context->pm,context->pc,context->p0,context->p1);
+ dd = FindDistance( context->p0, pos );
+ if ( IsClose(dd)) {
+ CreateMovingAnchor(context->p0,TRUE);
+ } else {
+ dd = FindDistance( context->p1, pos );
+ if ( IsClose(dd)) {
+ CreateMovingAnchor(context->p1,TRUE);
+ } else {
+ dd = FindDistance( context->pm, pos );
+ if ( IsClose(dd)) {
+ CreateMovingAnchor(context->pm,TRUE);
+ }
+ }
+ }
+ break;
+ case SEG_POLY:
+ case SEG_FILPOLY:;
+ CreateBoxAnchors(-1,&points(0));
+ break;
+ default:;
+ }
+ return C_CONTINUE;
+ break;
+ case C_DOWN:
+ if (context->rotate_state) return DrawGeomOriginMove(action,pos,context);
+ if (polyMode) return DrawGeomPolyModify(action,pos,context);
+ corner_mode = FALSE;
+ segInx = 0;
+ context->state = MOD_STARTED;
+ tempSegs(0).width = context->segPtr[segInx].width;
+ tempSegs(0).color = context->segPtr[segInx].color;
+ switch ( context->type ) {
+ case SEG_TBLEDGE:
+ if ( MyGetKeyState() & WKEY_CTRL )
+ OnTableEdgeEndPt( NULL, &pos );
+ case SEG_STRLIN:
+ case SEG_DIMLIN:
+ case SEG_BENCH:
+ p0 = context->p0;
+ p1 = context->p1;
+ lineInx = -1;
+ dd = FindDistance( p0, pos );
+ if ( IsClose(dd)) {
+ lineInx = 0;
+ } else {
+ dd = FindDistance( p1, pos );
+ if ( IsClose(dd)) {
+ lineInx = 1;
+ }
+ }
+ if (lineInx < 0 ) {
+ InfoMessage( _("Not close to end of line"));
+ } else {
+ InfoMessage("End selected, drag to reposition");
+ context->state = MOD_SELECTED_PT;
+ }
+ tempSegs(0).color = wDrawColorBlack;
+ tempSegs(0).width = 0;
+ tempSegs(0).type = context->type;
tempSegs(0).u.l.pos[0] = p0;
tempSegs(0).u.l.pos[1] = p1;
- tempSegs(0).u.l.option = segPtr[segInx].u.l.option;
+ tempSegs(0).u.l.option = context->segPtr[segInx].u.l.option;
segA1 = FindAngle( p1, p0 );
+ tempSegs_da.cnt = 1;
+ CreateLineAnchors(lineInx,p0,p1);
break;
case SEG_CRVLIN:
case SEG_FILCRCL:
- REORIGIN( pc, segPtr[segInx].u.c.center, angle, orig )
- tempSegs(0).type = segPtr[segInx].type;
- tempSegs(0).u.c.center = pc;
- tempSegs(0).u.c.radius = fabs(segPtr[segInx].u.c.radius);
- if (segPtr[segInx].u.c.a1 >= 360.0) {
+ curveInx = -1;
+ tempSegs(0).color = wDrawColorBlack;
+ tempSegs(0).width = 0;
+ tempSegs(0).type = context->type;
+ tempSegs(0).u.c.center = context->pc;
+ tempSegs(0).u.c.radius = context->radius;
+ if (context->segPtr[segInx].u.c.a1 >= 360.0) {
tempSegs(0).u.c.a0 = 0.0;
tempSegs(0).u.c.a1 = 360.0;
+ InfoMessage("Drag to Change Radius");
+ CreateCircleAnchor(TRUE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,FindAngle(tempSegs(0).u.c.center,pos));
} else {
- tempSegs(0).u.c.a0 = NormalizeAngle( segPtr[segInx].u.c.a0+angle );
- tempSegs(0).u.c.a1 = segPtr[segInx].u.c.a1;
- segA1 = NormalizeAngle( segPtr[segInx].u.c.a0 + segPtr[segInx].u.c.a1 + angle );
- PointOnCircle( &p0, pc, fabs(segPtr[segInx].u.c.radius), segPtr[segInx].u.c.a0+angle );
- PointOnCircle( &p1, pc, fabs(segPtr[segInx].u.c.radius), segPtr[segInx].u.c.a0+segPtr[segInx].u.c.a1+angle );
+ p0 = context->p0;
+ p1 = context->p1;
+ pm = context->pm;
+ pc = context->pc;
+ tempSegs(0).u.c.a0 = FindAngle(context->pc,context->p0);
+ tempSegs(0).u.c.a1 = DifferenceBetweenAngles(FindAngle(context->pc,context->p0),FindAngle(context->pc,context->p1));
+ tempSegs(0).u.c.center = context->pc;
+ tempSegs(0).u.c.radius = context->radius;
+ curveInx = -1;
+ dd = FindDistance( p0, pos );
+ if ( IsClose(dd)) {
+ curveInx = 0;
+ } else {
+ dd = FindDistance( p1, pos );
+ if ( IsClose(dd)) {
+ curveInx = 1;
+ } else {
+ dd = FindDistance( pm, pos );
+ if ( IsClose(dd)) {
+ curveInx = 2;
+ }
+ }
+ }
+ if (curveInx < 0) {
+ InfoMessage( _("Not close to ends or middle of mine, reselect"));
+ return C_CONTINUE;
+ } else {
+ if (curveInx <2 )
+ InfoMessage("Drag to move end, +Ctrl to lock to other objects");
+ else
+ InfoMessage("Drag to change radius");
+ }
+ tempSegs_da.cnt = 1;
+ if (tempSegs(0).u.c.a1 < 360.0)
+ CreateCurveAnchors(curveInx,pm,pc,p0,p1);
}
-
+ context->state = MOD_SELECTED_PT;
break;
case SEG_POLY:
case SEG_FILPOLY:
- tempSegs(0).type = segPtr[segInx].type;
- tempSegs(0).u.p.cnt = segPtr[segInx].u.p.cnt;
- tempSegs(0).u.p.angle = 0.0;
- tempSegs(0).u.p.orig = zero;
- tempSegs(0).u.p.polyType = segPtr[segInx].u.p.polyType;
- DYNARR_SET( coOrd, points_da, segPtr[segInx].u.p.cnt+1 );
- tempSegs(0).u.p.pts = &points(0);
d = 10000;
polyInx = 0;
- for ( inx=0; inx<segPtr[segInx].u.p.cnt; inx++ ) {
- REORIGIN( points(inx), segPtr[segInx].u.p.pts[inx], angle, orig );
- }
- for ( inx=0; inx<segPtr[segInx].u.p.cnt; inx++ ) {
+ for ( inx=0; inx<4; inx++ ) {
+ if (IsClose(FindDistance(pos,points(inx).pt))) {
+ corner_mode = TRUE;
+ polyInx = inx;
+ break;
+ }
p0 = pos;
- dd = LineDistance( &p0, points( inx==0?segPtr[segInx].u.p.cnt-1:inx-1), points( inx ) );
+ dd = LineDistance( &p0, points( inx==0?3:inx-1).pt, points( inx ).pt );
if ( d > dd ) {
d = dd;
- polyInx = inx;
+ inx_line = inx;
}
}
- if (segPtr[segInx].u.p.polyType == RECTANGLE) {
- d1 = FindDistance( points(polyInx), pos );
- d2 = FindDistance( points(polyInx==0?segPtr[segInx].u.p.cnt-1:polyInx-1), pos );
+ if (!corner_mode) {
+ d1 = FindDistance( points(inx_line).pt, pos );
+ d2 = FindDistance( points(inx_line==0?3:inx_line-1).pt, pos );
if (d2<d1) {
- inx_line = polyInx;
- polyInx = polyInx==0?segPtr[segInx].u.p.cnt-1:polyInx-1;
+ polyInx = inx_line==0?3:inx_line-1;
} else {
- inx_line = polyInx==0?segPtr[segInx].u.p.cnt-1:polyInx-1;
+ polyInx = inx_line;
}
- //polyInx is closest point
- inx1 = (polyInx==0?3:polyInx-1); //Prev point
- inx2 = (polyInx==3?0:polyInx+1); //Next Point
- inx_origin = (inx2==3?0:inx2+1); //Opposite point
- if ( IsClose(d2) || IsClose(d1) ) {
- corner_mode = TRUE;
- pos = points(polyInx);
- start_pos = pos;
- DrawArrowHeads( &tempSegs(1), pos, FindAngle(points(polyInx),points(inx_origin)), TRUE, wDrawColorRed );
- tempSegs_da.cnt = 6;
- InfoMessage( _("Drag to Move Corner Point"));
- } else {
- corner_mode = FALSE;
- start_pos = pos;
- pos.x = (points(polyInx).x + points(inx_line).x)/2;
- pos.y = (points(polyInx).y + points(inx_line).y)/2;
- DrawArrowHeads( &tempSegs(1), pos, FindAngle(points(polyInx),pos)+90, TRUE, wDrawColorRed );
- tempSegs_da.cnt = 6;
- InfoMessage( _("Drag to Move Edge "));
- }
- return C_CONTINUE;
+ }
+ inx1 = (polyInx==0?3:polyInx-1); //Prev point
+ inx2 = (polyInx==3?0:polyInx+1); //Next Point
+ inx_origin = (inx2==3?0:inx2+1); //Opposite point
+ if ( corner_mode ) {
+ start_pos = pos;
+ pos = points(inx).pt;
+ DYNARR_SET(trkSeg_t,anchors_da,5);
+ DrawArrowHeads( &anchors(0), pos, FindAngle(points(polyInx).pt,points(inx_origin).pt), TRUE, wDrawColorRed );
+ InfoMessage( _("Drag to Move Corner Point"));
} else {
- inx = (polyInx==0?segPtr[segInx].u.p.cnt-1:polyInx-1);
- d = FindDistance( points(inx), pos );
- dd = FindDistance( points(inx), points(polyInx) );
- if ( d < 0.25*dd ) {
- polyInx = inx;
- } else if ( d > 0.75*dd ) {
- ;
- } else {
- tempSegs(0).u.p.cnt++;
- for (inx=points_da.cnt-1; inx>polyInx; inx-- ) {
- points(inx) = points(inx-1);
- }
-/*fprintf( stderr, "Inserting vertix before %d\n", polyInx );*/
- }
- points(polyInx) = pos;
+ start_pos = pos;
+ pos.x = (points(inx_line).pt.x + points(inx_line==0?3:inx_line-1).pt.x)/2;
+ pos.y = (points(inx_line).pt.y + points(inx_line==0?3:inx_line-1).pt.y)/2;
+ DYNARR_SET(trkSeg_t,anchors_da,5);
+ DrawArrowHeads( &anchors(0), pos, FindAngle(points(polyInx).pt,pos)+90, TRUE, wDrawColorRed );
+ InfoMessage( _("Drag to Move Edge "));
}
- p1=p0;
- break;
+ context->state = MOD_SELECTED_PT;
+ return C_CONTINUE;
case SEG_TEXT:
segInx = -1;
return C_ERROR;
@@ -690,7 +2057,7 @@ STATUS_T DrawGeomModify(
segEp = 0;
else {
segEp = 1;
- switch ( segPtr[segInx].type ) {
+ switch ( context->type ) {
case SEG_TBLEDGE:
case SEG_STRLIN:
case SEG_DIMLIN:
@@ -701,176 +2068,454 @@ STATUS_T DrawGeomModify(
;
}
}
+ UndrawNewTrack( context->trk );
return C_CONTINUE;
case C_MOVE:
- if (segInx == -1)
- return C_ERROR;
- if ( ( MyGetKeyState() & WKEY_SHIFT ) &&
- (tempSegs(0).type == SEG_STRLIN || tempSegs(0).type == SEG_DIMLIN || tempSegs(0).type == SEG_BENCH || tempSegs(0).type == SEG_TBLEDGE) ) {
- d = FindDistance( pos, tempSegs(0).u.l.pos[1-segEp] );
- Translate( &pos, tempSegs(0).u.l.pos[1-segEp], segA1, d );
- } else if ( (MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) {
- OnTrack( &pos, FALSE, FALSE );
+ if (context->rotate_state) return DrawGeomOriginMove(action,pos,context);
+
+ if (polyMode) return DrawGeomPolyModify(action,pos,context);
+ if (context->state != MOD_SELECTED_PT) return C_CONTINUE;
+ switch (tempSegs(0).type) {
+ case SEG_STRLIN:
+ case SEG_DIMLIN:
+ case SEG_BENCH:
+ case SEG_TBLEDGE:
+ if ( (MyGetKeyState() & WKEY_SHIFT) != 0) {
+ d = FindDistance( pos, tempSegs(0).u.l.pos[1-lineInx] );
+ Translate( &pos, tempSegs(0).u.l.pos[1-lineInx], segA1, d );
+ } else if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_SHIFT ) {
+ OnTrack( &pos, FALSE, FALSE );
+ CreateEndAnchor(pos,TRUE);
+ }
+ break;
+ default:
+ break;
}
int prior_pnt, next_pnt, orig_pnt;
ANGLE_T prior_angle, next_angle, line_angle;
tempSegs_da.cnt = 1;
switch (tempSegs(0).type) {
case SEG_TBLEDGE:
-
+ if ( MyGetKeyState() & WKEY_CTRL )
+ OnTableEdgeEndPt( NULL, &pos );
+ /* no break */
case SEG_STRLIN:
case SEG_DIMLIN:
case SEG_BENCH:
- tempSegs(0).u.l.pos[segEp] = pos;
- InfoMessage( _("Length = %0.3f Angle = %0.3f"), FindDistance( tempSegs(0).u.l.pos[segEp], tempSegs(0).u.l.pos[1-segEp] ), FindAngle( tempSegs(0).u.l.pos[1-segEp], tempSegs(0).u.l.pos[segEp] ) );
+ if (lineInx<0 || lineInx>1) return C_CONTINUE;
+ tempSegs(0).u.l.pos[lineInx] = pos;
+ InfoMessage( _("Length = %0.3f Angle = %0.3f"), FindDistance( tempSegs(0).u.l.pos[lineInx], tempSegs(0).u.l.pos[1-lineInx] ), FindAngle( tempSegs(0).u.l.pos[1-lineInx], tempSegs(0).u.l.pos[lineInx] ) );
+ tempSegs_da.cnt = 1;
+ context->p0 = tempSegs(0).u.l.pos[0];
+ context->p1 = tempSegs(0).u.l.pos[1];
+ p0 = context->p0;
+ p1 = context->p1;
+ CreateLineAnchors(lineInx, p0, p1);
break;
case SEG_CRVLIN:
case SEG_FILCRCL:
if (tempSegs(0).u.c.a1 >= 360.0) {
- tempSegs(0).u.c.radius = FindDistance( tempSegs(0).u.c.center, pos );
+ tempSegs(0).u.c.radius = FindDistance( context->pc, pos );
+ CreateCircleAnchor(TRUE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,FindAngle(tempSegs(0).u.c.center,pos));
} else {
- a = FindAngle( tempSegs(0).u.c.center, pos );
- if (segEp==0) {
- tempSegs(0).u.c.a1 = NormalizeAngle(segA1-a);
- tempSegs(0).u.c.a0 = a;
+ if (context->state != MOD_SELECTED_PT) return C_CONTINUE;
+ if (curveInx < 0 || curveInx > 2) return C_CONTINUE;
+ p0 = context->p0;
+ p1 = context->p1;
+ pc = context->pc;
+ pm = context->pm;
+ if ( (MyGetKeyState() & WKEY_SHIFT) != 0) {
+ //Preserve Radius, Change swept angle
+ a = FindAngle( pc, pos );
+ if (curveInx==0) {
+ tempSegs(0).u.c.a1 = NormalizeAngle(FindAngle(pc,p1)-a);
+ tempSegs(0).u.c.a0 = a;
+ } else if (curveInx ==1) {
+ tempSegs(0).u.c.a1 = NormalizeAngle(a-tempSegs(0).u.c.a0);
+ }
+ PointOnCircle(&p0,pc,context->radius,tempSegs(0).u.c.a0);
+ PointOnCircle(&p1,pc,context->radius,tempSegs(0).u.c.a0+tempSegs(0).u.c.a1);
+ context->p0 = p0;
+ context->p1 = p1;
+ PointOnCircle(&pm,pc,context->radius,tempSegs(0).u.c.a0+(tempSegs(0).u.c.a1/2));
+ context->pm = pm;
} else {
- tempSegs(0).u.c.a1 = NormalizeAngle(a-tempSegs(0).u.c.a0);
+ if (curveInx == 0 || curveInx == 1) {
+ p0 = context->p0;
+ p1 = context->p1;
+ /* Preserve Curve "Deflection" */
+ d = context->disp; // Original Deflection
+ if (curveInx == 0) {
+ context->p0 = p0 = pos;
+ } else {
+ context->p1 = p1 = pos;
+ }
+ 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; //Middle of chord
+ ANGLE_T a0 = FindAngle( p1, p0 );
+ DIST_T d0 = FindDistance( p0, p1 )/2.0;
+ DIST_T r = 1000.0;
+ if ( fabs(d) >= 0.01 ) {
+ d2 = sqrt( d0*d0 + d*d )/2.0;
+ r = d2*d2*2.0/d;
+ if ( fabs(r) > 1000.0 )
+ r = ((r > 0)? 1 : -1) *1000.0;
+ } else {
+ r = ((r > 0) ? 1 : -1 ) *1000.0;
+ }
+ a0 -= 90.0;
+ if (r<0) {
+ coOrd pt = p0;
+ p0 = p1;
+ p1 = pt;
+ a0 += 180.0;
+ }
+ context->radius = tempSegs(0).u.c.radius = fabs(r);
+ Translate( &pc, posx, a0, fabs(r)-fabs(d) );
+ context->pc = tempSegs(0).u.c.center = pc;
+ tempSegs(0).u.c.a0 = FindAngle(pc,p0);
+ context->arc_angle = tempSegs(0).u.c.a1 = NormalizeAngle(FindAngle(pc,p1)-FindAngle(pc,p0));
+ PointOnCircle(&pm,pc,context->radius,tempSegs(0).u.c.a0+(tempSegs(0).u.c.a1/2.0));
+ context->pm = pm;
+ } else {
+ //Change radius using chord
+ p0 = context->p0;
+ p1 = context->p1;
+ pm = context->pm;
+ ANGLE_T a0 = FindAngle( p1, p0 );
+ DIST_T d0 = FindDistance( p0, p1 )/2.0;
+ coOrd pos2 = pos;
+ Rotate( &pos2, p1, -a0 );
+ pos2.x -= p1.x;
+ DIST_T r = 1000.0;
+ if ( fabs(pos2.x) >= 0.01 ) {
+ d2 = sqrt( d0*d0 + pos2.x*pos2.x )/2.0;
+ r = d2*d2*2.0/pos2.x;
+ if ( fabs(r) > 1000.0 )
+ r = ((r > 0) ? 1 : -1 ) *1000.0;
+ } else {
+ 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) {
+ coOrd pt = p0;
+ p0 = p1;
+ p1 = pt;
+ a0 += 180.0;
+ }
+ Translate( &pc, posx, a0, fabs(r) - fabs(pos2.x) );
+ context->pc = tempSegs(0).u.c.center = pc;
+ context->radius = tempSegs(0).u.c.radius = fabs(r);
+ a0 = FindAngle( pc, p0 );
+ ANGLE_T a1 = FindAngle( pc, p1 );
+ tempSegs(0).u.c.a0 = a0;
+ tempSegs(0).u.c.a1 = NormalizeAngle(a1-a0);
+ PointOnCircle(&pm,pc,context->radius,a0+(NormalizeAngle(a1-a0)/2));
+ context->p0 = p0;
+ context->p1 = p1;
+ context->pm = pm;
+ context->disp = pos2.x;
+ }
}
+ if (tempSegs(0).u.c.a1 < 360.0)
+ CreateCurveAnchors(curveInx,pm,pc,p0,p1);
}
break;
case SEG_POLY:
case SEG_FILPOLY:
- switch (tempSegs(0).u.p.polyType) {
- case RECTANGLE:
- if (!corner_mode) {
- /* Constrain movement to be perpendicular */
- d = FindDistance(start_pos, pos);
- line_angle = NormalizeAngle(FindAngle(points(inx_line),points(polyInx))-90);
- a = FindAngle(pos,start_pos);
- Translate( &pos, start_pos, line_angle, - d*cos(D2R(line_angle-a)));
- }
- d = FindDistance(start_pos,pos);
- a = FindAngle(start_pos, pos);
- start_pos = pos;
- prior_pnt = (polyInx == 0)?3:polyInx-1;
- next_pnt = (polyInx == 3)?0:polyInx+1;
- orig_pnt = (prior_pnt == 0)?3:prior_pnt-1;
- Translate( &points(polyInx), points(polyInx), a, d);
- d = FindDistance(points(orig_pnt),points(polyInx));
- a = FindAngle(points(orig_pnt),points(polyInx));
- prior_angle = FindAngle(points(orig_pnt),points(prior_pnt));
- Translate( &points(prior_pnt), points(orig_pnt), prior_angle, d*cos(D2R(prior_angle-a)));
- next_angle = FindAngle(points(orig_pnt),points(next_pnt));
- Translate( &points(next_pnt), points(orig_pnt), next_angle, d*cos(D2R(next_angle-a)));
- if (!corner_mode) {
- pos.x = (points(polyInx).x + points(inx_line).x)/2;
- pos.y = (points(polyInx).y + points(inx_line).y)/2;
- DrawArrowHeads( &tempSegs(1), pos, FindAngle(points(polyInx),points(inx_line))+90, TRUE, wDrawColorRed );
- tempSegs_da.cnt = 6;
- InfoMessage( _("Drag to Move Edge"));
- } else {
- pos = points(polyInx);
- DrawArrowHeads( &tempSegs(1), pos, FindAngle(points(polyInx),points(inx_origin)), TRUE, wDrawColorRed );
- tempSegs_da.cnt = 6;
- InfoMessage( _("Drag to Move Corner Point"));
- }
- break;
- default:
- points(polyInx) = pos;
+ if (!corner_mode) {
+ /* Constrain movement to be perpendicular */
+ d = FindDistance(start_pos, pos);
+ line_angle = NormalizeAngle(FindAngle(points(inx_line).pt,points(inx_line==3?0:inx_line+1).pt));
+ a = FindAngle(pos,start_pos);
+ Translate( &pos, start_pos, line_angle, - d*cos(D2R(line_angle-a)));
}
-
+ d = FindDistance(start_pos,pos);
+ a = FindAngle(start_pos, pos);
+ start_pos = pos;
+ prior_pnt = (polyInx == 0)?3:polyInx-1;
+ next_pnt = (polyInx == 3)?0:polyInx+1;
+ orig_pnt = (prior_pnt == 0)?3:prior_pnt-1;
+ Translate( &points(polyInx).pt, points(polyInx).pt, a, d);
+ d = FindDistance(points(orig_pnt).pt,points(polyInx).pt);
+ a = FindAngle(points(orig_pnt).pt,points(polyInx).pt);
+ prior_angle = FindAngle(points(orig_pnt).pt,points(prior_pnt).pt);
+ Translate( &points(prior_pnt).pt, points(orig_pnt).pt, prior_angle, d*cos(D2R(prior_angle-a)));
+ next_angle = FindAngle(points(orig_pnt).pt,points(next_pnt).pt);
+ Translate( &points(next_pnt).pt, points(orig_pnt).pt, next_angle, d*cos(D2R(next_angle-a)));
+ if (!corner_mode) {
+ pos.x = (points(inx_line).pt.x + points(inx_line==0?3:inx_line-1).pt.x)/2;
+ pos.y = (points(inx_line).pt.y + points(inx_line==0?3:inx_line-1).pt.y)/2;
+ DYNARR_SET(trkSeg_t,anchors_da,5);
+ DrawArrowHeads( &anchors(0), pos, FindAngle(points(inx_line).pt,points(inx_line==0?3:inx_line-1).pt)+90, TRUE, wDrawColorRed );
+ InfoMessage( _("Drag to Move Edge"));
+ } else {
+ pos = points(polyInx).pt;
+ DYNARR_SET(trkSeg_t,anchors_da,5);
+ DrawArrowHeads( &anchors(0), pos, FindAngle(points(polyInx).pt,points(inx_origin).pt), TRUE, wDrawColorRed );
+ InfoMessage( _("Drag to Move Corner Point"));
+ }
+ context->p0 = points(0).pt;
+ context->p1 = points(1).pt;
break;
default:
;
}
-
return C_CONTINUE;
case C_UP:
+
+ if (context->rotate_state) return DrawGeomOriginMove(action, pos, context);
+
+ if (polyMode) {
+ int rc;
+ rc = DrawGeomPolyModify(action,pos,context);
+ if (context->prev_inx != -1)
+ context->state = MOD_AFTER_PT;
+ return rc;
+ }
+
if (segInx == -1)
return C_CONTINUE;
switch (tempSegs(0).type) {
case SEG_TBLEDGE:
-
case SEG_STRLIN:
case SEG_DIMLIN:
case SEG_BENCH:
- pos = tempSegs(0).u.l.pos[segEp];
- pos.x -= orig.x;
- pos.y -= orig.y;
- Rotate( &pos, zero, -angle );
- segPtr[segInx].u.l.pos[segEp] = pos;
+ p0 = context->p0;
+ p1 = context->p1;
+ context->abs_angle = FindAngle(p0,p1);
+ context->length = FindDistance(p0,p1);
+ CreateLineAnchors(lineInx,p0,p1);
+ context->last_inx = lineInx;
break;
case SEG_CRVLIN:
case SEG_FILCRCL:
- if ( tempSegs(0).u.c.a1 >= 360.0 ) {
- segPtr[segInx].u.c.radius = fabs(tempSegs(0).u.c.radius);
+ if ( (tempSegs(0).type == SEG_FILCRCL) || (tempSegs(0).u.c.a1 == 360.0 || tempSegs(0).u.c.a1 == 0.0) ) {
+ context->radius = fabs(tempSegs(0).u.c.radius);
+ context->arc_angle = 360.0;
+ CreateCircleAnchor(FALSE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,FindAngle(tempSegs(0).u.c.center,pos));
} else {
- a = FindAngle( tempSegs(0).u.c.center, pos );
- a = NormalizeAngle( a-angle );
- segPtr[segInx].u.c.a1 = tempSegs(0).u.c.a1;
- if (segEp == 0) {
- segPtr[segInx].u.c.a0 = a;
- }
+ p0 = context->p0;
+ p1 = context->p1;
+ pc = context->pc;
+ pm = context->pm;
+ context->radius = fabs(tempSegs(0).u.c.radius);
+ context->arc_angle = tempSegs(0).u.c.a1;
+ CreateCurveAnchors(curveInx,pm,pc,p0,p1);
+ a = FindAngle(p1,p0);
+ Rotate(&pm,p1,-a);
+ context->disp = pm.x-p1.x;
}
+ context->last_inx = curveInx;
break;
case SEG_POLY:
case SEG_FILPOLY:
- switch(tempSegs(0).u.p.polyType) {
- case RECTANGLE:
- for (int i=0;i<4;i++) {
- pos = points(i);
- pos.x -= orig.x;
- pos.y -= orig.y;
- Rotate( &pos, zero, -angle );
- segPtr[segInx].u.p.pts[i] = pos;
- }
- break;
- default:
- mergePoints = FALSE;
- if ( IsClose( FindDistance( pos, points( polyInx==0?tempSegs(0).u.p.cnt-1:polyInx-1 ) ) ) ||
- IsClose( FindDistance( pos, points( (polyInx==tempSegs(0).u.p.cnt-1)?0:polyInx+1 ) ) ) ) {
- mergePoints = TRUE;
- if (segPtr[segInx].u.p.cnt <= 3) {
- ErrorMessage( MSG_POLY_SHAPES_3_SIDES );
+ CreateBoxAnchors(-1,tempSegs(0).u.p.pts);
+ context->width = FindDistance(tempSegs(0).u.p.pts[0].pt,tempSegs(0).u.p.pts[1].pt);
+ context->height = FindDistance(tempSegs(0).u.p.pts[1].pt,tempSegs(0).u.p.pts[2].pt);
+ context->last_inx = polyInx;
+ if (corner_mode) context->last_inx +=5;
+ break;
+ default:
+ ;
+ }
+ context->state = MOD_AFTER_PT;
+ curveInx = -1;
+ lineInx = -1;
+ polyInx = -1;
+ InfoMessage("Enter/Space to Accept, ESC to Reject");
+ return C_CONTINUE;
+ case C_UPDATE:
+ if (context->rotate_state) return DrawGeomOriginMove(action, pos, context);
+
+ if (polyMode) return DrawGeomPolyModify(action,pos,context);
+ if (context->state == MOD_AFTER_PT) {
+ switch (tempSegs(0).type) {
+ case SEG_TBLEDGE:
+ case SEG_STRLIN:
+ case SEG_DIMLIN:
+ case SEG_BENCH:
+ context->abs_angle = NormalizeAngle(context->abs_angle);
+ Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->abs_angle,context->length);
+ CreateLineAnchors(context->last_inx,tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1]);
+ context->p0 = tempSegs(0).u.l.pos[0];
+ context->p1 = tempSegs(0).u.l.pos[1];
+ break;
+ case SEG_CRVLIN:
+ case SEG_FILCRCL:
+ if (tempSegs(0).u.c.a1 == 360.0 || tempSegs(0).u.c.a1 == 0.0) {
+ tempSegs(0).u.c.a1 = 360.0;
+ tempSegs(0).u.c.radius = context->radius;
+ Translate(&p0,tempSegs(0).u.c.center,tempSegs(0).u.c.a0,tempSegs(0).u.c.radius);
+ context->p0 = p0;
+ context->p1 = p0;
+ context->pm = p0;
+ context->pc = tempSegs(0).u.c.center;
break;
}
- }
+ if (context->radius < 0) { //swap ends
+ context->radius = fabs(context->radius);
+ p1 = context->p0;
+ p0 = context->p1;
+ a = FindAngle(context->pc,context->pm);
+ Translate(&pm,context->pm,a+180,2*context->disp);
+ Translate(&pc,pm,a,context->radius);
+ context->pm = pm;
+ context->pc = pc;
+ context->p0 = p0;
+ context->p1 = p1;
+ } else {
+ pm = context->pm;
+ pc = context->pc;
+ p0 = context->p0;
+ p1 = context->p1;
+ }
+ if (context->last_inx == 0) {
+ p1 = context->p1;
+ pc = context->pc;
+ a = FindAngle(p1,pc);
+ Translate(&pc,p1,a,context->radius);
+ context->pc = pc;
+ PointOnCircle( &p0, context->pc, context->radius, NormalizeAngle(a+180-context->arc_angle) );
+ context->p0 = p0;
+ PointOnCircle( &pm, context->pc, context->radius, NormalizeAngle(a+180-(context->arc_angle/2)));
+ context->pm = pm;
+ } else if (context->last_inx == 1) {
+ p0 = context->p0;
+ pc = context->pc;
+ a = FindAngle(p0,pc);
+ Translate(&pc,p0,a,context->radius);
+ context->pc = pc;
+ PointOnCircle( &p1, context->pc, context->radius, NormalizeAngle(a+180+context->arc_angle) );
+ context->p1 = p1;
+ PointOnCircle( &pm, context->pc, context->radius, NormalizeAngle(a+180+(context->arc_angle/2)));
+ context->pm = pm;
+ } else { // Middle if neither
+ a = FindAngle(context->pm,context->pc);
+ Translate(&pc,context->pm,a,context->radius);
+ context->pc = pc;
+ PointOnCircle( &p1, context->pc, context->radius, NormalizeAngle(FindAngle(context->pc,context->pm)+(context->arc_angle/2)) );
+ PointOnCircle( &p0, context->pc, context->radius, NormalizeAngle(FindAngle(context->pc,context->pm)-(context->arc_angle/2)) );
+ context->p1 = p1;
+ context->p0 = p0;
+ }
+ a = FindAngle(p1,p0);
+ Rotate(&pm,p1,-a);
+ context->disp = pm.x-p1.x;
+ tempSegs(0).u.c.center = context->pc;
+ tempSegs(0).u.c.a0 = FindAngle(context->pc,context->p0);
+ tempSegs(0).u.c.a1 = NormalizeAngle(FindAngle(context->pc,context->p1)-tempSegs(0).u.c.a0);
+ if (tempSegs(0).u.c.a1 == 0.0) tempSegs(0).u.c.a1 = 360.0;
+ tempSegs(0).u.c.radius = context->radius;
+ CreateCurveAnchors(context->last_inx,context->pm,context->pc,context->p0,context->p1);
+ break;
+ case SEG_POLY:
+ case SEG_FILPOLY:
+ a = NormalizeAngle(FindAngle(points(0).pt,points(3).pt));
+ Translate( &points(3).pt, points(0).pt, a, context->height);
+ Translate( &points(2).pt, points(1).pt, a, context->height);
+ a = NormalizeAngle(FindAngle(points(0).pt,points(1).pt));;
+ Translate( &points(1).pt, points(0).pt, a, context->width);
+ Translate( &points(2).pt, points(3).pt, a, context->width);
+ CreateBoxAnchors(context->last_inx,&points(0));
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case C_TEXT:
+ if (context->rotate_state) DrawGeomOriginMove(action, pos, context);
- coOrd * oldPts = segPtr[segInx].u.p.pts;
- newPts = (coOrd*)MyMalloc( tempSegs(0).u.p.cnt * sizeof (coOrd) );
- int size = segPtr[segInx].u.p.cnt;
- memcpy( newPts, segPtr[segInx].u.p.pts, (size) * sizeof (coOrd) );
- segPtr[segInx].u.p.pts = newPts;
- MyFree(oldPts);
+ if (polyMode) return DrawGeomPolyModify(action,pos,context);
+ if (action>>8 == 'o') {
+ MenuMode(1);
+ }
- if ( tempSegs(0).u.p.cnt > segPtr[segInx].u.p.cnt ) {
- ASSERT( tempSegs(0).u.p.cnt == segPtr[segInx].u.p.cnt+1 );
- for (inx=tempSegs(0).u.p.cnt-1; inx>polyInx; inx--)
- segPtr[segInx].u.p.pts[inx] = segPtr[segInx].u.p.pts[inx-1];
- segPtr[segInx].u.p.cnt++;
+ if (action>>8 != 32 && action>>8 != 13) return C_CONTINUE;
+ /* no break */
+ case C_FINISH:
+ if (polyMode) {
+ DrawGeomPolyModify(action,pos,context);
+ context->segPtr[segInx].type = context->type;
+ context->segPtr[segInx].u.p.polyType = context->subtype;
+ return C_TERMINATE;
+ }
+ //copy changes back into track
+ context->orig.x = context->rot_center.x;
+ context->orig.y = context->rot_center.y;
+ context->rot_moved = FALSE;
+ context->angle = 0.0;
+ switch (tempSegs(0).type) {
+ case SEG_TBLEDGE:
+ case SEG_STRLIN:
+ case SEG_DIMLIN:
+ case SEG_BENCH:
+ for (int i=0;i<2;i++) {
+ pos = i==0?context->p0:context->p1;
+ pos.x -= context->rot_center.x;
+ pos.y -= context->rot_center.y;
+ context->segPtr[segInx].u.l.pos[i] = pos;
}
-
- pos = points(polyInx);
- if ( mergePoints ) {
- for (inx=polyInx+1; inx<segPtr[segInx].u.p.cnt; inx++)
- segPtr[segInx].u.p.pts[inx-1] = segPtr[segInx].u.p.pts[inx];
- segPtr[segInx].u.p.cnt--;
-/*fprintf( stderr, "Merging with vertix %d\n", polyInx );*/
- break;
+ break;
+ case SEG_CRVLIN:
+ case SEG_FILCRCL:
+ pc = context->pc;
+ pc.x -= context->rot_center.x;
+ pc.y -= context->rot_center.y;
+ context->segPtr[segInx].u.c.center = pc;
+ p0 = context->p0;
+ p0.x -= context->rot_center.x;
+ p0.y -= context->rot_center.y;
+ p1 = context->p1;
+ p1.x -= context->rot_center.x;
+ p1.y -= context->rot_center.y;
+ context->segPtr[segInx].u.c.a0 = FindAngle(pc,p0);
+ context->segPtr[segInx].u.c.a1 = NormalizeAngle(FindAngle(pc,p1)-FindAngle(pc,p0));
+ if (context->segPtr[segInx].u.c.a1 == 0) context->segPtr[segInx].u.c.a1 = 360.0;
+ context->segPtr[segInx].u.c.radius = context->radius;
+ break;
+ case SEG_POLY:
+ case SEG_FILPOLY:
+ for (int i=0;i<4;i++) {
+ pos = points(i).pt;
+ pos.x -= context->rot_center.x;
+ pos.y -= context->rot_center.y;
+ context->segPtr[segInx].u.p.pts[i].pt = pos;
}
- pos.x -= orig.x;
- pos.y -= orig.y;
- Rotate( &pos, zero, -angle );
- segPtr[segInx].u.p.pts[polyInx] = pos;
- }
- break;
- default:
- ;
+ break;
+ default:
+ break;
}
+ context->state = MOD_NONE;
+ context->rotate_state = FALSE;
+ context->last_inx = -1;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ DYNARR_RESET(trkSeg_t,tempSegs_da);
+ DrawNewTrack( context->trk );
return C_TERMINATE;
+ case C_REDRAW:
+ if (polyMode) return DrawGeomPolyModify(action,pos,context);
+ if (context->state == MOD_NONE) return C_CONTINUE;
+ DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack);
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ break;
+ case C_CANCEL:
+ case C_CONFIRM:
+ case C_TERMINATE:
+ context->state = MOD_NONE;
+ context->rotate_state = FALSE;
+ context->rot_moved = FALSE;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ DYNARR_RESET(trkSeg_t,tempSegs_da);
+ break;
default:
;
}
- return C_ERROR;
+ return C_CONTINUE;
}
diff --git a/app/bin/drawgeom.h b/app/bin/drawgeom.h
index d9f54f8..45814d7 100644
--- a/app/bin/drawgeom.h
+++ b/app/bin/drawgeom.h
@@ -47,7 +47,8 @@
#define OP_FILLBOX (16)
#define OP_FILLPOLY (17)
#define OP_BEZLIN (18)
-#define OP_LAST (OP_BEZLIN)
+#define OP_POLYLINE (19)
+#define OP_LAST (OP_POLYLINE)
typedef struct {
void (*message)( char *, ... );
@@ -55,20 +56,74 @@ typedef struct {
drawCmd_t *D;
long Op;
wDrawColor Color;
- long Width;
+ long line_Width;
+ double width;
+ ANGLE_T angle;
+ double length;
+ double radius;
long benchOption;
+ drawLineType_e lineType;
int State;
+ int index;
curveData_t ArcData;
ANGLE_T ArcAngle;
int Started;
BOOL_T Changed;
} drawContext_t;
+typedef enum {MOD_NONE, MOD_STARTED, MOD_SELECTED_PT, MOD_AFTER_PT,
+ MOD_ORIGIN, MOD_AFTER_ORIG } ModState_e;
+
+typedef struct {
+ void (*message)( char *, ... );
+ void (*Redraw)( void );
+ drawCmd_t *D;
+ double length;
+ ANGLE_T rel_angle;
+ double radius;
+ ANGLE_T arc_angle;
+ int last_inx;
+ ANGLE_T abs_angle;
+ double height;
+ double width;
+ int prev_inx;
+ int max_inx;
+ track_p trk;
+ char type;
+ coOrd orig; //Origin Pos
+ ANGLE_T angle; //Origin Angle
+ wIndex_t segCnt;
+ trkSeg_p segPtr;
+ wBool_t selected;
+ wBool_t circle;
+ ModState_e state;
+ coOrd rel_center;
+ coOrd rot_center;
+ wBool_t rot_moved;
+ coOrd translate_center;
+ coOrd moved;
+ coOrd arm;
+ coOrd new_arm;
+ ANGLE_T rot_angle;
+ coOrd p0;
+ coOrd p1;
+ coOrd pm;
+ coOrd pc;
+ DIST_T disp;
+ wBool_t rotate_state;
+ wBool_t open;
+ wBool_t filled;
+ PolyType_e subtype;
+ } drawModContext_t;
+
+typedef enum {LENGTH_UPDATE, WIDTH_UPDATE} drawUpdateType_e;
+
extern drawContext_t * drawContext;
extern wDrawColor lineColor;
extern long lineWidth;
void DrawGeomOp( void * );
-STATUS_T DrawGeomMouse( wAction_t, coOrd, drawContext_t * );
-STATUS_T DrawGeomModify( coOrd, ANGLE_T, wIndex_t, trkSeg_p, wAction_t, coOrd, wBool_t );
-#endif //HAVE_DRAWGEOM_H \ No newline at end of file
+STATUS_T DrawGeomMouse( wAction_t, coOrd, drawContext_t *);
+STATUS_T DrawGeomModify( wAction_t, coOrd, drawModContext_t * );
+STATUS_T DrawGeomOriginMove(wAction_t, coOrd, drawModContext_t * );
+#endif //HAVE_DRAWGEOM_H
diff --git a/app/bin/dxfoutput.c b/app/bin/dxfoutput.c
index 69c6df4..214f63c 100644
--- a/app/bin/dxfoutput.c
+++ b/app/bin/dxfoutput.c
@@ -135,15 +135,19 @@ static void DxfFillPoly(
drawCmd_p d,
int cnt,
coOrd * pts,
- wDrawColor color)
+ int * types,
+ wDrawColor color,
+ wDrawWidth width,
+ int fill,
+ int open )
{
int inx;
for (inx=1; inx<cnt; inx++) {
- DxfLine(d, pts[inx-1], pts[inx], 0, color);
+ DxfLine(d, pts[inx-1], pts[inx], width, color);
}
-
- DxfLine(d, pts[cnt-1], pts[0], 0, color);
+ if (!open)
+ DxfLine(d, pts[cnt-1], pts[0], width, color);
}
static void DxfFillCircle(drawCmd_p d, coOrd center, DIST_T radius,
@@ -192,7 +196,7 @@ static int DoExportDXFTracks(
}
oldLocale = SaveLocale("C");
- wSetCursor(wCursorWait);
+ wSetCursor(mainD.d, wCursorWait);
time(&clock);
DxfPrologue(&command, 10, 0.0, 0.0, mapD.size.x, mapD.size.y);
@@ -208,7 +212,7 @@ static int DoExportDXFTracks(
fclose(dxfF);
RestoreLocale(oldLocale);
Reset();
- wSetCursor(wCursorNormal);
+ wSetCursor(mainD.d, defaultCursor);
return TRUE;
}
diff --git a/app/bin/elev.c b/app/bin/elev.c
index 6b86bc1..a9e5fee 100644
--- a/app/bin/elev.c
+++ b/app/bin/elev.c
@@ -137,7 +137,8 @@ BOOL_T ComputeElev(
EPINX_T ep,
BOOL_T onpath,
DIST_T *elevR,
- DIST_T *gradeR )
+ DIST_T *gradeR,
+ BOOL_T force )
{
DIST_T grade;
DIST_T elev0, elev1, dist0, dist1;
@@ -176,6 +177,7 @@ if (oldElevationEvaluation) {
elev0 = 0.0;
}
} else {
+
track_p trk1;
EPINX_T ep1;
grade = -1;
@@ -184,30 +186,40 @@ if (oldElevationEvaluation) {
elev0 = GetTrkEndElevHeight(trk,ep);
rc = FALSE;
} else {
- elev0 = GetElevation( trk );
- dist0 = GetTrkLength( trk, ep, -1 );
+ if (force || (!GetTrkEndElevCachedHeight(trk,ep,&elev0,&dist0))) {
+ elev0 = GetElevation( trk );
+ dist0 = GetTrkLength( trk, ep, -1 );
+ }
+ SetTrkEndElevCachedHeight(trk,ep,elev0,dist0);
trk1 = GetTrkEndTrk( trk, ep );
if (trk1!=NULL) {
ep1 = GetEndPtConnectedToMe(trk1,trk);
- elev1 = GetElevation( trk1 );
- dist1 = GetTrkLength( trk1, ep1, -1 );
+ if (force || (!GetTrkEndElevCachedHeight(trk1,ep1,&elev1,&dist1))) {
+ elev1 = GetElevation( trk1 );
+ dist1 = GetTrkLength( trk1, ep1, -1 );
+ }
+ SetTrkEndElevCachedHeight(trk1,ep1,elev1,dist1);
if (dist0+dist1>0.1) {
grade = (elev1-elev0)/(dist0+dist1);
elev0 += grade*dist0;
} else {
elev0 = (elev0+elev1)/2.0;
rc = FALSE;
+ SetTrkEndElevCachedHeight(trk,ep,elev0,dist0);
+ SetTrkEndElevCachedHeight(trk1,ep1,elev0,dist1);
}
} else {
grade = 0.0;
}
+
}
}
- if ( elevR )
- *elevR = elev0;
- if ( gradeR )
- *gradeR = grade;
- return rc;
+if ( elevR )
+ *elevR = elev0;
+if ( gradeR )
+ *gradeR = grade;
+return rc;
+
}
@@ -988,7 +1000,7 @@ EXPORT void RecomputeElevations( void )
PropogateForkElevs();
PropogateDefElevs();
FindIslandElevs();
- MainRedraw();
+ MainRedraw(); // RecomputeElevations
LOG( log_fillElev, 1, ( "%s: Total (%ld)\n", elevPrefix, wGetTimer()-time0 ) )
if ( log_dumpElev > 0 ) {
track_p trk;
@@ -1087,6 +1099,7 @@ EXPORT void ClrTrkElev( track_p trk )
needElevUpdate = TRUE;
DrawTrackElev( trk, &mainD, FALSE );
ClrTrkBits( trk, TB_ELEVPATH );
+
}
@@ -1124,11 +1137,11 @@ EXPORT void SetTrkElevModes( BOOL_T connect, track_p trk0, EPINX_T ep0, track_p
update = FALSE;;
} else if ( connect ) {
if ( mode0 == ELEV_ALONE ) {
- ComputeElev( trk1, ep1, FALSE, &elev, NULL );
+ ComputeElev( trk1, ep1, FALSE, &elev, NULL, TRUE );
PropogateElevMode( trk0, elev, ELEV_ISLAND );
update = FALSE;
} else if ( mode1 == ELEV_ALONE ) {
- ComputeElev( trk0, ep0, FALSE, &elev, NULL );
+ ComputeElev( trk0, ep0, FALSE, &elev, NULL, TRUE );
PropogateElevMode( trk1, elev, ELEV_ISLAND );
update = FALSE;
}
@@ -1287,8 +1300,7 @@ EXPORT void DrawTrackElev( track_cp trk, drawCmd_p d, BOOL_T drawIt )
(labelScale < d->scale) ||
(!GetTrkOnElevPath( trk, &elev )) ||
((GetTrkBits(trk)&TB_ELEVPATH) == 0) ||
- (d->funcs->options & wDrawOptTemp) != 0 ||
- (d->options & DC_QUICK) != 0 )
+ (d->options & DC_SIMPLE) != 0 )
return;
if ( !GetCurveMiddle( trk, &pos ) ) {
diff --git a/app/bin/file2uri.c b/app/bin/file2uri.c
new file mode 100644
index 0000000..a9d8f4f
--- /dev/null
+++ b/app/bin/file2uri.c
@@ -0,0 +1,83 @@
+/** \file file2uri.c
+ * Conversion for filename to URI and reverse
+ */
+
+ /* XTrackCAD - Model Railroad CAD
+ * Copyright (C) 2019 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 <string.h>
+#include <stdio.h>
+#include "wlib.h"
+
+static char *reservedChars = "?#[]@!$&'()*+,;= ";
+
+unsigned
+File2URI(char *fileName, unsigned resultLen, char *resultBuffer)
+{
+ char *currentSource = fileName;
+ char *currentDest;
+
+ currentDest = resultBuffer;
+
+ while (*currentSource && ((unsigned)(currentDest - resultBuffer) < resultLen - 1)) {
+ if (*currentSource == FILE_SEP_CHAR[ 0 ]) {
+ *currentDest++ = '/';
+ currentSource++;
+ continue;
+ }
+ if (strchr(reservedChars, *currentSource))
+ {
+ sprintf(currentDest, "%%%02x", *currentSource);
+ currentSource++;
+ currentDest += 3;
+ } else {
+ *currentDest++ = *currentSource++;
+ }
+
+ }
+ *currentDest = '\0';
+ return(strlen(resultBuffer));
+}
+
+unsigned
+URI2File(char *encodedFileName, unsigned resultLen, char *resultBuffer)
+{
+ char *currentSource = encodedFileName;
+ char *currentDest = resultBuffer;
+
+ currentSource = encodedFileName;
+ while (*currentSource && ((unsigned)(currentDest - resultBuffer) < resultLen - 1)) {
+ if (*currentSource == '/') {
+ *currentDest++ = FILE_SEP_CHAR[0];
+ currentSource++;
+ continue;
+ }
+ if (*currentSource == '%') {
+ char hexCode[3];
+ memcpy(hexCode, currentSource + 1, 2);
+ hexCode[2] = '\0';
+ sscanf(hexCode, "%x", (unsigned int*)currentDest);
+ currentDest++;
+ currentSource += 3;
+ } else {
+ *currentDest++ = *currentSource++;
+ }
+ }
+ *currentDest = '\0';
+ return(strlen(resultBuffer));
+}
diff --git a/app/bin/file2uri.h b/app/bin/file2uri.h
new file mode 100644
index 0000000..921976a
--- /dev/null
+++ b/app/bin/file2uri.h
@@ -0,0 +1,27 @@
+/** \file file2uri.h
+ * Include file for file2uri.c
+ */
+
+ /* XTrackCAD - Model Railroad CAD
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef HAVE_FILE2URI_H
+unsigned File2URI(char *fileName, unsigned resultLen, char *resultBuffer);
+unsigned URI2File(char *encodedFileName, unsigned resultLen, char *resultBuffer);
+#endif // !HAVE_FILE2URI_H
+
diff --git a/app/bin/fileio.c b/app/bin/fileio.c
index 4e2a21d..cb0c8de 100644
--- a/app/bin/fileio.c
+++ b/app/bin/fileio.c
@@ -33,12 +33,10 @@
#include <time.h>
#include <ctype.h>
#ifdef WINDOWS
-#include <io.h>
-#include <windows.h>
- //#if _MSC_VER >=1400
- // #define strdup _strdup
- //#endif
-#else
+ #include <io.h>
+ #define W_OK (2)
+ #define access _access
+ #include <windows.h>
#endif
#include <sys/stat.h>
#include <stdarg.h>
@@ -48,35 +46,52 @@
#include <assert.h>
+#include <cJSON.h>
+
+#include "archive.h"
#include "common.h"
#include "compound.h"
#include "cselect.h"
#include "cundo.h"
#include "custom.h"
+#include "directory.h"
#include "draw.h"
#include "fileio.h"
+#include "fcntl.h"
#include "i18n.h"
#include "layout.h"
+#include "manifest.h"
#include "messages.h"
#include "misc.h"
#include "param.h"
+#include "include/paramfile.h"
#include "paths.h"
#include "track.h"
#include "utility.h"
#include "version.h"
+#include "dynstring.h"
+
+#ifdef WINDOWS
+#include "include/utf8convert.h"
+#endif // WINDOWS
/*#define TIME_READTRACKFILE*/
+#define COPYBLOCKSIZE 1024
+
EXPORT const char * workingDir;
EXPORT const char * libDir;
-static char * customPath = NULL;
-static char * customPathBak = NULL;
+EXPORT wMenuList_p fileList_ml;
EXPORT char * clipBoardN;
+static coOrd paste_offset, cursor_offset;
+
+EXPORT wBool_t bExample = FALSE;
+EXPORT wBool_t bReadOnly = FALSE;
+
-static int log_paramFile;
#ifdef WINDOWS
#define rename( F1, F2 ) Copyfile( F1, F2 )
@@ -151,20 +166,13 @@ RestoreLocale( char * locale )
EXPORT FILE * paramFile = NULL;
char *paramFileName;
EXPORT wIndex_t paramLineNum = 0;
-EXPORT char paramLine[STR_LONG_SIZE];
+EXPORT char paramLine[STR_HUGE_SIZE];
EXPORT char * curContents;
EXPORT char * curSubContents;
-static long paramCheckSum;
#define PARAM_DEMO (-1)
-typedef struct {
- char * name;
- readParam_t proc;
- } paramProc_t;
-static dynArr_t paramProc_da;
-#define paramProc(N) DYNARR_N( paramProc_t, paramProc_da, N )
-
+dynArr_t paramProc_da;
EXPORT void Stripcr( char * line )
{
@@ -179,13 +187,6 @@ EXPORT void Stripcr( char * line )
*cp = '\0';
}
-EXPORT void ParamCheckSumLine( char * line )
-{
- long mult=1;
- while ( *line )
- paramCheckSum += (((long)(*line++))&0xFF)*(mult++);
-}
-
EXPORT char * GetNextLine( void )
{
if (!paramFile) {
@@ -193,7 +194,12 @@ EXPORT char * GetNextLine( void )
return NULL;
}
if (fgets( paramLine, sizeof paramLine, paramFile ) == NULL) {
- AbortProg( "Permature EOF on %s", paramFileName );
+ sprintf( message, "INPUT ERROR: premature EOF on %s", paramFileName );
+ wNoticeEx( NT_ERROR, message, _("Ok"), NULL );
+ if ( paramFile ) {
+ fclose( paramFile );
+ paramFile = NULL;
+ }
}
Stripcr( paramLine );
ParamCheckSumLine( paramLine );
@@ -234,9 +240,14 @@ EXPORT int InputError(
}
strcat( mp, _("\nDo you want to continue?") );
if (!(ret = wNoticeEx( NT_ERROR, message, _("Continue"), _("Stop") ))) {
- if ( paramFile )
+ if ( paramFile ) {
fclose(paramFile);
- paramFile = NULL;
+ paramFile = NULL;
+ }
+ if ( paramFileName ) {
+ free( paramFileName );
+ paramFileName = NULL;
+ }
}
return ret;
}
@@ -251,6 +262,7 @@ EXPORT void SyntaxError(
TRUE, event, actual, expected );
}
+
/**
* Parse a line in XTrackCAD's file format
*
@@ -258,6 +270,24 @@ EXPORT void SyntaxError(
* \param format IN ???
*
* \return FALSE in case of parsing error, TRUE on success
+ * In the error case, InputError had been called which may have closed the input file (paramFile)
+ *
+ * format chars are:
+ * 0 - read a number and discard
+ * X - no read, *pi = 0
+ * Y - no read, *pf = 0L
+ * Z - no read, *pl = 0.0
+ * L - *pi = number
+ * d - *pi = number
+ * w - *pf = read a width
+ * u - *pul = number
+ * l - *pl = number
+ * f - *pf = number
+ * z - *pf = 0.0
+ * p - *pp = ( number, number ) a coOrd
+ * s - *ps = string
+ * q - *ps = quoted string
+ * c - *qp = position of next non-space char or NULL
*/
EXPORT BOOL_T GetArgs(
@@ -266,7 +296,6 @@ EXPORT BOOL_T GetArgs(
... )
{
char * cp, * cq;
- int argNo;
long * pl;
unsigned long *pul;
int * pi;
@@ -276,25 +305,24 @@ EXPORT BOOL_T GetArgs(
char ** qp;
va_list ap;
char *oldLocale = NULL;
+ char * sError = NULL;
oldLocale = SaveLocale("C");
cp = line;
va_start( ap, format );
- for (argNo=1;*format;argNo++,format++) {
+ for ( ; sError==NULL && *format; format++ ) {
while (isspace((unsigned char)*cp)) cp++;
if (!*cp && strchr( "XZYzc", *format ) == NULL ) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: EOL unexpected", TRUE, argNo );
- return FALSE;
+ sError = "EOL unexpected";
+ break;
}
switch (*format) {
case '0':
(void)strtol( cp, &cq, 10 );
if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected integer", TRUE, argNo );
- return FALSE;
+ sError = "%s: expected integer";
+ break;
}
cp = cq;
break;
@@ -314,9 +342,8 @@ EXPORT BOOL_T GetArgs(
pi = va_arg( ap, int * );
*pi = (int)strtol( cp, &cq, 10 );
if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected integer", TRUE, argNo );
- return FALSE;
+ sError = "%s: expected integer";
+ break;
}
cp = cq;
break;
@@ -324,9 +351,8 @@ EXPORT BOOL_T GetArgs(
pi = va_arg( ap, int * );
*pi = (int)strtol( cp, &cq, 10 );
if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected integer", TRUE, argNo );
- return FALSE;
+ sError = "%s: expected integer";
+ break;
}
cp = cq;
break;
@@ -334,9 +360,8 @@ EXPORT BOOL_T GetArgs(
pf = va_arg( ap, FLOAT_T * );
*pf = (FLOAT_T)strtol( cp, &cq, 10 );
if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected integer", TRUE, argNo );
- return FALSE;
+ sError = "%s: expected integer";
+ break;
}
if (*cq == '.')
*pf = strtod( cp, &cq );
@@ -348,9 +373,8 @@ EXPORT BOOL_T GetArgs(
pul = va_arg( ap, unsigned long * );
*pul = strtoul( cp, &cq, 10 );
if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected integer", TRUE, argNo );
- return FALSE;
+ sError = "%s: expected integer";
+ break;
}
cp = cq;
break;
@@ -358,9 +382,8 @@ EXPORT BOOL_T GetArgs(
pl = va_arg( ap, long * );
*pl = strtol( cp, &cq, 10 );
if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected integer", TRUE, argNo );
- return FALSE;
+ sError = "%s: expected integer";
+ break;
}
cp = cq;
break;
@@ -368,43 +391,27 @@ EXPORT BOOL_T GetArgs(
pf = va_arg( ap, FLOAT_T * );
*pf = strtod( cp, &cq );
if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected float", TRUE, argNo );
- return FALSE;
+ sError = "%s: expected float";
+ break;
}
cp = cq;
break;
case 'z':
pf = va_arg( ap, FLOAT_T * );
-#ifdef LATER
- if ( paramVersion >= 9 ) {
- *pf = strtod( cp, &cq );
- if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected float", TRUE, argNo );
- return FALSE;
- }
- cp = cq;
- } else {
- *pf = 0.0;
- }
-#endif
*pf = 0.0;
break;
case 'p':
pp = va_arg( ap, coOrd * );
p.x = strtod( cp, &cq );
if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected float", TRUE, argNo );
- return FALSE;
+ sError = "%s: expected float";
+ break;
}
cp = cq;
p.y = strtod( cp, &cq );
if (cp == cq) {
- RestoreLocale(oldLocale);
- InputError( "Arg %d: expected float", TRUE, argNo );
- return FALSE;
+ sError = "%s: expected float";
+ break;
}
cp = cq;
*pp = p;
@@ -446,7 +453,10 @@ EXPORT BOOL_T GetArgs(
} else {
message[0] = '\0';
}
- *qp = (char*)MyStrdup(message);
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(message);
+#endif
+ *qp = (char*)ConvertFromEscapedText(message);
break;
case 'c':
qp = va_arg( ap, char * * );
@@ -457,14 +467,76 @@ EXPORT BOOL_T GetArgs(
*qp = NULL;
break;
default:
- AbortProg( "getArgs: bad format char" );
+ AbortProg( "getArgs: bad format char: %c", *format );
}
}
va_end( ap );
RestoreLocale(oldLocale);
+ if ( sError ) {
+ InputError( sError, TRUE, cp );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+wBool_t IsEND( char * sEnd )
+{
+ char * cp;
+ wBool_t bAllowNakedENDs = paramVersion < 12;
+ for( cp = paramLine; *cp && (isspace( *cp ) || *cp == '\t'); cp++ );
+ if ( strncmp( cp, sEnd, strlen(sEnd) ) == 0 )
+ cp += strlen( sEnd );
+ else if ( bAllowNakedENDs && strncmp( cp, "END", 3 ) == 0 )
+ cp += 3;
+ else
+ return FALSE;
+ for ( ; *cp && isspace( *cp ); cp++ );
+ if ( *cp != '\0' )
+ return FALSE;
return TRUE;
}
+
+/**
+ * Read the text for a note/car. Lines are read from the input file
+ * until the END statement is found.
+ *
+ * \todo Handle premature end as an error
+ *
+ * \return pointer to string, has to be myfree'd by caller
+ */
+
+char *
+ReadMultilineText()
+{
+ char *string;
+ DynString noteText;
+ DynStringMalloc(&noteText, 0);
+ char *line;
+
+ line = GetNextLine();
+
+ while ( !IsEND("END") ) {
+ DynStringCatCStr(&noteText, line);
+ DynStringCatCStr(&noteText, "\n");
+ line = GetNextLine();
+ }
+ string = MyStrdup(DynStringToCStr(&noteText));
+ string[strlen(string) - 1] = '\0';
+
+#ifdef WINDOWS
+ if (wIsUTF8(string)) {
+ ConvertUTF8ToSystem(string);
+ }
+#endif // WINDOWS
+
+ DynStringFree(&noteText);
+ return(string);
+}
+
+
EXPORT wBool_t ParseRoomSize(
char * s,
coOrd * roomSizeRet )
@@ -493,179 +565,37 @@ EXPORT wBool_t ParseRoomSize(
return FALSE;
}
-
+/**
+ * Parameter file parser definitions
+ *
+ * \param [IN] name command
+ * \param [IN] proc function for reading the parameter definition
+ * \param [IN] delete if not NULL function for freeing the definition
+ */
EXPORT void AddParam(
char * name,
- readParam_t proc )
+ readParam_t proc)
{
DYNARR_APPEND( paramProc_t, paramProc_da, 10 );
paramProc(paramProc_da.cnt-1).name = name;
paramProc(paramProc_da.cnt-1).proc = proc;
}
-
-EXPORT BOOL_T ReadParams(
- long key,
- const char * dirName,
- const char * fileName )
+EXPORT char * PutTitle( char * cp )
{
- FILE * oldFile;
- char *cp;
- wIndex_t oldLineNum;
- wIndex_t pc;
- long oldCheckSum;
- long checkSum=0;
- BOOL_T checkSummed;
- long paramVersion = -1;
- char *oldLocale = NULL;
+ static char *title;
+ char * tp;
+ unsigned cnt = strlen(cp) * 2 + 3; // add 3 for quotes and terminating \0
- if (dirName) {
- MakeFullpath(&paramFileName, dirName, fileName, NULL);
+ if (!title) {
+ title = MyMalloc(cnt);
} else {
- MakeFullpath(&paramFileName, fileName, NULL);
- }
- paramLineNum = 0;
- curBarScale = -1;
- curContents = strdup( fileName );
- curSubContents = curContents;
-
-LOG1( log_paramFile, ("ReadParam( %s )\n", fileName ) )
-
- oldLocale = SaveLocale("C");
-
- paramFile = fopen( paramFileName, "r" );
- if (paramFile == NULL) {
- /* Reset the locale settings */
- RestoreLocale( oldLocale );
-
- NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Parameter"), paramFileName, strerror(errno) );
-
- return FALSE;
- }
- paramCheckSum = key;
- paramLineNum = 0;
- checkSummed = FALSE;
- while ( paramFile && ( fgets(paramLine, 256, paramFile) ) != NULL ) {
- paramLineNum++;
- Stripcr( paramLine );
- if (strncmp( paramLine, "CHECKSUM ", 9 ) == 0) {
- checkSum = atol( paramLine+9 );
- checkSummed = TRUE;
- goto nextLine;
- }
- ParamCheckSumLine( paramLine );
- if (paramLine[0] == '#') {
- /* comment */
- } else if (paramLine[0] == 0) {
- /* empty paramLine */
- } else if (strncmp( paramLine, "INCLUDE ", 8 ) == 0) {
- cp = &paramLine[8];
- while (*cp && isspace((unsigned char)*cp)) cp++;
- if (!*cp) {
- InputError( "INCLUDE - no file name", TRUE );
-
- /* Close file and reset the locale settings */
- if (paramFile) fclose(paramFile);
- RestoreLocale( oldLocale );
-
- return FALSE;
- }
- oldFile = paramFile;
- oldLineNum = paramLineNum;
- oldCheckSum = paramCheckSum;
- ReadParams( key, dirName, cp );
- paramFile = oldFile;
- paramLineNum = oldLineNum;
- paramCheckSum = oldCheckSum;
- if (dirName) {
- MakeFullpath(&paramFileName, dirName, fileName, NULL);
- } else {
- MakeFullpath(&paramFileName, fileName);
- }
- } else if (strncmp( paramLine, "CONTENTS ", 9) == 0 ) {
- curContents = MyStrdup( paramLine+9 );
- curSubContents = curContents;
- } else if (strncmp( paramLine, "SUBCONTENTS ", 12) == 0 ) {
- curSubContents = MyStrdup( paramLine+12 );
- } else if (strncmp( paramLine, "PARAM ", 6) == 0 ) {
- paramVersion = atol( paramLine+6 );
- } else {
- for (pc = 0; pc < paramProc_da.cnt; pc++ ) {
- if (strncmp( paramLine, paramProc(pc).name,
- strlen(paramProc(pc).name)) == 0 ) {
- paramProc(pc).proc( paramLine );
- goto nextLine;
- }
- }
- InputError( "Unknown param line", TRUE );
- }
- nextLine:;
+ title = MyRealloc(title, cnt);
}
- if ( key ) {
- if ( !checkSummed || checkSum != paramCheckSum ) {
- /* Close file and reset the locale settings */
- if (paramFile) fclose(paramFile);
- RestoreLocale( oldLocale );
-
- NoticeMessage( MSG_PROG_CORRUPTED, _("Ok"), NULL, paramFileName );
-
- return FALSE;
- }
- }
- if (paramFile)fclose( paramFile );
- free(paramFileName);
- paramFileName = NULL;
- RestoreLocale( oldLocale );
-
- return TRUE;
-}
+ tp = title;
-static void ReadCustom( void )
-{
- FILE * f;
- MakeFullpath(&customPath, workingDir, sCustomF, NULL);
- customPathBak = MyStrdup( customPath );
- customPathBak[ strlen(customPathBak)-1 ] = '1';
- f = fopen( customPath, "r" );
- if ( f != NULL ) {
- fclose( f );
- curParamFileIndex = PARAM_CUSTOM;
- ReadParams( 0, workingDir, sCustomF );
- }
-}
-
-
-/*
- * Open the file and then set the locale to "C". Old locale will be copied to
- * oldLocale. After the required file I/O is done, the caller must call
- * CloseCustom() with the same locale value that was returned in oldLocale by
- * this function.
- */
-EXPORT FILE * OpenCustom( char *mode )
-{
- FILE * ret = NULL;
-
- if (inPlayback)
- return NULL;
- if ( *mode == 'w' )
- rename( customPath, customPathBak );
- if (customPath) {
- ret = fopen( customPath, mode );
- if (ret == NULL) {
- NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Custom"), customPath, strerror(errno) );
- }
- }
-
- return ret;
-}
-
-
-EXPORT char * PutTitle( char * cp )
-{
- static char title[STR_SIZE];
- char * tp = title;
- while (*cp && (tp-title)<=(sizeof title)-3) {
+ while (*cp ) {
if (*cp == '\"') {
*tp++ = '\"';
*tp++ = '\"';
@@ -677,6 +607,16 @@ EXPORT char * PutTitle( char * cp )
if ( *cp )
NoticeMessage( _("putTitle: title too long: %s"), _("Ok"), NULL, title );
*tp = '\0';
+
+#ifdef WINDOWS
+ if(RequiresConvToUTF8(title)) {
+ char *out = MyMalloc(cnt);
+ wSystemToUTF8(title, out, cnt);
+ strcpy(title, out);
+ MyFree(out);
+ }
+#endif // WINDOWS
+
return title;
}
@@ -694,20 +634,25 @@ void SetWindowTitle( void )
return;
filename = GetLayoutFilename();
- sprintf( message, "%s%s - %s(%s)",
+ sprintf( message, "%s%s%s - %s(%s)",
(filename && filename[0])?filename: _("Unnamed Trackplan"),
- changed>0?"*":"", sProdName, sVersion );
+ bReadOnly?_(" (R/O)"):"",
+ changed>0?"*":"",
+ sProdName, sVersion );
wWinSetTitle( mainW, message );
}
-
+
+
+
/*****************************************************************************
*
* LOAD / SAVE TRACKS
*
*/
-static struct wFilSel_t * loadFile_fs;
-static struct wFilSel_t * saveFile_fs;
+static struct wFilSel_t * loadFile_fs = NULL;
+static struct wFilSel_t * saveFile_fs = NULL;
+static struct wFilSel_t * examplesFile_fs = NULL;
static wWin_p checkPointingW;
static paramData_t checkPointingPLs[] = {
@@ -716,6 +661,7 @@ static paramGroup_t checkPointingPG = { "checkpoint", 0, checkPointingPLs, sizeo
static char * checkPtFileName1;
static char * checkPtFileName2;
+static char * checkPtFileNameBackup;
/** Read the layout design.
*
@@ -760,8 +706,12 @@ static BOOL_T ReadTrackFile(
InfoMessage("0");
count = 0;
+ int skipLines = 0;
+ BOOL_T skip = FALSE;
while ( paramFile && ( fgets(paramLine, sizeof paramLine, paramFile) ) != NULL ) {
count++;
+ BOOL_T old_skip = skip;
+ skip = FALSE;
if (count%10 == 0) {
InfoMessage( "%d", count );
wFlush();
@@ -781,8 +731,8 @@ static BOOL_T ReadTrackFile(
}
if (ReadTrack( paramLine )) {
-
- } else if (strncmp( paramLine, "END", 3 ) == 0) {
+ continue;
+ } else if (IsEND( END_TRK_FILE ) ) {
break;
} else if (strncmp( paramLine, "VERSION ", 8 ) == 0) {
paramVersion = strtol( paramLine+8, &cp, 10 );
@@ -804,8 +754,14 @@ static BOOL_T ReadTrackFile(
if( !(ret = InputError( "unknown command", TRUE )))
break;
} else if (strncmp( paramLine, "TITLE1 ", 7 ) == 0) {
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(paramLine + 7);
+#endif // WINDOWS
SetLayoutTitle(paramLine + 7);
} else if (strncmp( paramLine, "TITLE2 ", 7 ) == 0) {
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(paramLine + 7);
+#endif // WINDOWS
SetLayoutSubtitle(paramLine + 7);
} else if (strncmp( paramLine, "ROOMSIZE", 8 ) == 0) {
if ( ParseRoomSize( paramLine+8, &roomSize ) ) {
@@ -829,39 +785,44 @@ static BOOL_T ReadTrackFile(
} else if (strncmp( paramLine, "LAYERS ", 7 ) == 0) {
ReadLayers( paramLine+7 );
} else {
- if( !(ret = InputError( "unknown command", TRUE )))
- break;
+ if (!old_skip) {
+ if (InputError(_("Unknown layout file object - skip until next good object?"), TRUE)) { //OK to carry on
+ /* SKIP until next main line we recognize */
+ skip = TRUE;
+ skipLines++;
+ continue;
+ } else {
+ break; //Close File
+ }
+ } else skip = TRUE;
+ skipLines++;
}
}
- if (paramFile)
+ if (paramFile) {
fclose(paramFile);
+ paramFile = NULL;
+ }
if( ret ) {
if (!noSetCurDir)
SetCurrentPath( LAYOUTPATHKEY, fileName );
-
- if (full) {
-// SetCurrentPath(LAYOUTPATHKEY, pathName);
- SetLayoutFullPath(pathName);
- //strcpy(curPathName, pathName);
- //curFileName = &curPathName[fileName-pathName];
- SetWindowTitle();
- }
}
+ if (skipLines>0)
+ NoticeMessage( MSG_LAYOUT_LINES_SKIPPED, _("Ok"), NULL, paramFileName, skipLines);
+
RestoreLocale( oldLocale );
paramFile = NULL;
free(paramFileName);
- paramFileName = NULL;
+ paramFileName = NULL;
InfoMessage( "%d", count );
return ret;
}
-
-EXPORT int LoadTracks(
+int LoadTracks(
int cnt,
char **fileName,
void * data)
@@ -869,18 +830,23 @@ EXPORT int LoadTracks(
#ifdef TIME_READTRACKFILE
long time0, time1;
#endif
- char *nameOfFile;
+ char *nameOfFile = NULL;
+
+ char *extOfFile;
assert( fileName != NULL );
- assert( cnt == 1 );
+ assert( cnt == 1 );
- SetCurrentPath(LAYOUTPATHKEY, fileName[0]);
+ if ( ! bExample )
+ SetCurrentPath(LAYOUTPATHKEY, fileName[0]);
+ bReadOnly = bExample;
paramVersion = -1;
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
Reset();
ClearTracks();
ResetLayers();
checkPtMark = changed = 0;
+ LayoutBackGroundInit(TRUE); //Keep values of background -> will be overriden my archive
UndoSuspend();
useCurrentLayer = FALSE;
#ifdef TIME_READTRACKFILE
@@ -888,8 +854,119 @@ EXPORT int LoadTracks(
#endif
nameOfFile = FindFilename( fileName[ 0 ] );
- if (ReadTrackFile( fileName[ 0 ], nameOfFile, TRUE, FALSE, TRUE )) {
- wMenuListAdd( fileList_ml, 0, nameOfFile, MyStrdup(fileName[0]) );
+ /*
+ * Support zipped filetype
+ */
+ extOfFile = FindFileExtension( nameOfFile);
+
+ BOOL_T zipped = FALSE;
+ BOOL_T loadXTC = TRUE;
+ char * full_path = strdup(fileName[0]);
+
+ if (extOfFile && (strcmp(extOfFile, ZIPFILETYPEEXTENSION )==0)) {
+
+ char * zip_input = GetZipDirectoryName(ARCHIVE_READ);
+
+ //If zipped unpack file into temporary input dir (cleared and re-created)
+
+ DeleteDirectory(zip_input);
+ SafeCreateDir(zip_input);
+
+ if (UnpackArchiveFor(fileName[0], nameOfFile, zip_input, FALSE)) {
+
+ char * manifest_file;
+
+ MakeFullpath(&manifest_file, zip_input, "manifest.json", NULL);
+
+ char * manifest = 0;
+ long length;
+
+ FILE * f = fopen (manifest_file, "rb");
+
+ if (f)
+ {
+ fseek(f, 0, SEEK_END);
+ length = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ manifest = malloc(length + 1);
+ if (manifest) {
+ size_t siz = fread(manifest, 1, length, f);
+ manifest[length] = '\0';
+ }
+ fclose(f);
+ } else
+ {
+ NoticeMessage(MSG_MANIFEST_OPEN_FAIL, _("Continue"), NULL, manifest_file);
+ }
+ free(manifest_file);
+
+ char * arch_file = NULL;
+
+ //Set filename to point to included .xtc file
+ //Use the name inside manifest (this helps if a user renames the zip)
+ if (manifest)
+ {
+ arch_file = ParseManifest(manifest, zip_input);
+ free(manifest);
+ }
+
+ free(full_path);
+ full_path = NULL;
+ // If no manifest value use same name as the archive
+ if (arch_file && arch_file[0])
+ {
+ MakeFullpath(&full_path, zip_input, arch_file, NULL);
+ } else
+ {
+ MakeFullpath(&full_path, zip_input, nameOfFile, NULL);
+ }
+
+ nameOfFile = FindFilename(full_path);
+ extOfFile = FindFileExtension(full_path);
+ if (strcmp(extOfFile, ZIPFILETYPEEXTENSION )==0)
+ {
+ for (int i=0; i<4; i++) {
+ extOfFile[i] = extOfFile[i+1];
+ }
+ }
+ LOG(log_zip, 1, ("Zip-File %s \n", full_path))
+ #if DEBUG
+ printf("File Path: %s \n", full_path);
+ #endif
+ } else {
+ loadXTC = FALSE; // when unzipping fails, don't attempt loading the trackplan
+ }
+ zipped = TRUE;
+
+ free(zip_input);
+
+
+ }
+
+ if ( bExample )
+ bReadOnly = TRUE;
+ else if ( access( fileName[0], W_OK ) == -1 )
+ bReadOnly = TRUE;
+ else
+ bReadOnly = FALSE;
+
+ char *copyOfFileName = MyStrdup(fileName[0]);
+
+ if (loadXTC && ReadTrackFile( full_path, FindFilename( fileName[0]), TRUE, TRUE, TRUE )) {
+
+ nameOfFile = NULL;
+ extOfFile = NULL;
+ SetCurrentPath( LAYOUTPATHKEY, copyOfFileName );
+ SetLayoutFullPath(copyOfFileName);
+ SetWindowTitle();
+
+ if ( ! bExample && (nameOfFile != NULL) ) {
+ char * copyFile = strdup(fileName[0]);
+ char * listName = FindFilename(strdup(fileName[0])); //Make sure the list name is new
+ wMenuListAdd( fileList_ml, 0, listName, copyFile );
+ }
+
+
ResolveIndex();
#ifdef TIME_READTRACKFILE
time1 = wGetTimer();
@@ -902,9 +979,14 @@ EXPORT int LoadTracks(
LoadLayerLists();
LayerSetCounts();
}
+
+ MyFree(copyOfFileName);
+ free(full_path);
+ full_path = NULL;
+
UndoResume();
Reset();
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
return TRUE;
}
@@ -913,7 +995,7 @@ EXPORT int LoadTracks(
* path.
* \param index IN ignored
* \param label IN ignored
- * \param data IN path and filename
+ * \param data IN path and filename
*/
EXPORT void DoFileList(
@@ -922,7 +1004,7 @@ EXPORT void DoFileList(
void * data )
{
char *pathName = (char*)data;
-
+ bExample = FALSE;
LoadTracks( 1, &pathName, NULL );
}
@@ -945,7 +1027,7 @@ static BOOL_T DoSaveTracks(
return FALSE;
}
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
time(&clock);
rc &= fprintf(f,"#%s Version: %s, Date: %s\n", sProdName, sVersion, ctime(&clock) )>0;
rc &= fprintf(f, "VERSION %d %s\n", iParamVersion, PARAMVERSIONVERSION )>0;
@@ -958,34 +1040,156 @@ static BOOL_T DoSaveTracks(
rc &= fprintf(f, "SCALE %s\n", curScaleName )>0;
rc &= WriteLayers( f );
rc &= WriteMainNote( f );
- rc &= WriteTracks( f );
- rc &= fprintf(f, "END\n")>0;
+ rc &= WriteTracks( f, TRUE );
+ rc &= fprintf(f, "%s\n", END_TRK_FILE)>0;
if ( !rc )
NoticeMessage( MSG_WRITE_FAILURE, _("Ok"), NULL, strerror(errno), fileName );
fclose(f);
+ bReadOnly = FALSE;
RestoreLocale( oldLocale );
checkPtMark = changed;
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
return rc;
}
+/************************************************
+ * Copy Dependency - copy file into another directory
+ *
+ * \param IN name
+ * \param IN target_dir
+ *
+ * \returns TRUE for success
+ *
+ */
+static BOOL_T CopyDependency(char * name, char * target_dir)
+{
+ char * backname = FindFilename(name);
+ BOOL_T copied = TRUE;
+ FILE * source = fopen(name, "rb");
+
+ if (source != NULL) {
+ char * target_file;
+ MakeFullpath(&target_file, target_dir, backname, NULL);
+ FILE * target = fopen(target_file, "wb");
+
+ if (target != NULL) {
+ char *buffer = MyMalloc(COPYBLOCKSIZE);
+ while (!feof(source)) {
+ size_t bytes = fread(buffer, 1, sizeof(buffer), source);
+ if (bytes) {
+ fwrite(buffer, 1, bytes, target);
+ }
+ }
+ MyFree(buffer);
+ LOG(log_zip, 1, ("Zip-Include %s into %s \n", name, target_file))
+#if DEBUG
+ printf("xtrkcad: Included file %s into %s \n",
+ name, target_file);
+#endif
+ fclose(target);
+ } else {
+ NoticeMessage(MSG_COPY_FAIL, _("Continue"), NULL, name, target_file);
+ copied = FALSE;
+ }
+ free(target_file);
+ fclose(source);
+ } else {
+ NoticeMessage(MSG_COPY_OPEN_FAIL, _("Continue"), NULL, name);
+ copied = FALSE;
+ }
+ return copied;
+}
+
static doSaveCallBack_p doAfterSave;
+
+
static int SaveTracks(
int cnt,
char **fileName,
void * data )
{
- char *nameOfFile;
assert( fileName != NULL );
assert( cnt == 1 );
+ char *nameOfFile = FindFilename(fileName[0]);
+
SetCurrentPath(LAYOUTPATHKEY, fileName[0]);
- DoSaveTracks( fileName[ 0 ] );
+
+ //Support Archive zipped files
+
+ char * extOfFile = FindFileExtension( fileName[0]);
+
+
+ if (extOfFile && (strcmp(extOfFile,ZIPFILETYPEEXTENSION)==0)) {
+
+ char * ArchiveName;
+
+ //Set filename to point to be the same as the included .xtc file.
+ //This is also in the manifest - in case a user renames the archive file.
+
+ char * zip_output = GetZipDirectoryName(ARCHIVE_WRITE);
+
+ DeleteDirectory(zip_output);
+ SafeCreateDir(zip_output);
+
+ MakeFullpath(&ArchiveName, zip_output, nameOfFile, NULL);
+
+ nameOfFile = FindFilename(ArchiveName);
+ extOfFile = FindFileExtension(ArchiveName);
+
+ if (extOfFile && strcmp(extOfFile, ZIPFILETYPEEXTENSION)==0) {
+ // Get rid of the 'e'
+ extOfFile[3] = '\0';
+ }
+
+ char * DependencyDir;
+
+ //The included files are placed (for now) into an includes directory - TODO an array of includes with directories by type
+ MakeFullpath(&DependencyDir, zip_output, "includes", NULL);
+
+ SafeCreateDir(DependencyDir);
+
+ char * background = GetLayoutBackGroundFullPath();
+
+ if (background && background[0])
+ CopyDependency(background,DependencyDir);
+
+ //The details are stored into the manifest - TODO use arrays for files, locations
+ char *oldLocale = SaveLocale("C");
+ char* json_Manifest = CreateManifest(nameOfFile, background, "includes");
+ char * manifest_file;
+
+ MakeFullpath(&manifest_file, zip_output, "manifest.json", NULL);
+
+ FILE *fp = fopen(manifest_file, "wb");
+ if (fp != NULL)
+ {
+ fputs(json_Manifest, fp);
+ fclose(fp);
+ } else {
+ NoticeMessage( MSG_MANIFEST_FAIL, _("Continue"), NULL, manifest_file );
+ }
+ RestoreLocale(oldLocale);
+
+ free(manifest_file);
+ free(json_Manifest);
+
+ DoSaveTracks( ArchiveName );
+
+ if (CreateArchive( zip_output, fileName[0]) != TRUE) {
+ NoticeMessage( MSG_ARCHIVE_FAIL, _("Continue"), NULL, fileName[0], zip_output );
+ }
+ free(zip_output);
+ free(ArchiveName);
+
+ } else
+
+ DoSaveTracks( fileName[ 0 ] );
nameOfFile = FindFilename( fileName[ 0 ] );
wMenuListAdd( fileList_ml, 0, nameOfFile, MyStrdup(fileName[ 0 ]) );
@@ -1003,16 +1207,18 @@ static int SaveTracks(
EXPORT void DoSave( doSaveCallBack_p after )
{
doAfterSave = after;
- if (*(GetLayoutFilename()) == '\0') {
+ if ( bReadOnly || *(GetLayoutFilename()) == '\0') {
if (saveFile_fs == NULL)
saveFile_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("Save Tracks"),
sSourceFilePattern, SaveTracks, NULL );
wFilSelect( saveFile_fs, GetCurrentPath(LAYOUTPATHKEY));
+ changed = checkPtMark = 1;
} else {
- char *temp = GetLayoutFullPath();
+ char *temp = GetLayoutFullPath();
SaveTracks( 1, &temp, NULL );
}
SetWindowTitle();
+ SaveState();
}
EXPORT void DoSaveAs( doSaveCallBack_p after )
@@ -1020,46 +1226,93 @@ EXPORT void DoSaveAs( doSaveCallBack_p after )
doAfterSave = after;
if (saveFile_fs == NULL)
saveFile_fs = wFilSelCreate( mainW, FS_SAVE, 0, _("Save Tracks As"),
- sSourceFilePattern, SaveTracks, NULL );
+ sSaveFilePattern, SaveTracks, NULL );
wFilSelect( saveFile_fs, GetCurrentPath(LAYOUTPATHKEY));
+ changed = checkPtMark = 1;
SetWindowTitle();
+ SaveState();
}
EXPORT void DoLoad( void )
{
- loadFile_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Open Tracks"),
- sSourceFilePattern, LoadTracks, NULL );
+ if (loadFile_fs == NULL)
+ loadFile_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Open Tracks"),
+ sSourceFilePattern, LoadTracks, NULL );
+ bExample = FALSE;
wFilSelect( loadFile_fs, GetCurrentPath(LAYOUTPATHKEY));
+ paste_offset = zero;
+ cursor_offset = zero;
+ SaveState();
}
+EXPORT void DoExamples( void )
+{
+ if (examplesFile_fs == NULL) {
+ static wBool_t bExample = TRUE;
+ examplesFile_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Example Tracks"),
+ sSourceFilePattern, LoadTracks, &bExample );
+ }
+ bExample = TRUE;
+ sprintf( message, "%s" FILE_SEP_CHAR "examples" FILE_SEP_CHAR, libDir );
+ wFilSelect( examplesFile_fs, message );
+ SaveState();
+}
+
+static wIndex_t generations_count = 0;
+wIndex_t max_generations_count = 10;
+static char sCheckPointBF[STR_LONG_SIZE];
+
+
EXPORT void DoCheckPoint( void )
{
int rc;
+ if (!checkPtFileNameBackup || (changed <= checkPtInterval+1)) {
+ sprintf(sCheckPointBF,"%s00.bkp",GetLayoutFilename());
+ MakeFullpath(&checkPtFileNameBackup, workingDir, sCheckPointBF, NULL);
+ }
+
if (checkPointingW == NULL) {
ParamRegister( &checkPointingPG );
checkPointingW = ParamCreateDialog( &checkPointingPG, MakeWindowTitle(_("Check Pointing")), NULL, NULL, NULL, FALSE, NULL, F_TOP|F_CENTER, NULL );
}
rename( checkPtFileName1, checkPtFileName2 );
- wShow( checkPointingW );
+ //wShow( checkPointingW );
rc = DoSaveTracks( checkPtFileName1 );
/* could the check point file be written ok? */
if( rc ) {
- /* yes, delete the backup copy of the checkpoint file */
- remove( checkPtFileName2 );
+ /* yes, archive/delete the backup copy of the checkpoint file */
+ if (checkPtFileNameBackup) {
+ char * spot = strrchr(checkPtFileNameBackup,'.');
+ if (spot && spot>checkPtFileNameBackup+3) {
+ spot[-2]=generations_count/10+'0';
+ spot[-1]=generations_count%10+'0';
+ }
+ generations_count++;
+ if (((autosaveChkPoints == 0) && (generations_count > 5)) ||
+ ((autosaveChkPoints > 0) && (generations_count > autosaveChkPoints)) ) {
+ generations_count = 0;
+ }
+ remove( checkPtFileNameBackup);
+ rename( checkPtFileName2, checkPtFileNameBackup );
+ } else {
+ remove(checkPtFileName2);
+ }
} else {
/* no, rename the backup copy back to the checkpoint file name */
rename( checkPtFileName2, checkPtFileName1 );
}
- wHide( checkPointingW );
+
+ //wHide( checkPointingW );
+ wShow( mainW );
}
/**
- * Remove all temporary files before exiting.When the program terminates
- * normally through the exit choice, files that are created temporarily are removed:
- * xtrkcad.ckp
+ * Remove all temporary files before exiting. When the program terminates
+ * normally through the exit choice, files and directories that were created
+ * temporarily are removed: xtrkcad.ckp
*
* \param none
* \return none
@@ -1068,12 +1321,27 @@ EXPORT void DoCheckPoint( void )
EXPORT void CleanupFiles( void )
{
- if( checkPtFileName1 )
+ char *tempDir;
+
+ if( checkPtFileName1 ) {
+ if (checkPtFileNameBackup) {
+ remove( checkPtFileNameBackup );
+ rename( checkPtFileName1, checkPtFileNameBackup );
+ }
remove( checkPtFileName1 );
+ }
+
+ for (int i = ARCHIVE_READ; i <= ARCHIVE_WRITE; ++i) {
+ tempDir = GetZipDirectoryName(i);
+ if (tempDir) {
+ DeleteDirectory(tempDir);
+ free(tempDir);
+ }
+ }
}
/**
- * Check for existance of checkpoint file. Existance of a checkpoint file means that XTrkCAD was not properly
+ * Check for existence of checkpoint file. Existence of a checkpoint file means that XTrkCAD was not properly
* terminated.
*
* \param none
@@ -1098,37 +1366,52 @@ EXPORT int ExistsCheckpoint( void )
/**
* Load checkpoint file
*
+ * \param if TRUE reuse old filename
+ * \param filename returned
* \return TRUE if exists, FALSE otherwise
*
*/
-EXPORT int LoadCheckpoint( void )
+EXPORT int LoadCheckpoint( BOOL_T sameName )
{
char *search;
paramVersion = -1;
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
MakeFullpath(&search, workingDir, sCheckPointF, NULL);
UndoSuspend();
if (ReadTrackFile( search, search + strlen(search) - strlen( sCheckPointF ), TRUE, TRUE, TRUE )) {
ResolveIndex();
+ LayoutBackGroundInit(FALSE); //Get Prior BackGround
+ LayoutBackGroundSave(); //Save Background Values
+
+ if (sameName) {
+ long iExample;
+ char * initialFile = (char*)wPrefGetString("misc", "lastlayout");
+ wPrefGetInteger("misc", "lastlayoutexample", &iExample, 0);
+ bExample = (iExample == 1);
+ if (initialFile && strlen(initialFile)) {
+ SetCurrentPath( LAYOUTPATHKEY, initialFile );
+ SetLayoutFullPath(initialFile);
+ }
+ } else SetLayoutFullPath("");
RecomputeElevations();
AttachTrains();
DoChangeNotification( CHANGE_ALL );
DoUpdateTitles();
- }
+ } else SetLayoutFullPath("");
Reset();
UndoResume();
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
+
- SetLayoutFullPath("");
SetWindowTitle();
- changed = TRUE;
+ checkPtMark = changed = 1;
free( search );
return TRUE;
}
@@ -1142,6 +1425,15 @@ EXPORT int LoadCheckpoint( void )
static struct wFilSel_t * exportFile_fs;
static struct wFilSel_t * importFile_fs;
+static int importAsModule;
+
+
+
+/*******************************************************************************
+ *
+ * Import Layout Dialog
+ *
+ */
static int ImportTracks(
int cnt,
@@ -1156,27 +1448,40 @@ static int ImportTracks(
nameOfFile = FindFilename(fileName[ 0 ]);
paramVersion = -1;
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
Reset();
SetAllTrackSelect( FALSE );
+ int saveLayer = curLayer;
+ int layer;
+ if (importAsModule) {
+ layer = FindUnusedLayer(0);
+ if (layer==-1) return FALSE;
+ char LayerName[80];
+ LayerName[0] = '\0';
+ sprintf(LayerName,_("Module - %s"),nameOfFile);
+ if (layer>=0) SetCurrLayer(layer, NULL, 0, NULL, NULL);
+ SetLayerName(layer,LayerName);
+ }
ImportStart();
UndoStart( _("Import Tracks"), "importTracks" );
useCurrentLayer = TRUE;
ReadTrackFile( fileName[ 0 ], nameOfFile, FALSE, FALSE, TRUE );
- ImportEnd();
+ ImportEnd(zero, TRUE, FALSE);
+ if (importAsModule) SetLayerModule(layer,TRUE);
+ useCurrentLayer = FALSE;
+ SetCurrLayer(saveLayer, NULL, 0, NULL, NULL);
/*DoRedraw();*/
EnableCommands();
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
paramVersion = paramVersionOld;
- importMove = TRUE;
DoCommandB( (void*)(intptr_t)selectCmdInx );
SelectRecount();
return TRUE;
}
-
-EXPORT void DoImport( void )
+EXPORT void DoImport( void * type )
{
+ importAsModule = (int)(long)type;
if (importFile_fs == NULL)
importFile_fs = wFilSelCreate( mainW, FS_LOAD, 0, _("Import Tracks"),
sImportFilePattern, ImportTracks, NULL );
@@ -1215,18 +1520,19 @@ static int DoExportTracks(
oldLocale = SaveLocale("C");
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
time(&clock);
fprintf(f,"#%s Version: %s, Date: %s\n", sProdName, sVersion, ctime(&clock) );
fprintf(f, "VERSION %d %s\n", iParamVersion, PARAMVERSIONVERSION );
- ExportTracks( f );
- fprintf(f, "END\n");
+ coOrd offset;
+ ExportTracks( f , &offset);
+ fprintf(f, "%s\n", END_TRK_FILE);
fclose(f);
RestoreLocale( oldLocale );
Reset();
- wSetCursor( wCursorNormal );
+ wSetCursor( mainD.d, defaultCursor );
UpdateAllElevations();
return TRUE;
}
@@ -1246,7 +1552,6 @@ EXPORT void DoExport( void )
}
-
EXPORT BOOL_T EditCopy( void )
{
FILE * f;
@@ -1268,10 +1573,11 @@ EXPORT BOOL_T EditCopy( void )
time(&clock);
fprintf(f,"#%s Version: %s, Date: %s\n", sProdName, sVersion, ctime(&clock) );
fprintf(f, "VERSION %d %s\n", iParamVersion, PARAMVERSIONVERSION );
- ExportTracks(f);
- fprintf(f, "END\n");
+ ExportTracks(f, &paste_offset);
+ fprintf(f, "%s\n", END_TRK_FILE );
RestoreLocale(oldLocale);
fclose(f);
+
return TRUE;
}
@@ -1284,6 +1590,7 @@ EXPORT BOOL_T EditCut( void )
return TRUE;
}
+
/**
* Paste clipboard content. XTrackCAD uses a disk file as clipboard replacement. This file is read and the
* content is inserted.
@@ -1291,16 +1598,24 @@ EXPORT BOOL_T EditCut( void )
* \return TRUE if success, FALSE on error (file not found)
*/
-EXPORT BOOL_T EditPaste( void )
+BOOL_T EditPastePlace( wBool_t inPlace )
{
+
BOOL_T rc = TRUE;
char *oldLocale = NULL;
oldLocale = SaveLocale("C");
- wSetCursor( wCursorWait );
+ wSetCursor( mainD.d, wCursorWait );
Reset();
SetAllTrackSelect( FALSE );
+
+ double offset = 20*mainD.scale/mainD.dpi;
+
+ paste_offset.x += offset;
+ paste_offset.y += offset;
+
+
ImportStart();
UndoStart( _("Paste"), "paste" );
useCurrentLayer = TRUE;
@@ -1308,18 +1623,33 @@ EXPORT BOOL_T EditPaste( void )
NoticeMessage( MSG_CANT_PASTE, _("Continue"), NULL );
rc = FALSE;
}
- ImportEnd();
+ if (inPlace)
+ ImportEnd(paste_offset, FALSE, TRUE);
+ else
+ ImportEnd(zero, FALSE, FALSE);
+ useCurrentLayer = FALSE;
/*DoRedraw();*/
EnableCommands();
- wSetCursor( wCursorNormal );
- importMove = TRUE;
+ wSetCursor( mainD.d, defaultCursor );
DoCommandB( (void*)(intptr_t)selectCmdInx );
SelectRecount();
UpdateAllElevations();
RestoreLocale(oldLocale);
+
return rc;
}
+
+EXPORT BOOL_T EditPaste( void) {
+ return EditPastePlace(FALSE);
+}
+EXPORT BOOL_T EditClone( void ) {
+ BOOL_T rc = TRUE;
+ if (!EditCopy()) return FALSE;
+ if (!EditPastePlace(TRUE)) return FALSE;
+ return rc;
+}
+
/*****************************************************************************
*
* INITIALIZATION
@@ -1333,23 +1663,8 @@ EXPORT void FileInit( void )
}
if ( (workingDir = wGetAppWorkDir()) == NULL )
AbortProg( "wGetAppWorkDir()" );
-}
-
-EXPORT BOOL_T ParamFileInit( void )
-{
- curParamFileIndex = PARAM_DEMO;
- log_paramFile = LogFindIndex( "paramFile" );
- if ( ReadParams( lParamKey, libDir, sParamQF ) == FALSE )
- return FALSE;
-
- curParamFileIndex = PARAM_CUSTOM;
- if (lParamKey == 0) {
- ReadParamFiles();
- ReadCustom();
- }
SetLayoutFullPath("");
- MakeFullpath(&clipBoardN, workingDir, sClipboardF, NULL);
- return TRUE;
+ MakeFullpath(&clipBoardN, workingDir, sClipboardF, NULL);
}
diff --git a/app/bin/fileio.h b/app/bin/fileio.h
index 4f5aa8d..13761bf 100644
--- a/app/bin/fileio.h
+++ b/app/bin/fileio.h
@@ -27,20 +27,24 @@
#include "common.h"
#include "misc.h"
-FILE * paramFile;
+extern FILE * paramFile;
extern char *paramFileName;
-wIndex_t paramLineNum;
-char paramLine[STR_LONG_SIZE];
-char * curContents;
-char * curSubContents;
+extern wIndex_t paramLineNum;
+extern char paramLine[STR_HUGE_SIZE];
+extern char * curContents;
+extern char * curSubContents;
#define PARAM_DEMO (-1)
typedef void (*playbackProc_p)( char * );
typedef BOOL_T (*readParam_t) ( char * );
+typedef BOOL_T (*deleteParam_t) (void *param);
extern const char * workingDir;
extern const char * libDir;
+extern wBool_t bReadOnly;
+extern wBool_t bExample;
+
#define PARAM_CUSTOM (-2)
#define PARAM_LAYOUT (-3)
extern int curParamFileIndex;
@@ -50,17 +54,20 @@ extern unsigned long playbackTimer;
extern wBool_t executableOk;
extern FILE * recordF;
-wBool_t inPlayback;
-wBool_t inPlaybackQuit;
-wWin_p demoW;
-int curDemo;
+extern wBool_t inPlayback;
+extern wBool_t inPlaybackQuit;
+extern wWin_p demoW;
+extern int curDemo;
+
+extern wMenuList_p fileList_ml;
-wMenuList_p fileList_ml;
+#define ZIPFILETYPEEXTENSION "xtce"
#define PARAM_SUBDIR "params"
#define LAYOUTPATHKEY "layout"
#define BITMAPPATHKEY "bitmap"
+#define BACKGROUNDPATHKEY "images"
#define DXFPATHKEY "dxf"
#define PARTLISTPATHKEY "parts"
#define CARSPATHKEY "cars"
@@ -68,16 +75,32 @@ wMenuList_p fileList_ml;
#define IMPORTPATHKEY "import"
#define MACROPATHKEY "macro"
#define CUSTOMPATHKEY "custom"
+#define ARCHIVEPATHKEY "archive"
+
+typedef struct {
+ char * name;
+ readParam_t proc;
+} paramProc_t;
+dynArr_t paramProc_da;
+#define paramProc(N) DYNARR_N( paramProc_t, paramProc_da, N )
void Stripcr( char * );
char * GetNextLine( void );
+#define END_TRK_FILE "END$TRACKS"
+#define END_BLOCK "END$BLOCK"
+#define END_SIGNAL "END$SIGNAL"
+#define END_SEGS "END$SEGS"
+#define END_MESSAGE "END$MESSAGE"
+wBool_t IsEND( char * sEnd );
+
BOOL_T GetArgs( char *, char *, ... );
+char * ReadMultilineText();
BOOL_T ParseRoomSize( char *, coOrd * );
int InputError( char *, BOOL_T, ... );
-void SyntaxError( char *, wIndex_t, wIndex_t );
+void SyntaxError( char *, wIndex_t, wIndex_t );
-void AddParam( char *, readParam_t );
+void AddParam( char *name, readParam_t proc );
FILE * OpenCustom( char * );
@@ -87,29 +110,29 @@ FILE * OpenCustom( char * );
void SetWindowTitle( void );
char * PutTitle( char * cp );
-wBool_t IsParamValid( int );
-char * GetParamFileName( int );
-void RememberParamFiles( void );
-int LoadParamFile( int files, char **fileName, void *data );
-void ReadParamFiles( void );
+
+void ParamFileListLoad(int paramFileCnt, dynArr_t *paramFiles);
+void DoParamFiles(void * junk);
+
int LoadTracks( int cnt, char **fileName, void *data );
-BOOL_T ReadParams( long, const char *, const char * );
typedef void (*doSaveCallBack_p)( void );
void DoSave( doSaveCallBack_p );
void DoSaveAs( doSaveCallBack_p );
void DoLoad( void );
+void DoExamples( void );
void DoFileList( int, char *, void * );
void DoCheckPoint( void );
void CleanupFiles( void );
int ExistsCheckpoint( void );
-int LoadCheckpoint( void );
-void DoImport( void );
+int LoadCheckpoint( BOOL_T );
+void DoImport( void * );
void DoExport( void );
void DoExportDXF( void );
BOOL_T EditCopy( void );
BOOL_T EditCut( void );
BOOL_T EditPaste( void );
+BOOL_T EditClone( void );
void DoRecord( void * );
@@ -124,10 +147,13 @@ void ReadKey( void );
void PopupRegister( void * );
void FileInit( void );
-BOOL_T ParamFileInit( void );
+
BOOL_T MacroInit( void );
char *SaveLocale( char *newLocale );
void RestoreLocale( char * locale );
+// Parameter file search
+void DoSearchParams(void * junk);
+
#endif
diff --git a/app/bin/filenoteui.c b/app/bin/filenoteui.c
new file mode 100644
index 0000000..5ffddd1
--- /dev/null
+++ b/app/bin/filenoteui.c
@@ -0,0 +1,330 @@
+/** \file filenoteui.c
+ * View for the file note
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2018 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 <string.h>
+#include <stdbool.h>
+#ifdef WINDOWS
+ #include <io.h>
+ #define access(path,mode) _access(path,mode)
+ #define F_OK (0)
+#else
+ #include <unistd.h>
+#endif
+#include "custom.h"
+#include "dynstring.h"
+#include "file2uri.h"
+#include "i18n.h"
+#include "misc.h"
+#include "note.h"
+#include "param.h"
+#include "paths.h"
+#include "include/stringxtc.h"
+#include "track.h"
+#include "wlib.h"
+
+extern BOOL_T inDescribeCmd;
+
+#define MYMIN(x, y) (((x) < (y)) ? (x) : (y))
+
+#define DOCUMENTFILEPATTERN "All Files (*.*)|*.*"
+#define DOCUMENTPATHKEY "document"
+
+static struct extraDataNote noteDataInUI;
+static struct wFilSel_t * documentFile_fs;
+
+static void NoteFileOpenExternal(void * junk);
+static void NoteFileBrowse(void * junk);
+
+static paramFloatRange_t r_1000_1000 = { -1000.0, 1000.0, 80 };
+
+// static char *toggleLabels[] = { N_("Copy to archive"), NULL };
+static paramData_t fileEditPLs[] = {
+#define I_ORIGX (0)
+ /*0*/ { PD_FLOAT, &noteDataInUI.pos.x, "origx", PDO_DIM, &r_1000_1000, N_("Position X") },
+#define I_ORIGY (1)
+ /*1*/ { PD_FLOAT, &noteDataInUI.pos.y, "origy", PDO_DIM, &r_1000_1000, N_("Position Y") },
+#define I_LAYER (2)
+ /*2*/ { PD_DROPLIST, &noteDataInUI.layer, "layer", 0, (void*)150, "Layer", 0 },
+#define I_TITLE (3)
+ /*3*/ { PD_STRING, NULL, "title", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)200, N_("Title"), 0, 0, TITLEMAXIMUMLENGTH-1 },
+#define I_PATH (4)
+ { PD_STRING, NULL, "filename", PDO_NOPSHUPD, (void*)200, N_("Document"), BO_READONLY, (void *)0L },
+#define I_BROWSE (5)
+ { PD_BUTTON, (void *)NoteFileBrowse, "browse", 0L, NULL, N_("Select...") },
+#define I_OPEN (6)
+ { PD_BUTTON, (void*)NoteFileOpenExternal, "openfile", PDO_DLGHORZ, NULL, N_("Open...") },
+//#define I_ARCHIVE (7)
+// { PD_TOGGLE, &noteFileData.inArchive, "archive", 0, toggleLabels, NULL },
+
+};
+
+static paramGroup_t fileEditPG = { "fileEdit", 0, fileEditPLs, sizeof fileEditPLs / sizeof fileEditPLs[0] };
+static wWin_p fileEditW;
+
+BOOL_T IsFileNote(track_p trk)
+{
+ struct extraDataNote * xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ return(xx->op == OP_NOTEFILE );
+}
+
+/** Check for the file existance
+ *
+ * \param fileName IN file
+ * \return TRUE if exists, FALSE otherwise
+ */
+BOOL_T IsFileValid(char *fileName)
+{
+ if (!strlen(fileName)) {
+ return(FALSE);
+ } else {
+ if (access(fileName, F_OK) == -1) {
+ return(FALSE);
+ }
+ }
+
+ return(TRUE);
+}
+
+/**
+ * Put the selected filename into the dialog
+ *
+ * \param files IN always 1
+ * \param fileName IN name of selected file
+ * \param data IN ignored
+ * \return always 0
+ */
+int LoadDocumentFile(
+ int files,
+ char ** fileName,
+ void * data)
+{
+ wControlActive(fileEditPLs[I_OPEN].control, TRUE);
+ ParamDialogOkActive(&fileEditPG, TRUE);
+ strscpy(noteDataInUI.noteData.fileData.path, *fileName, PATHMAXIMUMLENGTH );
+ ParamLoadControl(&fileEditPG, I_PATH);
+
+ return(0);
+}
+
+/**
+ * Select the file to attach
+ *
+ * \param junk unused
+ */
+static void NoteFileBrowse(void * junk)
+{
+ documentFile_fs = wFilSelCreate(mainW, FS_LOAD, 0, _("Add Document"), DOCUMENTFILEPATTERN, LoadDocumentFile, NULL);
+
+ wFilSelect(documentFile_fs, GetCurrentPath(DOCUMENTPATHKEY));
+
+ wControlActive(fileEditPLs[I_OPEN].control,
+ (strlen(noteDataInUI.noteData.fileData.path) ? TRUE : FALSE));
+
+ return;
+}
+
+/**
+ * Open the file using an external program. Before opening the file existance and permissions are checked.
+ * If access is not allowed the Open Button is disabled
+ *
+ * \param fileName IN file
+ */
+
+static void NoteFileOpen(char *fileName)
+{
+ if (IsFileValid(fileName)) {
+ wOpenFileExternal(fileName);
+ } else {
+ wNoticeEx(NT_ERROR, _("The file doesn't exist or cannot be read!"), _("Cancel"), NULL);
+ if (fileEditW) {
+ wControlActive(fileEditPLs[I_OPEN].control, FALSE);
+ }
+ }
+}
+
+static void
+NoteFileOpenExternal(void * junk)
+{
+ NoteFileOpen(noteDataInUI.noteData.fileData.path);
+}
+/**
+ * Handle the dialog actions
+ */
+static void
+FileDlgUpdate(
+ paramGroup_p pg,
+ int inx,
+ void * valueP)
+{
+ switch (inx) {
+ case I_ORIGX:
+ case I_ORIGY:
+ UpdateFile(&noteDataInUI, OR_NOTE, FALSE);
+ break;
+ case I_LAYER:
+ UpdateFile(&noteDataInUI, LY_NOTE, FALSE);
+ break;
+ case I_PATH:
+ if (IsFileValid(noteDataInUI.noteData.fileData.path)) {
+ wControlActive(fileEditPLs[I_OPEN].control, TRUE);
+ } else {
+ wControlActive(fileEditPLs[I_OPEN].control, FALSE);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+/**
+ * Handle Cancel button: restore old values for layer and position
+ */
+
+static void
+FileEditCancel( wWin_p junk)
+{
+ if (inDescribeCmd) {
+ UpdateFile(&noteDataInUI, CANCEL_NOTE, FALSE);
+ }
+ ResetIfNotSticky();
+ wHide(fileEditW);
+}
+/**
+ * Handle OK button: make sure the entered filename is syntactically valid, update
+ * the layout and close the dialog
+ *
+ * \param junk
+ */
+
+static void
+FileEditOK(void *junk)
+{
+ UpdateFile(&noteDataInUI, OK_FILE, FALSE);
+ wHide(fileEditW);
+ ResetIfNotSticky();
+ FileIsChanged();
+}
+
+/**
+ * Show the attachment edit dialog. Create if non-existant
+ *
+ * \param trk IN track element to edit
+ * \param windowTitle IN title for the edit dialog window
+ */
+
+void CreateEditFileDialog(track_p trk, char * windowTitle)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ if (!fileEditW) {
+ noteDataInUI.noteData.fileData.path = MyMalloc(PATHMAXIMUMLENGTH);
+ noteDataInUI.noteData.fileData.title = MyMalloc(TITLEMAXIMUMLENGTH);
+ fileEditPLs[I_TITLE].valueP = noteDataInUI.noteData.fileData.title;
+ fileEditPLs[I_PATH].valueP = noteDataInUI.noteData.fileData.path;
+
+ ParamRegister(&fileEditPG);
+ fileEditW = ParamCreateDialog(&fileEditPG,
+ "",
+ _("Done"), FileEditOK,
+ FileEditCancel, TRUE, NULL,
+ F_BLOCK,
+ FileDlgUpdate);
+ }
+
+ wWinSetTitle(fileEditPG.win, MakeWindowTitle(windowTitle));
+
+ noteDataInUI.pos = xx->pos;
+ noteDataInUI.layer = xx->layer;
+ noteDataInUI.trk = trk;
+ strscpy(noteDataInUI.noteData.fileData.title, xx->noteData.fileData.title, TITLEMAXIMUMLENGTH);
+ strscpy(noteDataInUI.noteData.fileData.path, xx->noteData.fileData.path, PATHMAXIMUMLENGTH);
+ FillLayerList((wList_p)fileEditPLs[I_LAYER].control);
+ ParamLoadControls(&fileEditPG);
+ wControlActive(fileEditPLs[I_OPEN].control, (IsFileValid(noteDataInUI.noteData.fileData.path)?TRUE:FALSE));
+
+ wShow(fileEditW);
+}
+
+/**
+ * Activate note if double clicked
+ * \param trk the note
+ */
+
+void ActivateFileNote(track_p trk)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ NoteFileOpen(xx->noteData.fileData.path);
+}
+
+/**
+ * Describe and enable editing of an existing link note
+ *
+ * \param trk the existing, valid note
+ * \param str the field to put a text version of the note so it will appear on the status line
+ * \param len the lenght of the field
+ */
+
+void DescribeFileNote(track_p trk, char * str, CSIZE_T len)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ DynString statusLine;
+
+ DynStringMalloc(&statusLine, 80);
+
+ DynStringPrintf(&statusLine,
+ _("Document(%d) Layer=%d %-.80s [%s]"),
+ GetTrkIndex(trk),
+ GetTrkLayer(trk) + 1,
+ xx->noteData.fileData.title,
+ xx->noteData.fileData.path);
+
+ strcpy(str, DynStringToCStr(&statusLine));
+ DynStringFree(&statusLine);
+
+ if (inDescribeCmd) {
+ NoteStateSave(trk);
+
+ CreateEditFileDialog(trk, _("Update document"));
+ }
+}
+
+/**
+ * Take a new note track element and initialize it. It will be
+ * initialized with defaults and can then be edited by the user.
+ *
+ * \param the newly created trk
+ */
+
+void NewFileNoteUI(track_p trk)
+{
+ struct extraDataNote * xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ char *tmpPtrText = _("Describe the file");
+
+ xx->noteData.fileData.title = MyStrdup(tmpPtrText);
+ xx->noteData.fileData.path = MyStrdup("");
+
+ CreateEditFileDialog(trk,
+ _("Attach document"));
+}
diff --git a/app/bin/helphelper.c b/app/bin/helphelper.c
index 013ff0a..36083b8 100644
--- a/app/bin/helphelper.c
+++ b/app/bin/helphelper.c
@@ -117,6 +117,7 @@ main( int argc, char **argv )
if( numBytes == sizeof(int)) {
printf( "HelpHelper: Expecting %d bytes\n", len );
numBytes2 = read( handleOfPipe, buffer, len + 1 );
+ buffer[numBytes2] = '\0';
if (numBytes2 > 0)
printf( "HelpHelper: Display help on: %s\n", buffer );
diff --git a/app/bin/include/dirent.h b/app/bin/include/dirent.h
new file mode 100644
index 0000000..fdfbe5b
--- /dev/null
+++ b/app/bin/include/dirent.h
@@ -0,0 +1,1254 @@
+/*
+ * Dirent interface for Microsoft Visual Studio
+ *
+ * Copyright (C) 2006-2012 Toni Ronkko
+ * This file is part of dirent. Dirent may be freely distributed
+ * under the MIT license. For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#ifndef DIRENT_H
+#define DIRENT_H
+
+ /*
+ * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
+ * Windows Sockets 2.0.
+ */
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+ /* Indicates that d_type field is available in dirent structure */
+#define _DIRENT_HAVE_D_TYPE
+
+/* Indicates that d_namlen field is available in dirent structure */
+#define _DIRENT_HAVE_D_NAMLEN
+
+/* Entries missing from MSVC 6.0 */
+#if !defined(FILE_ATTRIBUTE_DEVICE)
+# define FILE_ATTRIBUTE_DEVICE 0x40
+#endif
+
+/* File type and permission flags for stat(), general mask */
+#if !defined(S_IFMT)
+# define S_IFMT _S_IFMT
+#endif
+
+/* Directory bit */
+#if !defined(S_IFDIR)
+# define S_IFDIR _S_IFDIR
+#endif
+
+/* Character device bit */
+#if !defined(S_IFCHR)
+# define S_IFCHR _S_IFCHR
+#endif
+
+/* Pipe bit */
+#if !defined(S_IFFIFO)
+# define S_IFFIFO _S_IFFIFO
+#endif
+
+/* Regular file bit */
+#if !defined(S_IFREG)
+# define S_IFREG _S_IFREG
+#endif
+
+/* Read permission */
+#if !defined(S_IREAD)
+# define S_IREAD _S_IREAD
+#endif
+
+/* Write permission */
+#if !defined(S_IWRITE)
+# define S_IWRITE _S_IWRITE
+#endif
+
+/* Execute permission */
+#if !defined(S_IEXEC)
+# define S_IEXEC _S_IEXEC
+#endif
+
+/* Pipe */
+#if !defined(S_IFIFO)
+# define S_IFIFO _S_IFIFO
+#endif
+
+/* Block device */
+#if !defined(S_IFBLK)
+# define S_IFBLK 0
+#endif
+
+/* Link */
+#if !defined(S_IFLNK)
+# define S_IFLNK 0
+#endif
+
+/* Socket */
+#if !defined(S_IFSOCK)
+# define S_IFSOCK 0
+#endif
+
+/* Read user permission */
+#if !defined(S_IRUSR)
+# define S_IRUSR S_IREAD
+#endif
+
+/* Write user permission */
+#if !defined(S_IWUSR)
+# define S_IWUSR S_IWRITE
+#endif
+
+/* Execute user permission */
+#if !defined(S_IXUSR)
+# define S_IXUSR 0
+#endif
+
+/* Read group permission */
+#if !defined(S_IRGRP)
+# define S_IRGRP 0
+#endif
+
+/* Write group permission */
+#if !defined(S_IWGRP)
+# define S_IWGRP 0
+#endif
+
+/* Execute group permission */
+#if !defined(S_IXGRP)
+# define S_IXGRP 0
+#endif
+
+/* Read others permission */
+#if !defined(S_IROTH)
+# define S_IROTH 0
+#endif
+
+/* Write others permission */
+#if !defined(S_IWOTH)
+# define S_IWOTH 0
+#endif
+
+/* Execute others permission */
+#if !defined(S_IXOTH)
+# define S_IXOTH 0
+#endif
+
+/* Maximum length of file name */
+#if !defined(PATH_MAX)
+# define PATH_MAX MAX_PATH
+#endif
+#if !defined(FILENAME_MAX)
+# define FILENAME_MAX MAX_PATH
+#endif
+#if !defined(NAME_MAX)
+# define NAME_MAX FILENAME_MAX
+#endif
+
+/* File type flags for d_type */
+#define DT_UNKNOWN 0
+#define DT_REG S_IFREG
+#define DT_DIR S_IFDIR
+#define DT_FIFO S_IFIFO
+#define DT_SOCK S_IFSOCK
+#define DT_CHR S_IFCHR
+#define DT_BLK S_IFBLK
+#define DT_LNK S_IFLNK
+
+/* Macros for converting between st_mode and d_type */
+#define IFTODT(mode) ((mode) & S_IFMT)
+#define DTTOIF(type) (type)
+
+/*
+ * File type macros. Note that block devices, sockets and links cannot be
+ * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
+ * only defined for compatibility. These macros should always return false
+ * on Windows.
+ */
+#if !defined(S_ISFIFO)
+# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISDIR)
+# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG)
+# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISLNK)
+# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK)
+# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISCHR)
+# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISBLK)
+# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+#endif
+
+ /* Return the exact length of the file name without zero terminator */
+#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
+
+/* Return the maximum size of a file name */
+#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+ /* Wide-character version */
+ struct _wdirent {
+ /* Always zero */
+ long d_ino;
+
+ /* File position within stream */
+ long d_off;
+
+ /* Structure size */
+ unsigned short d_reclen;
+
+ /* Length of name without \0 */
+ size_t d_namlen;
+
+ /* File type */
+ int d_type;
+
+ /* File name */
+ wchar_t d_name[PATH_MAX + 1];
+ };
+ typedef struct _wdirent _wdirent;
+
+ struct _WDIR {
+ /* Current directory entry */
+ struct _wdirent ent;
+
+ /* Private file data */
+ WIN32_FIND_DATAW data;
+
+ /* True if data is valid */
+ int cached;
+
+ /* Win32 search handle */
+ HANDLE handle;
+
+ /* Initial directory name */
+ wchar_t *patt;
+ };
+ typedef struct _WDIR _WDIR;
+
+ /* Multi-byte character version */
+ struct dirent {
+ /* Always zero */
+ long d_ino;
+
+ /* File position within stream */
+ long d_off;
+
+ /* Structure size */
+ unsigned short d_reclen;
+
+ /* Length of name without \0 */
+ size_t d_namlen;
+
+ /* File type */
+ int d_type;
+
+ /* File name */
+ char d_name[PATH_MAX + 1];
+ };
+ typedef struct dirent dirent;
+
+ struct DIR {
+ struct dirent ent;
+ struct _WDIR *wdirp;
+ };
+ typedef struct DIR DIR;
+
+
+ /* Dirent functions */
+ static DIR *opendir(const char *dirname);
+ static _WDIR *_wopendir(const wchar_t *dirname);
+
+ static struct dirent *readdir(DIR *dirp);
+ static struct _wdirent *_wreaddir(_WDIR *dirp);
+
+ static int readdir_r(
+ DIR *dirp, struct dirent *entry, struct dirent **result);
+ static int _wreaddir_r(
+ _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
+
+ static int closedir(DIR *dirp);
+ static int _wclosedir(_WDIR *dirp);
+
+ static void rewinddir(DIR* dirp);
+ static void _wrewinddir(_WDIR* dirp);
+
+ static int scandir(const char *dirname, struct dirent ***namelist,
+ int(*filter)(const struct dirent*),
+ int(*compare)(const struct dirent**, const struct dirent**));
+
+ static int alphasort(const struct dirent **a, const struct dirent **b);
+
+ static int versionsort(const struct dirent **a, const struct dirent **b);
+
+
+ /* For compatibility with Symbian */
+#define wdirent _wdirent
+#define WDIR _WDIR
+#define wopendir _wopendir
+#define wreaddir _wreaddir
+#define wclosedir _wclosedir
+#define wrewinddir _wrewinddir
+
+
+/* Internal utility functions */
+ static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);
+ static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);
+
+ static int dirent_mbstowcs_s(
+ size_t *pReturnValue,
+ wchar_t *wcstr,
+ size_t sizeInWords,
+ const char *mbstr,
+ size_t count);
+
+ static int dirent_wcstombs_s(
+ size_t *pReturnValue,
+ char *mbstr,
+ size_t sizeInBytes,
+ const wchar_t *wcstr,
+ size_t count);
+
+ static void dirent_set_errno(int error);
+
+
+ /*
+ * Open directory stream DIRNAME for read and return a pointer to the
+ * internal working area that is used to retrieve individual directory
+ * entries.
+ */
+ static _WDIR*
+ _wopendir(
+ const wchar_t *dirname)
+ {
+ _WDIR *dirp = NULL;
+ int error;
+
+ /* Must have directory name */
+ if (dirname == NULL || dirname[0] == '\0') {
+ dirent_set_errno(ENOENT);
+ return NULL;
+ }
+
+ /* Allocate new _WDIR structure */
+ dirp = (_WDIR*)malloc(sizeof(struct _WDIR));
+ if (dirp != NULL) {
+ DWORD n;
+
+ /* Reset _WDIR structure */
+ dirp->handle = INVALID_HANDLE_VALUE;
+ dirp->patt = NULL;
+ dirp->cached = 0;
+
+ /* Compute the length of full path plus zero terminator
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume it is an absolute path.
+ */
+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ n = wcslen(dirname);
+# else
+ n = GetFullPathNameW(dirname, 0, NULL, NULL);
+# endif
+
+ /* Allocate room for absolute directory name and search pattern */
+ dirp->patt = (wchar_t*)malloc(sizeof(wchar_t) * n + 16);
+ if (dirp->patt) {
+
+ /*
+ * Convert relative directory name to an absolute one. This
+ * allows rewinddir() to function correctly even when current
+ * working directory is changed between opendir() and rewinddir().
+ *
+ * Note that on WinRT there's no way to convert relative paths
+ * into absolute paths, so just assume it is an absolute path.
+ */
+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ wcsncpy_s(dirp->patt, n + 1, dirname, n);
+# else
+ n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
+# endif
+ if (n > 0) {
+ wchar_t *p;
+
+ /* Append search pattern \* to the directory name */
+ p = dirp->patt + n;
+ if (dirp->patt < p) {
+ switch (p[-1]) {
+ case '\\':
+ case '/':
+ case ':':
+ /* Directory ends in path separator, e.g. c:\temp\ */
+ /*NOP*/;
+ break;
+
+ default:
+ /* Directory name doesn't end in path separator */
+ *p++ = '\\';
+ }
+ }
+ *p++ = '*';
+ *p = '\0';
+
+ /* Open directory stream and retrieve the first entry */
+ if (dirent_first(dirp)) {
+ /* Directory stream opened successfully */
+ error = 0;
+ }
+ else {
+ /* Cannot retrieve first entry */
+ error = 1;
+ dirent_set_errno(ENOENT);
+ }
+
+ }
+ else {
+ /* Cannot retrieve full path name */
+ dirent_set_errno(ENOENT);
+ error = 1;
+ }
+
+ }
+ else {
+ /* Cannot allocate memory for search pattern */
+ error = 1;
+ }
+
+ }
+ else {
+ /* Cannot allocate _WDIR structure */
+ error = 1;
+ }
+
+ /* Clean up in case of error */
+ if (error && dirp) {
+ _wclosedir(dirp);
+ dirp = NULL;
+ }
+
+ return dirp;
+ }
+
+ /*
+ * Read next directory entry.
+ *
+ * Returns pointer to static directory entry which may be overwritten by
+ * subsequent calls to _wreaddir().
+ */
+ static struct _wdirent*
+ _wreaddir(
+ _WDIR *dirp)
+ {
+ struct _wdirent *entry;
+
+ /*
+ * Read directory entry to buffer. We can safely ignore the return value
+ * as entry will be set to NULL in case of error.
+ */
+ (void)_wreaddir_r(dirp, &dirp->ent, &entry);
+
+ /* Return pointer to statically allocated directory entry */
+ return entry;
+ }
+
+ /*
+ * Read next directory entry.
+ *
+ * Returns zero on success. If end of directory stream is reached, then sets
+ * result to NULL and returns zero.
+ */
+ static int
+ _wreaddir_r(
+ _WDIR *dirp,
+ struct _wdirent *entry,
+ struct _wdirent **result)
+ {
+ WIN32_FIND_DATAW *datap;
+
+ /* Read next directory entry */
+ datap = dirent_next(dirp);
+ if (datap) {
+ size_t n;
+ DWORD attr;
+
+ /*
+ * Copy file name as wide-character string. If the file name is too
+ * long to fit in to the destination buffer, then truncate file name
+ * to PATH_MAX characters and zero-terminate the buffer.
+ */
+ n = 0;
+ while (n < PATH_MAX && datap->cFileName[n] != 0) {
+ entry->d_name[n] = datap->cFileName[n];
+ n++;
+ }
+ entry->d_name[n] = 0;
+
+ /* Length of file name excluding zero terminator */
+ entry->d_namlen = n;
+
+ /* File type */
+ attr = datap->dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+ entry->d_type = DT_CHR;
+ }
+ else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ entry->d_type = DT_DIR;
+ }
+ else {
+ entry->d_type = DT_REG;
+ }
+
+ /* Reset dummy fields */
+ entry->d_ino = 0;
+ entry->d_off = 0;
+ entry->d_reclen = sizeof(struct _wdirent);
+
+ /* Set result address */
+ *result = entry;
+
+ }
+ else {
+
+ /* Return NULL to indicate end of directory */
+ *result = NULL;
+
+ }
+
+ return /*OK*/0;
+ }
+
+ /*
+ * Close directory stream opened by opendir() function. This invalidates the
+ * DIR structure as well as any directory entry read previously by
+ * _wreaddir().
+ */
+ static int
+ _wclosedir(
+ _WDIR *dirp)
+ {
+ int ok;
+ if (dirp) {
+
+ /* Release search handle */
+ if (dirp->handle != INVALID_HANDLE_VALUE) {
+ FindClose(dirp->handle);
+ dirp->handle = INVALID_HANDLE_VALUE;
+ }
+
+ /* Release search pattern */
+ if (dirp->patt) {
+ free(dirp->patt);
+ dirp->patt = NULL;
+ }
+
+ /* Release directory structure */
+ free(dirp);
+ ok = /*success*/0;
+
+ }
+ else {
+
+ /* Invalid directory stream */
+ dirent_set_errno(EBADF);
+ ok = /*failure*/-1;
+
+ }
+ return ok;
+ }
+
+ /*
+ * Rewind directory stream such that _wreaddir() returns the very first
+ * file name again.
+ */
+ static void
+ _wrewinddir(
+ _WDIR* dirp)
+ {
+ if (dirp) {
+ /* Release existing search handle */
+ if (dirp->handle != INVALID_HANDLE_VALUE) {
+ FindClose(dirp->handle);
+ }
+
+ /* Open new search handle */
+ dirent_first(dirp);
+ }
+ }
+
+ /* Get first directory entry (internal) */
+ static WIN32_FIND_DATAW*
+ dirent_first(
+ _WDIR *dirp)
+ {
+ WIN32_FIND_DATAW *datap;
+
+ /* Open directory and retrieve the first entry */
+ dirp->handle = FindFirstFileExW(
+ dirp->patt, FindExInfoStandard, &dirp->data,
+ FindExSearchNameMatch, NULL, 0);
+ if (dirp->handle != INVALID_HANDLE_VALUE) {
+
+ /* a directory entry is now waiting in memory */
+ datap = &dirp->data;
+ dirp->cached = 1;
+
+ }
+ else {
+
+ /* Failed to re-open directory: no directory entry in memory */
+ dirp->cached = 0;
+ datap = NULL;
+
+ }
+ return datap;
+ }
+
+ /*
+ * Get next directory entry (internal).
+ *
+ * Returns
+ */
+ static WIN32_FIND_DATAW*
+ dirent_next(
+ _WDIR *dirp)
+ {
+ WIN32_FIND_DATAW *p;
+
+ /* Get next directory entry */
+ if (dirp->cached != 0) {
+
+ /* A valid directory entry already in memory */
+ p = &dirp->data;
+ dirp->cached = 0;
+
+ }
+ else if (dirp->handle != INVALID_HANDLE_VALUE) {
+
+ /* Get the next directory entry from stream */
+ if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) {
+ /* Got a file */
+ p = &dirp->data;
+ }
+ else {
+ /* The very last entry has been processed or an error occurred */
+ FindClose(dirp->handle);
+ dirp->handle = INVALID_HANDLE_VALUE;
+ p = NULL;
+ }
+
+ }
+ else {
+
+ /* End of directory stream reached */
+ p = NULL;
+
+ }
+
+ return p;
+ }
+
+ /*
+ * Open directory stream using plain old C-string.
+ */
+ static DIR*
+ opendir(
+ const char *dirname)
+ {
+ struct DIR *dirp;
+ int error;
+
+ /* Must have directory name */
+ if (dirname == NULL || dirname[0] == '\0') {
+ dirent_set_errno(ENOENT);
+ return NULL;
+ }
+
+ /* Allocate memory for DIR structure */
+ dirp = (DIR*)malloc(sizeof(struct DIR));
+ if (dirp) {
+ wchar_t wname[PATH_MAX + 1];
+ size_t n;
+
+ /* Convert directory name to wide-character string */
+ error = dirent_mbstowcs_s(
+ &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
+ if (!error) {
+
+ /* Open directory stream using wide-character name */
+ dirp->wdirp = _wopendir(wname);
+ if (dirp->wdirp) {
+ /* Directory stream opened */
+ error = 0;
+ }
+ else {
+ /* Failed to open directory stream */
+ error = 1;
+ }
+
+ }
+ else {
+ /*
+ * Cannot convert file name to wide-character string. This
+ * occurs if the string contains invalid multi-byte sequences or
+ * the output buffer is too small to contain the resulting
+ * string.
+ */
+ error = 1;
+ }
+
+ }
+ else {
+ /* Cannot allocate DIR structure */
+ error = 1;
+ }
+
+ /* Clean up in case of error */
+ if (error && dirp) {
+ free(dirp);
+ dirp = NULL;
+ }
+
+ return dirp;
+ }
+
+ /*
+ * Read next directory entry.
+ */
+ static struct dirent*
+ readdir(
+ DIR *dirp)
+ {
+ struct dirent *entry;
+
+ /*
+ * Read directory entry to buffer. We can safely ignore the return value
+ * as entry will be set to NULL in case of error.
+ */
+ (void)readdir_r(dirp, &dirp->ent, &entry);
+
+ /* Return pointer to statically allocated directory entry */
+ return entry;
+ }
+
+ /*
+ * Read next directory entry into called-allocated buffer.
+ *
+ * Returns zero on success. If the end of directory stream is reached, then
+ * sets result to NULL and returns zero.
+ */
+ static int
+ readdir_r(
+ DIR *dirp,
+ struct dirent *entry,
+ struct dirent **result)
+ {
+ WIN32_FIND_DATAW *datap;
+
+ /* Read next directory entry */
+ datap = dirent_next(dirp->wdirp);
+ if (datap) {
+ size_t n;
+ int error;
+
+ /* Attempt to convert file name to multi-byte string */
+ error = dirent_wcstombs_s(
+ &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
+
+ /*
+ * If the file name cannot be represented by a multi-byte string,
+ * then attempt to use old 8+3 file name. This allows traditional
+ * Unix-code to access some file names despite of unicode
+ * characters, although file names may seem unfamiliar to the user.
+ *
+ * Be ware that the code below cannot come up with a short file
+ * name unless the file system provides one. At least
+ * VirtualBox shared folders fail to do this.
+ */
+ if (error && datap->cAlternateFileName[0] != '\0') {
+ error = dirent_wcstombs_s(
+ &n, entry->d_name, PATH_MAX + 1,
+ datap->cAlternateFileName, PATH_MAX + 1);
+ }
+
+ if (!error) {
+ DWORD attr;
+
+ /* Length of file name excluding zero terminator */
+ entry->d_namlen = n - 1;
+
+ /* File attributes */
+ attr = datap->dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+ entry->d_type = DT_CHR;
+ }
+ else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ entry->d_type = DT_DIR;
+ }
+ else {
+ entry->d_type = DT_REG;
+ }
+
+ /* Reset dummy fields */
+ entry->d_ino = 0;
+ entry->d_off = 0;
+ entry->d_reclen = sizeof(struct dirent);
+
+ }
+ else {
+
+ /*
+ * Cannot convert file name to multi-byte string so construct
+ * an erroneous directory entry and return that. Note that
+ * we cannot return NULL as that would stop the processing
+ * of directory entries completely.
+ */
+ entry->d_name[0] = '?';
+ entry->d_name[1] = '\0';
+ entry->d_namlen = 1;
+ entry->d_type = DT_UNKNOWN;
+ entry->d_ino = 0;
+ entry->d_off = -1;
+ entry->d_reclen = 0;
+
+ }
+
+ /* Return pointer to directory entry */
+ *result = entry;
+
+ }
+ else {
+
+ /* No more directory entries */
+ *result = NULL;
+
+ }
+
+ return /*OK*/0;
+ }
+
+ /*
+ * Close directory stream.
+ */
+ static int
+ closedir(
+ DIR *dirp)
+ {
+ int ok;
+ if (dirp) {
+
+ /* Close wide-character directory stream */
+ ok = _wclosedir(dirp->wdirp);
+ dirp->wdirp = NULL;
+
+ /* Release multi-byte character version */
+ free(dirp);
+
+ }
+ else {
+
+ /* Invalid directory stream */
+ dirent_set_errno(EBADF);
+ ok = /*failure*/-1;
+
+ }
+ return ok;
+ }
+
+ /*
+ * Rewind directory stream to beginning.
+ */
+ static void
+ rewinddir(
+ DIR* dirp)
+ {
+ /* Rewind wide-character string directory stream */
+ _wrewinddir(dirp->wdirp);
+ }
+
+ /*
+ * Scan directory for entries.
+ */
+ static int
+ scandir(
+ const char *dirname,
+ struct dirent ***namelist,
+ int(*filter)(const struct dirent*),
+ int(*compare)(const struct dirent**, const struct dirent**))
+ {
+ struct dirent **files = NULL;
+ size_t size = 0;
+ size_t allocated = 0;
+ const size_t init_size = 1;
+ DIR *dir = NULL;
+ struct dirent *entry;
+ struct dirent *tmp = NULL;
+ size_t i;
+ int result = 0;
+
+ /* Open directory stream */
+ dir = opendir(dirname);
+ if (dir) {
+
+ /* Read directory entries to memory */
+ while (1) {
+
+ /* Enlarge pointer table to make room for another pointer */
+ if (size >= allocated) {
+ void *p;
+ size_t num_entries;
+
+ /* Compute number of entries in the enlarged pointer table */
+ if (size < init_size) {
+ /* Allocate initial pointer table */
+ num_entries = init_size;
+ }
+ else {
+ /* Double the size */
+ num_entries = size * 2;
+ }
+
+ /* Allocate first pointer table or enlarge existing table */
+ p = realloc(files, sizeof(void*) * num_entries);
+ if (p != NULL) {
+ /* Got the memory */
+ files = (dirent**)p;
+ allocated = num_entries;
+ }
+ else {
+ /* Out of memory */
+ result = -1;
+ break;
+ }
+
+ }
+
+ /* Allocate room for temporary directory entry */
+ if (tmp == NULL) {
+ tmp = (struct dirent*) malloc(sizeof(struct dirent));
+ if (tmp == NULL) {
+ /* Cannot allocate temporary directory entry */
+ result = -1;
+ break;
+ }
+ }
+
+ /* Read directory entry to temporary area */
+ if (readdir_r(dir, tmp, &entry) == /*OK*/0) {
+
+ /* Did we get an entry? */
+ if (entry != NULL) {
+ int pass;
+
+ /* Determine whether to include the entry in result */
+ if (filter) {
+ /* Let the filter function decide */
+ pass = filter(tmp);
+ }
+ else {
+ /* No filter function, include everything */
+ pass = 1;
+ }
+
+ if (pass) {
+ /* Store the temporary entry to pointer table */
+ files[size++] = tmp;
+ tmp = NULL;
+
+ /* Keep up with the number of files */
+ result++;
+ }
+
+ }
+ else {
+
+ /*
+ * End of directory stream reached => sort entries and
+ * exit.
+ */
+ qsort(files, size, sizeof(void*),
+ (int(*) (const void*, const void*)) compare);
+ break;
+
+ }
+
+ }
+ else {
+ /* Error reading directory entry */
+ result = /*Error*/ -1;
+ break;
+ }
+
+ }
+
+ }
+ else {
+ /* Cannot open directory */
+ result = /*Error*/ -1;
+ }
+
+ /* Release temporary directory entry */
+ if (tmp) {
+ free(tmp);
+ }
+
+ /* Release allocated memory on error */
+ if (result < 0) {
+ for (i = 0; i < size; i++) {
+ free(files[i]);
+ }
+ free(files);
+ files = NULL;
+ }
+
+ /* Close directory stream */
+ if (dir) {
+ closedir(dir);
+ }
+
+ /* Pass pointer table to caller */
+ if (namelist) {
+ *namelist = files;
+ }
+ return result;
+ }
+
+ /* Alphabetical sorting */
+ static int
+ alphasort(
+ const struct dirent **a, const struct dirent **b)
+ {
+ return strcoll((*a)->d_name, (*b)->d_name);
+ }
+
+ /* Sort versions */
+ static int
+ versionsort(
+ const struct dirent **a, const struct dirent **b)
+ {
+ /* FIXME: implement strverscmp and use that */
+ return alphasort(a, b);
+ }
+
+ /* Convert multi-byte string to wide character string */
+ static int
+ dirent_mbstowcs_s(
+ size_t *pReturnValue,
+ wchar_t *wcstr,
+ size_t sizeInWords,
+ const char *mbstr,
+ size_t count)
+ {
+ int error;
+ int n;
+ size_t len;
+ UINT cp;
+ DWORD flags;
+
+ /* Determine code page for multi-byte string */
+ if (AreFileApisANSI()) {
+ /* Default ANSI code page */
+ cp = GetACP();
+ }
+ else {
+ /* Default OEM code page */
+ cp = GetOEMCP();
+ }
+
+ /*
+ * Determine flags based on the character set. For more information,
+ * please see https://docs.microsoft.com/fi-fi/windows/desktop/api/stringapiset/nf-stringapiset-multibytetowidechar
+ */
+ switch (cp) {
+ case 42:
+ case 50220:
+ case 50221:
+ case 50222:
+ case 50225:
+ case 50227:
+ case 50229:
+ case 57002:
+ case 57003:
+ case 57004:
+ case 57005:
+ case 57006:
+ case 57007:
+ case 57008:
+ case 57009:
+ case 57010:
+ case 57011:
+ case 65000:
+ /* MultiByteToWideChar does not support MB_ERR_INVALID_CHARS */
+ flags = 0;
+ break;
+
+ default:
+ /*
+ * Ask MultiByteToWideChar to return an error if a multi-byte
+ * character cannot be converted to a wide-character.
+ */
+ flags = MB_ERR_INVALID_CHARS;
+ }
+
+ /* Compute the length of input string without zero-terminator */
+ len = 0;
+ while (mbstr[len] != '\0' && len < count) {
+ len++;
+ }
+
+ /* Convert to wide-character string */
+ n = MultiByteToWideChar(
+ /* Source code page */ cp,
+ /* Flags */ flags,
+ /* Pointer to string to convert */ mbstr,
+ /* Size of multi-byte string */ (int)len,
+ /* Pointer to output buffer */ wcstr,
+ /* Size of output buffer */ sizeInWords - 1
+ );
+
+ /* Ensure that output buffer is zero-terminated */
+ wcstr[n] = '\0';
+
+ /* Return length of wide-character string with zero-terminator */
+ *pReturnValue = (size_t)(n + 1);
+
+ /* Return zero if conversion succeeded */
+ if (n > 0) {
+ error = 0;
+ }
+ else {
+ error = 1;
+ }
+ return error;
+ }
+
+ /* Convert wide-character string to multi-byte string */
+ static int
+ dirent_wcstombs_s(
+ size_t *pReturnValue,
+ char *mbstr,
+ size_t sizeInBytes, /* max size of mbstr */
+ const wchar_t *wcstr,
+ size_t count)
+ {
+ int n;
+ int error;
+ UINT cp;
+ size_t len;
+ BOOL flag = 0;
+ LPBOOL pflag;
+
+ /* Determine code page for multi-byte string */
+ if (AreFileApisANSI()) {
+ /* Default ANSI code page */
+ cp = GetACP();
+ }
+ else {
+ /* Default OEM code page */
+ cp = GetOEMCP();
+ }
+
+ /* Compute the length of input string without zero-terminator */
+ len = 0;
+ while (wcstr[len] != '\0' && len < count) {
+ len++;
+ }
+
+ /*
+ * Determine if we can ask WideCharToMultiByte to return information on
+ * broken characters. For more information, please see
+ * https://docs.microsoft.com/en-us/windows/desktop/api/stringapiset/nf-stringapiset-widechartomultibyte
+ */
+ switch (cp) {
+ case CP_UTF7:
+ case CP_UTF8:
+ /*
+ * WideCharToMultiByte fails if we request information on default
+ * characters. This is just a nuisance but doesn't affect the
+ * conversion: if Windows is configured to use UTF-8, then the default
+ * character should not be needed anyway.
+ */
+ pflag = NULL;
+ break;
+
+ default:
+ /*
+ * Request that WideCharToMultiByte sets the flag if it uses the
+ * default character.
+ */
+ pflag = &flag;
+ }
+
+ /* Convert wide-character string to multi-byte character string */
+ n = WideCharToMultiByte(
+ /* Target code page */ cp,
+ /* Flags */ 0,
+ /* Pointer to unicode string */ wcstr,
+ /* Length of unicode string */ (int)len,
+ /* Pointer to output buffer */ mbstr,
+ /* Size of output buffer */ sizeInBytes - 1,
+ /* Default character */ NULL,
+ /* Whether default character was used or not */ pflag
+ );
+
+ /* Ensure that output buffer is zero-terminated */
+ mbstr[n] = '\0';
+
+ /* Return length of multi-byte string with zero-terminator */
+ *pReturnValue = (size_t)(n + 1);
+
+ /* Return zero if conversion succeeded without using default characters */
+ if (n > 0 && flag == 0) {
+ error = 0;
+ }
+ else {
+ error = 1;
+ }
+ return error;
+ }
+
+ /* Set errno variable */
+ static void
+ dirent_set_errno(
+ int error)
+ {
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+
+ /* Microsoft Visual Studio 2005 and later */
+ _set_errno(error);
+
+#else
+
+ /* Non-Microsoft compiler or older Microsoft compiler */
+ errno = error;
+
+#endif
+ }
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*DIRENT_H*/#pragma once
diff --git a/app/bin/include/paramfile.h b/app/bin/include/paramfile.h
new file mode 100644
index 0000000..b177b15
--- /dev/null
+++ b/app/bin/include/paramfile.h
@@ -0,0 +1,26 @@
+#ifndef HAVE_PARAMFILE_H
+ #define HAVE_PARAMFILE_H
+ #include <stdbool.h>
+ #include <wlib.h>
+ #include "common.h"
+
+ extern DIST_T curBarScale;
+ extern dynArr_t paramProc_da;
+ extern dynArr_t paramFileInfo_da;
+
+ void ParamCheckSumLine(char * line);
+ wBool_t IsParamValid(int fileInx);
+ bool IsParamFileDeleted(int fileInx);
+ bool IsParamFileFavorite(int fileInx);
+ void SetParamFileState(int index);
+ int ReadParamFile(const char *fileName);
+ int ReloadDeletedParamFile(int fileindex);
+ void SetParamFileDeleted(int fileInx, bool deleted);
+ void SetParamFileFavorite(int fileInx, bool favorite);
+ char * GetParamFileName(int fileInx);
+ char * GetParamFileContents(int fileInx);
+ bool ReadParams(long key, const char * dirName, const char * fileName);
+
+ #define CONTENTSCOMMAND "CONTENTS"
+ char *GetParameterFileContent(char *file);
+#endif // !HAVE_PARAMFILE_H
diff --git a/app/bin/include/paramfilelist.h b/app/bin/include/paramfilelist.h
new file mode 100644
index 0000000..a1c081d
--- /dev/null
+++ b/app/bin/include/paramfilelist.h
@@ -0,0 +1,32 @@
+#ifndef HAVE_PARAMFILELIST_H
+ #define HAVE_PARAMFILELIST_H
+ #include <stdbool.h>
+ #include "include/paramfile.h"
+
+ typedef struct {
+ char * name; /** < name of parameter file */
+ char * contents;
+ bool deleted;
+ bool valid; /** < FALSE for dropped file */
+ bool favorite;
+ enum paramFileState trackState;
+ } paramFileInfo_t;
+ typedef paramFileInfo_t * paramFileInfo_p;
+
+ #define paramFileInfo(N) DYNARR_N( paramFileInfo_t, paramFileInfo_da, N )
+
+ char *GetParamFileDir(void);
+ void SetParamFileDir(char *fullPath);
+ void LoadParamFileList(void);
+ BOOL_T ReadDefaultParams(const char * dirName);
+ void SaveParamFileList(void);
+ int GetParamFileCount();
+ void UpdateParamFileList(void);
+ void ParamFilesChange(long changes);
+ int LoadParamFile(int files, char ** fileName, void * data);
+ BOOL_T ParamFileListInit(void);
+
+ void SearchUiOk(void * junk);
+ bool ReloadParamFile(wIndex_t index);
+ bool UnloadParamFile(wIndex_t fileIndex);
+#endif // !HAVE_PARAMFILELIST_H
diff --git a/app/bin/include/partcatalog.h b/app/bin/include/partcatalog.h
new file mode 100644
index 0000000..eec9d1e
--- /dev/null
+++ b/app/bin/include/partcatalog.h
@@ -0,0 +1,70 @@
+/** \file partcatalog.h
+* Manage the catalog of track parameter files
+*/
+/* XTrkCad - Model Railroad CAD
+* Copyright (C) 2019 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.
+*/
+
+#ifndef HAVE_TRACKCATALOG_H
+#define HAVE_TRACKCATALOG_H
+
+#include <stdbool.h>
+
+#define MAXFILESPERCONTENT 10 /**< count of files with the same content header */
+#define ESTIMATED_CONTENTS_WORDS 10 /**< average count of words in CONTENTS header */
+
+struct sCatalogEntry {
+ struct sCatalogEntry *next;
+ unsigned files; /**< current count of files */
+ char *fullFileName[MAXFILESPERCONTENT]; /**< fully qualified file name */
+ char *contents; /**< content field of parameter file */
+ struct sCatalogEntry *indirect; /**< pointer to another catalog entry */
+};
+
+typedef struct sCatalogEntry CatalogEntry;
+
+struct sIndexEntry {
+ CatalogEntry *value; /**< catalog entry having the key word in contents */
+ char *keyWord; /**< keyword */
+};
+
+typedef struct sIndexEntry IndexEntry;
+
+struct sTrackLibrary {
+ CatalogEntry *catalog; /**< list of files cataloged */
+ IndexEntry *index; /**< Index for lookup */
+ unsigned wordCount; /**< How many words indexed */
+ void * words_array; /**< The array of words */
+ unsigned trackTypeCount; /**< */
+};
+
+typedef struct sTrackLibrary
+ TrackLibrary; /**< core data structure for the catalog */
+
+CatalogEntry *InitCatalog(void);
+TrackLibrary *InitLibrary(void);
+TrackLibrary *CreateLibrary(char *directory);
+void DeleteLibrary(TrackLibrary *tracklib);
+bool GetTrackFiles(TrackLibrary *trackLib, char *directory);
+int GetParameterFileInfo(int files, char ** fileName, void * data);
+unsigned CreateLibraryIndex(TrackLibrary *trackLib);
+unsigned SearchLibrary(TrackLibrary *library, char *searchExpression, CatalogEntry *resultEntries);
+unsigned CountCatalogEntries(CatalogEntry *listHeader);
+void EmptyCatalog(CatalogEntry *listHeader);
+unsigned SearchLibrary(TrackLibrary *library, char *searchExpression, CatalogEntry *resultEntries);
+bool FilterKeyword(char *word);
+#endif // !HAVE_TRACKCATALOG_H
diff --git a/app/bin/include/stringxtc.h b/app/bin/include/stringxtc.h
new file mode 100644
index 0000000..cbadd0e
--- /dev/null
+++ b/app/bin/include/stringxtc.h
@@ -0,0 +1,8 @@
+#include <stddef.h>
+
+#ifndef HAVE_STRINGXTC_H
+ #define HAVE_STRINGXTC_H
+ size_t strscpy(char *dest, const char *src, size_t count);
+ char *XtcStrlwr(char *str);
+ int XtcStricmp(const char *a, const char *b);
+#endif
diff --git a/app/bin/include/utf8convert.h b/app/bin/include/utf8convert.h
new file mode 100644
index 0000000..6a3e678
--- /dev/null
+++ b/app/bin/include/utf8convert.h
@@ -0,0 +1,24 @@
+/* XTrackCad - Model Railroad CAD
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef HAVE_UTF8CONVERT_H
+#include <stdbool.h>
+char *Convert2UTF8(char *string);
+bool RequiresConvToUTF8(char *string);
+void ConvertUTF8ToSystem(unsigned char *in);
+#endif // HAVE_UTF8CONVERT_H
diff --git a/app/bin/layout.c b/app/bin/layout.c
index 584e62b..a77cbb2 100644
--- a/app/bin/layout.c
+++ b/app/bin/layout.c
@@ -31,6 +31,8 @@
#include "paths.h"
#include "track.h"
#include "wlib.h"
+#include "fileio.h"
+#include "utility.h"
#define MINTRACKRADIUSPREFS "minTrackRadius"
@@ -43,6 +45,11 @@ struct sLayoutProps {
DIST_T minTrackRadius;
DIST_T maxTrackGrade;
coOrd roomSize;
+ DynString backgroundFileName;
+ coOrd backgroundPos;
+ ANGLE_T backgroundAngle;
+ int backgroundScreen;
+ double backgroundSize;
};
struct sDataLayout {
@@ -51,8 +58,8 @@ struct sDataLayout {
struct sLayoutProps *copyOfLayoutProps;
};
-struct sDataLayout thisLayout = {
- { "", "", -1, 0, 0, 0.0, 5.0, {0.0, 0.0} },
+static struct sDataLayout thisLayout = {
+ { "", "", -1, 0, 0, 0.0, 5.0, {0.0, 0.0}, NaS, {0.0, 0.0}, 0.0, 0, 0.0 },
NaS,
NULL,
};
@@ -60,6 +67,9 @@ struct sDataLayout thisLayout = {
static paramFloatRange_t r0_90 = { 0, 90 };
static paramFloatRange_t r1_10000 = { 1, 10000 };
static paramFloatRange_t r1_9999999 = { 1, 9999999 };
+static paramFloatRange_t r360_360 = { -360, 360 };
+static paramFloatRange_t rN_9999999 = { -99999, 99999 };
+static paramIntegerRange_t i0_100 = { 0, 100 };
static void LayoutDlgUpdate(paramGroup_p pg, int inx, void * valueP);
@@ -72,14 +82,18 @@ static void LayoutDlgUpdate(paramGroup_p pg, int inx, void * valueP);
void
SetLayoutFullPath(const char *fileName)
{
- if (DynStringToCStr(&thisLayout.fullFileName) != fileName) {
- if (isnas(&thisLayout.fullFileName)) {
- DynStringMalloc(&thisLayout.fullFileName, strlen(fileName) + 1);
- } else {
- DynStringClear(&thisLayout.fullFileName);
- }
-
- DynStringCatCStr(&thisLayout.fullFileName, fileName);
+ if (fileName && fileName[0]) {
+ if (DynStringSize(&thisLayout.fullFileName)) {
+ if (strcmp(DynStringToCStr(&thisLayout.fullFileName),fileName)==0) {
+ return;
+ }
+ DynStringClear(&thisLayout.fullFileName);
+ }
+ DynStringMalloc(&thisLayout.fullFileName, strlen(fileName) + 1);
+ DynStringCatCStr(&thisLayout.fullFileName, fileName);
+ } else {
+ DynStringMalloc(&thisLayout.fullFileName, 2);
+ DynStringCatCStr(&thisLayout.fullFileName, "");
}
}
@@ -157,6 +171,41 @@ SetLayoutCurGauge(GAUGEINX_T gauge)
thisLayout.props.curGaugeInx = gauge;
}
+void SetLayoutBackGroundFullPath(const char *fileName) {
+ if (fileName && fileName[0]) {
+ if (DynStringSize(&thisLayout.props.backgroundFileName)) {
+ if (strcmp(DynStringToCStr(&thisLayout.props.backgroundFileName),fileName)==0) {
+ return;
+ }
+ DynStringClear(&thisLayout.props.backgroundFileName);
+ }
+ DynStringMalloc(&thisLayout.props.backgroundFileName, strlen(fileName) + 1);
+ DynStringCatCStr(&thisLayout.props.backgroundFileName, fileName);
+ } else {
+ DynStringClear(&thisLayout.props.backgroundFileName);
+ DynStringCatCStr(&thisLayout.props.backgroundFileName, "");
+ }
+}
+
+void SetLayoutBackGroundSize(double size) {
+ thisLayout.props.backgroundSize = size;
+}
+
+void SetLayoutBackGroundPos(coOrd pos) {
+ thisLayout.props.backgroundPos = pos;
+
+}
+
+void SetLayoutBackGroundAngle(ANGLE_T angle) {
+ thisLayout.props.backgroundAngle = angle;
+
+}
+
+void SetLayoutBackGroundScreen(int screen) {
+ thisLayout.props.backgroundScreen = screen;
+
+}
+
/**
* Return the full filename.
*
@@ -166,7 +215,8 @@ SetLayoutCurGauge(GAUGEINX_T gauge)
char *
GetLayoutFullPath()
{
- return (DynStringToCStr(&thisLayout.fullFileName));
+ char * s = DynStringToCStr(&thisLayout.fullFileName);
+ return s;
}
/**
@@ -181,7 +231,7 @@ GetLayoutFilename()
char *string = DynStringToCStr(&thisLayout.fullFileName);
if (string) {
- return (FindFilename(string));
+ return FindFilename(string);
} else {
return (NULL);
}
@@ -222,14 +272,188 @@ GetLayoutCurScale()
{
return (thisLayout.props.curScaleInx);
}
+
+char *
+GetLayoutBackGroundFullPath()
+{
+ char * s = DynStringToCStr(&thisLayout.props.backgroundFileName);
+ return s;
+}
+
+double
+GetLayoutBackGroundSize()
+{
+ if (thisLayout.props.backgroundSize > 0.0) {
+ return (thisLayout.props.backgroundSize);
+ } else {
+ return (thisLayout.props.roomSize.x);
+ }
+}
+
+coOrd
+GetLayoutBackGroundPos()
+{
+ return (thisLayout.props.backgroundPos);
+}
+
+ANGLE_T
+GetLayoutBackGroundAngle()
+{
+ return (thisLayout.props.backgroundAngle);
+}
+
+int GetLayoutBackGroundScreen()
+{
+ return (thisLayout.props.backgroundScreen);
+}
+
/****************************************************************************
*
* Layout Dialog
*
*/
+static char backgroundFileName[STR_LONG_SIZE];
+#define TEXT_FIELD_LEN 40
static wWin_p layoutW;
+/**************************************************************************************
+* Show only the end of the background file path including the filename in the Dialog
+*/
+void SetName() {
+ char * name = GetLayoutBackGroundFullPath();
+ if (name && name[0]) { //Ignore ""
+ if (name && (strlen(name)<=TEXT_FIELD_LEN)) {
+ for (unsigned int i=0; i<=strlen(name);i++) {
+ backgroundFileName[i] = name[i];
+ }
+ backgroundFileName[strlen(name)] = '\0';
+ } else {
+ for (int i=TEXT_FIELD_LEN;i>=0; i--) {
+ backgroundFileName[i] = name[strlen(name)-(TEXT_FIELD_LEN-i)];
+ }
+ backgroundFileName[TEXT_FIELD_LEN] = '\0'; //Insurance
+ }
+ } else backgroundFileName[0] = '\0';
+}
+
+static struct wFilSel_t * imageFile_fs;
+
+static paramData_p layout_p;
+static paramGroup_t * layout_pg_p;
+static wBool_t file_changed;
+
+EXPORT BOOL_T haveBackground = FALSE;
+BOOL_T backgroundVisible = TRUE;
+
+char * noname = "";
+
+void
+BackgroundToggleShow()
+{
+ backgroundVisible = !backgroundVisible;
+ wButtonSetBusy(backgroundB, backgroundVisible);
+ MainRedraw();
+}
+
+int GetLayoutBackGroundVisible()
+{
+ return(backgroundVisible);
+}
+
+/*****************************************
+* Try to load the background image file
+*/
+wBool_t
+LoadBackGroundImage(void)
+{
+ char * error;
+ char * background = GetLayoutBackGroundFullPath();
+ if (wDrawSetBackground( mainD.d, background, &error)==-1) {
+ NoticeMessage(_("Unable to load Image File - %s"),_("Ok"),NULL,error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*******************************************************
+* Callback from File Select for Background Image File
+*
+* \param files number of files selected (only first file is used)
+* \param fileName array of pointers to filenames
+* \param data unused
+* \return FALSE
+*/
+EXPORT int LoadImageFile(
+ int files,
+ char ** fileName,
+ void * data )
+{
+ if (files >0) {
+ SetLayoutBackGroundFullPath( strdup(fileName[0]));
+
+ if (!LoadBackGroundImage()) {
+ SetLayoutBackGroundFullPath(noname);
+ backgroundVisible = FALSE;
+ }
+ else {
+ backgroundVisible = TRUE;
+ SetCurrentPath(BACKGROUNDPATHKEY, fileName[0]);
+ }
+ } else {
+ SetLayoutBackGroundFullPath(noname);
+ backgroundVisible = FALSE;
+ }
+ wControlActive((wControl_p)backgroundB, backgroundVisible);
+ wButtonSetBusy(backgroundB, backgroundVisible);
+
+ SetName();
+ file_changed = TRUE;
+ ParamLoadControl(layout_pg_p, 8);
+ return FALSE;
+}
+
+/**********************************************************
+ * Save the Background Parms - forcing a write
+ */
+void LayoutBackGroundSave(void) {
+ char * background = GetLayoutBackGroundFullPath();
+ wPrefSetString("layout", "BackgroundPath", background);
+ wPrefSetFloat("layout", "BackgroundPosX", thisLayout.props.backgroundPos.x);
+ wPrefSetFloat("layout", "BackgroundPosY", thisLayout.props.backgroundPos.y);
+ wPrefSetFloat("layout", "BackgroundAngle", thisLayout.props.backgroundAngle);
+ wPrefSetInteger("layout", "BackgroundScreen", thisLayout.props.backgroundScreen);
+ wPrefSetFloat("layout", "BackgroundSize", thisLayout.props.backgroundSize);
+
+ wPrefFlush();
+}
+
+/************************************************************
+ * Run File Select for the Background Image File
+ */
+static void ImageFileBrowse( void * junk )
+{
+ imageFile_fs = wFilSelCreate( mainW, FS_LOAD, FS_PICTURES, _("Load Background"), sImageFilePattern, LoadImageFile, NULL );
+
+ wFilSelect( imageFile_fs, GetCurrentPath( BACKGROUNDPATHKEY ) );
+ return;
+}
+
+/************************************************************
+ * Remove the background Image File
+ */
+static void ImageFileClear( void * junk)
+{
+ char * noname = "";
+ SetLayoutBackGroundFullPath(noname);
+ wDrawSetBackground( mainD.d, NULL, NULL);
+ SetName();
+ wControlActive((wControl_p)backgroundB, FALSE);
+ file_changed = TRUE;
+ ParamLoadControl(layout_pg_p, 8);
+ MainRedraw();
+}
+
static paramData_t layoutPLs[] = {
{ PD_FLOAT, &thisLayout.props.roomSize.x, "roomsizeX", PDO_NOPREF | PDO_DIM | PDO_NOPSHUPD | PDO_DRAW, &r1_9999999, N_("Room Width"), 0, (void*)(CHANGE_MAIN | CHANGE_MAP) },
{ PD_FLOAT, &thisLayout.props.roomSize.y, "roomsizeY", PDO_NOPREF | PDO_DIM | PDO_NOPSHUPD | PDO_DRAW | PDO_DLGHORZ, &r1_9999999, N_(" Height"), 0, (void*)(CHANGE_MAIN | CHANGE_MAP) },
@@ -241,7 +465,22 @@ static paramData_t layoutPLs[] = {
{ PD_DROPLIST, &thisLayout.props.curGaugeInx, "gauge", PDO_NOPREF | PDO_NOPSHUPD | PDO_NORECORD | PDO_NOUPDACT | PDO_DLGHORZ, (void *)120, N_(" Gauge"), 0, (void *)(CHANGE_SCALE) },
#define MINRADIUSENTRY (6)
{ PD_FLOAT, &thisLayout.props.minTrackRadius, "mintrackradius", PDO_DIM | PDO_NOPSHUPD | PDO_NOPREF, &r1_10000, N_("Min Track Radius"), 0, (void*)(CHANGE_MAIN | CHANGE_LIMITS) },
- { PD_FLOAT, &thisLayout.props.maxTrackGrade, "maxtrackgrade", PDO_NOPSHUPD | PDO_DLGHORZ, &r0_90, N_(" Max Track Grade (%)"), 0, (void*)(CHANGE_MAIN) }
+ { PD_FLOAT, &thisLayout.props.maxTrackGrade, "maxtrackgrade", PDO_NOPSHUPD | PDO_DLGHORZ, &r0_90, N_(" Max Track Grade (%)"), 0, (void*)(CHANGE_MAIN) },
+#define BACKGROUNDFILEENTRY (8) //Note this value used in the file section routines above - if it chnages, they will need to change
+ { PD_STRING, &backgroundFileName, "backgroundfile", PDO_NOPSHUPD, NULL, N_("Background File Path"), 0, (void *)(CHANGE_BACKGROUND) },
+ { PD_BUTTON, (void*)ImageFileBrowse, "browse", PDO_DLGHORZ, NULL, N_("Browse ...") },
+ { PD_BUTTON, (void*)ImageFileClear, "clear", PDO_DLGHORZ, NULL, N_("Clear") },
+#define BACKGROUNDPOSX (11)
+ { PD_FLOAT, &thisLayout.props.backgroundPos.x, "backgroundposX", PDO_DIM | PDO_NOPSHUPD | PDO_DRAW, &rN_9999999, N_("Background PosX,Y"), 0, (void*)(CHANGE_BACKGROUND) },
+#define BACKGROUNDPOSY (12)
+ { PD_FLOAT, &thisLayout.props.backgroundPos.y, "backgroundposY", PDO_DIM | PDO_NOPSHUPD | PDO_DRAW | PDO_DLGHORZ, &rN_9999999, NULL, 0, (void*)(CHANGE_BACKGROUND) },
+#define BACKGROUNDWIDTH (13)
+ { PD_FLOAT, &thisLayout.props.backgroundSize, "backgroundWidth", PDO_DIM | PDO_NOPSHUPD | PDO_DRAW, &r1_9999999, N_("Background Size"), 0, (void*)(CHANGE_BACKGROUND) },
+#define BACKGROUNDSCREEN (14)
+ { PD_LONG, &thisLayout.props.backgroundScreen, "backgroundScreen", PDO_NOPSHUPD | PDO_DRAW, &i0_100, N_("Background Screen %"), 0, (void*)(CHANGE_BACKGROUND) },
+#define BACKGROUNDANGLE (15)
+ { PD_FLOAT, &thisLayout.props.backgroundAngle, "backgroundAngle", PDO_NOPSHUPD | PDO_DRAW, &r360_360, N_("Background Angle"), 0, (void*)(CHANGE_BACKGROUND) }
+
};
static paramGroup_t layoutPG = { "layout", PGO_RECORD | PGO_PREFMISC, layoutPLs, sizeof layoutPLs / sizeof layoutPLs[0] };
@@ -278,10 +517,20 @@ static void LayoutOk(void * junk)
wPrefSetFloat("misc", prefString, thisLayout.props.minTrackRadius);
}
+ if ((changes & CHANGE_BACKGROUND) || file_changed) {
+
+ LayoutBackGroundSave();
+ file_changed = FALSE;
+ }
+
free(thisLayout.copyOfLayoutProps);
wHide(layoutW);
+
+ MainLayout( TRUE, TRUE );
}
+
+
/**
* Discard the changes entered and replace with earlier values
*
@@ -297,7 +546,7 @@ static void LayoutCancel(struct wWin_t *junk)
static void LayoutChange(long changes)
{
- if (changes & (CHANGE_SCALE | CHANGE_UNITS))
+ if (changes & (CHANGE_SCALE | CHANGE_UNITS | CHANGE_BACKGROUND))
if (layoutW != NULL && wWinIsVisible(layoutW)) {
ParamLoadControls(&layoutPG);
}
@@ -305,7 +554,7 @@ static void LayoutChange(long changes)
void DoLayout(void * junk)
{
- thisLayout.props.roomSize = mapD.size;
+ SetLayoutRoomSize(mapD.size);
if (layoutW == NULL) {
layoutW = ParamCreateDialog(&layoutPG, MakeWindowTitle(_("Layout Options")),
@@ -313,6 +562,8 @@ void DoLayout(void * junk)
LoadScaleList((wList_p)layoutPLs[4].control);
}
+ ParamControlActive(&layoutPG, BACKGROUNDFILEENTRY, FALSE);
+
LoadGaugeList((wList_p)layoutPLs[5].control,
thisLayout.props.curScaleDescInx); /* set correct gauge list here */
thisLayout.copyOfLayoutProps = malloc(sizeof(struct sLayoutProps));
@@ -320,7 +571,7 @@ void DoLayout(void * junk)
if (!thisLayout.copyOfLayoutProps) {
exit(1);
}
-
+ SetName();
*(thisLayout.copyOfLayoutProps) = thisLayout.props;
ParamLoadControls(&layoutPG);
@@ -331,6 +582,8 @@ EXPORT addButtonCallBack_t LayoutInit(void)
{
ParamRegister(&layoutPG);
RegisterChangeNotification(LayoutChange);
+ layout_p = layoutPLs;
+ layout_pg_p = &layoutPG;
return &DoLayout;
}
@@ -372,4 +625,83 @@ LayoutDlgUpdate(
wStringSetValue((wString_p)layoutPLs[MINRADIUSENTRY].control,
FormatDistance(thisLayout.props.minTrackRadius));
}
+ if (inx == BACKGROUNDPOSX) {
+ coOrd pos;
+ pos.x = *(double *)valueP;
+ pos.y = GetLayoutBackGroundPos().y;
+ SetLayoutBackGroundPos(pos);
+ MainRedraw();
+ }
+ if (inx == BACKGROUNDPOSY) {
+ coOrd pos;
+ pos.y = *(double *)valueP;
+ pos.x = GetLayoutBackGroundPos().x;
+ SetLayoutBackGroundPos(pos);
+ MainRedraw();
+ }
+ if (inx == BACKGROUNDWIDTH) {
+ SetLayoutBackGroundSize(*(double *)valueP);
+ MainRedraw();
+ }
+ if (inx == BACKGROUNDSCREEN) {
+ SetLayoutBackGroundScreen(*(int *)valueP);
+ MainRedraw();
+ }
+ if (inx == BACKGROUNDANGLE) {
+
+ ANGLE_T angle = NormalizeAngle(*(double *)valueP);
+ wStringSetValue((wString_p)layoutPLs[BACKGROUNDANGLE].control,FormatFloat(angle));
+ SetLayoutBackGroundAngle(angle);
+ MainRedraw();
+ }
+
+}
+/***************************************************************************************
+ * Load Background Options from Saved Parms
+ ***************************************************************************************/
+void
+LayoutBackGroundLoad(void) {
+ SetLayoutBackGroundFullPath(wPrefGetString("layout", "BackgroundPath"));
+
+ wPrefGetFloat("layout", "BackgroundPosX", &thisLayout.props.backgroundPos.x, 0.0);
+ wPrefGetFloat("layout", "BackgroundPosY", &thisLayout.props.backgroundPos.y, 0.0);
+ wPrefGetFloat("layout", "BackgroundAngle", &thisLayout.props.backgroundAngle, 0.0);
+ long screen_long;
+ wPrefGetInteger("layout", "BackgroundScreen", &screen_long, 0L);
+ thisLayout.props.backgroundScreen = screen_long;
+ wPrefGetFloat("layout", "BackgroundSize", &thisLayout.props.backgroundSize, 0.0);
+}
+
+static wBool_t inited;
+
+/**************************************************************************************
+ * Either Clear Background Parms or (if the first time called) Load from Saved Parms
+ **************************************************************************************/
+void
+LayoutBackGroundInit(BOOL_T clear) {
+ if (clear) {
+ SetLayoutBackGroundFullPath(noname);
+ SetLayoutBackGroundPos(zero);
+ SetLayoutBackGroundAngle(0.0);
+ SetLayoutBackGroundScreen(0);
+ SetLayoutBackGroundSize(0.0);
+ LayoutBackGroundSave();
+ } else { //First Time and not "Clear"
+ inited = TRUE;
+ LayoutBackGroundLoad();
+ }
+ char * str = GetLayoutBackGroundFullPath();
+ if (str && str[0]) {
+ if (!LoadBackGroundImage()) { //Failed -> Wipe Out
+ SetLayoutBackGroundFullPath(noname);
+ SetLayoutBackGroundPos(zero);
+ SetLayoutBackGroundAngle(0.0);
+ SetLayoutBackGroundScreen(0);
+ SetLayoutBackGroundSize(0.0);
+ LayoutBackGroundSave();
+ }
+ } else {
+ wDrawSetBackground( mainD.d, NULL, NULL);
+ }
+
}
diff --git a/app/bin/layout.h b/app/bin/layout.h
index 4a581df..fcb5160 100644
--- a/app/bin/layout.h
+++ b/app/bin/layout.h
@@ -38,6 +38,11 @@ void SetLayoutCurScale(SCALEINX_T scale);
void SetLayoutCurScaleDesc(SCALEDESCINX_T desc);
void SetLayoutCurGauge(GAUGEINX_T gauge);
void SetLayoutScaleGauge(SCALEDESCINX_T desc, GAUGEINX_T gauge);
+void SetLayoutBackGroundFullPath(const char *fileName);
+void SetLayoutBackGroundSize(double size);
+void SetLayoutBackGroundPos(coOrd pos);
+void SetLayoutBackGroundAngle(ANGLE_T angle);
+void SetLayoutBackGroundScreen(int screen);
char *GetLayoutFullPath(void);
char *GetLayoutFilename(void);
@@ -48,9 +53,18 @@ SCALEINX_T GetLayoutCurScale(void );
SCALEDESCINX_T GetLayoutCurScaleDesc(void);
//GAUGEINX_T GetLayoutCurGauge(void);
-
ANGLE_T GetLayoutMaxTrackGrade(void);
SCALEDESCINX_T GetLayoutCurScaleDesc(void);
-
+char *GetLayoutBackGroundFullPath(void);
+double GetLayoutBackGroundSize(void);
+coOrd GetLayoutBackGroundPos(void);
+ANGLE_T GetLayoutBackGroundAngle(void);
+int GetLayoutBackGroundScreen(void);
+int GetLayoutBackGroundVisible(void);
+void LayoutBackGroundInit(BOOL_T clear);
+void LayoutBackGroundLoad(void);
+void LayoutBackGroundSave(void);
+void BackgroundToggleShow(void);
void DoLayout(void * junk);
-#endif \ No newline at end of file
+int LoadImageFile(int files,char ** fileName,void * data );
+#endif
diff --git a/app/bin/linknoteui.c b/app/bin/linknoteui.c
new file mode 100644
index 0000000..daa3ccf
--- /dev/null
+++ b/app/bin/linknoteui.c
@@ -0,0 +1,260 @@
+/** \file linknoteui.c
+ * View for the text note
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2018 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 <string.h>
+#include <stdbool.h>
+
+#include "custom.h"
+#include "dynstring.h"
+#include "i18n.h"
+#include "misc.h"
+#include "note.h"
+#include "param.h"
+#include "include/stringxtc.h"
+#include "track.h"
+#include "validator.h"
+#include "wlib.h"
+
+extern BOOL_T inDescribeCmd;
+
+#define DEFAULTLINKURL "http://www.xtrkcad.org/"
+#define DEFAULTLINKTITLE "The XTrackCAD Homepage"
+
+static struct extraDataNote noteDataInUI;
+
+static void NoteLinkBrowse(void *junk);
+static void NoteLinkOpen(char *url );
+
+static paramFloatRange_t r_1000_1000 = { -1000.0, 1000.0, 80 };
+static paramData_t linkEditPLs[] = {
+#define I_ORIGX (0)
+ /*0*/ { PD_FLOAT, &noteDataInUI.pos.x, "origx", PDO_DIM, &r_1000_1000, N_("Position X") },
+#define I_ORIGY (1)
+ /*1*/ { PD_FLOAT, &noteDataInUI.pos.y, "origy", PDO_DIM, &r_1000_1000, N_("Position Y") },
+#define I_LAYER (2)
+ /*2*/ { PD_DROPLIST, &noteDataInUI.layer, "layer", 0, (void*)150, "Layer", 0 },
+#define I_TITLE (3)
+ /*3*/ { PD_STRING, NULL, "title", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)200, N_("Title"), 0, 0, TITLEMAXIMUMLENGTH-1 },
+#define I_URL (4)
+ /*4*/ { PD_STRING, NULL, "name", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)200, N_("URL"), 0, 0, URLMAXIMUMLENGTH-1 },
+#define I_OPEN (5)
+ /*5*/{ PD_BUTTON, (void*)NoteLinkBrowse, "openlink", PDO_DLGHORZ, NULL, N_("Open...") },
+};
+
+static paramGroup_t linkEditPG = { "linkEdit", 0, linkEditPLs, sizeof linkEditPLs / sizeof linkEditPLs[0] };
+static wWin_p linkEditW;
+
+BOOL_T
+IsLinkNote(track_p trk)
+{
+ struct extraDataNote * xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ return(xx->op == OP_NOTELINK);
+}
+
+
+/**
+ * Callback for Open URL button
+ *
+ * \param junk IN ignored
+ */
+static void NoteLinkBrowse(void *junk)
+{
+ NoteLinkOpen(noteDataInUI.noteData.linkData.url);
+}
+
+/**
+ * Open the URL in the external default browser
+ *
+ * \param url IN url to open
+ */
+static void NoteLinkOpen(char *url)
+{
+ wOpenFileExternal(url);
+}
+
+static void
+LinkDlgUpdate(
+ paramGroup_p pg,
+ int inx,
+ void * valueP)
+{
+ switch (inx) {
+ case I_URL:
+ if (strlen(noteDataInUI.noteData.linkData.url) > URLMAXIMUMLENGTH) {
+ DynString message;
+
+ DynStringMalloc(&message, 80);
+ DynStringPrintf(&message, _("The entered URL is too long. The maximum allowed length is %d. Please edit the entered value."), URLMAXIMUMLENGTH);
+ wNoticeEx(NT_ERROR,
+ DynStringToCStr(&message),
+ _("Re-edit"),
+ NULL);
+ DynStringFree(&message);
+ }
+
+ if (IsValidURL(noteDataInUI.noteData.linkData.url) &&
+ (strlen(noteDataInUI.noteData.linkData.url) <= URLMAXIMUMLENGTH))
+ {
+ wControlActive(linkEditPLs[I_OPEN].control, TRUE);
+ ParamDialogOkActive(&linkEditPG, TRUE);
+ } else {
+ wControlActive(linkEditPLs[I_OPEN].control, FALSE);
+ ParamDialogOkActive(&linkEditPG, FALSE);
+ }
+ break;
+ case I_ORIGX:
+ case I_ORIGY:
+ UpdateLink(&noteDataInUI, OR_NOTE, FALSE);
+ break;
+ case I_LAYER:
+ UpdateLink(&noteDataInUI, LY_NOTE, FALSE);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+* Handle Cancel button: restore old values for layer and position
+*/
+
+static void
+LinkEditCancel( wWin_p junk)
+{
+ if (inDescribeCmd) {
+ UpdateFile(&noteDataInUI, CANCEL_NOTE, FALSE);
+ }
+ ResetIfNotSticky();
+ wHide(linkEditW);
+}
+
+/**
+ * Handle OK button: make sure the entered URL is syntactically valid, update
+ * the layout and close the dialog
+ *
+ * \param junk
+ */
+
+static void
+LinkEditOK(void *junk)
+{
+ UpdateLink(&noteDataInUI, OK_LINK, FALSE);
+ wHide(linkEditW);
+ ResetIfNotSticky();
+ FileIsChanged();
+}
+
+
+static void
+CreateEditLinkDialog(track_p trk, char *title)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ // create the dialog if necessary
+ if (!linkEditW) {
+ noteDataInUI.noteData.linkData.url = MyMalloc(URLMAXIMUMLENGTH);
+ noteDataInUI.noteData.linkData.title = MyMalloc(TITLEMAXIMUMLENGTH);
+ linkEditPLs[I_TITLE].valueP = noteDataInUI.noteData.linkData.title;
+ linkEditPLs[I_URL].valueP = noteDataInUI.noteData.linkData.url;
+ ParamRegister(&linkEditPG);
+ linkEditW = ParamCreateDialog(&linkEditPG,
+ "",
+ _("Done"), LinkEditOK,
+ LinkEditCancel, TRUE, NULL,
+ F_BLOCK,
+ LinkDlgUpdate);
+ }
+
+ wWinSetTitle(linkEditPG.win, MakeWindowTitle(title));
+
+ // initialize the dialog fields
+ noteDataInUI.pos = xx->pos;
+ noteDataInUI.layer = xx->layer;
+ noteDataInUI.trk = trk;
+ strscpy(noteDataInUI.noteData.linkData.url, xx->noteData.linkData.url,URLMAXIMUMLENGTH );
+ strscpy(noteDataInUI.noteData.linkData.title, xx->noteData.linkData.title, TITLEMAXIMUMLENGTH );
+
+ FillLayerList((wList_p)linkEditPLs[I_LAYER].control);
+ ParamLoadControls(&linkEditPG);
+
+ // and show the dialog
+ wShow(linkEditW);
+}
+
+/**
+ * Activate note if double clicked
+ * \param trk the note
+ */
+
+void ActivateLinkNote(track_p trk)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ NoteLinkOpen(xx->noteData.linkData.url);
+}
+
+
+/**
+ * Describe and enable editing of an existing link note
+ *
+ * \param trk the existing, valid note
+ * \param str the field to put a text version of the note so it will appear on the status line
+ * \param len the lenght of the field
+ */
+
+void DescribeLinkNote(track_p trk, char * str, CSIZE_T len)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ DynString statusLine;
+
+ DynStringMalloc(&statusLine, 80);
+ DynStringPrintf(&statusLine,
+ "Link: Layer=%d %-.80s (%s)",
+ GetTrkLayer(trk)+1,
+ xx->noteData.linkData.title,
+ xx->noteData.linkData.url);
+ strcpy(str, DynStringToCStr(&statusLine));
+ DynStringFree(&statusLine);
+
+ if (inDescribeCmd) {
+ NoteStateSave(trk);
+
+ CreateEditLinkDialog(trk, _("Update link"));
+ }
+}
+
+/**
+ * Take a new note track element and initialize it. It will be
+ * initialized with defaults and can then be edited by the user.
+ *
+ * \param the newly created trk
+ */
+
+void NewLinkNoteUI(track_p trk)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ xx->noteData.linkData.url = MyStrdup( DEFAULTLINKURL );
+ xx->noteData.linkData.title = MyStrdup( DEFAULTLINKTITLE );
+
+ CreateEditLinkDialog(trk, _("Create link"));
+}
diff --git a/app/bin/macro.c b/app/bin/macro.c
index 1c711ce..8db996d 100644
--- a/app/bin/macro.c
+++ b/app/bin/macro.c
@@ -1,4 +1,5 @@
/** \file macro.c
+
* Macros
*/
@@ -60,6 +61,7 @@
#include "param.h"
#include "paths.h"
#include "track.h"
+#include "trackx.h"
#include "utility.h"
#include "version.h"
@@ -67,6 +69,9 @@ EXPORT long adjTimer;
static void DemoInitValues( void );
extern char *userLocale;
+static int log_playbackCursor = 0;
+
+
/*****************************************************************************
*
@@ -185,7 +190,7 @@ static int StartRecord( int cnt, char ** pathName, void * context )
if ( logTable_da.cnt > 11 )
lprintf( "StartRecord( %s ) @ %s\n", pathName, ctime(&clock) );
ParamStartRecord();
- WriteTracks( recordF );
+ WriteTracks( recordF, TRUE );
WriteLayers( recordF );
fprintf( recordF, "REDRAW\n" );
fflush( recordF );
@@ -207,7 +212,7 @@ static void DoRecordButton( void * context )
case 0: /* Stop */
fprintf( recordF, "CLEAR\nMESSAGE\n");
fprintf( recordF, N_("End of Playback. Hit Step to exit\n"));
- fprintf( recordF, "END\nSTEP\n" );
+ fprintf( recordF, "%s\nSTEP\n", END_MESSAGE );
fclose( recordF );
recordF = NULL;
wHide( recordW );
@@ -226,7 +231,7 @@ static void DoRecordButton( void * context )
wTextGetText( recordT, cp, len );
if ( cp[len-1] == '\n' ) len--;
cp[len] = '\0';
- fprintf( recordF, "%s\nEND\nSTEP\n", cp );
+ fprintf( recordF, "%s\n%s\nSTEP\n", cp, END_MESSAGE );
MyFree( cp );
recordingMessage = FALSE;
}
@@ -284,59 +289,101 @@ EXPORT void DoRecord( void * context )
*
*/
+static drawCmd_p playbackD = NULL;
static wDrawBitMap_p playbackBm = NULL;
static wDrawColor playbackColor;
-static drawCmd_p playbackD;
static wPos_t playbackX, playbackY;
+static wBool_t bDoFlash = FALSE;
+static wDrawColor flashColor;
#include "bitmaps/arrow0.xbm"
+#include "bitmaps/arrow0_shift.xbm"
+#include "bitmaps/arrow0_ctl.xbm"
#include "bitmaps/arrow3.xbm"
+#include "bitmaps/arrow3_shift.xbm"
+#include "bitmaps/arrow3_ctl.xbm"
#include "bitmaps/arrows.xbm"
+#include "bitmaps/arrowr3.xbm"
+#include "bitmaps/arrowr3_shift.xbm"
+#include "bitmaps/arrowr3_ctl.xbm"
#include "bitmaps/flash.xbm"
static wDrawColor rightDragColor;
static wDrawColor leftDragColor;
static wDrawBitMap_p arrow0_bm;
+static wDrawBitMap_p arrow0_shift_bm;
+static wDrawBitMap_p arrow0_ctl_bm;
static wDrawBitMap_p arrow3_bm;
+static wDrawBitMap_p arrow3_shift_bm;
+static wDrawBitMap_p arrow3_ctl_bm;
static wDrawBitMap_p arrows_bm;
+static wDrawBitMap_p arrowr3_bm;
+static wDrawBitMap_p arrowr3_shift_bm;
+static wDrawBitMap_p arrowr3_ctl_bm;
static wDrawBitMap_p flash_bm;
-static long flashTO = 60;
-static DIST_T PixelsPerStep = 20;
+static long flashTO = 120;
+static DIST_T PixelsPerStep = 5;
static long stepTO = 100;
EXPORT unsigned long playbackTimer;
static wBool_t didPause;
static wBool_t flashTwice = FALSE;
+int DBMCount=0;
#define DRAWALL
+typedef enum { FLASH_PLUS, FLASH_MINUS, REDRAW, CLEAR, DRAW, RESET, ORIG, MOVE_PLYBCK1, MOVE_PLYBCK2, MOVE_PLYBCK3, MOVE_PLYBCK4, QUIT } DrawBitMap_e;
+
+char * DrawBitMapToString(DrawBitMap_e dbm) {
+ switch(dbm) {
+ case FLASH_PLUS:
+ return "Flsh+";
+ case FLASH_MINUS:
+ return "Flsh-";
+ case REDRAW:
+ return "Redraw";
+ case CLEAR:
+ return "Clr";
+ case DRAW:
+ return "Draw";
+ case RESET:
+ return "RESET";
+ case ORIG:
+ return "ORIG";
+ case MOVE_PLYBCK1:
+ return "MPBC1";
+ case MOVE_PLYBCK2:
+ return "MPBC2";
+ case MOVE_PLYBCK3:
+ return "MPBC3";
+ case MOVE_PLYBCK4:
+ return "MPBC4";
+ case QUIT:
+ return "Quit";
+ default:
+ return "";
+ }
+}
+
static void MacroDrawBitMap(
- drawCmd_p d,
+ DrawBitMap_e dbm,
wDrawBitMap_p bm,
wPos_t x,
wPos_t y,
wDrawColor color )
{
- wDrawBitMap( d->d, bm, x, y, color, wDrawOptTemp|wDrawOptNoClip );
+ wDrawBitMap( playbackD->d, bm, x, y, color, wDrawOptTemp|wDrawOptNoClip );
wFlush();
+
+ LOG( log_playbackCursor, 1, ("%s %d DrawBitMap( %p %p %d %d %d %d )\n", DrawBitMapToString(dbm), DBMCount++, playbackD->d, bm, x, y, color, wDrawOptTemp|wDrawOptNoClip ) );
}
-static void Flash( drawCmd_p d, wPos_t x, wPos_t y, wDrawColor flashColor )
+static void Flash( drawCmd_p d, wPos_t x, wPos_t y, wDrawColor color )
{
- if (playbackTimer != 0)
- return;
- MacroDrawBitMap( d, flash_bm, x, y, flashColor );
- wPause( flashTO );
- MacroDrawBitMap( d, flash_bm, x, y, flashColor );
- wPause( flashTO );
-#ifdef LATER
- MacroDrawBitMap( d->d, flash_bm, x, y, flashColor );
- wPause( flashTO );
- MacroDrawBitMap( d->d, flash_bm, x, y, flashColor );
- wPause( flashTO );
-#endif
+ bDoFlash = TRUE;
+ flashColor = color;
}
@@ -358,13 +405,26 @@ static void SetPlaybackSpeed(
playbackSpeed = inx;
}
-static void ClearPlaybackCursor( void )
-{
- if (playbackBm != NULL)
- MacroDrawBitMap( playbackD, playbackBm, playbackX, playbackY, playbackColor );
- playbackBm = NULL;
-}
+EXPORT void RedrawPlaybackCursor() {
+ if ( playbackD && playbackBm && inPlayback) {
+ wBool_t ret;
+ if ( playbackD->d != mainD.d )
+ ret = wDrawSetTempMode( playbackD->d, TRUE );
+ if ( bDoFlash && playbackTimer == 0 ) {
+ MacroDrawBitMap( FLASH_PLUS, flash_bm, playbackX, playbackY, flashColor );
+ wPause( flashTO*2 );
+ if ( flashTwice ) {
+ MacroDrawBitMap( FLASH_PLUS, flash_bm, playbackX, playbackY, flashColor );
+ wPause( flashTO*2 );
+ }
+ bDoFlash = FALSE;
+ }
+ MacroDrawBitMap( DRAW, playbackBm, playbackX, playbackY, playbackColor );
+ if ( playbackD->d != mainD.d )
+ wDrawSetTempMode( playbackD->d, ret );
+ }
+}
static void MoveCursor(
drawCmd_p d,
@@ -378,45 +438,56 @@ static void MoveCursor(
coOrd pos1, dpos;
int i, steps;
wPos_t x, y;
- wPos_t xx, yy;
-
- ClearPlaybackCursor();
+ wPos_t x0=playbackX;
+ wPos_t y0=playbackY;
if (d == NULL)
return;
- pos1 = pos;
d->CoOrd2Pix( d, pos, &x, &y );
- if (playbackTimer == 0 && playbackD == d && !didPause) {
- dx = (DIST_T)(x-playbackX);
- dy = (DIST_T)(y-playbackY);
+ if (playbackTimer == 0 /*&& !didPause*/) {
+ playbackBm = bm;
+ playbackColor = color;
+ dx = (DIST_T)(x-x0);
+ dy = (DIST_T)(y-y0);
dist = sqrt( dx*dx + dy*dy );
steps = (int)(dist / PixelsPerStep ) + 1;
dx /= steps;
dy /= steps;
- d->Pix2CoOrd( d, playbackX, playbackY, &pos1 );
+ d->Pix2CoOrd( d, x0, y0, &pos1 );
dpos.x = (pos.x-pos1.x)/steps;
dpos.y = (pos.y-pos1.y)/steps;
+
for ( i=1; i<=steps; i++ ) {
- xx = playbackX+(wPos_t)(i*dx);
- yy = playbackY+(wPos_t)(i*dy);
- MacroDrawBitMap( d, bm, xx, yy, color );
+
+ playbackX = x0+(wPos_t)(i*dx);
+ playbackY = y0+(wPos_t)(i*dy);
+
pos1.x += dpos.x;
pos1.y += dpos.y;
- if (proc)
+ if ( proc != NULL ) {
proc( action, pos1 );
- else if (d->d == mainD.d) {
+ } else {
+ TempRedraw();
+ }
+// DrawPlaybackCursor( d, bm, xx, yy, color );
+ if ( d->d == mainD.d ) {
InfoPos( pos1 );
+ wFlush();
}
- wPause( stepTO*playbackDelay/100 );
- MacroDrawBitMap( d, bm, xx, yy, color );
+ // Simple mouse moves happen twice as fast
+ wPause( stepTO*playbackDelay/100/(action==wActionMove?2:1) );
+
+
if (!inPlayback) {
return;
}
}
+ } else {
+ playbackX = x;
+ playbackY = y;
}
- MacroDrawBitMap( playbackD=d, playbackBm=bm, playbackX=x, playbackY=y, playbackColor=color );
}
@@ -427,76 +498,86 @@ static void PlaybackCursor(
coOrd pos,
wDrawColor color )
{
- wDrawBitMap_p bm;
+ wDrawBitMap_p bm = playbackBm;
+ playbackD = d;
wPos_t x, y;
long time0, time1;
time0 = wGetTimer();
- ClearPlaybackCursor();
d->CoOrd2Pix( d, pos, &x, &y );
- switch( action ) {
+
+
+ switch( action&0xFF ) {
case wActionMove:
- MacroDrawBitMap( playbackD=d, playbackBm=arrow0_bm, playbackX=x, playbackY=y, playbackColor=wDrawColorBlack );
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrow0_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrow0_ctl_bm:arrow0_bm); //0 is normal, shift, ctrl
+ MoveCursor( d, proc, wActionMove, pos, bm, wDrawColorBlack );
break;
case C_DOWN:
- MoveCursor( d, proc, wActionMove, pos, arrow0_bm, wDrawColorBlack );
- if (flashTwice) Flash( d, x, y, rightDragColor );
- MacroDrawBitMap( d, arrow0_bm, x, y, wDrawColorBlack );
- MacroDrawBitMap( playbackD=d, playbackBm=((MyGetKeyState()&WKEY_SHIFT)?arrows_bm:arrow3_bm), playbackX=x, playbackY=y,
- playbackColor=rightDragColor );
- Flash( d, x, y, rightDragColor );
- break;
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrow0_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrow0_ctl_bm:arrow0_bm);
+ MoveCursor( d, proc, wActionMove, pos, bm, wDrawColorBlack ); //Go to spot
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrow3_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrow3_ctl_bm:arrow3_bm);
+ Flash( d, x, y, playbackColor=rightDragColor );
+ proc( action, pos );
+ /* no break */
case C_MOVE:
- bm = ((MyGetKeyState()&WKEY_SHIFT)?arrows_bm:arrow3_bm);
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrow3_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrow3_ctl_bm:arrow3_bm);
MoveCursor( d, proc, C_MOVE, pos, bm, rightDragColor );
- playbackD=d; playbackBm=bm; playbackX=x; playbackY=y; playbackColor=rightDragColor;
break;
case C_UP:
- bm = ((MyGetKeyState()&WKEY_SHIFT)?arrows_bm:arrow3_bm);
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrow3_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrow3_ctl_bm:arrow0_bm);
MoveCursor( d, proc, C_MOVE, pos, bm, rightDragColor );
- /*MacroDrawBitMap( d, bm, x, y, rightDragColor );*/
- if (flashTwice) Flash( d, x, y, rightDragColor );
- MacroDrawBitMap( d, bm, x, y, rightDragColor );
- MacroDrawBitMap( playbackD=d, playbackBm=arrow0_bm, playbackX=x, playbackY=y, playbackColor=wDrawColorBlack );
Flash( d, x, y, rightDragColor );
+ proc( action, pos );
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrow0_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrow0_ctl_bm:arrow0_bm);
+ MoveCursor( d, NULL, 0, pos, bm, wDrawColorBlack );
break;
case C_RDOWN:
- MoveCursor( d, proc, wActionMove, pos, arrow0_bm, wDrawColorBlack );
- if (flashTwice) Flash( d, x, y, leftDragColor );
- MacroDrawBitMap( d, arrow0_bm, x, y, wDrawColorBlack );
- MacroDrawBitMap( playbackD=d, playbackBm=((MyGetKeyState()&WKEY_SHIFT)?arrows_bm:arrow3_bm), playbackX=x, playbackY=y, playbackColor=leftDragColor );
- Flash( d, x, y, leftDragColor );
- break;
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrow0_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrow0_ctl_bm:arrow0_bm);
+ MoveCursor( d, proc, wActionMove, pos, bm, wDrawColorBlack ); //Go to spot
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrowr3_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrowr3_ctl_bm:arrowr3_bm);
+ Flash( d, x, y, playbackColor=leftDragColor );
+ proc( action, pos );
+ /* no break */
case C_RMOVE:
- bm = ((MyGetKeyState()&WKEY_SHIFT)?arrows_bm:arrow3_bm);
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrowr3_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrowr3_ctl_bm:arrowr3_bm);
MoveCursor( d, proc, C_RMOVE, pos, bm, leftDragColor );
- playbackD=d; playbackBm=bm; playbackX=x; playbackY=y; playbackColor=leftDragColor;
break;
case C_RUP:
- bm = ((MyGetKeyState()&WKEY_SHIFT)?arrows_bm:arrow3_bm);
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrowr3_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrowr3_ctl_bm:arrowr3_bm);
MoveCursor( d, proc, C_RMOVE, pos, bm, leftDragColor );
- if (flashTwice) Flash( d, x, y, leftDragColor );
- MacroDrawBitMap( d, bm, x, y, leftDragColor );
- MacroDrawBitMap( playbackD=d, playbackBm=arrow0_bm, playbackX=x, playbackY=y, playbackColor=wDrawColorBlack );
Flash( d, x, y, leftDragColor );
+ proc( action, pos );
+ bm = ((MyGetKeyState()&WKEY_SHIFT)?arrow0_shift_bm:(MyGetKeyState()&WKEY_CTRL)?arrow0_ctl_bm:arrow0_bm);
+ MoveCursor( d, NULL, 0, pos, bm, wDrawColorBlack );
break;
case C_REDRAW:
- MacroDrawBitMap( playbackD, playbackBm, playbackX, playbackY, playbackColor );
+ proc( action, pos ); //Send Redraw to functions
+ playbackD = &tempD;
+ MacroDrawBitMap( REDRAW, playbackBm, playbackX, playbackY, playbackColor );
+ break;
+
+ case C_TEXT:
+ proc( action, pos);
+ char c = action>>8;
+ bm = playbackBm;
break;
+
default:
- ;
+ bm = playbackBm;
}
+
+ playbackBm = bm;
time1 = wGetTimer();
adjTimer += (time1-time0);
}
@@ -509,25 +590,7 @@ EXPORT void PlaybackMouse(
coOrd pos,
wDrawColor color )
{
-#ifdef LATER
- if (action == C_DOWN || action == C_RDOWN) {
- MoveCursor( d, proc, wActionMove, pos, arrow0_bm, wDrawColorBlack );
- ClearPlaybackCursor();
- } else {
- PlaybackCursor( d, proc, action, pos, wDrawColorBlack );
- }
-#endif
PlaybackCursor( d, proc, action, pos, wDrawColorBlack );
- if (playbackBm != NULL)
- MacroDrawBitMap( playbackD, playbackBm, playbackX, playbackY, playbackColor );
- proc( action, pos );
- if (playbackBm != NULL)
- MacroDrawBitMap( playbackD, playbackBm, playbackX, playbackY, playbackColor );
-#ifdef LATER
- if (action == C_DOWN || action == C_RDOWN) {
- PlaybackCursor( d, proc, action, pos, wDrawColorBlack );
- }
-#endif
didPause = FALSE;
}
@@ -535,17 +598,29 @@ EXPORT void PlaybackMouse(
EXPORT void MovePlaybackCursor(
drawCmd_p d,
wPos_t x,
- wPos_t y )
+ wPos_t y, wBool_t direct, wControl_p control)
{
coOrd pos;
+ playbackD = &tempD;
d->Pix2CoOrd( d, x, y, &pos );
d->CoOrd2Pix( d, pos, &x, &y );
- MoveCursor( d, NULL, wActionMove, pos, arrow0_bm, wDrawColorBlack );
- MacroDrawBitMap( d, arrow0_bm, x, y, wDrawColorBlack );
- MacroDrawBitMap( d, arrow3_bm, x, y, rightDragColor );
+ if (!direct)
+ MoveCursor( d, NULL, wActionMove, pos, arrow0_bm, wDrawColorBlack );
+ wBool_t ret = wDrawSetTempMode( d->d, TRUE );
+ MacroDrawBitMap( MOVE_PLYBCK1, arrow0_bm, x, y, wDrawColorBlack );
+ MacroDrawBitMap( MOVE_PLYBCK2, arrow3_bm, x, y, rightDragColor );
+
Flash( d, x, y, rightDragColor );
- MacroDrawBitMap( d, arrow3_bm, x, y, rightDragColor );
- MacroDrawBitMap( d, arrow0_bm, x, y, wDrawColorBlack );
+ if (direct) {
+ wControlHilite(control,TRUE);
+ }
+ MacroDrawBitMap( MOVE_PLYBCK3, arrow3_bm, x, y, rightDragColor );
+ MacroDrawBitMap( MOVE_PLYBCK4, arrow0_bm, x, y, wDrawColorBlack );
+ if (direct) {
+ wPause(1000);
+ wControlHilite(control,FALSE);
+ }
+ wDrawSetTempMode( d->d, ret );
}
/*****************************************************************************
@@ -580,12 +655,10 @@ static coOrd oldMainOrig;
static coOrd oldMainSize;
static DIST_T oldMainScale;
static char * oldScaleName;
+static int oldMagneticSnap;
static wBool_t pauseDemo = FALSE;
static long bigPause = 2000;
-#ifdef LATER
-static long MSEC_PER_PIXEL = 6;
-#endif
#ifdef DEMOPAUSE
static wButton_p demoPause;
#endif
@@ -639,15 +712,13 @@ static void PlaybackQuit( void )
if (paramFile)
fclose( paramFile );
paramFile = NULL;
- if (!inPlayback)
- return;
inPlaybackQuit = TRUE;
- ClearPlaybackCursor();
wPrefReset();
wHide( demoW );
wWinSetBusy( mainW, FALSE );
wWinSetBusy( mapW, FALSE );
ParamRestoreAll();
+ magneticSnap = oldMagneticSnap;
RestoreLayers();
wEnableBalloonHelp( (int)enableBalloonHelp );
mainD.scale = oldMainScale;
@@ -657,15 +728,14 @@ static void PlaybackQuit( void )
tempD.orig = mainD.orig;
tempD.size = mainD.size;
tempD.scale = mainD.scale;
+ Reset();
ClearTracks();
checkPtMark = changed = 0;
RestoreTrackState();
inPlaybackQuit = FALSE;
- Reset();
DoSetScale( oldScaleName );
DoChangeNotification( CHANGE_ALL );
CloseDemoWindows();
- inPlayback = FALSE;
curDemo = -1;
wPrefSetInteger( "misc", "playbackspeed", playbackSpeed );
playbackNonStop = FALSE;
@@ -729,6 +799,137 @@ EXPORT void TakeSnapshot( drawCmd_t * d )
}
}
+/*
+* Regression test
+*/
+static int log_regression = 0;
+wBool_t bWriteEndPtDirectIndex;
+
+static BOOL_T DoRegression( char * sFileName )
+{
+ typedef enum { REGRESSION_NONE, REGRESSION_CHECK, REGRESSION_QUIET, REGRESSION_SAVE } E_REGRESSION;
+ E_REGRESSION eRegression = REGRESSION_NONE;
+ long oldParamVersion;
+ long regressVersion;
+ FILE * fRegression;
+ char * sRegressionFile = NULL;
+ wBool_t bWroteActualTracks;
+ eRegression = log_regression > 0 ? logTable(log_regression).level : 0;
+ char * cp;
+ regressVersion = strtol( paramLine+16, &cp, 10 );
+ if (cp == paramLine+16 )
+ regressVersion = PARAMVERSION;
+ LOG( log_regression, 1, ("REGRESSION %s %d %s:%d %s\n",
+ eRegression==REGRESSION_SAVE?"SAVE":"CHECK",
+ regressVersion,
+ sFileName, paramLineNum,
+ cp ) );
+ MakeFullpath( &sRegressionFile, workingDir, "xtrkcad.regress", NULL );
+ switch ( eRegression ){
+ case REGRESSION_SAVE:
+ fRegression = fopen( sRegressionFile, "a" );
+ if ( fRegression == NULL ) {
+ NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Regression"), sFileName, strerror(errno) );
+ } else {
+ fprintf( fRegression, "REGRESSION START %d %s\n",
+ PARAMVERSION, cp );
+ fprintf( fRegression, "# %s - %d\n", sFileName, paramLineNum );
+ WriteTracks( fRegression, FALSE );
+ fprintf( fRegression, "REGRESSION END\n" );
+ fclose( fRegression );
+ }
+ while ( fgets(paramLine, STR_LONG_SIZE, paramFile) != NULL ) {
+ if ( strncmp( paramLine, "REGRESSION END", 14 ) == 0)
+ break;
+ }
+ break;
+ case REGRESSION_CHECK:
+ case REGRESSION_QUIET:
+ oldParamVersion = paramVersion;
+ paramVersion = regressVersion;
+ bWroteActualTracks = FALSE;
+ track_p to_first_save = to_first;
+ track_p* to_last_save = to_last;
+ while ( GetNextLine() ) {
+ if ( paramLine[0] == '#' )
+ continue;
+ // Read Expected track
+ to_first = NULL;
+ to_last = &to_first;
+ paramVersion = regressVersion;
+ if ( !ReadTrack( paramLine ) ) {
+ if ( paramFile == NULL )
+ return FALSE;
+ break;
+ }
+ if ( to_first == NULL ) {
+ // Something bad happened
+ break;
+ }
+ track_cp tExpected = to_first;
+ to_first = to_first_save;
+ // Find corresponding Actual track
+ track_cp tActual = FindTrack( GetTrkIndex( tExpected ) );
+ strcat( message, "Regression " );
+ if ( ! CompareTrack( tActual, tExpected ) ) {
+ // Actual doesn't match Expected
+ LOG( log_regression, 1, (" FAIL: %s", message) );
+ fRegression = fopen( sRegressionFile, "a" );
+ if ( fRegression == NULL ) {
+ NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Regression"), sRegressionFile, strerror(errno) );
+ break;
+ }
+ fprintf( fRegression, "REGRESSION FAIL %d\n",
+ PARAMVERSION );
+ fprintf( fRegression, "# %s - %d\n", sFileName, paramLineNum );
+ fprintf( fRegression, "# %s", message );
+ if ( !bWroteActualTracks ) {
+ // Print Actual tracks
+ fprintf( fRegression, "Actual Tracks\n" );
+ paramVersion = PARAMVERSION;
+ WriteTracks( fRegression, FALSE );
+ bWroteActualTracks = TRUE;
+ }
+ // Print Expected track
+ to_first = tExpected;
+ fprintf( fRegression, "Expected Track\n" );
+ WriteTracks( fRegression, FALSE );
+ fclose( fRegression );
+ strcat( message, "Continue test?" );
+ if ( eRegression == REGRESSION_CHECK ) {
+ int rc = wNoticeEx( NT_ERROR, message, _("Stop"), _("Continue") );
+ if ( !rc ) {
+ while ( GetNextLine() &&
+ strncmp( paramLine, "REGRESSION END", 14 ) != 0 )
+ ;
+ break;
+ }
+ }
+ }
+ // Delete Expected track
+ to_first = tExpected;
+ to_last = &to_first;
+ FreeTrack( tExpected );
+ }
+ to_first = to_first_save;
+ to_last = to_last_save;
+ if ( strncmp( paramLine, "REGRESSION END", 14 ) != 0 )
+ InputError( "Expected REGRESSION END", TRUE );
+ paramVersion = oldParamVersion;
+ break;
+ case REGRESSION_NONE:
+ default:
+ while ( GetNextLine() ) {
+ if ( strncmp( paramLine, "REGRESSION END", 14 ) == 0 )
+ break;
+ }
+ break;
+ }
+ free( sRegressionFile );
+
+ return TRUE;
+}
+
static void EnableButtons(
BOOL_T enable )
{
@@ -774,7 +975,6 @@ static void PlaybackSetup( void )
wTextClear( demoT );
wShow( demoW );
wFlush();
- RulerRedraw( TRUE );
wPrefFlush();
wWinSetBusy( mainW, TRUE );
wWinSetBusy( mapW, TRUE );
@@ -785,6 +985,8 @@ static void PlaybackSetup( void )
oldMainSize = mainD.size;
oldMainScale = mainD.scale;
oldScaleName = curScaleName;
+ playbackX = 0;
+ playbackY = 0;
Reset();
paramVersion = -1;
playbackColor=wDrawColorBlack;
@@ -816,11 +1018,15 @@ static void Playback( void )
wWinTop( mainW );
demoWinOnTop = FALSE;
}
+ char * oldLocale = NULL;
+ oldLocale = SaveLocale( "C" );
while (TRUE) {
+ if ( ! inPlayback )
+ // User pressed Quit
+ break;
if ( paramFile == NULL ||
fgets(paramLine, STR_LONG_SIZE, paramFile) == NULL ) {
paramTogglePlaybackHilite = FALSE;
- ClearPlaybackCursor();
CloseDemoWindows();
if (paramFile) {
fclose( paramFile );
@@ -837,6 +1043,8 @@ static void Playback( void )
paramFile = fopen( demoFileName, "r" );
if ( paramFile == NULL ) {
NoticeMessage( MSG_OPEN_FAIL, _("Continue"), NULL, _("Demo"), demoFileName, strerror(errno) );
+ RestoreLocale( oldLocale );
+ inPlayback = FALSE;
return;
}
@@ -848,13 +1056,14 @@ static void Playback( void )
UndoSuspend();
wWinBlockEnable( FALSE );
checkPtMark = 0;
- RulerRedraw( TRUE );
DoChangeNotification( CHANGE_ALL );
CompoundClearDemoDefns();
if ( fgets(paramLine, STR_LONG_SIZE, paramFile) == NULL ) {
NoticeMessage( MSG_CANT_READ_DEMO, _("Continue"), NULL, sProdName, demoFileName );
fclose( paramFile );
paramFile = NULL;
+ RestoreLocale( oldLocale );
+ inPlayback = FALSE;
return;
}
free(demoFileName);
@@ -880,6 +1089,10 @@ static void Playback( void )
} else if (paramLine[0] == 0) {
/* empty paramLine */
} else if (ReadTrack( paramLine ) ) {
+ if ( paramFile == NULL ) {
+ inPlayback = FALSE;
+ break;
+ }
} else if (strncmp( paramLine, "STEP", 5 ) == 0) {
paramTogglePlaybackHilite = TRUE;
wWinTop( demoW );
@@ -898,6 +1111,8 @@ static void Playback( void )
wPause( 1000 );
EnableButtons( FALSE );
} else {
+ RestoreLocale( oldLocale );
+ inPlayback = FALSE;
return;
}
} else if (strncmp( paramLine, "CLEAR", 5 ) == 0) {
@@ -908,12 +1123,14 @@ static void Playback( void )
demoWinOnTop = TRUE;
while ( ( fgets( paramLine, STR_LONG_SIZE, paramFile ) ) != NULL ) {
paramLineNum++;
- if ( strncmp(paramLine, "END", 3) == 0 )
+ if ( IsEND( END_MESSAGE ) )
break;
if ( strncmp(paramLine, "STEP", 3) == 0 ) {
wWinTop( demoW );
demoWinOnTop = TRUE;
EnableButtons( TRUE );
+ RestoreLocale( oldLocale );
+ inPlayback = FALSE;
return;
}
PlaybackMessage( paramLine );
@@ -928,14 +1145,13 @@ static void Playback( void )
RecomputeElevations();
DoRedraw();
/*DoChangeNotification( CHANGE_ALL );*/
- if (playbackD != NULL && playbackBm != NULL)
- MacroDrawBitMap( playbackD, playbackBm, playbackX, playbackY, wDrawColorBlack );
} else if (strncmp( paramLine, "COMMAND ", 8 ) == 0) {
paramTogglePlaybackHilite = FALSE;
PlaybackCommand( paramLine, paramLineNum );
} else if (strncmp( paramLine, "RESET", 5 ) == 0) {
paramTogglePlaybackHilite = TRUE;
- Reset();
+ InfoMessage("Esc Key Pressed");
+ ConfirmReset(TRUE);
} else if (strncmp( paramLine, "VERSION", 7 ) == 0) {
paramVersion = atol( paramLine+8 );
if ( paramVersion > iParamVersion ) {
@@ -949,7 +1165,18 @@ static void Playback( void )
} else if (strncmp( paramLine, "ORIG ", 5 ) == 0) {
if ( !GetArgs( paramLine+5, "fff", &zoom, &x, &y ) )
continue;
+ if (zoom == 0.0) {
+ double scale_x = mapD.size.x/(mainD.size.x/mainD.scale);
+ double scale_y = mapD.size.y/(mainD.size.y/mainD.scale);
+ if (scale_x<scale_y)
+ scale_x = scale_y;
+ scale_x = ceil(scale_x);
+ if (scale_x < 1) scale_x = 1;
+ if (scale_x > MAX_MAIN_SCALE) scale_x = MAX_MAIN_SCALE;
+ zoom = scale_x;
+ }
mainD.scale = zoom;
+ InfoMessage("Zoom Set to %.0f", zoom);
mainD.orig.x = x;
mainD.orig.y = y;
SetMainSize();
@@ -958,8 +1185,6 @@ static void Playback( void )
tempD.scale = mainD.scale;
DoRedraw();
- if (playbackD != NULL && playbackBm != NULL)
- MacroDrawBitMap( playbackD, playbackBm, playbackX, playbackY, wDrawColorBlack );
} else if (strncmp( paramLine, "PAUSE ", 6 ) == 0) {
paramTogglePlaybackHilite = TRUE;
@@ -1028,13 +1253,16 @@ static void Playback( void )
} else if (strncmp( paramLine, "DOCUMENT COPY", 13 ) == 0 ) {
while ( ( fgets( paramLine, STR_LONG_SIZE, paramFile ) ) != NULL ) {
paramLineNum++;
- if ( strncmp(paramLine, "END", 3) == 0 )
+ if ( IsEND( END_MESSAGE ) )
break;
if ( documentCopy && documentFile )
fprintf( documentFile, "%s", paramLine );
}
} else if ( strncmp( paramLine, "DEMOINIT", 8 ) == 0 ) {
DemoInitValues();
+ } else if ( strncmp( paramLine, "REGRESSION START", 16 ) == 0 ) {
+ DoRegression( curDemo < 1 ? paramFileName :
+ demoList(curDemo-1).fileName );
} else {
if (strncmp( paramLine, "MOUSE ", 6 ) == 0) {
thisCmd = mouseCmd;
@@ -1066,6 +1294,8 @@ static void Playback( void )
if (pauseDemo) {
EnableButtons( TRUE );
pauseDemo = FALSE;
+ RestoreLocale( oldLocale );
+ inPlayback = FALSE;
return;
}
}
@@ -1077,7 +1307,9 @@ static void Playback( void )
fclose( documentFile );
documentFile = NULL;
}
+ inPlayback = FALSE;
PlaybackQuit();
+ RestoreLocale( oldLocale );
}
@@ -1093,13 +1325,15 @@ static int StartPlayback( int cnt, char **pathName, void * context )
return FALSE;
}
- strcpy( paramFileName, pathName[0] );
+ paramFileName = strdup( pathName[0] );
PlaybackSetup();
curDemo = -1;
UndoSuspend();
wWinBlockEnable( FALSE );
Playback();
+ free( paramFileName );
+ paramFileName = NULL;
return TRUE;
}
@@ -1138,7 +1372,13 @@ static void DoDemoButton( void * command )
break;
case 3:
/* quit */
- PlaybackQuit();
+ if ( inPlayback ) {
+ // We will exit the loop in Playback() after the current command
+ inPlayback = FALSE;
+ } else {
+ // We're waiting for the user to press 'Step'
+ PlaybackQuit();
+ }
break;
default:
;
@@ -1196,11 +1436,10 @@ static char * demoInitParams[] = {
"GROUP layout",
"display tunnels 1",
"display endpt 2",
- "display labelenable 7",
+ "display labelenable 0",
"display description-fontsize 48",
"display labelscale 8",
"display layoutlabels 6",
- "display color-layers 0",
"display tworailscale 16",
"display tiedraw 0",
"pref mingridspacing 5",
@@ -1211,8 +1450,7 @@ static char * demoInitParams[] = {
"display carhotbarlabels 1",
"display hideTrainsInTunnels 0",
"GROUP display",
- "cmdopt move-quick 0",
- "pref turntable-angle 7.500",
+ "pref turntable-angle 15.00",
"cmdopt preselect 1",
"pref coupling-speed-max 100",
"cmdopt rightclickmode 0",
@@ -1261,10 +1499,12 @@ static char * demoInitParams[] = {
"GROUP grid",
"misc toolbarset 65535",
"GROUP misc",
- "sticky set 268435383", /* 0xfffffb7 - all but Helix and Turntable */
+ "sticky set 67108479", /* 0x3fffe7f - all but Helix and Turntable */
"GROUP sticky",
"turnout hide 0",
"layer button-count 10",
+ "cmdopt selectmode 0",
+ "cmdopt selectzero 1",
NULL };
static void DemoInitValues( void )
@@ -1291,6 +1531,8 @@ static void DemoInitValues( void )
}
for ( cpp = demoInitParams; *cpp; cpp++ )
paramPlaybackProc( *cpp );
+ // Have to do this manually
+ oldMagneticSnap = MagneticSnap( TRUE );
}
@@ -1369,11 +1611,22 @@ EXPORT BOOL_T MacroInit( void )
leftDragColor = drawColorBlue;
arrow0_bm = wDrawBitMapCreate( mainD.d, arrow0_width, arrow0_height, 12, 12, arrow0_bits );
+ arrow0_shift_bm = wDrawBitMapCreate( mainD.d, arrow0_shift_width, arrow0_shift_height, 12, 12, arrow0_shift_bits );
+ arrow0_ctl_bm = wDrawBitMapCreate( mainD.d, arrow0_ctl_width, arrow0_ctl_height, 12, 12, arrow0_ctl_bits );
arrow3_bm = wDrawBitMapCreate( mainD.d, arrow3_width, arrow3_height, 12, 12, arrow3_bits );
+ arrow3_shift_bm = wDrawBitMapCreate( mainD.d, arrow3_shift_width, arrow3_shift_height, 12, 12, arrow3_shift_bits );
+ arrow3_ctl_bm = wDrawBitMapCreate( mainD.d, arrow3_ctl_width, arrow3_ctl_height, 12, 12, arrow3_ctl_bits );
+ arrowr3_bm = wDrawBitMapCreate( mainD.d, arrowr3_width, arrowr3_height, 12, 12, arrowr3_bits );
+ arrowr3_shift_bm = wDrawBitMapCreate( mainD.d, arrowr3_shift_width, arrowr3_shift_height, 12, 12, arrowr3_shift_bits );
+ arrowr3_ctl_bm = wDrawBitMapCreate( mainD.d, arrowr3_ctl_width, arrowr3_ctl_height, 12, 12, arrowr3_ctl_bits );
arrows_bm = wDrawBitMapCreate( mainD.d, arrows_width, arrows_height, 12, 12, arrows_bits );
flash_bm = wDrawBitMapCreate( mainD.d, flash_width, flash_height, 12, 12, flash_bits );
ParamRegister( &recordPG );
ParamRegister( &demoPG );
+
+ log_playbackCursor = LogFindIndex( "playbackcursor" );
+ log_regression = LogFindIndex( "regression" );
+
return TRUE;
}
diff --git a/app/bin/manifest.c b/app/bin/manifest.c
new file mode 100644
index 0000000..1652996
--- /dev/null
+++ b/app/bin/manifest.c
@@ -0,0 +1,176 @@
+/** \file manifest.c
+ * JSON routines
+ */
+ /* 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 <string.h>
+
+#include "cJSON.h"
+#include "fileio.h"
+#include "layout.h"
+#include "misc2.h"
+#include "paths.h"
+#include "include/utf8convert.h"
+
+extern int log_zip;
+
+ /**********************************************************
+ * Build JSON Manifest - manifest.json
+ * There are only two objects in the root -
+ * - The layout object defines the correct filename for the layout
+ * - The dependencies object is an arraylist of included elements
+ *
+ * Each element has a name, a filename and an arch-path (where in the archive it is located)
+ * It may have other values - a common one the copy-path is where it was copied from the originators machine (info only)
+ *
+ * There is one reserved name - "background" which is for the image file that is used as a layout background
+ *
+ *\param IN nameOfLayout - the layout this is a manifest for
+ *\param IN background - the full filepath to the background image (or NULL) -> TODO this will become an array with a count
+ *\param IN DependencyDir - the relative path in the archive to the directory in which the included object(s) will be stored
+ *
+ *\returns a String containing the JSON object
+ */
+
+char* CreateManifest(char* nameOfLayout, char* background,
+ char* dependencyDir)
+{
+ cJSON* manifest = cJSON_CreateObject();
+ if (manifest != NULL) {
+ char *copyOfFileName = MyStrdup(nameOfLayout);
+ cJSON* a_object = cJSON_CreateObject();
+ cJSON_AddItemToObject(manifest, "layout", a_object);
+#ifdef WINDOWS
+ copyOfFileName = Convert2UTF8(copyOfFileName);
+#endif // WINDOWS
+ cJSON_AddStringToObject(a_object, "name", copyOfFileName);
+ MyFree(copyOfFileName);
+
+ cJSON* dependencies = cJSON_AddArrayToObject(manifest, "dependencies");
+ cJSON* b_object = cJSON_CreateObject();
+ if (background && background[0]) {
+ char *backg;
+ cJSON_AddStringToObject(b_object, "name", "background");
+
+ backg = MyStrdup(FindFilename(background));
+#ifdef WINDOWS
+ backg = Convert2UTF8(backg);
+#endif
+ cJSON_AddStringToObject(b_object, "filename", backg);
+ MyFree(backg);
+ backg = MyStrdup(background);
+#ifdef WINDOWS
+ backg = Convert2UTF8(backg);
+ ConvertPathForward(backg);
+#endif // WINDOWS
+ cJSON_AddStringToObject(b_object, "copy-path", backg);
+ cJSON_AddStringToObject(b_object, "arch-path", dependencyDir);
+ MyFree(backg);
+ cJSON_AddNumberToObject(b_object, "size", GetLayoutBackGroundSize());
+ cJSON_AddNumberToObject(b_object, "pos-x", GetLayoutBackGroundPos().x);
+ cJSON_AddNumberToObject(b_object, "pos-y", GetLayoutBackGroundPos().y);
+ cJSON_AddNumberToObject(b_object, "screen", GetLayoutBackGroundScreen());
+ cJSON_AddNumberToObject(b_object, "angle", GetLayoutBackGroundAngle());
+ cJSON_AddItemToArray(dependencies, b_object);
+ }
+ }
+ char* json_Manifest = cJSON_Print(manifest);
+ cJSON_Delete(manifest);
+ return json_Manifest;
+}
+
+/**************************************************************************
+ * Pull in a Manifest File and extract values from it
+ * \param IN manifest - the full path to the mainifest.json file
+ * \param IN zip_directory - the path to the directory for extracted objects
+ *
+ * \returns - the layout filename
+ */
+
+char* ParseManifest(char* manifest, char* zip_directory)
+{
+ char* background_file[1] = { NULL };
+ char* layoutname;
+
+ char *oldLocale = SaveLocale("C");
+ cJSON* json_manifest = cJSON_Parse(manifest);
+ RestoreLocale(oldLocale);
+
+ cJSON* layout = cJSON_GetObjectItemCaseSensitive(json_manifest, "layout");
+ cJSON* name = cJSON_GetObjectItemCaseSensitive(layout, "name");
+ layoutname = cJSON_GetStringValue(name);
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(layoutname);
+#endif // WINDOWS
+
+ LOG(log_zip, 1, ("Zip-Manifest %s \n", layoutname))
+#if DEBUG
+ fprintf(stderr, "Layout name %s \n", layoutname);
+#endif
+
+ cJSON* dependencies = cJSON_GetObjectItemCaseSensitive(json_manifest,
+ "dependencies");
+ cJSON* dependency;
+ cJSON_ArrayForEach(dependency, dependencies) {
+ cJSON* name = cJSON_GetObjectItemCaseSensitive(dependency, "name");
+ if (strcmp(cJSON_GetStringValue(name), "background") == 0) {
+ char *file;
+ char *path;
+ cJSON* filename = cJSON_GetObjectItemCaseSensitive(dependency, "filename");
+ cJSON* archpath = cJSON_GetObjectItemCaseSensitive(dependency, "arch-path");
+ file = MyStrdup(cJSON_GetStringValue(filename));
+ path = MyStrdup(cJSON_GetStringValue(archpath));
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(file);
+ ConvertUTF8ToSystem(path);
+#endif
+ MakeFullpath(&background_file[0], zip_directory, path,
+ file, NULL);
+ MyFree(file);
+ MyFree(path);
+#if DEBUG
+ printf("Link to background image %s \n", background_file[0]);
+#endif
+ LoadImageFile(1, &background_file[0], NULL);
+ cJSON* size = cJSON_GetObjectItemCaseSensitive(dependency, "size");
+ SetLayoutBackGroundSize(size->valuedouble);
+ cJSON* posx = cJSON_GetObjectItemCaseSensitive(dependency, "pos-x");
+ cJSON* posy = cJSON_GetObjectItemCaseSensitive(dependency, "pos-y");
+ coOrd pos;
+ pos.x = posx->valuedouble;
+ pos.y = posy->valuedouble;
+ SetLayoutBackGroundPos(pos);
+ cJSON* screen = cJSON_GetObjectItemCaseSensitive(dependency, "screen");
+ SetLayoutBackGroundScreen((int)screen->valuedouble);
+ cJSON* angle = cJSON_GetObjectItemCaseSensitive(dependency, "angle");
+ SetLayoutBackGroundAngle(angle->valuedouble);
+ LayoutBackGroundSave(); //Force out Values to override saved
+ }
+ }
+ char *str = NULL;
+ if (background_file[0]) {
+ free(background_file[0]);
+ }
+ if (layoutname) {
+ str = strdup(layoutname);
+ }
+ cJSON_Delete(json_manifest);
+ return str;
+}
+
diff --git a/app/bin/manifest.h b/app/bin/manifest.h
new file mode 100644
index 0000000..8e751f0
--- /dev/null
+++ b/app/bin/manifest.h
@@ -0,0 +1,6 @@
+#ifndef HAVE_MANIFEST_H
+#define HAVE_MANIFEST_H
+ char* CreateManifest(char* nameOfLayout, char* background,
+ char* DependencyDir);
+ char* ParseManifest(char* manifest, char* zip_directory);
+#endif
diff --git a/app/bin/misc.c b/app/bin/misc.c
index 827c2db..2ac1e2f 100644
--- a/app/bin/misc.c
+++ b/app/bin/misc.c
@@ -1,4 +1,4 @@
-/* \file misc.c
+/* file misc.c
* Main routine and initialization for the application
*/
@@ -40,7 +40,7 @@
#define R_OK (02)
#define access _access
#if _MSC_VER >1300
- #define strdup _strdup
+#define strdup _strdup
#endif
#else
#include <sys/stat.h>
@@ -62,6 +62,7 @@
#include "messages.h"
#include "misc.h"
#include "param.h"
+#include "include/paramfilelist.h"
#include "paths.h"
#include "smalldlg.h"
#include "track.h"
@@ -72,6 +73,10 @@
char *userLocale = NULL;
extern wBalloonHelp_t balloonHelp[];
+
+static wMenuToggle_p mapShowMI;
+static wMenuToggle_p magnetsMI;
+
#ifdef DEBUG
#define CHECK_BALLOONHELP
/*#define CHECK_UNUSED_BALLOONHELP*/
@@ -83,7 +88,7 @@ void DoCarDlg(void);
/****************************************************************************
*
- EXPORTED VARIABLES
+ EXPORTED VARIABLES
*
*/
@@ -96,7 +101,7 @@ EXPORT wWin_p mainW;
EXPORT wIndex_t changed = 0;
-EXPORT char message[STR_LONG_SIZE];
+EXPORT char message[STR_HUGE_SIZE];
static char message2[STR_LONG_SIZE];
EXPORT REGION_T curRegion = 0;
@@ -107,7 +112,7 @@ EXPORT coOrd zero = { 0.0, 0.0 };
EXPORT wBool_t extraButtons = FALSE;
-EXPORT long onStartup; /**< controls behaviour after startup: load last layout if zero, else start with blank canvas */
+EXPORT long onStartup; /**< controls behaviour after startup: load last layout if zero, else start with blank canvas */
EXPORT wButton_p undoB;
EXPORT wButton_p redoB;
@@ -115,13 +120,15 @@ EXPORT wButton_p redoB;
EXPORT wButton_p zoomUpB;
EXPORT wButton_p zoomDownB;
wButton_p mapShowB;
+wButton_p magnetsB;
+wButton_p backgroundB;
EXPORT wIndex_t checkPtMark = 0;
EXPORT wMenu_p demoM;
EXPORT wMenu_p popup1M, popup2M;
EXPORT wMenu_p popup1aM, popup2aM;
-
+EXPORT wMenu_p popup1mM, popup2mM;
static wIndex_t curCommand = 0;
EXPORT void * commandContext;
@@ -129,6 +136,8 @@ EXPORT wIndex_t cmdGroup;
EXPORT wIndex_t joinCmdInx;
EXPORT wIndex_t modifyCmdInx;
EXPORT long rightClickMode = 0;
+EXPORT long selectMode = 0;
+EXPORT long selectZero = 1;
EXPORT DIST_T easementVal = 0.0;
EXPORT DIST_T easeR = 0.0;
EXPORT DIST_T easeL = 0.0;
@@ -151,7 +160,7 @@ static int verbose = 0;
static wMenuList_p winList_mi;
static BOOL_T inMainW = TRUE;
-static long stickySet;
+static long stickySet = 0;
static long stickyCnt = 0;
static char * stickyLabels[33];
#define TOOLBARSET_INIT (0xFFFF)
@@ -168,10 +177,11 @@ static BOOL_T messageListEmpty = TRUE;
extern long curTurnoutEp;
static wIndex_t printCmdInx;
static wIndex_t gridCmdInx;
-static paramData_t menuPLs[101] = {
- { PD_LONG, &toolbarSet, "toolbarset" },
- { PD_LONG, &curTurnoutEp, "cur-turnout-ep" } };
+static paramData_t menuPLs[101] = { { PD_LONG, &toolbarSet, "toolbarset" }, {
+ PD_LONG, &curTurnoutEp, "cur-turnout-ep" } };
static paramGroup_t menuPG = { "misc", PGO_RECORD, menuPLs, 2 };
+
+extern wBool_t wDrawDoTempDraw;
/****************************************************************************
*
@@ -186,12 +196,11 @@ EXPORT long totalReallocs = 0;
EXPORT long totalFreeed = 0;
EXPORT long totalFrees = 0;
-static unsigned long guard0 = 0xDEADBEEF;
-static unsigned long guard1 = 0xAF00BA8A;
+static unsigned long guard0 = 0xDEADBEEF;
+static unsigned long guard1 = 0xAF00BA8A;
static int log_malloc;
-EXPORT void * MyMalloc ( long size )
-{
+EXPORT void * MyMalloc(long size) {
void * p;
totalMallocs++;
totalMalloced += size;
@@ -200,29 +209,26 @@ EXPORT void * MyMalloc ( long size )
AbortProg( "mallocing > 65500 bytes" );
}
#endif
- p = malloc( (size_t)size + sizeof (size_t) + 2 * sizeof (unsigned long) );
+ p = malloc((size_t) size + sizeof(size_t) + 2 * sizeof(unsigned long));
if (p == NULL)
- AbortProg( "No memory" );
-
-LOG1( log_malloc, ( "Malloc(%ld) = %lx (%lx-%lx)\n", size,
- (long)((char*)p+sizeof (size_t) + sizeof (unsigned long)),
- (long)p,
- (long)((char*)p+size+sizeof (size_t) + 2 * sizeof(unsigned long)) ));
- *(size_t*)p = (size_t)size;
- p = (char*)p + sizeof (size_t);
- *(unsigned long*)p = guard0;
- p = (char*)p + sizeof (unsigned long);
- *(unsigned long*)((char*)p+size) = guard1;
- memset( p, 0, (size_t)size );
+ AbortProg("No memory");
+
+ LOG1(log_malloc,
+ ( "Malloc(%ld) = %lx (%lx-%lx)\n", size, (long)((char*)p+sizeof (size_t) + sizeof (unsigned long)), (long)p, (long)((char*)p+size+sizeof (size_t) + 2 * sizeof(unsigned long)) ));
+ *(size_t*) p = (size_t) size;
+ p = (char*) p + sizeof(size_t);
+ *(unsigned long*) p = guard0;
+ p = (char*) p + sizeof(unsigned long);
+ *(unsigned long*) ((char*) p + size) = guard1;
+ memset(p, 0, (size_t )size);
return p;
}
-EXPORT void * MyRealloc( void * old, long size )
-{
+EXPORT void * MyRealloc(void * old, long size) {
size_t oldSize;
void * new;
- if (old==NULL)
- return MyMalloc( size );
+ if (old == NULL)
+ return MyMalloc(size);
totalReallocs++;
totalRealloced += size;
#if defined(WINDOWS) && ! defined(WIN32)
@@ -230,67 +236,61 @@ EXPORT void * MyRealloc( void * old, long size )
AbortProg( "reallocing > 65500 bytes" );
}
#endif
- if ( *(unsigned long*)((char*)old - sizeof (unsigned long)) != guard0 ) {
- AbortProg( "Guard0 is hosed" );
+ if (*(unsigned long*) ((char*) old - sizeof(unsigned long)) != guard0) {
+ AbortProg("Guard0 is hosed");
}
- oldSize = *(size_t*)((char*)old - sizeof (unsigned long) - sizeof (size_t));
- if ( *(unsigned long*)((char*)old + oldSize) != guard1 ) {
- AbortProg( "Guard1 is hosed" );
+ oldSize = *(size_t*) ((char*) old - sizeof(unsigned long) - sizeof(size_t));
+ if (*(unsigned long*) ((char*) old + oldSize) != guard1) {
+ AbortProg("Guard1 is hosed");
}
-LOG1( log_malloc, ("Realloc(%lx,%ld) was %d\n", (long)old, size, oldSize ) )
- if ((long)oldSize == size) {
+ LOG1(log_malloc, ("Realloc(%lx,%ld) was %d\n", (long)old, size, oldSize ))
+ if ((long) oldSize == size) {
return old;
}
if (size == 0) {
- free( (char*)old - sizeof *(long*)0 - sizeof *(size_t*)0 );
+ free((char*) old - sizeof *(long*) 0 - sizeof *(size_t*) 0);
return NULL;
}
- new = MyMalloc( size );
+ new = MyMalloc(size);
if (new == NULL && size)
- AbortProg( "No memory" );
- memcpy( new, old, min((size_t)size, oldSize) );
+ AbortProg("No memory");
+ memcpy(new, old, min((size_t )size, oldSize));
MyFree(old);
return new;
}
-
-EXPORT void MyFree( void * ptr )
-{
+EXPORT void MyFree(void * ptr) {
size_t oldSize;
totalFrees++;
if (ptr) {
- if ( *(unsigned long*)((char*)ptr - sizeof (unsigned long)) != guard0 ) {
- AbortProg( "Guard0 is hosed" );
+ if (*(unsigned long*) ((char*) ptr - sizeof(unsigned long)) != guard0) {
+ AbortProg("Guard0 is hosed");
}
- oldSize = *(size_t*)((char*)ptr - sizeof (unsigned long) - sizeof (size_t));
- if ( *(unsigned long*)((char*)ptr + oldSize) != guard1 ) {
- AbortProg( "Guard1 is hosed" );
+ oldSize = *(size_t*) ((char*) ptr - sizeof(unsigned long)
+ - sizeof(size_t));
+ if (*(unsigned long*) ((char*) ptr + oldSize) != guard1) {
+ AbortProg("Guard1 is hosed");
}
-LOG1( log_malloc, ("Free %d at %lx (%lx-%lx)\n", oldSize, (long)ptr,
- (long)((char*)ptr-sizeof *(size_t*)0-sizeof *(long*)0),
- (long)((char*)ptr+oldSize+sizeof *(long*)0)) )
+ LOG1(log_malloc,
+ ("Free %d at %lx (%lx-%lx)\n", oldSize, (long)ptr, (long)((char*)ptr-sizeof *(size_t*)0-sizeof *(long*)0), (long)((char*)ptr+oldSize+sizeof *(long*)0)))
totalFreeed += oldSize;
- free( (char*)ptr - sizeof *(long*)0 - sizeof *(size_t*)0 );
+ free((char*) ptr - sizeof *(long*) 0 - sizeof *(size_t*) 0);
}
}
-
-EXPORT void * memdup( void * src, size_t size )
-{
+EXPORT void * memdup(void * src, size_t size) {
void * p;
- p = MyMalloc( size );
+ p = MyMalloc(size);
if (p == NULL)
- AbortProg( "No memory" );
- memcpy( p, src, size );
+ AbortProg("No memory");
+ memcpy(p, src, size);
return p;
}
-
-EXPORT char * MyStrdup( const char * str )
-{
+EXPORT char * MyStrdup(const char * str) {
char * ret;
- ret = (char*)MyMalloc( strlen( str ) + 1 );
- strcpy( ret, str );
+ ret = (char*) MyMalloc(strlen(str) + 1);
+ strcpy(ret, str);
return ret;
}
@@ -304,32 +304,70 @@ EXPORT char * MyStrdup( const char * str )
*
*/
EXPORT char * ConvertToEscapedText(const char * text) {
- int text_i=0;
+ int text_i = 0;
int add = 0; //extra chars for escape
- while(text[text_i]) {
+ while (text[text_i]) {
switch (text[text_i]) {
- case '\n': add++; break;
- case '\t': add++; break;
- case '\\': add++; break;
- case '\"': add++; break;
+ case '\n':
+ add++;
+ break;
+ case '\t':
+ add++;
+ break;
+ case '\\':
+ add++;
+ break;
+ case '\"':
+ add++;
+ break;
}
text_i++;
}
- char * cout = MyMalloc(strlen(text)+1+add);
+ unsigned cnt = strlen(text) + 1 + add;
+#ifdef WINDOWS
+ cnt *= 2;
+#endif
+ char * cout = MyMalloc(cnt);
int cout_i = 0;
text_i = 0;
- while(text[text_i]) {
+ while (text[text_i]) {
char c = text[text_i];
switch (c) {
- case '\n': cout[cout_i] = '\\'; cout_i++; cout[cout_i] = 'n'; cout_i++; break; // Line Feed
- case '\t': cout[cout_i] = '\\'; cout_i++; cout[cout_i] = 't'; cout_i++; break; // Tab
- case '\\': cout[cout_i] = '\\'; cout_i++; cout[cout_i] = '\\'; cout_i++; break; // BackSlash
- case '\"': cout[cout_i] = '\"'; cout_i++; cout[cout_i] = '\"'; cout_i++; break; // Double Quotes
- default: cout[cout_i] = c; cout_i++;
+ case '\n':
+ cout[cout_i] = '\\';
+ cout_i++;
+ cout[cout_i] = 'n';
+ cout_i++;
+ break; // Line Feed
+ case '\t':
+ cout[cout_i] = '\\';
+ cout_i++;
+ cout[cout_i] = 't';
+ cout_i++;
+ break; // Tab
+ case '\\':
+ cout[cout_i] = '\\';
+ cout_i++;
+ cout[cout_i] = '\\';
+ cout_i++;
+ break; // BackSlash
+ case '\"':
+ cout[cout_i] = '\"';
+ cout_i++;
+ cout[cout_i] = '\"';
+ cout_i++;
+ break; // Double Quotes
+ default:
+ cout[cout_i] = c;
+ cout_i++;
}
text_i++;
}
cout[cout_i] = '\0';
+#ifdef WINDOWS
+ wSystemToUTF8(cout, cout, cnt);
+#endif // WINDOWS
+
return cout;
}
@@ -340,83 +378,82 @@ EXPORT char * ConvertToEscapedText(const char * text) {
* \n = LineFeed 0x0A
* \t = Tab 0x09
* \\ = \ The way to still produce backslash
- * "" = " Take out quotes included so that other (CSV-like) programs could read the files
*
*/
EXPORT char * ConvertFromEscapedText(const char * text) {
- enum { CHARACTER, ESCAPE, QUOTE } state = CHARACTER;
- char * cout = MyMalloc(strlen(text)+1); //always equal to or shorter than
- int text_i = 0;
- int cout_i = 0;
- int c;
- while (text[text_i]) {
- c = text[text_i];
- switch (state) {
- case CHARACTER:
- if (c == '\\') {
- state = ESCAPE;
- } else if (c == '\"') {
- state = QUOTE;
- } else {
- cout[cout_i] = c;
- cout_i++;
- }
- break;
-
- case ESCAPE:
- switch (c) {
- case '\\': cout[cout_i] = '\\'; cout_i++; break; // "\\" = "\"
- case 'n': cout[cout_i] = '\n'; cout_i++; break; // LF
- case 't': cout[cout_i] = '\t'; cout_i++; break; // TAB
- }
- state = CHARACTER;
- break;
- case QUOTE:
- switch(c) {
- case '\"': cout[cout_i] = c; cout_i++; break; //One quote = NULL, Two quotes = 1 quote
- }
- state = CHARACTER;
- }
- text_i++;
- }
- cout[cout_i] = '\0';
- return cout;
-}
+ enum {
+ CHARACTER, ESCAPE
+ } state = CHARACTER;
+ char * cout = MyMalloc(strlen(text) + 1); //always equal to or shorter than
+ int text_i = 0;
+ int cout_i = 0;
+ int c;
+ while (text[text_i]) {
+ c = text[text_i];
+ switch (state) {
+ case CHARACTER:
+ if (c == '\\') {
+ state = ESCAPE;
+ } else {
+ cout[cout_i] = c;
+ cout_i++;
+ }
+ break;
+ case ESCAPE:
+ switch (c) {
+ case '\\':
+ cout[cout_i] = '\\';
+ cout_i++;
+ break; // "\\" = "\"
+ case 'n':
+ cout[cout_i] = '\n';
+ cout_i++;
+ break; // LF
+ case 't':
+ cout[cout_i] = '\t';
+ cout_i++;
+ break; // TAB
+ }
+ state = CHARACTER;
+ break;
+ }
+ text_i++;
+ }
+ cout[cout_i] = '\0';
+ return cout;
+}
-EXPORT void AbortProg(
- char * msg,
- ... )
-{
+EXPORT void AbortProg(char * msg, ...) {
static BOOL_T abort2 = FALSE;
int rc;
va_list ap;
- va_start( ap, msg );
- vsprintf( message, msg, ap );
- va_end( ap );
+ va_start(ap, msg);
+ vsprintf(message, msg, ap);
+ va_end(ap);
if (abort2) {
- wNoticeEx( NT_ERROR, message, _("ABORT"), NULL );
+ wNoticeEx( NT_ERROR, message, _("ABORT"), NULL);
} else {
- strcat( message, _("\nDo you want to save your layout?") );
- rc = wNoticeEx( NT_ERROR, message, _("Ok"), _("ABORT") );
+ strcat(message, _("\nDo you want to save your layout?"));
+ rc = wNoticeEx( NT_ERROR, message, _("Ok"), _("ABORT"));
if (rc) {
- DoSaveAs( (doSaveCallBack_p)abort );
+ DoSaveAs((doSaveCallBack_p) abort);
} else {
abort();
}
}
}
-
-EXPORT char * Strcpytrimed( char * dst, char * src, BOOL_T double_quotes )
-{
+EXPORT char * Strcpytrimed(char * dst, char * src, BOOL_T double_quotes) {
char * cp;
- while (*src && isspace((unsigned char)*src) ) src++;
+ while (*src && isspace((unsigned char) *src))
+ src++;
if (!*src)
return dst;
- cp = src+strlen(src)-1;
- while ( cp>src && isspace((unsigned char)*cp) ) cp--;
- while ( src<=cp ) {
+ cp = src + strlen(src) - 1;
+ while (cp > src && isspace((unsigned char) *cp))
+ cp--;
+ while (src <= cp) {
if (*src == '"' && double_quotes)
*dst++ = '"';
*dst++ = *src++;
@@ -425,50 +462,83 @@ EXPORT char * Strcpytrimed( char * dst, char * src, BOOL_T double_quotes )
return dst;
}
+static char * directory;
-EXPORT char * BuildTrimedTitle( char * cp, char * sep, char * mfg, char * desc, char * partno )
-{
- cp = Strcpytrimed( cp, mfg, FALSE );
- strcpy( cp, sep );
+#ifdef WINDOWS
+#define F_OK (0)
+#endif
+
+EXPORT wBool_t CheckHelpTopicExists(const char * topic) {
+
+ char * htmlFile;
+
+ // Check the file exits in the distro
+
+ if (!directory)
+ directory = malloc(BUFSIZ);
+
+ if (directory == NULL) return 0;
+
+ sprintf(directory, "%s/html/", wGetAppLibDir());
+
+ htmlFile = malloc(strlen(directory)+strlen(topic) + 6);
+
+ sprintf(htmlFile, "%s%s.html", directory, topic);
+
+ if( access( htmlFile, F_OK ) == -1 ) {
+
+ printf("Missing help topic %s\n",topic);
+
+ free(htmlFile);
+
+ return 0;
+
+ }
+
+ free(htmlFile);
+
+ return 1;
+
+}
+
+EXPORT char * BuildTrimedTitle(char * cp, char * sep, char * mfg, char * desc,
+ char * partno) {
+ cp = Strcpytrimed(cp, mfg, FALSE);
+ strcpy(cp, sep);
cp += strlen(cp);
- cp = Strcpytrimed( cp, desc, FALSE );
- strcpy( cp, sep );
+ cp = Strcpytrimed(cp, desc, FALSE);
+ strcpy(cp, sep);
cp += strlen(cp);
- cp = Strcpytrimed( cp, partno, FALSE );
+ cp = Strcpytrimed(cp, partno, FALSE);
return cp;
}
-
-static void ShowMessageHelp( int index, const char * label, void * data )
-{
+static void ShowMessageHelp(int index, const char * label, void * data) {
char msgKey[STR_SIZE], *cp, *msgSrc;
- msgSrc = (char*)data;
+ msgSrc = (char*) data;
if (!msgSrc)
return;
- cp = strchr( msgSrc, '\t' );
- if (cp==NULL) {
- sprintf( msgKey, _("No help for %s"), msgSrc );
- wNoticeEx( NT_INFORMATION, msgKey, _("Ok"), NULL );
+ cp = strchr(msgSrc, '\t');
+ if (cp == NULL) {
+ sprintf(msgKey, _("No help for %s"), msgSrc);
+ wNoticeEx( NT_INFORMATION, msgKey, _("Ok"), NULL);
return;
}
- memcpy( msgKey, msgSrc, cp-msgSrc );
- msgKey[cp-msgSrc] = 0;
- wHelp( msgKey );
+ memcpy(msgKey, msgSrc, cp - msgSrc);
+ msgKey[cp - msgSrc] = 0;
+ wHelp(msgKey);
}
-
-static char * ParseMessage(
- char *msgSrc )
-{
- char *cp1=NULL, *cp2=NULL;
+static char * ParseMessage(char *msgSrc) {
+ char *cp1 = NULL, *cp2 = NULL;
static char shortMsg[STR_SIZE];
- cp1 = strchr( _(msgSrc), '\t' );
+ cp1 = strchr(_(msgSrc), '\t');
if (cp1) {
- cp2 = strchr( cp1+1, '\t' );
+ cp2 = strchr(cp1 + 1, '\t');
if (cp2) {
cp1++;
- memcpy( shortMsg, cp1, cp2-cp1 );
- shortMsg[cp2-cp1] = 0;
+ memcpy(shortMsg, cp1, cp2 - cp1);
+ shortMsg[cp2 - cp1] = 0;
cp1 = shortMsg;
cp2++;
} else {
@@ -476,157 +546,177 @@ static char * ParseMessage(
cp2 = cp1;
}
if (messageListEmpty) {
- wMenuListDelete( messageList_ml, _(MESSAGE_LIST_EMPTY) );
+ wMenuListDelete(messageList_ml, _(MESSAGE_LIST_EMPTY));
messageListEmpty = FALSE;
}
- wMenuListAdd( messageList_ml, 0, cp1, _(msgSrc) );
+ wMenuListAdd(messageList_ml, 0, cp1, _(msgSrc));
return cp2;
} else {
return _(msgSrc);
}
}
-
-EXPORT void InfoMessage( char * format, ... )
-{
+EXPORT void InfoMessage(char * format, ...) {
va_list ap;
- va_start( ap, format );
- format = ParseMessage( format );
- vsprintf( message2, format, ap );
- va_end( ap );
+ va_start(ap, format);
+ format = ParseMessage(format);
+ vsprintf(message2, format, ap);
+ va_end(ap);
/*InfoSubstituteControl( NULL, NULL );*/
if (inError)
return;
- SetMessage( message2 );
+ SetMessage(message2);
}
-
-EXPORT void ErrorMessage( char * format, ... )
-{
+EXPORT void ErrorMessage(char * format, ...) {
va_list ap;
- va_start( ap, format );
- format = ParseMessage( format );
- vsprintf( message2, format, ap );
- va_end( ap );
- InfoSubstituteControls( NULL, NULL );
- SetMessage( message2 );
+ va_start(ap, format);
+ format = ParseMessage(format);
+ vsprintf(message2, format, ap);
+ va_end(ap);
+ InfoSubstituteControls( NULL, NULL);
+ SetMessage(message2);
wBeep();
inError = TRUE;
}
+EXPORT int NoticeMessage(char * format, char * yes, char * no, ...) {
+ va_list ap;
+ va_start(ap, no);
+ format = ParseMessage(format);
+ vsprintf(message2, format, ap);
+ va_end(ap);
+ return wNotice(message2, yes, no);
+}
-EXPORT int NoticeMessage( char * format, char * yes, char * no, ... )
-{
+EXPORT int NoticeMessage2(int playbackRC, char * format, char * yes, char * no,
+ ...) {
va_list ap;
- va_start( ap, no );
- format = ParseMessage( format );
- vsprintf( message2, format, ap );
- va_end( ap );
- return wNotice( message2, yes, no );
+ if (inPlayback)
+ return playbackRC;
+ va_start(ap, no);
+ format = ParseMessage(format);
+ vsprintf(message2, format, ap);
+ va_end(ap);
+ return wNoticeEx( NT_INFORMATION, message2, yes, no);
}
+/**
+* Set the file's changed flag and update the window title.
+*/
-EXPORT int NoticeMessage2( int playbackRC, char * format, char * yes, char * no, ... )
+void
+FileIsChanged(void)
{
- va_list ap;
- if ( inPlayback )
- return playbackRC;
- va_start( ap, no );
- format = ParseMessage( format );
- vsprintf( message2, format, ap );
- va_end( ap );
- return wNoticeEx( NT_INFORMATION, message2, yes, no );
+ changed++;
+ SetWindowTitle();
}
-
+
/*****************************************************************************
*
* MAIN BUTTON HANDLERS
*
*/
+ /**
+ * Confirm a requested operation in case of possible loss of changes.
+ *
+ * \param label2 IN operation to be cancelled, unused at the moment
+ * \param after IN function to be executed on positive confirmation
+ * \return true if proceed, false if cancel operation
+ */
+/** TODO: make sensible messages when requesting confirmation */
-EXPORT void Confirm( char * label2, doSaveCallBack_p after )
+bool
+Confirm(char * label2, doSaveCallBack_p after)
{
- int rc;
+ int rc = -1;
if (changed) {
- rc = wNotice3(
- _("Save changes to the layout design before closing?\n\n"
- "If you don't save now, your unsaved changes will be discarded."),
- _("&Save"), _("&Cancel"), _("&Don't Save") );
- if (rc == 1) {
- DoSave( after );
- return;
- } else if (rc == 0) {
- return;
- }
+ rc = wNotice3(_("Save changes to the layout design before closing?\n\n"
+ "If you don't save now, your unsaved changes will be discarded."),
+ _("&Save"), _("&Cancel"), _("&Don't Save"));
}
- after();
- return;
+
+ switch (rc) {
+ case -1: /* do not save */
+ after();
+ break;
+ case 0: /* cancel operation */
+ break;
+ case 1: /* save */
+ LayoutBackGroundInit(FALSE);
+ LayoutBackGroundSave();
+ DoSave(after);
+ break;
+ }
+ return(rc != 0);
}
-static void ChkLoad( void )
-{
+static void ChkLoad(void) {
Confirm(_("Load"), DoLoad);
}
-static void ChkRevert( void )
+static void ChkExamples( void )
{
- int rc;
-
- if( changed) {
- rc = wNoticeEx( NT_WARNING, _("Do you want to return to the last saved state?\n\n"
- "Revert will cause all changes done since last save to be lost."),
- _("&Revert"), _("&Cancel") );
- if( rc ) {
- /* load the file */
- char *filename = GetLayoutFullPath();
- LoadTracks( 1, &filename, NULL );
- }
- }
+ Confirm(_("examples"), DoExamples);
}
+static void ChkRevert(void)
+{
+ int rc;
+
+ if (changed) {
+ rc = wNoticeEx(NT_WARNING,
+ _("Do you want to return to the last saved state?\n\n"
+ "Revert will cause all changes done since last save to be lost."),
+ _("&Revert"), _("&Cancel"));
+ if (rc) {
+ /* load the file */
+ char *filename = GetLayoutFullPath();
+ LoadTracks(1, &filename, NULL);
+ }
+ }
+}
static char * fileListPathName;
-static void AfterFileList( void )
-{
- DoFileList( 0, NULL, fileListPathName );
+static void AfterFileList(void) {
+ DoFileList(0, NULL, fileListPathName);
}
-static void ChkFileList( int index, const char * label, void * data )
-{
- fileListPathName = (char*)data;
- Confirm( _("Load"), AfterFileList );
+static void ChkFileList(int index, const char * label, void * data) {
+ fileListPathName = (char*) data;
+ Confirm(_("Load"), AfterFileList);
}
/**
* Save information about current files and some settings to preferences file.
*/
-EXPORT void SaveState( void )
-{
+EXPORT void SaveState(void) {
wPos_t width, height;
const char * fileName;
void * pathName;
char file[6];
int inx;
- wWinGetSize( mainW, &width, &height );
- wPrefSetInteger( "draw", "mainwidth", width );
- wPrefSetInteger( "draw", "mainheight", height );
- RememberParamFiles();
+ wWinGetSize(mainW, &width, &height);
+ wPrefSetInteger("draw", "mainwidth", width);
+ wPrefSetInteger("draw", "mainheight", height);
+ SaveParamFileList();
ParamUpdatePrefs();
wPrefSetString( "misc", "lastlayout", GetLayoutFullPath());
+ wPrefSetInteger( "misc", "lastlayoutexample", bExample );
- if ( fileList_ml ) {
- strcpy( file, "file" );
+ if (fileList_ml) {
+ strcpy(file, "file");
file[5] = 0;
- for ( inx=0; inx<NUM_FILELIST; inx++ ) {
- fileName = wMenuListGet( fileList_ml, inx, &pathName );
+ for (inx = 0; inx < NUM_FILELIST; inx++) {
+ fileName = wMenuListGet(fileList_ml, inx, &pathName);
if (fileName) {
- file[4] = '0'+inx;
- sprintf( message, "%s", (char*)pathName );
- wPrefSetString( "filelist", file, message );
+ file[4] = '0' + inx;
+ sprintf(message, "%s", (char* )pathName);
+ wPrefSetString("filelist", file, message);
}
}
}
@@ -637,8 +727,7 @@ EXPORT void SaveState( void )
/*
* Clean up before quitting
*/
-static void DoQuitAfter( void )
-{
+static void DoQuitAfter(void) {
changed = 0;
SaveState();
@@ -649,34 +738,34 @@ static void DoQuitAfter( void )
* to close the application. Before shutting down confirmation is gotten to
* prevent data loss.
*/
-void DoQuit( void )
-{
- Confirm(_("Quit"), DoQuitAfter );
+void DoQuit(void) {
+ if (Confirm(_("Quit"), DoQuitAfter)) {
+
#ifdef CHECK_UNUSED_BALLOONHELP
- ShowUnusedBalloonHelp();
+ ShowUnusedBalloonHelp();
#endif
- LogClose();
- wExit(0);
+ LogClose();
+ wExit(0);
+ }
}
-static void DoClearAfter( void )
-{
-
+static void DoClearAfter(void) {
+
+ Reset();
ClearTracks();
/* set all layers to their default properties and set current layer to 0 */
- DefaultLayerProperties();
DoLayout(NULL);
- checkPtMark = 0;
- Reset();
+ checkPtMark = changed = 0;
DoChangeNotification( CHANGE_MAIN|CHANGE_MAP );
+ bReadOnly = TRUE;
EnableCommands();
SetLayoutFullPath("");
SetWindowTitle();
+ LayoutBackGroundInit(TRUE);
}
-static void DoClear( void )
-{
+static void DoClear(void) {
Confirm(_("Clear"), DoClearAfter);
}
@@ -684,9 +773,8 @@ static void DoClear( void )
* Toggle visibility state of map window.
*/
-void MapWindowToggleShow(void)
-{
- MapWindowShow(!mapVisible);
+void MapWindowToggleShow(void) {
+ MapWindowShow(!mapVisible);
}
/**
@@ -695,114 +783,114 @@ void MapWindowToggleShow(void)
* \param state IN TRUE if visible, FALSE if hidden
*/
-void MapWindowShow(int state)
-{
- mapVisible = state;
- wPrefSetInteger("misc", "mapVisible", mapVisible);
- wMenuToggleSet(mapShowMI, mapVisible);
+void MapWindowShow(int state) {
+ mapVisible = state;
+ wPrefSetInteger("misc", "mapVisible", mapVisible);
+ wMenuToggleSet(mapShowMI, mapVisible);
- if (mapVisible) {
- DoChangeNotification(CHANGE_MAP);
- }
+ if (mapVisible) {
+ DoChangeNotification(CHANGE_MAP);
+ }
- wWinShow(mapW, mapVisible);
- wButtonSetBusy(mapShowB, (wBool_t)mapVisible);
+ wWinShow(mapW, mapVisible);
+ wButtonSetBusy(mapShowB, (wBool_t) mapVisible);
}
-static void DoShowWindow(
- int index,
- const char * name,
- void * data )
+/**
+ * Set magnets state
+ */
+int MagneticSnap(int state)
{
+ int oldState = magneticSnap;
+ magneticSnap = state;
+ wPrefSetInteger("misc", "magnets", magneticSnap);
+ wMenuToggleSet(magnetsMI, magneticSnap);
+ wButtonSetBusy(magnetsB, (wBool_t) magneticSnap);
+ return oldState;
+}
+
+/**
+ * Toggle magnets on/off
+ */
+void MagneticSnapToggle(void) {
+ MagneticSnap(!magneticSnap);
+}
+
+
+static void DoShowWindow(int index, const char * name, void * data) {
if (data == mapW) {
if (mapVisible == FALSE) {
- MapWindowShow( TRUE );
+ MapWindowShow( TRUE);
return;
}
}
- wWinShow( (wWin_p)data, TRUE );
+ wWinShow((wWin_p) data, TRUE);
}
-
static dynArr_t demoWindows_da;
#define demoWindows(N) DYNARR_N( wWin_p, demoWindows_da, N )
-EXPORT void wShow(
- wWin_p win )
-{
+EXPORT void wShow(wWin_p win) {
int inx;
if (inPlayback && win != demoW) {
- wWinSetBusy( win, TRUE );
- for ( inx=0; inx<demoWindows_da.cnt; inx++ )
- if ( demoWindows(inx) == win )
+ wWinSetBusy(win, TRUE);
+ for (inx = 0; inx < demoWindows_da.cnt; inx++)
+ if ( demoWindows(inx) == win)
break;
- if ( inx >= demoWindows_da.cnt ) {
- for ( inx=0; inx<demoWindows_da.cnt; inx++ )
- if ( demoWindows(inx) == NULL )
- break;
- if ( inx >= demoWindows_da.cnt ) {
- DYNARR_APPEND( wWin_p, demoWindows_da, 10 );
- inx = demoWindows_da.cnt-1;
+ if (inx >= demoWindows_da.cnt) {
+ for (inx = 0; inx < demoWindows_da.cnt; inx++)
+ if ( demoWindows(inx) == NULL)
+ break;
+ if (inx >= demoWindows_da.cnt) {
+ DYNARR_APPEND(wWin_p, demoWindows_da, 10);
+ inx = demoWindows_da.cnt - 1;
}
demoWindows(inx) = win;
}
}
if (win != mainW)
- wMenuListAdd( winList_mi, -1, wWinGetTitle(win), win );
- wWinShow( win, TRUE );
+ wMenuListAdd(winList_mi, -1, wWinGetTitle(win), win);
+ wWinShow(win, TRUE);
}
-
-EXPORT void wHide(
- wWin_p win )
-{
+EXPORT void wHide(wWin_p win) {
int inx;
- wWinShow( win, FALSE );
- wWinSetBusy( win, FALSE );
- if ( inMainW && win == aboutW )
+ wWinShow(win, FALSE);
+ wWinSetBusy(win, FALSE);
+ if (inMainW && win == aboutW)
return;
- wMenuListDelete( winList_mi, wWinGetTitle(win) );
- if ( inPlayback )
- for ( inx=0; inx<demoWindows_da.cnt; inx++ )
- if ( demoWindows(inx) == win )
+ wMenuListDelete(winList_mi, wWinGetTitle(win));
+ if (inPlayback)
+ for (inx = 0; inx < demoWindows_da.cnt; inx++)
+ if ( demoWindows(inx) == win)
demoWindows(inx) = NULL;
}
-
-EXPORT void CloseDemoWindows( void )
-{
+EXPORT void CloseDemoWindows(void) {
int inx;
- for ( inx=0; inx<demoWindows_da.cnt; inx++ )
- if ( demoWindows(inx) != NULL )
- wHide( demoWindows(inx) );
+ for (inx = 0; inx < demoWindows_da.cnt; inx++)
+ if ( demoWindows(inx) != NULL)
+ wHide(demoWindows(inx));
demoWindows_da.cnt = 0;
}
-
-EXPORT void DefaultProc(
- wWin_p win,
- winProcEvent e,
- void * data )
-{
- switch( e ) {
+EXPORT void DefaultProc(wWin_p win, winProcEvent e, void * data) {
+ switch (e) {
case wClose_e:
- wMenuListDelete( winList_mi, wWinGetTitle(win) );
+ wMenuListDelete(winList_mi, wWinGetTitle(win));
if (data != NULL)
- ConfirmReset( FALSE );
- wWinDoCancel( win );
+ ConfirmReset( FALSE);
+ wWinDoCancel(win);
break;
default:
break;
}
}
-
-static void NextWindow( void )
-{
+static void NextWindow(void) {
}
-EXPORT void SelectFont( void )
-{
+EXPORT void SelectFont(void) {
wSelectFont(_("XTrackCAD Font"));
}
@@ -817,38 +905,36 @@ EXPORT void SelectFont( void )
#define NUM_CMDMENUS (4)
static struct {
- wControl_p control;
- wBool_t enabled;
- wPos_t x, y;
- long options;
- int group;
- wIndex_t cmdInx;
- } buttonList[BUTTON_MAX];
+ wControl_p control;
+ wBool_t enabled;
+ wPos_t x, y;
+ long options;
+ int group;
+ wIndex_t cmdInx;
+} buttonList[BUTTON_MAX];
static int buttonCnt = 0;
static struct {
- procCommand_t cmdProc;
- char * helpKey;
- wIndex_t buttInx;
- char * labelStr;
- wIcon_p icon;
- int reqLevel;
- wBool_t enabled;
- long options;
- long stickyMask;
- long acclKey;
- wMenuPush_p menu[NUM_CMDMENUS];
- void * context;
- } commandList[COMMAND_MAX];
+ procCommand_t cmdProc;
+ char * helpKey;
+ wIndex_t buttInx;
+ char * labelStr;
+ wIcon_p icon;
+ int reqLevel;
+ wBool_t enabled;
+ long options;
+ long stickyMask;
+ long acclKey;
+ wMenuPush_p menu[NUM_CMDMENUS];
+ void * context;
+} commandList[COMMAND_MAX];
static int commandCnt = 0;
-
#ifdef CHECK_UNUSED_BALLOONHELP
int * balloonHelpCnts;
#endif
-EXPORT const char * GetBalloonHelpStr( char * helpKey )
-{
+EXPORT const char * GetBalloonHelpStr(char * helpKey) {
wBalloonHelp_t * bh;
#ifdef CHECK_UNUSED_BALLOONHELP
if ( balloonHelpCnts == NULL ) {
@@ -857,8 +943,8 @@ EXPORT const char * GetBalloonHelpStr( char * helpKey )
memset( balloonHelpCnts, 0, (sizeof *(int*)0) * (bh-balloonHelp) );
}
#endif
- for ( bh=balloonHelp; bh->name; bh++ ) {
- if ( strcmp( bh->name, helpKey ) == 0 ) {
+ for (bh = balloonHelp; bh->name; bh++) {
+ if (strcmp(bh->name, helpKey) == 0) {
#ifdef CHECK_UNUSED_BALLOONHELP
balloonHelpCnts[(bh-balloonHelp)]++;
#endif
@@ -866,107 +952,134 @@ EXPORT const char * GetBalloonHelpStr( char * helpKey )
}
}
#ifdef CHECK_BALLOONHELP
-fprintf( stderr, _("No balloon help for %s\n"), helpKey );
+ fprintf( stderr, _("No balloon help for %s\n"), helpKey );
#endif
return _("No Help");
}
-
#ifdef CHECK_UNUSED_BALLOONHELP
static void ShowUnusedBalloonHelp( void )
{
int cnt;
for ( cnt=0; balloonHelp[cnt].name; cnt++ )
- if ( balloonHelpCnts[cnt] == 0 )
- fprintf( stderr, "unused BH %s\n", balloonHelp[cnt].name );
+ if ( balloonHelpCnts[cnt] == 0 )
+ fprintf( stderr, "unused BH %s\n", balloonHelp[cnt].name );
}
#endif
+EXPORT const char* GetCurCommandName() {
+ return commandList[curCommand].helpKey;
+}
-EXPORT void EnableCommands( void )
-{
+EXPORT void EnableCommands(void) {
int inx, minx;
wBool_t enable;
-LOG( log_command, 5, ( "COMMAND enable S%d M%d\n", selectedTrackCount, programMode ) )
- for ( inx=0; inx<commandCnt; inx++ ) {
+ LOG(log_command, 5,
+ ( "COMMAND enable S%d M%d\n", selectedTrackCount, programMode ))
+ for (inx = 0; inx < commandCnt; inx++) {
if (commandList[inx].buttInx) {
- if ( (commandList[inx].options & IC_SELECTED) &&
- selectedTrackCount <= 0 )
+ if ((commandList[inx].options & IC_SELECTED)
+ && selectedTrackCount <= 0)
enable = FALSE;
- else if ( (programMode==MODE_TRAIN&&(commandList[inx].options&(IC_MODETRAIN_TOO|IC_MODETRAIN_ONLY))==0) ||
- (programMode!=MODE_TRAIN&&(commandList[inx].options&IC_MODETRAIN_ONLY)!=0) )
+ else if ((programMode == MODE_TRAIN
+ && (commandList[inx].options
+ & (IC_MODETRAIN_TOO | IC_MODETRAIN_ONLY)) == 0)
+ || (programMode != MODE_TRAIN
+ && (commandList[inx].options & IC_MODETRAIN_ONLY)
+ != 0))
enable = FALSE;
else
enable = TRUE;
- if ( commandList[inx].enabled != enable ) {
- if ( commandList[inx].buttInx >= 0 )
- wControlActive( buttonList[commandList[inx].buttInx].control, enable );
- for ( minx=0; minx<NUM_CMDMENUS; minx++ )
+ if (commandList[inx].enabled != enable) {
+ if (commandList[inx].buttInx >= 0)
+ wControlActive(buttonList[commandList[inx].buttInx].control,
+ enable);
+ for (minx = 0; minx < NUM_CMDMENUS; minx++)
if (commandList[inx].menu[minx])
- wMenuPushEnable( commandList[inx].menu[minx], enable );
+ wMenuPushEnable(commandList[inx].menu[minx], enable);
commandList[inx].enabled = enable;
}
}
}
- for ( inx=0; inx<menuPG.paramCnt; inx++ ) {
- if ( menuPLs[inx].control == NULL )
+ for (inx = 0; inx < menuPG.paramCnt; inx++) {
+ if (menuPLs[inx].control == NULL)
continue;
- if ( (menuPLs[inx].option & IC_SELECTED) &&
- selectedTrackCount <= 0 )
+ if ((menuPLs[inx].option & IC_SELECTED) && selectedTrackCount <= 0)
enable = FALSE;
- else if ( (programMode==MODE_TRAIN&&(menuPLs[inx].option&(IC_MODETRAIN_TOO|IC_MODETRAIN_ONLY))==0) ||
- (programMode!=MODE_TRAIN&&(menuPLs[inx].option&IC_MODETRAIN_ONLY)!=0) )
+ else if ((programMode == MODE_TRAIN
+ && (menuPLs[inx].option & (IC_MODETRAIN_TOO | IC_MODETRAIN_ONLY))
+ == 0)
+ || (programMode != MODE_TRAIN
+ && (menuPLs[inx].option & IC_MODETRAIN_ONLY) != 0))
enable = FALSE;
else
enable = TRUE;
- wMenuPushEnable( (wMenuPush_p)menuPLs[inx].control, enable );
+ wMenuPushEnable((wMenuPush_p) menuPLs[inx].control, enable);
}
- for ( inx=0; inx<buttonCnt; inx++ ) {
- if ( buttonList[inx].cmdInx < 0 && (buttonList[inx].options&IC_SELECTED) )
- wControlActive( buttonList[inx].control, selectedTrackCount>0 );
- }
+ for (inx = 0; inx < buttonCnt; inx++) {
+ if (buttonList[inx].cmdInx < 0
+ && (buttonList[inx].options & IC_SELECTED))
+ wControlActive(buttonList[inx].control, selectedTrackCount > 0);
+ }
}
+EXPORT wIndex_t GetCurrentCommand() {
+ return curCommand;
+}
-EXPORT void Reset( void )
-{
+static wIndex_t autosave_count = 0;
+
+EXPORT void Reset(void) {
if (recordF) {
- fprintf( recordF, "RESET\n" );
- fflush( recordF );
- }
-LOG( log_command, 2, ( "COMMAND CANCEL %s\n", commandList[curCommand].helpKey ) )
- commandList[curCommand].cmdProc( C_CANCEL, zero );
- if ( commandList[curCommand].buttInx>=0 )
- wButtonSetBusy( (wButton_p)buttonList[commandList[curCommand].buttInx].control, FALSE );
- curCommand = (preSelect?selectCmdInx:describeCmdInx);
+ fprintf(recordF, "RESET\n");
+ fflush(recordF);
+ }
+ LOG(log_command, 2,
+ ( "COMMAND CANCEL %s\n", commandList[curCommand].helpKey ))
+ commandList[curCommand].cmdProc( C_CANCEL, zero);
+ if (commandList[curCommand].buttInx >= 0)
+ wButtonSetBusy(
+ (wButton_p) buttonList[commandList[curCommand].buttInx].control,
+ FALSE);
+ curCommand = (preSelect ? selectCmdInx : describeCmdInx);
+ wSetCursor(mainD.d, preSelect ? defaultCursor : wCursorQuestion);
commandContext = commandList[curCommand].context;
- if ( commandList[curCommand].buttInx >= 0 )
- wButtonSetBusy( (wButton_p)buttonList[commandList[curCommand].buttInx].control, TRUE );
+ if (commandList[curCommand].buttInx >= 0)
+ wButtonSetBusy(
+ (wButton_p) buttonList[commandList[curCommand].buttInx].control,
+ TRUE);
tempSegs_da.cnt = 0;
- if (checkPtInterval > 0 &&
- changed >= checkPtMark+(wIndex_t)checkPtInterval &&
- !inPlayback ) {
+ if (checkPtInterval > 0
+ && changed >= checkPtMark + (wIndex_t) checkPtInterval
+ && !inPlayback) {
DoCheckPoint();
checkPtMark = changed;
+
+ autosave_count++;
+
+ if ((autosaveChkPoints>0) && (autosave_count>=autosaveChkPoints)) {
+ DoSave(NULL);
+ InfoMessage(_("File AutoSaved"));
+ autosave_count = 0;
+ }
}
- MainRedraw();
- MapRedraw();
+
+
+
+ ClrAllTrkBits( TB_UNDRAWN );
+ DoRedraw(); // Reset
EnableCommands();
ResetMouseState();
-LOG( log_command, 1, ( "COMMAND RESET %s\n", commandList[curCommand].helpKey ) )
- (void)commandList[curCommand].cmdProc( C_START, zero );
+ LOG(log_command, 1,
+ ( "COMMAND RESET %s\n", commandList[curCommand].helpKey ))
+ (void) commandList[curCommand].cmdProc( C_START, zero);
}
-
-static BOOL_T CheckClick(
- wAction_t *action,
- coOrd *pos,
- BOOL_T checkLeft,
- BOOL_T checkRight )
-{
+static BOOL_T CheckClick(wAction_t *action, coOrd *pos, BOOL_T checkLeft,
+ BOOL_T checkRight) {
static long time0;
static coOrd pos0;
long time1;
@@ -974,6 +1087,11 @@ static BOOL_T CheckClick(
DIST_T distDelta;
switch (*action) {
+ case C_LDOUBLE:
+ if (!checkLeft)
+ return TRUE;
+ time0 = 0;
+ break;
case C_DOWN:
if (!checkLeft)
return TRUE;
@@ -986,9 +1104,8 @@ static BOOL_T CheckClick(
if (time0 != 0) {
time1 = wGetTimer() - adjTimer;
timeDelta = time1 - time0;
- distDelta = FindDistance( *pos, pos0 );
- if ( timeDelta > dragTimeout ||
- distDelta > dragDistance ) {
+ distDelta = FindDistance(*pos, pos0);
+ if (timeDelta > dragTimeout || distDelta > dragDistance) {
time0 = 0;
*pos = pos0;
*action = C_DOWN;
@@ -1003,7 +1120,7 @@ static BOOL_T CheckClick(
if (time0 != 0) {
time1 = wGetTimer() - adjTimer;
timeDelta = time1 - time0;
- distDelta = FindDistance( *pos, pos0 );
+ distDelta = FindDistance(*pos, pos0);
time0 = 0;
*action = C_LCLICK;
}
@@ -1020,9 +1137,8 @@ static BOOL_T CheckClick(
if (time0 != 0) {
time1 = wGetTimer() - adjTimer;
timeDelta = time1 - time0;
- distDelta = FindDistance( *pos, pos0 );
- if ( timeDelta > dragTimeout ||
- distDelta > dragDistance ) {
+ distDelta = FindDistance(*pos, pos0);
+ if (timeDelta > dragTimeout || distDelta > dragDistance) {
time0 = 0;
*pos = pos0;
*action = C_RDOWN;
@@ -1043,66 +1159,90 @@ static BOOL_T CheckClick(
return TRUE;
}
-
-EXPORT wBool_t DoCurCommand( wAction_t action, coOrd pos )
-{
+EXPORT wBool_t DoCurCommand(wAction_t action, coOrd pos) {
wAction_t rc;
int mode;
+ wBool_t bExit = FALSE;
- if ( action == wActionMove && (commandList[curCommand].options & IC_WANT_MOVE) == 0 )
- return C_CONTINUE;
-
- if ( !CheckClick( &action, &pos,
- (int)(commandList[curCommand].options & IC_LCLICK), TRUE ) )
- return C_CONTINUE;
-
- if ( action == C_RCLICK && (commandList[curCommand].options&IC_RCLICK)==0 ) {
- if ( !inPlayback ) {
+ if (action == wActionMove) {
+ if ((commandList[curCommand].options & IC_WANT_MOVE) == 0) {
+ bExit = TRUE;
+ }
+ } else if ((action&0xFF) == wActionModKey) {
+ if ((commandList[curCommand].options & IC_WANT_MODKEYS) == 0) {
+ bExit = TRUE;
+ }
+ } else if (!CheckClick(&action, &pos,
+ (int) (commandList[curCommand].options & IC_LCLICK), TRUE)) {
+ bExit = TRUE;
+ } else if (action == C_RCLICK
+ && (commandList[curCommand].options & IC_RCLICK) == 0) {
+ if (!inPlayback) {
mode = MyGetKeyState();
- if ( ( mode & (~WKEY_SHIFT) ) != 0 ) {
+ if ((mode & (~WKEY_SHIFT)) != 0) {
wBeep();
- return C_CONTINUE;
- }
- if ( ((mode&WKEY_SHIFT) == 0) == (rightClickMode==0) ) {
- if ( selectedTrackCount > 0 ) {
+ bExit = TRUE;
+ } else if (((mode & WKEY_SHIFT) == 0) == (rightClickMode == 0)) {
+ if (selectedTrackCount > 0) {
if (commandList[curCommand].options & IC_CMDMENU) {
}
- wMenuPopupShow( popup2M );
+ wMenuPopupShow(popup2M);
} else {
- wMenuPopupShow( popup1M );
+ wMenuPopupShow(popup1M);
}
- return C_CONTINUE;
- } else if ( (commandList[curCommand].options & IC_CMDMENU) ) {
+ bExit = TRUE;
+ } else if ((commandList[curCommand].options & IC_CMDMENU)) {
cmdMenuPos = pos;
action = C_CMDMENU;
} else {
wBeep();
- return C_CONTINUE;
+ bExit = TRUE;
}
} else {
- return C_CONTINUE;
+ bExit = TRUE;
}
}
+ if ( bExit ) {
+ TempRedraw(); // DoCurCommand: precommand
+ return C_CONTINUE;
+ }
-LOG( log_command, 2, ( "COMMAND MOUSE %s %d @ %0.3f %0.3f\n", commandList[curCommand].helpKey, (int)action, pos.x, pos.y ) )
- rc = commandList[curCommand].cmdProc( action, pos );
-LOG( log_command, 4, ( " COMMAND returns %d\n", rc ) )
- if ( (rc == C_TERMINATE || rc == C_INFO) &&
- (commandList[curCommand].options & IC_STICKY) &&
- (commandList[curCommand].stickyMask & stickySet) ) {
+ LOG(log_command, 2,
+ ( "COMMAND MOUSE %s %d @ %0.3f %0.3f\n", commandList[curCommand].helpKey, (int)action, pos.x, pos.y ))
+ rc = commandList[curCommand].cmdProc(action, pos);
+ LOG(log_command, 4, ( " COMMAND returns %d\n", rc ))
+ switch ( action & 0xFF ) {
+ case wActionMove:
+ case wActionModKey:
+ case C_DOWN:
+ case C_MOVE:
+ case C_UP:
+ case C_RDOWN:
+ case C_RMOVE:
+ case C_RUP:
+ case C_LCLICK:
+ case C_RCLICK:
+ case C_TEXT:
+ case C_OK:
+ if (rc== C_TERMINATE) MainRedraw();
+ else TempRedraw(); // DoCurCommand: postcommand
+ break;
+ default:
+ break;
+ }
+ if ((rc == C_TERMINATE || rc == C_INFO)
+ && (commandList[curCommand].options & IC_STICKY)
+ && (commandList[curCommand].stickyMask & stickySet)) {
tempSegs_da.cnt = 0;
UpdateAllElevations();
- if (action != C_REDRAW) {
- MainRedraw();
- MapRedraw();
- }
if (commandList[curCommand].options & IC_NORESTART) {
return C_CONTINUE;
}
-LOG( log_command, 1, ( "COMMAND START %s\n", commandList[curCommand].helpKey ) )
- rc = commandList[curCommand].cmdProc( C_START, pos );
-LOG( log_command, 4, ( " COMMAND returns %d\n", rc ) )
- switch( rc ) {
+ LOG(log_command, 1,
+ ( "COMMAND START %s\n", commandList[curCommand].helpKey ))
+ rc = commandList[curCommand].cmdProc( C_START, pos);
+ LOG(log_command, 4, ( " COMMAND returns %d\n", rc ))
+ switch (rc) {
case C_CONTINUE:
break;
case C_ERROR:
@@ -1112,7 +1252,7 @@ LOG( log_command, 4, ( " COMMAND returns %d\n", rc ) )
#endif
break;
case C_TERMINATE:
- InfoMessage( "" );
+ InfoMessage("");
case C_INFO:
Reset();
break;
@@ -1121,60 +1261,67 @@ LOG( log_command, 4, ( " COMMAND returns %d\n", rc ) )
return rc;
}
-
-EXPORT void ConfirmReset( BOOL_T retry )
-{
+EXPORT void ConfirmReset(BOOL_T retry) {
wAction_t rc;
- if (curCommand != describeCmdInx && curCommand != selectCmdInx ) {
-LOG( log_command, 3, ( "COMMAND CONFIRM %s\n", commandList[curCommand].helpKey ) )
- rc = commandList[curCommand].cmdProc( C_CONFIRM, zero );
-LOG( log_command, 4, ( " COMMAND returns %d\n", rc ) )
- if ( rc == C_ERROR ) {
+ if (curCommand != describeCmdInx && curCommand != selectCmdInx) {
+ LOG(log_command, 3,
+ ( "COMMAND CONFIRM %s\n", commandList[curCommand].helpKey ))
+ rc = commandList[curCommand].cmdProc( C_CONFIRM, zero);
+ LOG(log_command, 4, ( " COMMAND returns %d\n", rc ))
+ if (rc == C_ERROR) {
if (retry)
- rc = wNotice3(
- _("Cancelling the current command will undo the changes\n"
- "you are currently making. Do you want to update?"),
- _("Yes"), _("No"), _("Cancel") );
+ rc =
+ wNotice3(
+ _(
+ "Cancelling the current command will undo the changes\n"
+ "you are currently making. Do you want to update?"),
+ _("Yes"), _("No"), _("Cancel"));
else
- rc = wNoticeEx( NT_WARNING,
- _("Cancelling the current command will undo the changes\n"
- "you are currently making. Do you want to update?"),
- _("Yes"), _("No") );
+ rc =
+ wNoticeEx( NT_WARNING,
+ _(
+ "Cancelling the current command will undo the changes\n"
+ "you are currently making. Do you want to update?"),
+ _("Yes"), _("No"));
if (rc == 1) {
-LOG( log_command, 3, ( "COMMAND OK %s\n", commandList[curCommand].helpKey ) )
- commandList[curCommand].cmdProc( C_OK, zero );
+ LOG(log_command, 3,
+ ( "COMMAND OK %s\n", commandList[curCommand].helpKey ))
+ commandList[curCommand].cmdProc( C_OK, zero);
return;
} else if (rc == -1) {
return;
}
- } else if ( rc == C_TERMINATE ) {
+ } else if (rc == C_TERMINATE) {
return;
}
}
- Reset();
if (retry) {
/* because user pressed esc */
- SetAllTrackSelect( FALSE );
+ SetAllTrackSelect( FALSE);
}
-LOG( log_command, 1, ( "COMMAND RESET %s\n", commandList[curCommand].helpKey ) )
- commandList[curCommand].cmdProc( C_START, zero );
+ Reset();
+ LOG(log_command, 1,
+ ( "COMMAND RESET %s\n", commandList[curCommand].helpKey ))
+ commandList[curCommand].cmdProc( C_START, zero);
}
+EXPORT BOOL_T IsCurCommandSticky(void) {
+ if ((commandList[curCommand].options & IC_STICKY) != 0
+ && (commandList[curCommand].stickyMask & stickySet) != 0)
+ return TRUE;
+ return FALSE;
+}
-EXPORT void ResetIfNotSticky( void )
-{
- if ( (commandList[curCommand].options & IC_STICKY) == 0 ||
- (commandList[curCommand].stickyMask & stickySet) == 0 )
+EXPORT void ResetIfNotSticky(void) {
+ if ((commandList[curCommand].options & IC_STICKY) == 0
+ || (commandList[curCommand].stickyMask & stickySet) == 0)
Reset();
}
-
-EXPORT void DoCommandB(
- void * data )
-{
- wIndex_t inx = (wIndex_t)(long)data;
+EXPORT void DoCommandB(void * data) {
+ wIndex_t inx = (wIndex_t) (long) data;
STATUS_T rc;
- static coOrd pos = {0,0};
+ static coOrd pos = { 0, 0 };
static int inDoCommandB = FALSE;
wIndex_t buttInx;
@@ -1183,62 +1330,74 @@ EXPORT void DoCommandB(
inDoCommandB = TRUE;
if (inx < 0 || inx >= commandCnt) {
- ASSERT( FALSE );
+ ASSERT(FALSE);
inDoCommandB = FALSE;
return;
}
- if ( (!inPlayback) && (!commandList[inx].enabled) ) {
- ErrorMessage( MSG_COMMAND_DISABLED );
+ if ((!inPlayback) && (!commandList[inx].enabled)) {
+ ErrorMessage(MSG_COMMAND_DISABLED);
inx = describeCmdInx;
}
- InfoMessage( "" );
- if (curCommand != selectCmdInx ) {
-LOG( log_command, 3, ( "COMMAND FINISH %s\n", commandList[curCommand].helpKey ) )
- rc = commandList[curCommand].cmdProc( C_FINISH, zero );
-LOG( log_command, 3, ( "COMMAND CONFIRM %s\n", commandList[curCommand].helpKey ) )
- rc = commandList[curCommand].cmdProc( C_CONFIRM, zero );
-LOG( log_command, 4, ( " COMMAND returns %d\n", rc ) )
- if ( rc == C_ERROR ) {
+ InfoMessage("");
+ if (curCommand != selectCmdInx) {
+ LOG(log_command, 3,
+ ( "COMMAND FINISH %s\n", commandList[curCommand].helpKey ))
+ rc = commandList[curCommand].cmdProc( C_FINISH, zero);
+ LOG(log_command, 3,
+ ( "COMMAND CONFIRM %s\n", commandList[curCommand].helpKey ))
+ rc = commandList[curCommand].cmdProc( C_CONFIRM, zero);
+ LOG(log_command, 4, ( " COMMAND returns %d\n", rc ))
+ if (rc == C_ERROR) {
rc = wNotice3(
- _("Cancelling the current command will undo the changes\n"
- "you are currently making. Do you want to update?"),
- _("Yes"), _("No"), _("Cancel") );
+ _("Cancelling the current command will undo the changes\n"
+ "you are currently making. Do you want to update?"),
+ _("Yes"), _("No"), _("Cancel"));
if (rc == 1)
- commandList[curCommand].cmdProc( C_OK, zero );
+ commandList[curCommand].cmdProc( C_OK, zero);
else if (rc == -1) {
inDoCommandB = FALSE;
return;
}
}
-LOG( log_command, 3, ( "COMMAND CANCEL %s\n", commandList[curCommand].helpKey ) )
- commandList[curCommand].cmdProc( C_CANCEL, pos );
+ LOG(log_command, 3,
+ ( "COMMAND CANCEL %s\n", commandList[curCommand].helpKey ))
+ commandList[curCommand].cmdProc( C_CANCEL, pos);
tempSegs_da.cnt = 0;
}
- if (commandList[curCommand].buttInx>=0)
- wButtonSetBusy( (wButton_p)buttonList[commandList[curCommand].buttInx].control, FALSE );
+ if (commandList[curCommand].buttInx >= 0)
+ wButtonSetBusy(
+ (wButton_p) buttonList[commandList[curCommand].buttInx].control,
+ FALSE);
if (recordF) {
- fprintf( recordF, "COMMAND %s\n", commandList[inx].helpKey+3 );
- fflush( recordF );
+ fprintf(recordF, "COMMAND %s\n", commandList[inx].helpKey + 3);
+ fflush(recordF);
}
curCommand = inx;
commandContext = commandList[curCommand].context;
- if ( (buttInx=commandList[curCommand].buttInx) >= 0 ) {
- if ( buttonList[buttInx].cmdInx != curCommand ) {
- wButtonSetLabel( (wButton_p)buttonList[buttInx].control, (char*)commandList[curCommand].icon );
- wControlSetHelp( buttonList[buttInx].control, GetBalloonHelpStr(commandList[curCommand].helpKey) );
- wControlSetContext( buttonList[buttInx].control, (void*)(intptr_t)curCommand );
+ if ((buttInx = commandList[curCommand].buttInx) >= 0) {
+ if (buttonList[buttInx].cmdInx != curCommand) {
+ wButtonSetLabel((wButton_p) buttonList[buttInx].control,
+ (char*) commandList[curCommand].icon);
+ wControlSetHelp(buttonList[buttInx].control,
+ GetBalloonHelpStr(commandList[curCommand].helpKey));
+ wControlSetContext(buttonList[buttInx].control,
+ (void*) (intptr_t) curCommand);
buttonList[buttInx].cmdInx = curCommand;
}
- wButtonSetBusy( (wButton_p)buttonList[commandList[curCommand].buttInx].control, TRUE );
+ wButtonSetBusy(
+ (wButton_p) buttonList[commandList[curCommand].buttInx].control,
+ TRUE);
}
-LOG( log_command, 1, ( "COMMAND START %s\n", commandList[curCommand].helpKey ) )
- rc = commandList[curCommand].cmdProc( C_START, pos );
-LOG( log_command, 4, ( " COMMAND returns %d\n", rc ) )
- switch( rc ) {
+ LOG(log_command, 1,
+ ( "COMMAND START %s\n", commandList[curCommand].helpKey ))
+ rc = commandList[curCommand].cmdProc( C_START, pos);
+ LOG(log_command, 4, ( " COMMAND returns %d\n", rc ))
+ TempRedraw(); // DoCommandB
+ switch (rc) {
case C_CONTINUE:
break;
case C_ERROR:
@@ -1250,26 +1409,21 @@ LOG( log_command, 4, ( " COMMAND returns %d\n", rc ) )
case C_TERMINATE:
case C_INFO:
if (rc == C_TERMINATE)
- InfoMessage( "" );
+ InfoMessage("");
Reset();
break;
}
inDoCommandB = FALSE;
}
-
-static void DoCommandBIndirect( void * cmdInxP )
-{
+static void DoCommandBIndirect(void * cmdInxP) {
wIndex_t cmdInx;
- cmdInx = *(wIndex_t*)cmdInxP;
- DoCommandB( (void*)(intptr_t)cmdInx );
+ cmdInx = *(wIndex_t*) cmdInxP;
+ DoCommandB((void*) (intptr_t) cmdInx);
}
-
-EXPORT void LayoutSetPos(
- wIndex_t inx )
-{
- wPos_t w, h;
+EXPORT void LayoutSetPos(wIndex_t inx) {
+ wPos_t w, h, offset;
static wPos_t toolbarRowHeight = 0;
static wPos_t width;
static int lastGroup;
@@ -1277,59 +1431,66 @@ EXPORT void LayoutSetPos(
static int layerButtCnt;
int currGroup;
- if ( inx == 0 ) {
+ if (inx == 0) {
lastGroup = 0;
- wWinGetSize( mainW, &width, &h );
+ wWinGetSize(mainW, &width, &h);
gap = 5;
- toolbarWidth = width-20+5;
+ toolbarWidth = width - 20 + 5;
layerButtCnt = 0;
toolbarHeight = 0;
}
if (buttonList[inx].control) {
- if ( toolbarRowHeight <= 0 )
- toolbarRowHeight = wControlGetHeight( buttonList[inx].control );
+ if (toolbarRowHeight <= 0)
+ toolbarRowHeight = wControlGetHeight(buttonList[inx].control);
currGroup = buttonList[inx].group & ~BG_BIGGAP;
- if ( currGroup != lastGroup && (buttonList[inx].group&BG_BIGGAP) ) {
- gap = 15;
+ if (currGroup != lastGroup && (buttonList[inx].group & BG_BIGGAP)) {
+ gap = 15;
}
- if ((toolbarSet & (1<<currGroup)) &&
- (programMode!=MODE_TRAIN||(buttonList[inx].options&(IC_MODETRAIN_TOO|IC_MODETRAIN_ONLY))) &&
- (programMode==MODE_TRAIN||(buttonList[inx].options&IC_MODETRAIN_ONLY)==0) &&
- ((buttonList[inx].group&~BG_BIGGAP) != BG_LAYER ||
- layerButtCnt++ <= layerCount) ) {
- if (currGroup != lastGroup) {
- toolbarWidth += gap;
- lastGroup = currGroup;
- gap = 5;
- }
- w = wControlGetWidth( buttonList[inx].control );
- h = wControlGetHeight( buttonList[inx].control );
- if ( inx<buttonCnt-1 && (buttonList[inx+1].options&IC_ABUT) )
- w += wControlGetWidth( buttonList[inx+1].control );
- if (toolbarWidth+w>width-20) {
- toolbarWidth = 0;
- toolbarHeight += h + 5;
- }
- wControlSetPos( buttonList[inx].control, toolbarWidth, toolbarHeight-(h+5) );
- buttonList[inx].x = toolbarWidth;
- buttonList[inx].y = toolbarHeight-(h+5);
- toolbarWidth += wControlGetWidth( buttonList[inx].control );
- wControlShow( buttonList[inx].control, TRUE );
+ if ((toolbarSet & (1 << currGroup))
+ && (programMode != MODE_TRAIN
+ || (buttonList[inx].options
+ & (IC_MODETRAIN_TOO | IC_MODETRAIN_ONLY)))
+ && (programMode == MODE_TRAIN
+ || (buttonList[inx].options & IC_MODETRAIN_ONLY) == 0)
+ && ((buttonList[inx].group & ~BG_BIGGAP) != BG_LAYER
+ || layerButtCnt++ <= layerCount)) {
+ if (currGroup != lastGroup) {
+ toolbarWidth += gap;
+ lastGroup = currGroup;
+ gap = 5;
+ }
+ w = wControlGetWidth(buttonList[inx].control);
+ h = wControlGetHeight(buttonList[inx].control);
+ if (h<toolbarRowHeight) {
+ offset = (h-toolbarRowHeight)/2;
+ h = toolbarRowHeight; //Uniform
+ } else offset = 0;
+ if (inx < buttonCnt - 1 && (buttonList[inx + 1].options & IC_ABUT))
+ w += wControlGetWidth(buttonList[inx + 1].control);
+ if (toolbarWidth + w > width - 20) {
+ toolbarWidth = 0;
+ toolbarHeight += h + 5;
+ }
+ wControlSetPos(buttonList[inx].control, toolbarWidth,
+ toolbarHeight - (h + 5 +offset));
+ buttonList[inx].x = toolbarWidth;
+ buttonList[inx].y = toolbarHeight - (h + 5 + offset);
+ toolbarWidth += wControlGetWidth(buttonList[inx].control);
+ wControlShow(buttonList[inx].control, TRUE);
} else {
- wControlShow( buttonList[inx].control, FALSE );
+ wControlShow(buttonList[inx].control, FALSE);
}
}
}
-
EXPORT void LayoutToolBar( void * data )
{
int inx;
- for (inx = 0; inx<buttonCnt; inx++) {
- LayoutSetPos( inx );
+ for (inx = 0; inx < buttonCnt; inx++) {
+ LayoutSetPos(inx);
}
if (toolbarSet&(1<<BG_HOTBAR)) {
LayoutHotBar(data);
@@ -1338,14 +1499,12 @@ EXPORT void LayoutToolBar( void * data )
}
}
-
-static void ToolbarChange( long changes )
-{
- if ( (changes&CHANGE_TOOLBAR) ) {
+static void ToolbarChange(long changes) {
+ if ((changes & CHANGE_TOOLBAR)) {
/*if ( !(changes&CHANGE_MAIN) )*/
- MainProc( mainW, wResize_e, NULL, NULL );
+ MainProc( mainW, wResize_e, NULL, NULL );
/*else
- LayoutToolBar();*/
+ LayoutToolBar();*/
}
}
@@ -1355,26 +1514,15 @@ static void ToolbarChange( long changes )
*
*/
-
-EXPORT BOOL_T CommandEnabled(
- wIndex_t cmdInx )
-{
+EXPORT BOOL_T CommandEnabled(wIndex_t cmdInx) {
return commandList[cmdInx].enabled;
}
-
-static wIndex_t AddCommand(
- procCommand_t cmdProc,
- char * helpKey,
- char * nameStr,
- wIcon_p icon,
- int reqLevel,
- long options,
- long acclKey,
- void * context )
-{
- if (commandCnt >= COMMAND_MAX-1) {
- AbortProg("addCommand: too many commands" );
+static wIndex_t AddCommand(procCommand_t cmdProc, char * helpKey,
+ char * nameStr, wIcon_p icon, int reqLevel, long options, long acclKey,
+ void * context) {
+ if (commandCnt >= COMMAND_MAX - 1) {
+ AbortProg("addCommand: too many commands");
}
commandList[commandCnt].labelStr = MyStrdup(nameStr);
commandList[commandCnt].helpKey = MyStrdup(helpKey);
@@ -1391,15 +1539,12 @@ static wIndex_t AddCommand(
commandList[commandCnt].menu[2] = NULL;
commandList[commandCnt].menu[3] = NULL;
commandCnt++;
- return commandCnt-1;
+ return commandCnt - 1;
}
-EXPORT void AddToolbarControl(
- wControl_p control,
- long options )
-{
- if (buttonCnt >= COMMAND_MAX-1) {
- AbortProg("addToolbarControl: too many buttons" );
+EXPORT void AddToolbarControl(wControl_p control, long options) {
+ if (buttonCnt >= COMMAND_MAX - 1) {
+ AbortProg("addToolbarControl: too many buttons");
}
buttonList[buttonCnt].enabled = TRUE;
buttonList[buttonCnt].options = options;
@@ -1408,98 +1553,77 @@ EXPORT void AddToolbarControl(
buttonList[buttonCnt].y = 0;
buttonList[buttonCnt].control = control;
buttonList[buttonCnt].cmdInx = -1;
- LayoutSetPos( buttonCnt );
+ LayoutSetPos(buttonCnt);
buttonCnt++;
}
-
-EXPORT wButton_p AddToolbarButton(
- char * helpStr,
- wIcon_p icon,
- long options,
- wButtonCallBack_p action,
- void * context )
-{
+EXPORT wButton_p AddToolbarButton(char * helpStr, wIcon_p icon, long options,
+ wButtonCallBack_p action, void * context) {
wButton_p bb;
wIndex_t inx;
GetBalloonHelpStr(helpStr);
- if ( context == NULL ) {
- for ( inx=0; inx<menuPG.paramCnt; inx++ ) {
- if ( action != DoCommandB && menuPLs[inx].valueP == (void*)action ) {
+ if (context == NULL) {
+ for (inx = 0; inx < menuPG.paramCnt; inx++) {
+ if (action != DoCommandB && menuPLs[inx].valueP == (void*) action) {
context = &menuPLs[inx];
action = ParamMenuPush;
- menuPLs[inx].context = (void*)(intptr_t)buttonCnt;
+ menuPLs[inx].context = (void*) (intptr_t) buttonCnt;
menuPLs[inx].option |= IC_PLAYBACK_PUSH;
break;
}
}
}
- bb = wButtonCreate( mainW, 0, 0, helpStr, (char*)icon,
- BO_ICON/*|((options&IC_CANCEL)?BB_CANCEL:0)*/, 0,
- action, context );
- AddToolbarControl( (wControl_p)bb, options );
+ bb = wButtonCreate(mainW, 0, 0, helpStr, (char*) icon,
+ BO_ICON/*|((options&IC_CANCEL)?BB_CANCEL:0)*/, 0, action, context);
+ AddToolbarControl((wControl_p) bb, options);
return bb;
}
-
-EXPORT void PlaybackButtonMouse(
- wIndex_t buttInx )
-{
+EXPORT void PlaybackButtonMouse(wIndex_t buttInx) {
wPos_t cmdX, cmdY;
- if ( buttInx < 0 || buttInx >= buttonCnt ) return;
- if ( buttonList[buttInx].control == NULL ) return;
- cmdX = buttonList[buttInx].x+17;
- cmdY = toolbarHeight - (buttonList[buttInx].y+17) +
- (wPos_t)(mainD.size.y/mainD.scale*mainD.dpi) + 30;
- MovePlaybackCursor( &mainD, cmdX, cmdY );
- if ( playbackTimer == 0 ) {
- wButtonSetBusy( (wButton_p)buttonList[buttInx].control, TRUE );
+ if (buttInx < 0 || buttInx >= buttonCnt)
+ return;
+ if (buttonList[buttInx].control == NULL)
+ return;
+ cmdX = buttonList[buttInx].x + 17;
+ cmdY = toolbarHeight - (buttonList[buttInx].y + 17)
+ + (wPos_t) (mainD.size.y / mainD.scale * mainD.dpi) + 30;
+
+ MovePlaybackCursor(&mainD, cmdX, cmdY,TRUE,buttonList[buttInx].control);
+ if (playbackTimer == 0) {
+ wButtonSetBusy((wButton_p) buttonList[buttInx].control, TRUE);
wFlush();
- wPause( 500 );
- wButtonSetBusy( (wButton_p)buttonList[buttInx].control, FALSE );
+ wPause(500);
+ wButtonSetBusy((wButton_p) buttonList[buttInx].control, FALSE);
wFlush();
}
}
-
#include "bitmaps/openbutt.xpm"
static char * buttonGroupMenuTitle;
static char * buttonGroupHelpKey;
static char * buttonGroupStickyLabel;
static wMenu_p buttonGroupPopupM;
-EXPORT void ButtonGroupBegin(
- char * menuTitle,
- char * helpKey,
- char * stickyLabel )
-{
+EXPORT void ButtonGroupBegin(char * menuTitle, char * helpKey,
+ char * stickyLabel) {
buttonGroupMenuTitle = menuTitle;
buttonGroupHelpKey = helpKey;
buttonGroupStickyLabel = stickyLabel;
buttonGroupPopupM = NULL;
}
-EXPORT void ButtonGroupEnd( void )
-{
+EXPORT void ButtonGroupEnd(void) {
buttonGroupMenuTitle = NULL;
buttonGroupHelpKey = NULL;
buttonGroupPopupM = NULL;
}
-
-EXPORT wIndex_t AddMenuButton(
- wMenu_p menu,
- procCommand_t command,
- char * helpKey,
- char * nameStr,
- wIcon_p icon,
- int reqLevel,
- long options,
- long acclKey,
- void * context )
-{
+EXPORT wIndex_t AddMenuButton(wMenu_p menu, procCommand_t command,
+ char * helpKey, char * nameStr, wIcon_p icon, int reqLevel,
+ long options, long acclKey, void * context) {
wIndex_t buttInx = -1;
wIndex_t cmdInx;
BOOL_T newButtonGroup = FALSE;
@@ -1509,225 +1633,223 @@ EXPORT wIndex_t AddMenuButton(
static wMenu_p popup1Submenu;
static wMenu_p popup2Submenu;
- if ( icon ) {
- if ( buttonGroupPopupM!=NULL ) {
- buttInx = buttonCnt-2;
+ if (icon) {
+ if (buttonGroupPopupM != NULL) {
+ buttInx = buttonCnt - 2;
} else {
buttInx = buttonCnt;
- AddToolbarButton( helpKey, icon, options, (wButtonCallBack_p)DoCommandB, (void*)(intptr_t)commandCnt );
+ AddToolbarButton(helpKey, icon, options,
+ (wButtonCallBack_p) DoCommandB,
+ (void*) (intptr_t) commandCnt);
buttonList[buttInx].cmdInx = commandCnt;
}
- if ( buttonGroupMenuTitle!=NULL && buttonGroupPopupM==NULL ) {
- if ( openbuttIcon == NULL )
+ if (buttonGroupMenuTitle != NULL && buttonGroupPopupM == NULL) {
+ if (openbuttIcon == NULL)
openbuttIcon = wIconCreatePixMap(openbutt_xpm);
- buttonGroupPopupM = wMenuPopupCreate( mainW, buttonGroupMenuTitle );
- AddToolbarButton( buttonGroupHelpKey, openbuttIcon, IC_ABUT, (wButtonCallBack_p)wMenuPopupShow, (void*)buttonGroupPopupM );
+ buttonGroupPopupM = wMenuPopupCreate(mainW, buttonGroupMenuTitle);
+ AddToolbarButton(buttonGroupHelpKey, openbuttIcon, IC_ABUT,
+ (wButtonCallBack_p) wMenuPopupShow,
+ (void*) buttonGroupPopupM);
newButtonGroup = TRUE;
- commandsSubmenu = wMenuMenuCreate( menu, "", buttonGroupMenuTitle );
- popup1Submenu = wMenuMenuCreate( ((options&IC_POPUP2)?popup1aM:popup1M), "", buttonGroupMenuTitle );
- popup2Submenu = wMenuMenuCreate( ((options&IC_POPUP2)?popup2aM:popup2M), "", buttonGroupMenuTitle );
+ commandsSubmenu = wMenuMenuCreate(menu, "", buttonGroupMenuTitle);
+ if (options & IC_POPUP2) {
+ popup1Submenu = wMenuMenuCreate(popup1aM, "", buttonGroupMenuTitle);
+ popup2Submenu = wMenuMenuCreate(popup2aM, "", buttonGroupMenuTitle);
+ } else if (options & IC_POPUP3) {
+ popup1Submenu= wMenuMenuCreate(popup1mM, "", buttonGroupMenuTitle);
+ popup2Submenu = wMenuMenuCreate(popup2mM, "", buttonGroupMenuTitle);
+
+ } else {
+ popup1Submenu = wMenuMenuCreate(popup1M, "", buttonGroupMenuTitle);
+ popup2Submenu = wMenuMenuCreate(popup2M, "", buttonGroupMenuTitle);
+ }
}
}
- cmdInx = AddCommand( command, helpKey, nameStr, icon, reqLevel, options, acclKey, context );
+ cmdInx = AddCommand(command, helpKey, nameStr, icon, reqLevel, options,
+ acclKey, context);
commandList[cmdInx].buttInx = buttInx;
if (nameStr[0] == '\0')
return cmdInx;
- if (commandList[cmdInx].options&IC_STICKY) {
- if ( buttonGroupPopupM==NULL || newButtonGroup ) {
- if ( stickyCnt > 32 )
- AbortProg( "stickyCnt>32" );
+ if (commandList[cmdInx].options & IC_STICKY) {
+ if (buttonGroupPopupM == NULL || newButtonGroup) {
+ if (stickyCnt > 32)
+ AbortProg("stickyCnt>32");
stickyCnt++;
}
- if ( buttonGroupPopupM==NULL) {
- stickyLabels[stickyCnt-1] = nameStr;
+ if (buttonGroupPopupM == NULL) {
+ stickyLabels[stickyCnt - 1] = nameStr;
} else {
- stickyLabels[stickyCnt-1] = buttonGroupStickyLabel;
+ stickyLabels[stickyCnt - 1] = buttonGroupStickyLabel;
}
stickyLabels[stickyCnt] = NULL;
- commandList[cmdInx].stickyMask = 1L<<(stickyCnt-1);
+ long stickyMask = 1L<<(stickyCnt-1);
+ commandList[cmdInx].stickyMask = stickyMask;
+ if ( ( commandList[cmdInx].options & IC_INITNOTSTICKY ) == 0 )
+ stickySet |= stickyMask;
}
- if ( buttonGroupPopupM ) {
- commandList[cmdInx].menu[0] =
- wMenuPushCreate( buttonGroupPopupM, helpKey, GetBalloonHelpStr(helpKey), 0, DoCommandB, (void*)(intptr_t)cmdInx );
+ if (buttonGroupPopupM) {
+ commandList[cmdInx].menu[0] = wMenuPushCreate(buttonGroupPopupM,
+ helpKey, GetBalloonHelpStr(helpKey), 0, DoCommandB,
+ (void*) (intptr_t) cmdInx);
tm = commandsSubmenu;
p1m = popup1Submenu;
p2m = popup2Submenu;
} else {
tm = menu;
- p1m = (options&IC_POPUP2)?popup1aM:popup1M;
- p2m = (options&IC_POPUP2)?popup2aM:popup2M;
- }
- commandList[cmdInx].menu[1] =
- wMenuPushCreate( tm, helpKey, nameStr, acclKey, DoCommandB, (void*)(intptr_t)cmdInx );
- if ( (options & (IC_POPUP|IC_POPUP2)) ) {
- if ( !(options & IC_SELECTED) ) {
- commandList[cmdInx].menu[2] =
- wMenuPushCreate( p1m, helpKey, nameStr, 0, DoCommandB, (void*)(intptr_t)cmdInx );
+ p1m = (options & IC_POPUP2) ? popup1aM : (options & IC_POPUP3) ? popup1mM : popup1M;
+ p2m = (options & IC_POPUP2) ? popup2aM : (options & IC_POPUP3) ? popup2mM : popup2M;
+ }
+ commandList[cmdInx].menu[1] = wMenuPushCreate(tm, helpKey, nameStr, acclKey,
+ DoCommandB, (void*) (intptr_t) cmdInx);
+ if ((options & (IC_POPUP | IC_POPUP2 | IC_POPUP3))) {
+ if (!(options & IC_SELECTED)) {
+ commandList[cmdInx].menu[2] = wMenuPushCreate(p1m, helpKey, nameStr,
+ 0, DoCommandB, (void*) (intptr_t) cmdInx);
}
- commandList[cmdInx].menu[3] =
- wMenuPushCreate( p2m, helpKey, nameStr, 0, DoCommandB, (void*)(intptr_t)cmdInx );
+ commandList[cmdInx].menu[3] = wMenuPushCreate(p2m, helpKey, nameStr, 0,
+ DoCommandB, (void*) (intptr_t) cmdInx);
}
return cmdInx;
}
-
-EXPORT wIndex_t InitCommand(
- wMenu_p menu,
- procCommand_t command,
- char * nameStr,
- char * bits,
- int reqLevel,
- long options,
- long acclKey )
-{
+EXPORT wIndex_t InitCommand(wMenu_p menu, procCommand_t command, char * nameStr,
+ char * bits, int reqLevel, long options, long acclKey) {
char helpKey[STR_SHORT_SIZE];
wIcon_p icon = NULL;
if (bits)
- icon = wIconCreateBitMap( 16, 16, bits, wDrawColorBlack );
- strcpy( helpKey, "cmd" );
- strcat( helpKey, nameStr );
- return AddMenuButton( menu, command, helpKey, _(nameStr), icon, reqLevel, options, acclKey, NULL );
+ icon = wIconCreateBitMap(16, 16, bits, wDrawColorBlack);
+ strcpy(helpKey, "cmd");
+ strcat(helpKey, nameStr);
+ return AddMenuButton(menu, command, helpKey, _(nameStr), icon, reqLevel,
+ options, acclKey, NULL);
}
/*--------------------------------------------------------------------*/
-EXPORT void PlaybackCommand(
- char * line,
- wIndex_t lineNum )
-{
+EXPORT void PlaybackCommand(char * line, wIndex_t lineNum) {
wIndex_t inx;
wIndex_t buttInx;
int len1, len2;
- len1 = strlen(line+8);
- for (inx=0;inx<commandCnt;inx++) {
- len2 = strlen(commandList[inx].helpKey+3);
- if (len1 == len2 && strncmp( line+8, commandList[inx].helpKey+3, len2 ) == 0) {
+ len1 = strlen(line + 8);
+ for (inx = 0; inx < commandCnt; inx++) {
+ len2 = strlen(commandList[inx].helpKey + 3);
+ if (len1 == len2
+ && strncmp(line + 8, commandList[inx].helpKey + 3, len2) == 0) {
break;
}
}
if (inx >= commandCnt) {
- fprintf(stderr, "Unknown playback COMMAND command %d : %s\n",
- lineNum, line );
+ fprintf(stderr, "Unknown playback COMMAND command %d : %s\n", lineNum,
+ line);
} else {
wPos_t cmdX, cmdY;
- if ((buttInx=commandList[inx].buttInx)>=0) {
- cmdX = buttonList[buttInx].x+17;
- cmdY = toolbarHeight - (buttonList[buttInx].y+17) +
- (wPos_t)(mainD.size.y/mainD.scale*mainD.dpi) + 30;
- MovePlaybackCursor( &mainD, cmdX, cmdY );
+ if ((buttInx = commandList[inx].buttInx) >= 0) {
+ cmdX = buttonList[buttInx].x + 17;
+ cmdY = toolbarHeight - (buttonList[buttInx].y + 17)
+ + (wPos_t) (mainD.size.y / mainD.scale * mainD.dpi) + 30;
+ MovePlaybackCursor(&mainD, cmdX, cmdY,TRUE,buttonList[buttInx].control);
}
- if (strcmp( line+8, "Undo") == 0) {
- if (buttInx>0 && playbackTimer == 0) {
- wButtonSetBusy( (wButton_p)buttonList[buttInx].control, TRUE );
+ if (strcmp(line + 8, "Undo") == 0) {
+ if (buttInx > 0 && playbackTimer == 0) {
+ wButtonSetBusy((wButton_p) buttonList[buttInx].control, TRUE);
wFlush();
- wPause( 500 );
- wButtonSetBusy( (wButton_p)buttonList[buttInx].control, FALSE );
+ wPause(500);
+ wButtonSetBusy((wButton_p) buttonList[buttInx].control, FALSE);
wFlush();
}
UndoUndo();
- } else if (strcmp( line+8, "Redo") == 0) {
- if (buttInx>=0 && playbackTimer == 0) {
- wButtonSetBusy( (wButton_p)buttonList[buttInx].control, TRUE );
+ } else if (strcmp(line + 8, "Redo") == 0) {
+ if (buttInx >= 0 && playbackTimer == 0) {
+ wButtonSetBusy((wButton_p) buttonList[buttInx].control, TRUE);
wFlush();
- wPause( 500 );
- wButtonSetBusy( (wButton_p)buttonList[buttInx].control, FALSE );
+ wPause(500);
+ wButtonSetBusy((wButton_p) buttonList[buttInx].control, FALSE);
wFlush();
}
UndoRedo();
} else {
- if ( buttInx>=0 &&
- playbackTimer == 0 ) {
- wButtonSetBusy( (wButton_p)buttonList[buttInx].control, TRUE );
+ if (buttInx >= 0 && playbackTimer == 0) {
+ wButtonSetBusy((wButton_p) buttonList[buttInx].control, TRUE);
wFlush();
- wPause( 500 );
- wButtonSetBusy( (wButton_p)buttonList[buttInx].control, FALSE );
+ wPause(500);
+ wButtonSetBusy((wButton_p) buttonList[buttInx].control, FALSE);
wFlush();
}
- DoCommandB( (void*)(intptr_t)inx );
+ DoCommandB((void*) (intptr_t) inx);
}
}
}
-
/*--------------------------------------------------------------------*/
typedef struct {
- char * label;
- wMenu_p menu;
- } menuTrace_t, *menuTrace_p;
+ char * label;
+ wMenu_p menu;
+} menuTrace_t, *menuTrace_p;
static dynArr_t menuTrace_da;
#define menuTrace(N) DYNARR_N( menuTrace_t, menuTrace_da, N )
-
-static void DoMenuTrace(
- wMenu_p menu,
- const char * label,
- void * data )
-{
+static void DoMenuTrace(wMenu_p menu, const char * label, void * data) {
/*printf( "MENUTRACE: %s/%s\n", (char*)data, label );*/
if (recordF) {
- fprintf( recordF, "MOUSE 1 %0.3f %0.3f\n", oldMarker.x, oldMarker.y );
- fprintf( recordF, "MENU %0.3f %0.3f \"%s\" \"%s\"\n", oldMarker.x, oldMarker.y, (char*)data, label );
+ fprintf(recordF, "MOUSE 1 %0.3f %0.3f\n", oldMarker.x, oldMarker.y);
+ fprintf(recordF, "MENU %0.3f %0.3f \"%s\" \"%s\"\n", oldMarker.x,
+ oldMarker.y, (char*) data, label);
}
}
-
-EXPORT wMenu_p MenuRegister( char * label )
-{
+EXPORT wMenu_p MenuRegister(char * label) {
wMenu_p m;
menuTrace_p mt;
- m = wMenuPopupCreate( mainW, label );
- DYNARR_APPEND( menuTrace_t, menuTrace_da, 10 );
- mt = &menuTrace( menuTrace_da.cnt-1 );
+ m = wMenuPopupCreate(mainW, label);
+ DYNARR_APPEND(menuTrace_t, menuTrace_da, 10);
+ mt = &menuTrace(menuTrace_da.cnt - 1);
mt->label = strdup(label);
mt->menu = m;
- wMenuSetTraceCallBack( m, DoMenuTrace, mt->label );
+ wMenuSetTraceCallBack(m, DoMenuTrace, mt->label);
return m;
}
-
-void MenuPlayback( char * line )
-{
- char * menuName, * itemName;
+void MenuPlayback(char * line) {
+ char * menuName, *itemName;
coOrd pos;
wPos_t x, y;
menuTrace_p mt;
- if (!GetArgs( line, "pqq", &pos, &menuName, &itemName ))
+ if (!GetArgs(line, "pqq", &pos, &menuName, &itemName))
return;
- for ( mt=&menuTrace(0); mt<&menuTrace(menuTrace_da.cnt); mt++ ) {
- if ( strcmp( mt->label, menuName ) == 0 ) {
- mainD.CoOrd2Pix( &mainD, pos, &x, &y );
- MovePlaybackCursor( &mainD, x, y );
+ for (mt = &menuTrace(0); mt < &menuTrace(menuTrace_da.cnt); mt++) {
+ if (strcmp(mt->label, menuName) == 0) {
+ mainD.CoOrd2Pix(&mainD, pos, &x, &y);
+ MovePlaybackCursor(&mainD, x, y, FALSE, NULL);
oldMarker = cmdMenuPos = pos;
- wMenuAction( mt->menu, _(itemName) );
+ wMenuAction(mt->menu, _(itemName));
return;
}
}
- AbortProg( "menuPlayback: %s not found", menuName );
+ AbortProg("menuPlayback: %s not found", menuName);
}
/*--------------------------------------------------------------------*/
-
static wWin_p stickyW;
-static void StickyOk( void * );
-static paramData_t stickyPLs[] = {
- { PD_TOGGLE, &stickySet, "set", 0, stickyLabels } };
-static paramGroup_t stickyPG = { "sticky", PGO_RECORD, stickyPLs, sizeof stickyPLs/sizeof stickyPLs[0] };
-
+static void StickyOk(void *);
+static paramData_t stickyPLs[] = { { PD_TOGGLE, &stickySet, "set", 0,
+ stickyLabels } };
+static paramGroup_t stickyPG = { "sticky", PGO_RECORD, stickyPLs,
+ sizeof stickyPLs / sizeof stickyPLs[0] };
-static void StickyOk( void * junk )
-{
- wHide( stickyW );
+static void StickyOk(void * junk) {
+ wHide(stickyW);
}
-static void DoSticky( void )
-{
- if ( !stickyW )
- stickyW = ParamCreateDialog( &stickyPG, MakeWindowTitle(_("Sticky Commands")), _("Ok"), StickyOk, NULL, TRUE, NULL, 0, NULL );
- ParamLoadControls( &stickyPG );
- wShow( stickyW );
+static void DoSticky(void) {
+ if (!stickyW)
+ stickyW = ParamCreateDialog(&stickyPG,
+ MakeWindowTitle(_("Sticky Commands")), _("Ok"), StickyOk, wHide,
+ TRUE, NULL, 0, NULL);
+ ParamLoadControls(&stickyPG);
+ wShow(stickyW);
}
/*--------------------------------------------------------------------*/
@@ -1737,43 +1859,21 @@ static void DoSticky( void )
* specified in the following array.
* Note: text and choices must be given in the same order.
*/
-static char *AllToolbarLabels[] = {
- N_("File Buttons"),
- N_("Zoom Buttons"),
- N_("Undo Buttons"),
- N_("Easement Button"),
- N_("SnapGrid Buttons"),
- N_("Create Track Buttons"),
- N_("Layout Control Elements"),
- N_("Modify Track Buttons"),
- N_("Properties/Select"),
- N_("Track Group Buttons"),
- N_("Train Group Buttons"),
- N_("Create Misc Buttons"),
- N_("Ruler Button"),
- N_("Layer Buttons"),
- N_("Hot Bar"),
- NULL };
-static long AllToolbarMasks[] = {
- 1<<BG_FILE,
- 1<<BG_ZOOM,
- 1<<BG_UNDO,
- 1<<BG_EASE,
- 1<<BG_SNAP,
- 1<<BG_TRKCRT,
- 1<<BG_CONTROL,
- 1<<BG_TRKMOD,
- 1<<BG_SELECT,
- 1<<BG_TRKGRP,
- 1<<BG_TRAIN,
- 1<<BG_MISCCRT,
- 1<<BG_RULER,
- 1<<BG_LAYER,
- 1<<BG_HOTBAR};
-
-static void ToolbarAction( wBool_t set, void * data )
-{
- long mask = (long)data;
+static char *AllToolbarLabels[] = { N_("File Buttons"), N_("Import/Export Buttons"), N_("Zoom Buttons"), N_(
+ "Undo Buttons"), N_("Easement Button"), N_("SnapGrid Buttons"), N_(
+ "Create Track Buttons"), N_("Layout Control Elements"), N_(
+ "Modify Track Buttons"), N_("Properties/Select"), N_(
+ "Track Group Buttons"), N_("Train Group Buttons"), N_(
+ "Create Misc Buttons"), N_("Ruler Button"), N_("Layer Buttons"), N_(
+ "Hot Bar"),
+NULL };
+static long AllToolbarMasks[] = { 1 << BG_FILE, 1<< BG_EXPORTIMPORT, 1 << BG_ZOOM, 1 << BG_UNDO, 1
+ << BG_EASE, 1 << BG_SNAP, 1 << BG_TRKCRT, 1 << BG_CONTROL, 1
+ << BG_TRKMOD, 1 << BG_SELECT, 1 << BG_TRKGRP, 1 << BG_TRAIN, 1
+ << BG_MISCCRT, 1 << BG_RULER, 1 << BG_LAYER, 1 << BG_HOTBAR };
+
+static void ToolbarAction(wBool_t set, void * data) {
+ long mask = (long) data;
if (set)
toolbarSet |= mask;
else
@@ -1781,7 +1881,8 @@ static void ToolbarAction( wBool_t set, void * data )
wPrefSetInteger( "misc", "toolbarset", toolbarSet );
MainProc( mainW, wResize_e, NULL, NULL );
if (recordF)
- fprintf( recordF, "PARAMETER %s %s %ld", "misc", "toolbarset", toolbarSet );
+ fprintf(recordF, "PARAMETER %s %s %ld", "misc", "toolbarset",
+ toolbarSet);
}
/**
@@ -1791,19 +1892,19 @@ static void ToolbarAction( wBool_t set, void * data )
* \param toolbarM IN menu to which the toogles will be added
*/
-static void CreateToolbarM( wMenu_p toolbarM )
-{
+static void CreateToolbarM(wMenu_p toolbarM) {
int inx, cnt;
long *masks;
char **labels;
wBool_t set;
- cnt = sizeof(AllToolbarMasks)/sizeof(AllToolbarMasks[0]);
+ cnt = sizeof(AllToolbarMasks) / sizeof(AllToolbarMasks[0]);
masks = AllToolbarMasks;
labels = AllToolbarLabels;
- for (inx=0; inx<cnt; inx++,masks++,labels++) {
- set = ( toolbarSet & *masks ) != 0;
- wMenuToggleCreate( toolbarM, "toolbarM", _(*labels), 0, set, ToolbarAction, (void*)*masks );
+ for (inx = 0; inx < cnt; inx++, masks++, labels++) {
+ set = (toolbarSet & *masks) != 0;
+ wMenuToggleCreate(toolbarM, "toolbarM", _(*labels), 0, set,
+ ToolbarAction, (void*) *masks);
}
}
@@ -1812,157 +1913,148 @@ static void CreateToolbarM( wMenu_p toolbarM )
static wWin_p addElevW;
#define addElevF (wFloat_p)addElevPD.control
EXPORT DIST_T addElevValueV;
-static void DoAddElev( void * );
+static void DoAddElev(void *);
static paramFloatRange_t rn1000_1000 = { -1000.0, 1000.0 };
-static paramData_t addElevPLs[] = {
- { PD_FLOAT, &addElevValueV, "value", PDO_DIM, &rn1000_1000, NULL, 0 } };
-static paramGroup_t addElevPG = { "addElev", 0, addElevPLs, sizeof addElevPLs/sizeof addElevPLs[0] };
-
+static paramData_t addElevPLs[] = { { PD_FLOAT, &addElevValueV, "value",
+ PDO_DIM, &rn1000_1000, NULL, 0 } };
+static paramGroup_t addElevPG = { "addElev", 0, addElevPLs, sizeof addElevPLs
+ / sizeof addElevPLs[0] };
-static void DoAddElev( void * junk )
-{
- ParamLoadData( &addElevPG );
- AddElevations( addElevValueV );
- wHide( addElevW );
+static void DoAddElev(void * junk) {
+ ParamLoadData(&addElevPG);
+ AddElevations(addElevValueV);
+ wHide(addElevW);
}
-
-static void ShowAddElevations( void )
-{
- if ( selectedTrackCount <= 0 ) {
- ErrorMessage( MSG_NO_SELECTED_TRK );
+static void ShowAddElevations(void) {
+ if (selectedTrackCount <= 0) {
+ ErrorMessage(MSG_NO_SELECTED_TRK);
return;
}
if (addElevW == NULL)
- addElevW = ParamCreateDialog( &addElevPG, MakeWindowTitle(_("Change Elevations")), _("Change"), DoAddElev, wHide, FALSE, NULL, 0, NULL );
- wShow( addElevW );
+ addElevW = ParamCreateDialog(&addElevPG,
+ MakeWindowTitle(_("Change Elevations")), _("Change"), DoAddElev,
+ wHide, FALSE, NULL, 0, NULL);
+ wShow(addElevW);
}
/*--------------------------------------------------------------------*/
static wWin_p rotateW;
static wWin_p moveW;
-static long rotateValue;
+static double rotateValue;
static coOrd moveValue;
static rotateDialogCallBack_t rotateDialogCallBack;
static moveDialogCallBack_t moveDialogCallBack;
-static void RotateEnterOk( void * );
-
-static paramIntegerRange_t rn360_360 = { -360, 360, 80 };
-static paramData_t rotatePLs[] = {
- { PD_LONG, &rotateValue, "rotate", PDO_ANGLE, &rn360_360, N_("Angle:") } };
-static paramGroup_t rotatePG = { "rotate", 0, rotatePLs, sizeof rotatePLs/sizeof rotatePLs[0] };
-
-static paramFloatRange_t r_1000_1000 = { -1000.0, 1000.0, 80 };
-static void MoveEnterOk( void * );
-static paramData_t movePLs[] = {
- { PD_FLOAT, &moveValue.x, "moveX", PDO_DIM, &r_1000_1000, N_("Move X:") },
- { PD_FLOAT, &moveValue.y, "moveY", PDO_DIM, &r_1000_1000, N_("Move Y:") } };
-static paramGroup_t movePG = { "move", 0, movePLs, sizeof movePLs/sizeof movePLs[0] };
-
-
-EXPORT void StartRotateDialog( rotateDialogCallBack_t func )
-{
- if ( rotateW == NULL )
- rotateW = ParamCreateDialog( &rotatePG, MakeWindowTitle(_("Rotate")), _("Ok"), RotateEnterOk, wHide, FALSE, NULL, 0, NULL );
- ParamLoadControls( &rotatePG );
+static void RotateEnterOk(void *);
+
+static paramFloatRange_t rn360_360 = { -360.0, 360.0, 80.0 };
+static paramData_t rotatePLs[] = { { PD_FLOAT, &rotateValue, "rotate", PDO_ANGLE,
+ &rn360_360, N_("Angle:") } };
+static paramGroup_t rotatePG = { "rotate", 0, rotatePLs, sizeof rotatePLs
+ / sizeof rotatePLs[0] };
+
+static paramFloatRange_t r_1000_1000 = { -1000.0, 1000.0, 80 };
+static void MoveEnterOk(void *);
+static paramData_t movePLs[] = { { PD_FLOAT, &moveValue.x, "moveX", PDO_DIM,
+ &r_1000_1000, N_("Move X:") }, { PD_FLOAT, &moveValue.y, "moveY",
+ PDO_DIM, &r_1000_1000, N_("Move Y:") } };
+static paramGroup_t movePG = { "move", 0, movePLs, sizeof movePLs
+ / sizeof movePLs[0] };
+
+EXPORT void StartRotateDialog(rotateDialogCallBack_t func) {
+ if (rotateW == NULL)
+ rotateW = ParamCreateDialog(&rotatePG, MakeWindowTitle(_("Rotate")),
+ _("Ok"), RotateEnterOk, wHide, FALSE, NULL, 0, NULL);
+ ParamLoadControls(&rotatePG);
rotateDialogCallBack = func;
- wShow( rotateW );
+ wShow(rotateW);
}
-EXPORT void StartMoveDialog( moveDialogCallBack_t func )
-{
- if ( moveW == NULL )
- moveW = ParamCreateDialog( &movePG, MakeWindowTitle(_("Move")), _("Ok"), MoveEnterOk, wHide, FALSE, NULL, 0, NULL );
- ParamLoadControls( &movePG );
+EXPORT void StartMoveDialog(moveDialogCallBack_t func) {
+ if (moveW == NULL)
+ moveW = ParamCreateDialog(&movePG, MakeWindowTitle(_("Move")), _("Ok"),
+ MoveEnterOk, wHide, FALSE, NULL, 0, NULL);
+ ParamLoadControls(&movePG);
moveDialogCallBack = func;
moveValue = zero;
- wShow( moveW );
+ wShow(moveW);
}
-static void MoveEnterOk( void * junk )
-{
- ParamLoadData( &movePG );
- moveDialogCallBack( (void*) &moveValue );
- wHide( moveW );
+static void MoveEnterOk(void * junk) {
+ ParamLoadData(&movePG);
+ moveDialogCallBack((void*) &moveValue);
+ wHide(moveW);
}
-static void RotateEnterOk( void * junk )
-{
- ParamLoadData( &rotatePG );
- if (angleSystem==ANGLE_POLAR)
- rotateDialogCallBack( (void*)rotateValue );
+static void RotateEnterOk(void * junk) {
+ ParamLoadData(&rotatePG);
+ if (angleSystem == ANGLE_POLAR)
+ rotateDialogCallBack((void*) (long)(rotateValue*1000));
else
- rotateDialogCallBack( (void*)-rotateValue );
- wHide( rotateW );
+ rotateDialogCallBack((void*) (long)(-rotateValue*1000));
+ wHide(rotateW);
}
-
-static void RotateDialogInit( void )
-{
- ParamRegister( &rotatePG );
+static void RotateDialogInit(void) {
+ ParamRegister(&rotatePG);
}
-static void MoveDialogInit (void)
-{
- ParamRegister( &movePG );
+static void MoveDialogInit(void) {
+ ParamRegister(&movePG);
}
-
-EXPORT void AddMoveMenu(
- wMenu_p m,
- moveDialogCallBack_t func ) {
- wMenuPushCreate( m, "", _("Enter Move ..."), 0, (wMenuCallBack_p)StartMoveDialog, (void*)func );
+EXPORT void AddMoveMenu(wMenu_p m, moveDialogCallBack_t func) {
+ wMenuPushCreate(m, "", _("Enter Move ..."), 0,
+ (wMenuCallBack_p) StartMoveDialog, (void*) func);
}
-EXPORT void AddRotateMenu(
- wMenu_p m,
- rotateDialogCallBack_t func )
-{
- wMenuPushCreate( m, "", _("180 "), 0, func, (void*)180 );
- wMenuPushCreate( m, "", _("90 CW"), 0, func, (void*)(long)(90) );
- wMenuPushCreate( m, "", _("45 CW"), 0, func, (void*)(long)(45) );
- wMenuPushCreate( m, "", _("30 CW"), 0, func, (void*)(long)(30) );
- wMenuPushCreate( m, "", _("15 CW"), 0, func, (void*)(long)(15) );
- wMenuPushCreate( m, "", _("15 CCW"), 0, func, (void*)(long)(360-15) );
- wMenuPushCreate( m, "", _("30 CCW"), 0, func, (void*)(long)(360-30) );
- wMenuPushCreate( m, "", _("45 CCW"), 0, func, (void*)(long)(360-45) );
- wMenuPushCreate( m, "", _("90 CCW"), 0, func, (void*)(long)(360-90) );
- wMenuPushCreate( m, "", _("Enter Angle ..."), 0, (wMenuCallBack_p)StartRotateDialog, (void*)func );
+//All values multipled by 100 to support decimal points from PD_FLOAT
+EXPORT void AddRotateMenu(wMenu_p m, rotateDialogCallBack_t func) {
+ wMenuPushCreate(m, "", _("180 "), 0, func, (void*) 180000);
+ wMenuPushCreate(m, "", _("90 CW"), 0, func, (void*) (long) (90000));
+ wMenuPushCreate(m, "", _("45 CW"), 0, func, (void*) (long) (45000));
+ wMenuPushCreate(m, "", _("30 CW"), 0, func, (void*) (long) (30000));
+ wMenuPushCreate(m, "", _("15 CW"), 0, func, (void*) (long) (15000));
+ wMenuPushCreate(m, "", _("15 CCW"), 0, func, (void*) (long) (360000 - 15000));
+ wMenuPushCreate(m, "", _("30 CCW"), 0, func, (void*) (long) (360000 - 30000));
+ wMenuPushCreate(m, "", _("45 CCW"), 0, func, (void*) (long) (360000 - 45000));
+ wMenuPushCreate(m, "", _("90 CCW"), 0, func, (void*) (long) (360000 - 90000));
+ wMenuPushCreate(m, "", _("Enter Angle ..."), 0,
+ (wMenuCallBack_p) StartRotateDialog, (void*) func);
}
-
+
/*****************************************************************************
*
* INITIALIZATON
*
*/
-
static wWin_p debugW;
static int debugCnt = 0;
static paramIntegerRange_t r0_100 = { 0, 100, 80 };
-static void DebugOk( void * junk );
+static void DebugOk(void * junk);
static paramData_t debugPLs[30];
static long debug_values[30];
static int debug_index[30];
+
static paramGroup_t debugPG = { "debug", 0, debugPLs, 0 };
-static void DebugOk( void * junk )
-{
+static void DebugOk(void * junk) {
for (int i = 0; i<debugCnt;i++) {
- logTable(debug_index[i]).level = debug_values[i];
+ logTable(debug_index[i]).level = debug_values[i];
}
- wHide( debugW );
+ wHide(debugW);
}
-static void CreateDebugW( void )
-{
+static void CreateDebugW(void) {
debugPG.paramCnt = debugCnt;
- ParamRegister( &debugPG );
- debugW = ParamCreateDialog( &debugPG, MakeWindowTitle(_("Debug")), _("Ok"), DebugOk, NULL, FALSE, NULL, 0, NULL );
+ ParamRegister(&debugPG);
+ debugW = ParamCreateDialog(&debugPG, MakeWindowTitle(_("Debug")), _("Ok"),
+ DebugOk, wHide, FALSE, NULL, 0, NULL);
wHide(debugW);
}
@@ -1995,108 +2087,77 @@ EXPORT void DebugInit(void) {
wShow(debugW);
}
-EXPORT void InitDebug(
- char * label,
- long * valueP)
-{
- if ( debugCnt >= sizeof debugPLs/sizeof debugPLs[0] )
- AbortProg( "Too many debug flags" );
- memset( &debugPLs[debugCnt], 0, sizeof debugPLs[debugCnt] );
+
+EXPORT void InitDebug(char * label, long * valueP) {
+ if (debugCnt >= sizeof debugPLs / sizeof debugPLs[0])
+ AbortProg("Too many debug flags");
+ memset(&debugPLs[debugCnt], 0, sizeof debugPLs[debugCnt]);
debugPLs[debugCnt].type = PD_LONG;
debugPLs[debugCnt].valueP = valueP;
debugPLs[debugCnt].nameStr = label;
debugPLs[debugCnt].winData = &r0_100;
debugPLs[debugCnt].winLabel = label;
debugCnt++;
-
}
+void RecomputeElevations(void);
-void RecomputeElevations( void );
-
-static void MiscMenuItemCreate(
- wMenu_p m1,
- wMenu_p m2,
- char * name,
- char * label,
- long acclKey,
- void * func,
- long option,
- void * context )
-{
+static void MiscMenuItemCreate(wMenu_p m1, wMenu_p m2, char * name,
+ char * label, long acclKey, void * func, long option, void * context) {
wMenuPush_p mp;
- mp = wMenuPushCreate( m1, name, label, acclKey, ParamMenuPush, &menuPLs[menuPG.paramCnt] );
- if ( m2 )
- wMenuPushCreate( m2, name, label, acclKey, ParamMenuPush, &menuPLs[menuPG.paramCnt] );
- menuPLs[menuPG.paramCnt].control = (wControl_p)mp;
+ mp = wMenuPushCreate(m1, name, label, acclKey, ParamMenuPush,
+ &menuPLs[menuPG.paramCnt]);
+ if (m2)
+ wMenuPushCreate(m2, name, label, acclKey, ParamMenuPush,
+ &menuPLs[menuPG.paramCnt]);
+ menuPLs[menuPG.paramCnt].control = (wControl_p) mp;
menuPLs[menuPG.paramCnt].type = PD_MENUITEM;
menuPLs[menuPG.paramCnt].valueP = func;
menuPLs[menuPG.paramCnt].nameStr = name;
menuPLs[menuPG.paramCnt].option = option;
menuPLs[menuPG.paramCnt].context = context;
- if ( name ) GetBalloonHelpStr( name );
+ if (name)
+ GetBalloonHelpStr(name);
menuPG.paramCnt++;
}
+static char * accelKeyNames[] = { "Del", "Ins", "Home", "End", "Pgup", "Pgdn",
+ "Up", "Down", "Right", "Left", "Back", "F1", "F2", "F3", "F4", "F5",
+ "F6", "F7", "F8", "F9", "F10", "F11", "F12", "NumpadAdd", "NumpadSub" };
-static char * accelKeyNames[] = {
- "Del",
- "Ins",
- "Home",
- "End",
- "Pgup",
- "Pgdn",
- "Up",
- "Down",
- "Right",
- "Left",
- "Back",
- "F1",
- "F2",
- "F3",
- "F4",
- "F5",
- "F6",
- "F7",
- "F8",
- "F9",
- "F10",
- "F11",
- "F12",
- "NumpadAdd",
- "NumpadSub"};
-
-static void SetAccelKey(
- char * prefName,
- wAccelKey_e key,
- int mode,
- wAccelKeyCallBack_p func,
- void * context )
-{
- int mode1 = 0;
- int inx;
- const char * prefValue = wPrefGetString( "accelKey", prefName );
- if ( prefValue != NULL ) {
- while ( prefValue[1] == '-' ) {
- switch ( prefValue[0] ) {
- case 'S': mode1 |= WKEY_SHIFT; break;
- case 'C': mode1 |= WKEY_CTRL; break;
- case 'A': mode1 |= WKEY_ALT; break;
- default:
- ;
- }
- prefValue += 2;
- }
- for ( inx=0; inx<sizeof accelKeyNames/sizeof accelKeyNames[0]; inx++ ) {
- if ( strcmp( prefValue, accelKeyNames[inx] ) == 0 ) {
- key = inx+1;
- mode = mode1;
- break;
- }
- }
- }
- wAttachAccelKey( key, mode, func, context );
+static void SetAccelKey(char * prefName, wAccelKey_e key, int mode,
+ wAccelKeyCallBack_p func, void * context) {
+ int mode1 = 0;
+ int inx;
+ const char * prefValue = wPrefGetString("accelKey", prefName);
+ if (prefValue != NULL) {
+ while (prefValue[1] == '-') {
+ switch (prefValue[0]) {
+ case 'S':
+ mode1 |= WKEY_SHIFT;
+ break;
+ case 'C':
+ mode1 |= WKEY_CTRL;
+ break;
+ case 'A':
+ mode1 |= WKEY_ALT;
+ break;
+ default:
+ ;
+ }
+ prefValue += 2;
+ }
+ for (inx = 0; inx < sizeof accelKeyNames / sizeof accelKeyNames[0];
+ inx++) {
+ if (strcmp(prefValue, accelKeyNames[inx]) == 0) {
+ key = inx + 1;
+ mode = mode1;
+ break;
+ }
+ }
+ }
+ wAttachAccelKey(key, mode, func, context);
}
#include "bitmaps/zoomin.xpm"
@@ -2105,130 +2166,231 @@ static void SetAccelKey(
#include "bitmaps/edit-undo.xpm"
#include "bitmaps/edit-redo.xpm"
#include "bitmaps/partlist.xpm"
-#include "bitmaps/export.xpm"
-#include "bitmaps/import.xpm"
+#include "bitmaps/document-export.xpm"
+#include "bitmaps/document-exportdxf.xpm"
+#include "bitmaps/document-import.xpm"
+#include "bitmaps/document-importmod.xpm"
#include "bitmaps/document-new.xpm"
#include "bitmaps/document-save.xpm"
#include "bitmaps/document-open.xpm"
#include "bitmaps/document-print.xpm"
#include "bitmaps/map.xpm"
+#include "bitmaps/magnet.xpm"
-static void CreateMenus( void )
-{
- wMenu_p fileM, editM, viewM, optionM, windowM, macroM, helpM, toolbarM, messageListM, manageM, addM, changeM, drawM;
+static void CreateMenus(void) {
+ wMenu_p fileM, editM, viewM, optionM, windowM, macroM, helpM, toolbarM,
+ messageListM, manageM, addM, changeM, drawM;
wMenu_p zoomM, zoomSubM;
wMenuPush_p zoomInM, zoomOutM;
- fileM = wMenuBarAdd( mainW, "menuFile", _("&File") );
- editM = wMenuBarAdd( mainW, "menuEdit", _("&Edit") );
- viewM = wMenuBarAdd( mainW, "menuView", _("&View") );
- addM = wMenuBarAdd( mainW, "menuAdd", _("&Add") );
- changeM = wMenuBarAdd( mainW, "menuChange", _("&Change") );
- drawM = wMenuBarAdd( mainW, "menuDraw", _("&Draw") );
- manageM = wMenuBarAdd( mainW, "menuManage", _("&Manage") );
- optionM = wMenuBarAdd( mainW, "menuOption", _("&Options") );
- macroM = wMenuBarAdd( mainW, "menuMacro", _("&Macro") );
- windowM = wMenuBarAdd( mainW, "menuWindow", _("&Window") );
- helpM = wMenuBarAdd( mainW, "menuHelp", _("&Help") );
+ fileM = wMenuBarAdd(mainW, "menuFile", _("&File"));
+ editM = wMenuBarAdd(mainW, "menuEdit", _("&Edit"));
+ viewM = wMenuBarAdd(mainW, "menuView", _("&View"));
+ addM = wMenuBarAdd(mainW, "menuAdd", _("&Add"));
+ changeM = wMenuBarAdd(mainW, "menuChange", _("&Change"));
+ drawM = wMenuBarAdd(mainW, "menuDraw", _("&Draw"));
+ manageM = wMenuBarAdd(mainW, "menuManage", _("&Manage"));
+ optionM = wMenuBarAdd(mainW, "menuOption", _("&Options"));
+ macroM = wMenuBarAdd(mainW, "menuMacro", _("&Macro"));
+ windowM = wMenuBarAdd(mainW, "menuWindow", _("&Window"));
+ helpM = wMenuBarAdd(mainW, "menuHelp", _("&Help"));
/*
* POPUP MENUS
*/
-
- popup1M = wMenuPopupCreate( mainW, _("Commands") );
- popup2M = wMenuPopupCreate( mainW, _("Commands") );
- MiscMenuItemCreate( popup1M, popup2M, "cmdUndo", _("Undo"), 0, (void*)(wMenuCallBack_p)UndoUndo, 0, (void *)0 );
- MiscMenuItemCreate( popup1M, popup2M, "cmdRedo", _("Redo"), 0, (void*)(wMenuCallBack_p)UndoRedo, 0, (void *)0 );
- wMenuPushCreate( popup1M, "cmdZoomIn", _("Zoom In"), 0, (wMenuCallBack_p)DoZoomUp, (void*)1 );
- wMenuPushCreate( popup2M, "cmdZoomIn", _("Zoom In"), 0, (wMenuCallBack_p)DoZoomUp, (void*)1 );
- wMenuPushCreate( popup1M, "cmdZoomOut", _("Zoom Out"), 0, (wMenuCallBack_p)DoZoomDown, (void*)1 );
- wMenuPushCreate( popup2M, "cmdZoomOut", _("Zoom Out"), 0, (wMenuCallBack_p)DoZoomDown, (void*)1 );
- MiscMenuItemCreate( popup1M, popup2M, "cmdGridEnable", _("SnapGrid Enable"), 0, (void*)(wMenuCallBack_p)SnapGridEnable, 0, (void *)0 );
- MiscMenuItemCreate( popup1M, popup2M, "cmdGridShow", _("SnapGrid Show"), 0, (void*)(wMenuCallBack_p)SnapGridShow, 0, (void *)0 );
- MiscMenuItemCreate( popup1M, popup2M, "cmdMapShow", _("Show/Hide Map"), 0, (void*)(wMenuCallBack_p)MapWindowToggleShow, 0, (void *)0);
- wMenuSeparatorCreate( popup1M );
- wMenuSeparatorCreate( popup2M );
- MiscMenuItemCreate( popup2M, NULL, "cmdCopy", _("Copy"), 0, (void*)(wMenuCallBack_p)EditCopy, 0, (void *)0 );
- MiscMenuItemCreate( popup1M, popup2M, "cmdPaste", _("Paste"), 0, (void*)(wMenuCallBack_p)EditPaste, 0, (void *)0 );
- MiscMenuItemCreate( popup1M, popup2M, "cmdSelectAll", _("Select All"), 0, (void*)(wMenuCallBack_p)SetAllTrackSelect, 0, (void *)1 );
- MiscMenuItemCreate( popup1M, popup2M, "cmdSelectCurrentLayer", _("Select Current Layer"), 0, (void*)(wMenuCallBack_p)SelectCurrentLayer, 0, (void *)0 );
- MiscMenuItemCreate( popup2M, NULL, "cmdDeselectAll", _("Deselect All"), 0, (void*)(wMenuCallBack_p)SetAllTrackSelect, 0, (void *)0 );
- wMenuPushCreate( popup2M, "cmdMove", _("Move"), 0, (wMenuCallBack_p)DoCommandBIndirect, &moveCmdInx );
- wMenuPushCreate( popup2M, "cmdRotate", _("Rotate"), 0, (wMenuCallBack_p)DoCommandBIndirect, &rotateCmdInx );
- MiscMenuItemCreate( popup2M, NULL, "cmdTunnel", _("Tunnel"), 0, (void*)(wMenuCallBack_p)SelectTunnel, 0, (void *)0 );
- wMenuSeparatorCreate( popup1M );
- wMenuSeparatorCreate( popup2M );
- MiscMenuItemCreate( popup2M, NULL, "cmdDelete", _("Delete"), 0, (void*)(wMenuCallBack_p)SelectDelete, 0, (void *)0 );
- wMenuSeparatorCreate( popup2M );
- popup1aM = wMenuMenuCreate( popup1M, "", _("More") );
- popup2aM = wMenuMenuCreate( popup2M, "", _("More") );
+ /* Select Commands */
+ /* Select All */
+ /* Select All Current */
+
+ /* Common View Commands Menu */
+ /* Zoom In/Out */
+ /* Snap Grid Menu */
+ /* Show/Hide Map */
+ /* Show/Hide Background */
+
+ /* Selected Commands */
+ /*--------------*/
+ /* DeSelect All */
+ /* Select All */
+ /* Select All Current */
+ /*--------------*/
+ /* Quick Move */
+ /* Quick Rotate */
+ /* Quick Align */
+ /*--------------*/
+ /* Move To Current Layer */
+ /* Move/Rotate Cmds */
+ /* Cut/Paste/Delete */
+ /* Group/Un-group Selected */
+ /*----------*/
+ /* Thick/Thin */
+ /* Bridge/Tunnel */
+ /* Ties/NoTies */
+ /*-----------*/
+ /* More Commands */
+
+ popup1M = wMenuPopupCreate(mainW, _("Context Commands"));
+ popup2M = wMenuPopupCreate(mainW, _("Shift Context Commands"));
+ MiscMenuItemCreate(popup1M, popup2M, "cmdUndo", _("Undo"), 0,
+ (void*) (wMenuCallBack_p) UndoUndo, 0, (void *) 0);
+ MiscMenuItemCreate(popup1M, popup2M, "cmdRedo", _("Redo"), 0,
+ (void*) (wMenuCallBack_p) UndoRedo, 0, (void *) 0);
+ /* Zoom */
+ wMenuPushCreate(popup1M, "cmdZoomIn", _("Zoom In"), 0,
+ (wMenuCallBack_p) DoZoomUp, (void*) 1);
+ wMenuPushCreate(popup2M, "cmdZoomIn", _("Zoom In"), 0,
+ (wMenuCallBack_p) DoZoomUp, (void*) 1);
+ wMenuPushCreate(popup1M, "cmdZoomOut", _("Zoom Out"), 0,
+ (wMenuCallBack_p) DoZoomDown, (void*) 1);
+ wMenuPushCreate(popup2M, "cmdZoomOut", _("Zoom Out"), 0,
+ (wMenuCallBack_p) DoZoomDown, (void*) 1);
+ /* Display */
+ MiscMenuItemCreate(popup1M, popup2M, "cmdGridEnable", _("Enable SnapGrid"),
+ 0, (void*) (wMenuCallBack_p) SnapGridEnable, 0, (void *) 0);
+ MiscMenuItemCreate(popup1M, popup2M, "cmdGridShow", _("SnapGrid Show"), 0,
+ (void*) (wMenuCallBack_p) SnapGridShow, 0, (void *) 0);
+ MiscMenuItemCreate(popup1M, popup2M, "cmdMagneticSnap", _(" Enable Magnetic Snap"), 0,
+ (void*) (wMenuCallBack_p) MagneticSnapToggle, 0, (void *) 0);
+ MiscMenuItemCreate(popup1M, popup2M, "cmdMapShow", _("Show/Hide Map"), 0,
+ (void*) (wMenuCallBack_p) MapWindowToggleShow, 0, (void *) 0);
+ MiscMenuItemCreate(popup1M, popup2M, "cmdBackgroundShow", _("Show/Hide Background"), 0,
+ (void*) (wMenuCallBack_p) BackgroundToggleShow, 0, (void *) 0);
+ wMenuSeparatorCreate(popup1M);
+ wMenuSeparatorCreate(popup2M);
+ /* Copy/Paste */
+ MiscMenuItemCreate(popup2M, NULL, "cmdCut", _("Cut"), 0,
+ (void*) (wMenuCallBack_p) EditCut, 0, (void *) 0);
+ MiscMenuItemCreate(popup2M, NULL, "cmdCopy", _("Copy"), 0,
+ (void*) (wMenuCallBack_p) EditCopy, 0, (void *) 0);
+ MiscMenuItemCreate(popup1M, popup2M, "cmdPaste", _("Paste"), 0,
+ (void*) (wMenuCallBack_p) EditPaste, 0, (void *) 0);
+ MiscMenuItemCreate(popup2M, NULL, "cmdClone", _("Clone"), 0,
+ (void*) (wMenuCallBack_p) EditClone, 0, (void *) 0);
+ /*Select*/
+ MiscMenuItemCreate(popup1M, popup2M, "cmdSelectAll", _("Select All"), 0,
+ (void*) (wMenuCallBack_p) SetAllTrackSelect, 0, (void *) 1);
+ MiscMenuItemCreate(popup1M, popup2M, "cmdSelectCurrentLayer",
+ _("Select Current Layer"), 0,
+ (void*) (wMenuCallBack_p) SelectCurrentLayer, 0, (void *) 0);
+ MiscMenuItemCreate(popup2M, NULL, "cmdDeselectAll", _("Deselect All"), 0,
+ (void*) (wMenuCallBack_p) SetAllTrackSelect, 0, (void *) 0);
+ /* Modify */
+ wMenuPushCreate(popup2M, "cmdMove", _("Move"), 0,
+ (wMenuCallBack_p) DoCommandBIndirect, &moveCmdInx);
+ wMenuPushCreate(popup2M, "cmdRotate", _("Rotate"), 0,
+ (wMenuCallBack_p) DoCommandBIndirect, &rotateCmdInx);
+ wMenuSeparatorCreate(popup1M);
+ wMenuSeparatorCreate(popup2M);
+ MiscMenuItemCreate(popup2M, NULL, "cmdDelete", _("Delete"), 0,
+ (void*) (wMenuCallBack_p) SelectDelete, 0, (void *) 0);
+ wMenuSeparatorCreate(popup2M);
+ popup1aM = wMenuMenuCreate(popup1M, "", _("Add..."));
+ popup2aM = wMenuMenuCreate(popup2M, "", _("Add..."));
+ wMenuSeparatorCreate(popup2M);
+ wMenuSeparatorCreate(popup1M);
+ popup1mM = wMenuMenuCreate(popup1M, "", _("More..."));
+ popup2mM = wMenuMenuCreate(popup2M, "", _("More..."));
cmdGroup = BG_FILE;
- AddToolbarButton( "menuFile-clear", wIconCreatePixMap(document_new), IC_MODETRAIN_TOO, (addButtonCallBack_t)DoClear, NULL );
- AddToolbarButton( "menuFile-load", wIconCreatePixMap(document_open), IC_MODETRAIN_TOO, (addButtonCallBack_t)ChkLoad, NULL );
- AddToolbarButton( "menuFile-save", wIconCreatePixMap(document_save), IC_MODETRAIN_TOO, (addButtonCallBack_t)DoSave, NULL );
+ AddToolbarButton("menuFile-clear", wIconCreatePixMap(document_new),
+ IC_MODETRAIN_TOO, (addButtonCallBack_t) DoClear, NULL);
+ AddToolbarButton("menuFile-load", wIconCreatePixMap(document_open),
+ IC_MODETRAIN_TOO, (addButtonCallBack_t) ChkLoad, NULL);
+ AddToolbarButton("menuFile-save", wIconCreatePixMap(document_save),
+ IC_MODETRAIN_TOO, (addButtonCallBack_t) DoSave, NULL);
+
+ InitCmdExport();
cmdGroup = BG_ZOOM;
- zoomUpB = AddToolbarButton( "cmdZoomIn", wIconCreatePixMap(zoomin_xpm), IC_MODETRAIN_TOO,
- (addButtonCallBack_t)DoZoomUp, NULL );
+ zoomUpB = AddToolbarButton("cmdZoomIn", wIconCreatePixMap(zoomin_xpm),
+ IC_MODETRAIN_TOO, (addButtonCallBack_t) DoZoomUp, NULL);
- zoomM = wMenuPopupCreate( mainW, "" );
- AddToolbarButton( "cmdZoom", wIconCreatePixMap(zoom_xpm), IC_MODETRAIN_TOO, (wButtonCallBack_p)wMenuPopupShow, zoomM );
+ zoomM = wMenuPopupCreate(mainW, "");
+ AddToolbarButton("cmdZoom", wIconCreatePixMap(zoom_xpm), IC_MODETRAIN_TOO,
+ (wButtonCallBack_p) wMenuPopupShow, zoomM);
- zoomDownB = AddToolbarButton( "cmdZoomOut", wIconCreatePixMap(zoomout_xpm), IC_MODETRAIN_TOO,
- (addButtonCallBack_t)DoZoomDown, NULL );
+ zoomDownB = AddToolbarButton("cmdZoomOut", wIconCreatePixMap(zoomout_xpm),
+ IC_MODETRAIN_TOO, (addButtonCallBack_t) DoZoomDown, NULL);
cmdGroup = BG_UNDO;
- undoB = AddToolbarButton( "cmdUndo", wIconCreatePixMap(edit_undo), 0, (addButtonCallBack_t)UndoUndo, NULL );
- redoB = AddToolbarButton( "cmdRedo", wIconCreatePixMap(edit_redo), 0, (addButtonCallBack_t)UndoRedo, NULL );
-
- wControlActive( (wControl_p)undoB, FALSE );
- wControlActive( (wControl_p)redoB, FALSE );
+ undoB = AddToolbarButton("cmdUndo", wIconCreatePixMap(edit_undo), 0,
+ (addButtonCallBack_t) UndoUndo, NULL);
+ redoB = AddToolbarButton("cmdRedo", wIconCreatePixMap(edit_redo), 0,
+ (addButtonCallBack_t) UndoRedo, NULL);
+ wControlActive((wControl_p) undoB, FALSE);
+ wControlActive((wControl_p) redoB, FALSE);
/*
* FILE MENU
*/
- MiscMenuItemCreate( fileM, NULL, "menuFile-clear", _("&New ..."), ACCL_NEW, (void*)(wMenuCallBack_p)DoClear, 0, (void *)0 );
- wMenuPushCreate( fileM, "menuFile-load", _("&Open ..."), ACCL_OPEN, (wMenuCallBack_p)ChkLoad, NULL );
- wMenuSeparatorCreate( fileM );
-
- wMenuPushCreate( fileM, "menuFile-save", _("&Save"), ACCL_SAVE, (wMenuCallBack_p)DoSave, NULL );
- wMenuPushCreate( fileM, "menuFile-saveAs", _("Save &As ..."), ACCL_SAVEAS, (wMenuCallBack_p)DoSaveAs, NULL );
- wMenuPushCreate( fileM, "menuFile-revert", _("Revert"), ACCL_REVERT, (wMenuCallBack_p)ChkRevert, NULL );
- wMenuSeparatorCreate( fileM );
- MiscMenuItemCreate( fileM, NULL, "printSetup", _("P&rint Setup ..."), ACCL_PRINTSETUP, (void*)(wMenuCallBack_p)wPrintSetup, 0, (void *)0 );
- printCmdInx = InitCmdPrint( fileM );
- wMenuSeparatorCreate( fileM );
- MiscMenuItemCreate( fileM, NULL, "cmdImport", _("&Import"), ACCL_IMPORT, (void*)(wMenuCallBack_p)DoImport, 0, (void *)0 );
- MiscMenuItemCreate( fileM, NULL, "cmdOutputbitmap", _("Export to &Bitmap"), ACCL_PRINTBM, (void*)(wMenuCallBack_p)OutputBitMapInit(), 0, (void *)0 );
- MiscMenuItemCreate( fileM, NULL, "cmdExport", _("E&xport"), ACCL_EXPORT, (void*)(wMenuCallBack_p)DoExport, IC_SELECTED, (void *)0 );
- MiscMenuItemCreate( fileM, NULL, "cmdExportDXF", _("Export D&XF"), ACCL_EXPORTDXF, (void*)(wMenuCallBack_p)DoExportDXF, IC_SELECTED, (void *)0 );
- wMenuSeparatorCreate( fileM );
-
- MiscMenuItemCreate( fileM, NULL, "cmdPrmfile", _("Parameter &Files ..."), ACCL_PARAMFILES, (void*)ParamFilesInit(), 0, (void *)0 );
- MiscMenuItemCreate( fileM, NULL, "cmdFileNote", _("No&tes ..."), ACCL_NOTES, (void*)(wMenuCallBack_p)DoNote, 0, (void *)0 );
-
- wMenuSeparatorCreate( fileM );
- fileList_ml = wMenuListCreate( fileM, "menuFileList", NUM_FILELIST, ChkFileList );
- wMenuSeparatorCreate( fileM );
- wMenuPushCreate( fileM, "menuFile-quit", _("E&xit"), 0,
- (wMenuCallBack_p)DoQuit, NULL );
+ MiscMenuItemCreate(fileM, NULL, "menuFile-clear", _("&New ..."), ACCL_NEW,
+ (void*) (wMenuCallBack_p) DoClear, 0, (void *) 0);
+ wMenuPushCreate(fileM, "menuFile-load", _("&Open ..."), ACCL_OPEN,
+ (wMenuCallBack_p) ChkLoad, NULL);
+ wMenuSeparatorCreate(fileM);
+
+ wMenuPushCreate(fileM, "menuFile-save", _("&Save"), ACCL_SAVE,
+ (wMenuCallBack_p) DoSave, NULL);
+ wMenuPushCreate(fileM, "menuFile-saveAs", _("Save &As ..."), ACCL_SAVEAS,
+ (wMenuCallBack_p) DoSaveAs, NULL);
+ wMenuPushCreate(fileM, "menuFile-revert", _("Revert"), ACCL_REVERT,
+ (wMenuCallBack_p) ChkRevert, NULL);
+ wMenuSeparatorCreate(fileM);
+ MiscMenuItemCreate(fileM, NULL, "printSetup", _("P&rint Setup ..."),
+ ACCL_PRINTSETUP, (void*) (wMenuCallBack_p) wPrintSetup, 0,
+ (void *) 0);
+ printCmdInx = InitCmdPrint(fileM);
+ wMenuSeparatorCreate(fileM);
+ MiscMenuItemCreate(fileM, NULL, "cmdImport", _("&Import"), ACCL_IMPORT,
+ (void*) (wMenuCallBack_p) DoImport, 0, (void *) 0);
+ MiscMenuItemCreate(fileM, NULL, "cmdImportModule", _("Import &Module"), ACCL_IMPORT_MOD,
+ (void*) (wMenuCallBack_p) DoImport, 0, (void *) 1);
+ MiscMenuItemCreate(fileM, NULL, "cmdOutputbitmap", _("Export to &Bitmap"),
+ ACCL_PRINTBM, (void*) (wMenuCallBack_p) OutputBitMapInit(), 0,
+ (void *) 0);
+ MiscMenuItemCreate(fileM, NULL, "cmdExport", _("E&xport"), ACCL_EXPORT,
+ (void*) (wMenuCallBack_p) DoExport, IC_SELECTED, (void *) 0);
+ MiscMenuItemCreate(fileM, NULL, "cmdExportDXF", _("Export D&XF"),
+ ACCL_EXPORTDXF, (void*) (wMenuCallBack_p) DoExportDXF, IC_SELECTED,
+ (void *) 0);
+ wMenuSeparatorCreate(fileM);
+
+ MiscMenuItemCreate(fileM, NULL, "cmdPrmfile", _("Parameter &Files ..."),
+ ACCL_PARAMFILES, (void*) ParamFilesInit(), 0, (void *) 0);
+ MiscMenuItemCreate(fileM, NULL, "cmdFileNote", _("No&tes ..."), ACCL_NOTES,
+ (void*) (wMenuCallBack_p) DoNote, 0, (void *) 0);
+
+ wMenuSeparatorCreate(fileM);
+ fileList_ml = wMenuListCreate(fileM, "menuFileList", NUM_FILELIST,
+ ChkFileList);
+ wMenuSeparatorCreate(fileM);
+ wMenuPushCreate(fileM, "menuFile-quit", _("E&xit"), 0,
+ (wMenuCallBack_p) DoQuit, NULL);
/*
* EDIT MENU
*/
- MiscMenuItemCreate( editM, NULL, "cmdUndo", _("&Undo"), ACCL_UNDO, (void*)(wMenuCallBack_p)UndoUndo, 0, (void *)0 );
- MiscMenuItemCreate( editM, NULL, "cmdRedo", _("R&edo"), ACCL_REDO, (void*)(wMenuCallBack_p)UndoRedo, 0, (void *)0 );
- wMenuSeparatorCreate( editM );
- MiscMenuItemCreate( editM, NULL, "cmdCut", _("Cu&t"), ACCL_CUT, (void*)(wMenuCallBack_p)EditCut, IC_SELECTED, (void *)0 );
- MiscMenuItemCreate( editM, NULL, "cmdCopy", _("&Copy"), ACCL_COPY, (void*)(wMenuCallBack_p)EditCopy, IC_SELECTED, (void *)0 );
- MiscMenuItemCreate( editM, NULL, "cmdPaste", _("&Paste"), ACCL_PASTE, (void*)(wMenuCallBack_p)EditPaste, 0, (void *)0 );
- MiscMenuItemCreate( editM, NULL, "cmdDelete", _("De&lete"), ACCL_DELETE, (void*)(wMenuCallBack_p)SelectDelete, IC_SELECTED, (void *)0 );
- MiscMenuItemCreate( editM, NULL, "cmdMoveToCurrentLayer", _("Move To Current Layer"), ACCL_MOVCURLAYER, (void*)(wMenuCallBack_p)MoveSelectedTracksToCurrentLayer, IC_SELECTED, (void *)0 );
-
-
+ MiscMenuItemCreate(editM, NULL, "cmdUndo", _("&Undo"), ACCL_UNDO,
+ (void*) (wMenuCallBack_p) UndoUndo, 0, (void *) 0);
+ MiscMenuItemCreate(editM, NULL, "cmdRedo", _("R&edo"), ACCL_REDO,
+ (void*) (wMenuCallBack_p) UndoRedo, 0, (void *) 0);
+ wMenuSeparatorCreate(editM);
+ MiscMenuItemCreate(editM, NULL, "cmdCut", _("Cu&t"), ACCL_CUT,
+ (void*) (wMenuCallBack_p) EditCut, IC_SELECTED, (void *) 0);
+ MiscMenuItemCreate(editM, NULL, "cmdCopy", _("&Copy"), ACCL_COPY,
+ (void*) (wMenuCallBack_p) EditCopy, IC_SELECTED, (void *) 0);
+ MiscMenuItemCreate(editM, NULL, "cmdPaste", _("&Paste"), ACCL_PASTE,
+ (void*) (wMenuCallBack_p) EditPaste, 0, (void *) 0);
+ MiscMenuItemCreate(editM, NULL, "cmdClone", _("C&lone"), ACCL_CLONE,
+ (void*) (wMenuCallBack_p) EditClone, 0, (void *) 0);
+ MiscMenuItemCreate(editM, NULL, "cmdDelete", _("De&lete"), ACCL_DELETE,
+ (void*) (wMenuCallBack_p) SelectDelete, IC_SELECTED, (void *) 0);
+ MiscMenuItemCreate(editM, NULL, "cmdMoveToCurrentLayer",
+ _("Move To Current Layer"), ACCL_MOVCURLAYER,
+ (void*) (wMenuCallBack_p) MoveSelectedTracksToCurrentLayer,
+ IC_SELECTED, (void *) 0);
wMenuSeparatorCreate( editM );
menuPLs[menuPG.paramCnt].context = (void*)1;
MiscMenuItemCreate( editM, NULL, "cmdSelectAll", _("Select &All"), ACCL_SELECTALL, (void*)(wMenuCallBack_p)SetAllTrackSelect, 0, (void *)1 );
@@ -2238,8 +2400,10 @@ static void CreateMenus( void )
MiscMenuItemCreate( editM, NULL, "cmdSelectOrphaned", _("Select Stranded Track"), 0L, (void*)(wMenuCallBack_p)OrphanedTrackSelect, 0, (void *)0 );
wMenuSeparatorCreate( editM );
MiscMenuItemCreate( editM, NULL, "cmdTunnel", _("Tu&nnel"), ACCL_TUNNEL, (void*)(wMenuCallBack_p)SelectTunnel, IC_SELECTED, (void *)0 );
- MiscMenuItemCreate( editM, NULL, "cmdAbove", _("A&bove"), ACCL_ABOVE, (void*)(wMenuCallBack_p)SelectAbove, IC_SELECTED, (void *)0 );
- MiscMenuItemCreate( editM, NULL, "cmdBelow", _("Belo&w"), ACCL_BELOW, (void*)(wMenuCallBack_p)SelectBelow, IC_SELECTED, (void *)0 );
+ MiscMenuItemCreate( editM, NULL, "cmdBridge", _("B&ridge"), ACCL_BRIDGE, (void*)(wMenuCallBack_p)SelectBridge, IC_SELECTED, (void *)0);
+ MiscMenuItemCreate( editM, NULL, "cmdTies", _("Ties/NoTies"), ACCL_TIES, (void*)(wMenuCallBack_p)SelectTies, IC_SELECTED, (void *)0);
+ MiscMenuItemCreate( editM, NULL, "cmdAbove", _("Move to &Front"), ACCL_ABOVE, (void*)(wMenuCallBack_p)SelectAbove, IC_SELECTED, (void *)0 );
+ MiscMenuItemCreate( editM, NULL, "cmdBelow", _("Move to &Back"), ACCL_BELOW, (void*)(wMenuCallBack_p)SelectBelow, IC_SELECTED, (void *)0 );
wMenuSeparatorCreate( editM );
MiscMenuItemCreate( editM, NULL, "cmdWidth0", _("Thin Tracks"), ACCL_THIN, (void*)(wMenuCallBack_p)SelectTrackWidth, IC_SELECTED, (void *)0 );
@@ -2249,199 +2413,273 @@ static void CreateMenus( void )
/*
* VIEW MENU
*/
- zoomInM = wMenuPushCreate( viewM, "menuEdit-zoomIn", _("Zoom &In"), ACCL_ZOOMIN, (wMenuCallBack_p)DoZoomUp, (void*)1 );
- zoomSubM = wMenuMenuCreate( viewM, "menuEdit-zoomTo", _("&Zoom") );
- zoomOutM = wMenuPushCreate( viewM, "menuEdit-zoomOut", _("Zoom &Out"), ACCL_ZOOMOUT, (wMenuCallBack_p)DoZoomDown, (void*)1 );
- wMenuSeparatorCreate( viewM );
+ zoomInM = wMenuPushCreate(viewM, "menuEdit-zoomIn", _("Zoom &In"),
+ ACCL_ZOOMIN, (wMenuCallBack_p) DoZoomUp, (void*) 1);
+ zoomSubM = wMenuMenuCreate(viewM, "menuEdit-zoomTo", _("&Zoom"));
+ zoomOutM = wMenuPushCreate(viewM, "menuEdit-zoomOut", _("Zoom &Out"),
+ ACCL_ZOOMOUT, (wMenuCallBack_p) DoZoomDown, (void*) 1);
+ wMenuSeparatorCreate(viewM);
- InitCmdZoom( zoomM, zoomSubM );
+ InitCmdZoom(zoomM, zoomSubM, NULL, NULL);
/* these menu choices and toolbar buttons are synonymous and should be treated as such */
- wControlLinkedSet( (wControl_p)zoomInM, (wControl_p)zoomUpB );
- wControlLinkedSet( (wControl_p)zoomOutM, (wControl_p)zoomDownB );
-
- wMenuPushCreate( viewM, "menuEdit-redraw", _("&Redraw"), ACCL_REDRAW, (wMenuCallBack_p)MainRedraw, NULL );
- wMenuPushCreate( viewM, "menuEdit-redraw", _("Redraw All"), ACCL_REDRAWALL, (wMenuCallBack_p)DoRedraw, NULL );
- wMenuSeparatorCreate( viewM );
-
- snapGridEnableMI = wMenuToggleCreate( viewM, "cmdGridEnable", _("Enable SnapGrid"), ACCL_SNAPENABLE,
- 0, (wMenuToggleCallBack_p)SnapGridEnable, NULL );
- snapGridShowMI = wMenuToggleCreate( viewM, "cmdGridShow", _("Show SnapGrid"), ACCL_SNAPSHOW,
- FALSE, (wMenuToggleCallBack_p)SnapGridShow, NULL );
- gridCmdInx = InitGrid( viewM );
+ wControlLinkedSet((wControl_p) zoomInM, (wControl_p) zoomUpB);
+ wControlLinkedSet((wControl_p) zoomOutM, (wControl_p) zoomDownB);
+
+ wMenuPushCreate(viewM, "menuEdit-redraw", _("&Redraw"), ACCL_REDRAW,
+ (wMenuCallBack_p) MainRedraw, NULL);
+ wMenuPushCreate(viewM, "menuEdit-redraw", _("Redraw All"), ACCL_REDRAWALL,
+ (wMenuCallBack_p) DoRedraw, NULL);
+ wMenuSeparatorCreate(viewM);
+
+ snapGridEnableMI = wMenuToggleCreate(viewM, "cmdGridEnable",
+ _("Enable SnapGrid"), ACCL_SNAPENABLE, 0,
+ (wMenuToggleCallBack_p) SnapGridEnable, NULL);
+ snapGridShowMI = wMenuToggleCreate(viewM, "cmdGridShow", _("Show SnapGrid"),
+ ACCL_SNAPSHOW,
+ FALSE, (wMenuToggleCallBack_p) SnapGridShow, NULL);
+ gridCmdInx = InitGrid(viewM);
+
+ // visibility toggle for anchors
+ // get the start value
+ long anchors_long;
+ wPrefGetInteger("misc", "anchors", (long *)&anchors_long, 1);
+ magneticSnap = anchors_long ? TRUE : FALSE;
+ magnetsMI = wMenuToggleCreate(viewM, "cmdMagneticSnap", _("Enable Magnetic Snap"),
+ 0, magneticSnap,
+ (wMenuToggleCallBack_p)MagneticSnapToggle, NULL);
// visibility toggle for map window
// get the start value
long mapVisible_long;
- wPrefGetInteger( "misc", "mapVisible", (long *)&mapVisible_long, 1 );
- mapVisible = mapVisible_long?TRUE:FALSE;
- mapShowMI = wMenuToggleCreate( viewM, "cmdMapShow", _("Show/Hide Map"), ACCL_MAPSHOW,
- mapVisible, (wMenuToggleCallBack_p)MapWindowToggleShow, NULL );
+ wPrefGetInteger("misc", "mapVisible", (long *) &mapVisible_long, 1);
+ mapVisible = mapVisible_long ? TRUE : FALSE;
+ mapShowMI = wMenuToggleCreate(viewM, "cmdMapShow", _("Show/Hide Map"),
+ ACCL_MAPSHOW, mapVisible,
+ (wMenuToggleCallBack_p) MapWindowToggleShow, NULL);
- wMenuSeparatorCreate( viewM );
+ wMenuSeparatorCreate(viewM);
- toolbarM = wMenuMenuCreate( viewM, "toolbarM", _("&Tool Bar") );
- CreateToolbarM( toolbarM );
+ toolbarM = wMenuMenuCreate(viewM, "toolbarM", _("&Tool Bar"));
+ CreateToolbarM(toolbarM);
- cmdGroup = BG_EASE;
+ cmdGroup = BG_EASE;
InitCmdEasement();
cmdGroup = BG_SNAP;
InitSnapGridButtons();
- mapShowB = AddToolbarButton("cmdMapShow", wIconCreatePixMap(map_xpm), IC_MODETRAIN_TOO,
- (addButtonCallBack_t)MapWindowToggleShow, NULL);
- wControlLinkedSet((wControl_p)mapShowMI, (wControl_p)mapShowB);
- wButtonSetBusy(mapShowB, (wBool_t)mapVisible);
+ magnetsB = AddToolbarButton("cmdMagneticSnap", wIconCreatePixMap(magnet_xpm),
+ IC_MODETRAIN_TOO, (addButtonCallBack_t) MagneticSnapToggle, NULL);
+ wControlLinkedSet((wControl_p) magnetsMI, (wControl_p) magnetsB);
+ wButtonSetBusy(magnetsB, (wBool_t) magneticSnap);
+
+ mapShowB = AddToolbarButton("cmdMapShow", wIconCreatePixMap(map_xpm),
+ IC_MODETRAIN_TOO, (addButtonCallBack_t) MapWindowToggleShow, NULL);
+ wControlLinkedSet((wControl_p) mapShowMI, (wControl_p) mapShowB);
+ wButtonSetBusy(mapShowB, (wBool_t) mapVisible);
/*
* ADD MENU
*/
- cmdGroup = BG_TRKCRT|BG_BIGGAP;
- InitCmdStraight( addM );
- InitCmdCurve( addM );
- InitCmdParallel( addM );
- InitCmdTurnout( addM );
- InitCmdHandLaidTurnout( addM );
- InitCmdStruct( addM );
- InitCmdHelix( addM );
- InitCmdTurntable( addM );
+ cmdGroup = BG_TRKCRT | BG_BIGGAP;
+ InitCmdStraight(addM);
+ InitCmdCurve(addM);
+ InitCmdParallel(addM);
+ InitCmdTurnout(addM);
+ InitCmdHandLaidTurnout(addM);
+ InitCmdStruct(addM);
+ InitCmdHelix(addM);
+ InitCmdTurntable(addM);
cmdGroup = BG_CONTROL;
- InitCmdBlock( addM );
- InitCmdSwitchMotor( addM );
- InitCmdSignal( addM );
- InitCmdControl( addM );
- InitCmdSensor( addM );
-
+ ButtonGroupBegin( _("Control Element"), "cmdControlElements", _("Control Element") );
+ InitCmdBlock(addM);
+ InitCmdSwitchMotor(addM);
+ InitCmdSignal(addM);
+ InitCmdControl(addM);
+ InitCmdSensor(addM);
+ ButtonGroupEnd();
+
/*
* CHANGE MENU
*/
cmdGroup = BG_SELECT;
- InitCmdDescribe( changeM );
- InitCmdSelect( changeM );
- InitCmdPan( changeM );
- wMenuSeparatorCreate( changeM );
+ InitCmdDescribe(changeM);
+ InitCmdSelect(changeM);
+ InitCmdPan(changeM);
+ wMenuSeparatorCreate(changeM);
cmdGroup = BG_TRKGRP;
- InitCmdMove( changeM );
+ InitCmdMove(changeM);
InitCmdDelete();
InitCmdTunnel();
+ InitCmdBridge();
InitCmdAboveBelow();
cmdGroup = BG_TRKMOD;
if (extraButtons)
- MiscMenuItemCreate( changeM, NULL, "loosen", _("&Loosen Tracks"), ACCL_LOOSEN, (void*)(wMenuCallBack_p)LoosenTracks, IC_SELECTED, (void *)0 );
-
- InitCmdModify( changeM );
- InitCmdJoin( changeM );
- InitCmdPull( changeM );
- InitCmdSplit( changeM );
- InitCmdMoveDescription( changeM );
- wMenuSeparatorCreate( changeM );
-
- MiscMenuItemCreate( changeM, NULL, "cmdAddElevations", _("Raise/Lower Elevations"), ACCL_CHGELEV, (void*)(wMenuCallBack_p)ShowAddElevations, IC_SELECTED, (void *)0 );
- InitCmdElevation( changeM );
- InitCmdProfile( changeM );
-
- MiscMenuItemCreate( changeM, NULL, "cmdClearElevations", _("Clear Elevations"), ACCL_CLRELEV, (void*)(wMenuCallBack_p)ClearElevations, IC_SELECTED, (void *)0 );
- MiscMenuItemCreate( changeM, NULL, "cmdElevation", _("Recompute Elevations"), 0, (void*)(wMenuCallBack_p)RecomputeElevations, 0, (void *)0 );
- ParamRegister( &addElevPG );
-
- wMenuSeparatorCreate( changeM );
- MiscMenuItemCreate( changeM, NULL, "cmdRescale", _("Change Scale"), 0, (void*)(wMenuCallBack_p)DoRescale, IC_SELECTED, (void *)0 );
+ MiscMenuItemCreate(changeM, NULL, "loosen", _("&Loosen Tracks"),
+ ACCL_LOOSEN, (void*) (wMenuCallBack_p) LoosenTracks,
+ IC_SELECTED, (void *) 0);
+
+ InitCmdModify(changeM);
+ InitCmdJoin(changeM);
+ InitCmdPull(changeM);
+ InitCmdSplit(changeM);
+ InitCmdMoveDescription(changeM);
+ wMenuSeparatorCreate(changeM);
+
+ MiscMenuItemCreate(changeM, NULL, "cmdAddElevations",
+ _("Raise/Lower Elevations"), ACCL_CHGELEV,
+ (void*) (wMenuCallBack_p) ShowAddElevations, IC_SELECTED,
+ (void *) 0);
+ InitCmdElevation(changeM);
+ InitCmdProfile(changeM);
+
+ MiscMenuItemCreate(changeM, NULL, "cmdClearElevations",
+ _("Clear Elevations"), ACCL_CLRELEV,
+ (void*) (wMenuCallBack_p) ClearElevations, IC_SELECTED, (void *) 0);
+ MiscMenuItemCreate(changeM, NULL, "cmdElevation", _("Recompute Elevations"),
+ 0, (void*) (wMenuCallBack_p) RecomputeElevations, 0, (void *) 0);
+ ParamRegister(&addElevPG);
+
+ wMenuSeparatorCreate(changeM);
+ MiscMenuItemCreate(changeM, NULL, "cmdRescale", _("Change Scale"), 0,
+ (void*) (wMenuCallBack_p) DoRescale, IC_SELECTED, (void *) 0);
+
+ wMenuSeparatorCreate(changeM);
+
+ InitCmdCornu(changeM);
/*
* DRAW MENU
*/
cmdGroup = BG_MISCCRT;
- InitCmdDraw( drawM );
- InitCmdText( drawM );
- InitCmdNote( drawM );
+ InitCmdDraw(drawM);
+ InitCmdText(drawM);
+ InitTrkNote(drawM);
cmdGroup = BG_RULER;
- InitCmdRuler( drawM );
-
+ InitCmdRuler(drawM);
/*
* OPTION MENU
*/
- MiscMenuItemCreate( optionM, NULL, "cmdLayout", _("L&ayout ..."), ACCL_LAYOUTW, (void*)LayoutInit(), IC_MODETRAIN_TOO, (void *)0 );
- MiscMenuItemCreate( optionM, NULL, "cmdDisplay", _("&Display ..."), ACCL_DISPLAYW, (void*)DisplayInit(), IC_MODETRAIN_TOO, (void *)0 );
- MiscMenuItemCreate( optionM, NULL, "cmdCmdopt", _("Co&mmand ..."), ACCL_CMDOPTW, (void*)CmdoptInit(), IC_MODETRAIN_TOO, (void *)0 );
- MiscMenuItemCreate( optionM, NULL, "cmdEasement", _("&Easements ..."), ACCL_EASEW, (void*)(wMenuCallBack_p)DoEasementRedir, IC_MODETRAIN_TOO, (void *)0 );
- MiscMenuItemCreate( optionM, NULL, "fontSelW", _("&Fonts ..."), ACCL_FONTW, (void*)(wMenuCallBack_p)SelectFont, IC_MODETRAIN_TOO, (void *)0 );
- MiscMenuItemCreate( optionM, NULL, "cmdSticky", _("Stic&ky ..."), ACCL_STICKY, (void*)(wMenuCallBack_p)DoSticky, IC_MODETRAIN_TOO, (void *)0 );
+ MiscMenuItemCreate(optionM, NULL, "cmdLayout", _("L&ayout ..."),
+ ACCL_LAYOUTW, (void*) LayoutInit(), IC_MODETRAIN_TOO, (void *) 0);
+ MiscMenuItemCreate(optionM, NULL, "cmdDisplay", _("&Display ..."),
+ ACCL_DISPLAYW, (void*) DisplayInit(), IC_MODETRAIN_TOO, (void *) 0);
+ MiscMenuItemCreate(optionM, NULL, "cmdCmdopt", _("Co&mmand ..."),
+ ACCL_CMDOPTW, (void*) CmdoptInit(), IC_MODETRAIN_TOO, (void *) 0);
+ MiscMenuItemCreate(optionM, NULL, "cmdEasement", _("&Easements ..."),
+ ACCL_EASEW, (void*) (wMenuCallBack_p) DoEasementRedir,
+ IC_MODETRAIN_TOO, (void *) 0);
+ MiscMenuItemCreate(optionM, NULL, "fontSelW", _("&Fonts ..."), ACCL_FONTW,
+ (void*) (wMenuCallBack_p) SelectFont, IC_MODETRAIN_TOO, (void *) 0);
+ MiscMenuItemCreate(optionM, NULL, "cmdSticky", _("Stic&ky ..."),
+ ACCL_STICKY, (void*) (wMenuCallBack_p) DoSticky, IC_MODETRAIN_TOO,
+ (void *) 0);
if (extraButtons) {
menuPLs[menuPG.paramCnt].context = debugW;
- MiscMenuItemCreate( optionM, NULL, "cmdDebug", _("&Debug ..."), 0, (void*)(wMenuCallBack_p)DebugInit, IC_MODETRAIN_TOO, (void *)0 );
+ MiscMenuItemCreate(optionM, NULL, "cmdDebug", _("&Debug ..."), 0,
+ (void*) (wMenuCallBack_p) DebugInit, IC_MODETRAIN_TOO, (void *) 0);
}
- MiscMenuItemCreate( optionM, NULL, "cmdPref", _("&Preferences ..."), ACCL_PREFERENCES, (void*)PrefInit(), IC_MODETRAIN_TOO, (void *)0 );
- MiscMenuItemCreate( optionM, NULL, "cmdColor", _("&Colors ..."), ACCL_COLORW, (void*)ColorInit(), IC_MODETRAIN_TOO, (void *)0 );
+ MiscMenuItemCreate(optionM, NULL, "cmdPref", _("&Preferences ..."),
+ ACCL_PREFERENCES, (void*) PrefInit(), IC_MODETRAIN_TOO, (void *) 0);
+ MiscMenuItemCreate(optionM, NULL, "cmdColor", _("&Colors ..."), ACCL_COLORW,
+ (void*) ColorInit(), IC_MODETRAIN_TOO, (void *) 0);
/*
* MACRO MENU
*/
- wMenuPushCreate( macroM, "cmdRecord", _("&Record ..."), ACCL_RECORD, DoRecord, NULL );
- wMenuPushCreate( macroM, "cmdDemo", _("&Play Back ..."), ACCL_PLAYBACK, DoPlayBack, NULL );
-
+ wMenuPushCreate(macroM, "cmdRecord", _("&Record ..."), ACCL_RECORD,
+ DoRecord, NULL);
+ wMenuPushCreate(macroM, "cmdDemo", _("&Play Back ..."), ACCL_PLAYBACK,
+ DoPlayBack, NULL);
/*
* WINDOW MENU
*/
- wMenuPushCreate( windowM, "menuWindow", _("Main window"), 0, (wMenuCallBack_p)wShow, mainW );
- winList_mi = wMenuListCreate( windowM, "menuWindow", -1, DoShowWindow );
+ wMenuPushCreate(windowM, "menuWindow", _("Main window"), 0,
+ (wMenuCallBack_p) wShow, mainW);
+ winList_mi = wMenuListCreate(windowM, "menuWindow", -1, DoShowWindow);
/*
* HELP MENU
*/
/* main help window */
- wMenuAddHelp( helpM );
+ wMenuAddHelp(helpM);
/* help on recent messages */
- wMenuSeparatorCreate( helpM );
- messageListM = wMenuMenuCreate( helpM, "menuHelpRecentMessages", _("Recent Messages") );
- messageList_ml = wMenuListCreate( messageListM, "messageListM", 10, ShowMessageHelp );
- wMenuListAdd( messageList_ml, 0, _(MESSAGE_LIST_EMPTY), NULL );
+ wMenuSeparatorCreate(helpM);
+ messageListM = wMenuMenuCreate(helpM, "menuHelpRecentMessages",
+ _("Recent Messages"));
+ messageList_ml = wMenuListCreate(messageListM, "messageListM", 10,
+ ShowMessageHelp);
+ wMenuListAdd(messageList_ml, 0, _(MESSAGE_LIST_EMPTY), NULL);
/* tip of the day */
wMenuSeparatorCreate( helpM );
wMenuPushCreate( helpM, "cmdTip", _("Tip of the Day..."), 0, (wMenuCallBack_p)ShowTip, (void *)(SHOWTIP_FORCESHOW | SHOWTIP_NEXTTIP));
demoM = wMenuMenuCreate( helpM, "cmdDemo", _("&Demos") );
+ wMenuPushCreate( helpM, "cmdExamples", _("Examples..."), 0, (wMenuCallBack_p)ChkExamples, (void *)0);
/* about window */
- wMenuSeparatorCreate( helpM );
- wMenuPushCreate( helpM, "about", _("About"), 0, (wMenuCallBack_p)CreateAboutW, NULL );
+ wMenuSeparatorCreate(helpM);
+ wMenuPushCreate(helpM, "about", _("About"), 0,
+ (wMenuCallBack_p) CreateAboutW, NULL);
/*
* MANAGE MENU
*/
- cmdGroup = BG_TRAIN|BG_BIGGAP;
- InitCmdTrain( manageM );
- wMenuSeparatorCreate( manageM );
+ cmdGroup = BG_TRAIN | BG_BIGGAP;
+ InitCmdTrain(manageM);
+ wMenuSeparatorCreate(manageM);
+
+ InitNewTurn(
+ wMenuMenuCreate(manageM, "cmdTurnoutNew",
+ _("Tur&nout Designer...")));
- InitNewTurn( wMenuMenuCreate( manageM, "cmdTurnoutNew", _("Tur&nout Designer...") ) );
+ MiscMenuItemCreate(manageM, NULL, "cmdContmgm",
+ _("Layout &Control Elements"), ACCL_CONTMGM,
+ (void*) ControlMgrInit(), 0, (void*) 0);
+ MiscMenuItemCreate(manageM, NULL, "cmdGroup", _("&Group"), ACCL_GROUP,
+ (void*) (wMenuCallBack_p) DoGroup, IC_SELECTED, (void *) 0);
+ MiscMenuItemCreate(manageM, NULL, "cmdUngroup", _("&Ungroup"), ACCL_UNGROUP,
+ (void*) (wMenuCallBack_p) DoUngroup, IC_SELECTED, (void *) 0);
- MiscMenuItemCreate( manageM, NULL, "cmdContmgm", _("Layout &Control Elements"), ACCL_CONTMGM,(void*)ControlMgrInit(),0,(void*) 0);
- MiscMenuItemCreate( manageM, NULL, "cmdGroup", _("&Group"), ACCL_GROUP, (void*)(wMenuCallBack_p)DoGroup, IC_SELECTED, (void *)0 );
- MiscMenuItemCreate( manageM, NULL, "cmdUngroup", _("&Ungroup"), ACCL_UNGROUP, (void*)(wMenuCallBack_p)DoUngroup, IC_SELECTED, (void *)0 );
+ MiscMenuItemCreate(manageM, NULL, "cmdCustmgm",
+ _("Custom defined parts..."), ACCL_CUSTMGM, (void*) CustomMgrInit(),
+ 0, (void *) 0);
+ MiscMenuItemCreate(manageM, NULL, "cmdRefreshCompound",
+ _("Update Turnouts and Structures"), 0,
+ (void*) (wMenuCallBack_p) DoRefreshCompound, 0, (void *) 0);
- MiscMenuItemCreate( manageM, NULL, "cmdCustmgm", _("Custom defined parts..."), ACCL_CUSTMGM, (void*)CustomMgrInit(), 0, (void *)0 );
- MiscMenuItemCreate( manageM, NULL, "cmdRefreshCompound", _("Update Turnouts and Structures"), 0, (void*)(wMenuCallBack_p)DoRefreshCompound, 0, (void *)0 );
+ MiscMenuItemCreate(manageM, NULL, "cmdCarInventory", _("Car Inventory"),
+ ACCL_CARINV, (void*) (wMenuCallBack_p) DoCarDlg, IC_MODETRAIN_TOO,
+ (void *) 0);
- MiscMenuItemCreate( manageM, NULL, "cmdCarInventory", _("Car Inventory"), ACCL_CARINV, (void*)(wMenuCallBack_p)DoCarDlg, IC_MODETRAIN_TOO, (void *)0 );
+ wMenuSeparatorCreate(manageM);
- wMenuSeparatorCreate( manageM );
+ MiscMenuItemCreate(manageM, NULL, "cmdLayer", _("Layers ..."), ACCL_LAYERS,
+ (void*) InitLayersDialog(), 0, (void *) 0);
+ wMenuSeparatorCreate(manageM);
- MiscMenuItemCreate( manageM, NULL, "cmdLayer", _("Layers ..."), ACCL_LAYERS, (void*)InitLayersDialog(), 0, (void *)0 );
- wMenuSeparatorCreate( manageM );
+ MiscMenuItemCreate(manageM, NULL, "cmdEnumerate", _("Parts &List ..."),
+ ACCL_PARTSLIST, (void*) (wMenuCallBack_p) EnumerateTracks, 0,
+ (void *) 0);
+ MiscMenuItemCreate(manageM, NULL, "cmdPricelist", _("Price List..."),
+ ACCL_PRICELIST, (void*) PriceListInit(), 0, (void *) 0);
- MiscMenuItemCreate( manageM, NULL, "cmdEnumerate", _("Parts &List ..."), ACCL_PARTSLIST, (void*)(wMenuCallBack_p)EnumerateTracks, 0, (void *)0 );
- MiscMenuItemCreate( manageM, NULL, "cmdPricelist", _("Price List..."), ACCL_PRICELIST, (void*)PriceListInit(), 0, (void *)0 );
+ cmdGroup = BG_LAYER | BG_BIGGAP;
+
+ InitCmdSelect2(changeM);
+ InitCmdDescribe2(changeM);
+ InitCmdPan2(changeM);
- cmdGroup = BG_LAYER|BG_BIGGAP;
InitLayers();
cmdGroup = BG_HOTBAR;
@@ -2459,51 +2697,73 @@ static void CreateMenus( void )
wAttachAccelKey( wAccelKey_Del, WKEY_SHIFT, (wAccelKeyCallBack_p)EditCut, 0 );
wAttachAccelKey( wAccelKey_F6, 0, (wAccelKeyCallBack_p)NextWindow, 0 );
#endif
- SetAccelKey( "zoomUp", wAccelKey_Pgdn, 0, (wAccelKeyCallBack_p)DoZoomUp, (void*)1 );
- SetAccelKey( "zoomDown", wAccelKey_Pgup, 0, (wAccelKeyCallBack_p)DoZoomDown, (void*)1 );
- SetAccelKey( "redraw", wAccelKey_F5, 0, (wAccelKeyCallBack_p)MainRedraw, (void*)1 );
- SetAccelKey( "delete", wAccelKey_Del, 0, (wAccelKeyCallBack_p)SelectDelete, (void*)1 );
- SetAccelKey( "copy", wAccelKey_Ins, WKEY_CTRL, (wAccelKeyCallBack_p)EditCopy, 0 );
- SetAccelKey( "paste", wAccelKey_Ins, WKEY_SHIFT, (wAccelKeyCallBack_p)EditPaste, 0 );
- SetAccelKey( "undo", wAccelKey_Back, WKEY_SHIFT, (wAccelKeyCallBack_p)UndoUndo, 0 );
- SetAccelKey( "cut", wAccelKey_Del, WKEY_SHIFT, (wAccelKeyCallBack_p)EditCut, 0 );
- SetAccelKey( "nextWindow", wAccelKey_F6, 0, (wAccelKeyCallBack_p)NextWindow, 0 );
- SetAccelKey( "zoomUp", wAccelKey_Numpad_Add, WKEY_CTRL, (wAccelKeyCallBack_p)DoZoomUp, (void*)1 );
- SetAccelKey( "zoomDown", wAccelKey_Numpad_Subtract, WKEY_CTRL, (wAccelKeyCallBack_p)DoZoomDown, (void*)1 );
+ SetAccelKey("zoomUp", wAccelKey_Pgdn, 0, (wAccelKeyCallBack_p) DoZoomUp,
+ (void*) 1);
+ SetAccelKey("zoomDown", wAccelKey_Pgup, 0, (wAccelKeyCallBack_p) DoZoomDown,
+ (void*) 1);
+ SetAccelKey("redraw", wAccelKey_F5, 0, (wAccelKeyCallBack_p) MainRedraw,
+ (void*) 1);
+ SetAccelKey("delete", wAccelKey_Del, 0, (wAccelKeyCallBack_p) SelectDelete,
+ (void*) 1);
+ SetAccelKey("copy", wAccelKey_Ins, WKEY_CTRL,
+ (wAccelKeyCallBack_p) EditCopy, 0);
+ SetAccelKey("paste", wAccelKey_Ins, WKEY_SHIFT,
+ (wAccelKeyCallBack_p) EditPaste, 0);
+ SetAccelKey("undo", wAccelKey_Back, WKEY_SHIFT,
+ (wAccelKeyCallBack_p) UndoUndo, 0);
+ SetAccelKey("cut", wAccelKey_Del, WKEY_SHIFT, (wAccelKeyCallBack_p) EditCut,
+ 0);
+ SetAccelKey("nextWindow", wAccelKey_F6, 0, (wAccelKeyCallBack_p) NextWindow,
+ 0);
+ SetAccelKey("zoomUp", wAccelKey_Numpad_Add, WKEY_CTRL,
+ (wAccelKeyCallBack_p) DoZoomUp, (void*) 1);
+ SetAccelKey("zoomDown", wAccelKey_Numpad_Subtract, WKEY_CTRL,
+ (wAccelKeyCallBack_p) DoZoomDown, (void*) 1);
+ SetAccelKey("help", wAccelKey_F1, WKEY_SHIFT,
+ (wAccelKeyCallBack_p) wDoAccelHelp, (void*) 1);
+ SetAccelKey("help-context", wAccelKey_F1, 0,
+ (wAccelKeyCallBack_p) wDoAccelHelp, (void*) 3);
InitBenchDialog();
+ wPrefGetInteger( "DialogItem", "sticky-set", &stickySet, stickySet );
}
-
-static void LoadFileList( void )
-{
+static void LoadFileList(void) {
char file[6];
int inx;
const char * cp;
const char *fileName, *pathName;
- strcpy( file, "fileX" );
- for (inx=NUM_FILELIST-1; inx>=0; inx--) {
- file[4] = '0'+inx;
- cp = wPrefGetString( "filelist", file );
+ strcpy(file, "fileX");
+ for (inx = NUM_FILELIST - 1; inx >= 0; inx--) {
+ file[4] = '0' + inx;
+ cp = wPrefGetString("filelist", file);
if (!cp)
continue;
pathName = MyStrdup(cp);
- fileName = FindFilename((char *)pathName);
+ fileName = FindFilename((char *) pathName);
if (fileName)
- wMenuListAdd( fileList_ml, 0, fileName, pathName );
+ wMenuListAdd(fileList_ml, 0, fileName, pathName);
}
}
-EXPORT void InitCmdEnumerate( void )
-{
- AddToolbarButton( "cmdEnumerate", wIconCreatePixMap(partlist_xpm), IC_SELECTED|IC_ACCLKEY, (addButtonCallBack_t)EnumerateTracks, NULL );
+EXPORT void InitCmdEnumerate(void) {
+ AddToolbarButton("cmdEnumerate", wIconCreatePixMap(partlist_xpm),
+ IC_SELECTED | IC_ACCLKEY, (addButtonCallBack_t) EnumerateTracks,
+ NULL);
}
-
-EXPORT void InitCmdExport( void )
-{
- AddToolbarButton( "cmdExport", wIconCreatePixMap(export_xpm), IC_SELECTED|IC_ACCLKEY, (addButtonCallBack_t)DoExport, NULL );
- AddToolbarButton( "cmdImport", wIconCreatePixMap(import_xpm), IC_ACCLKEY, (addButtonCallBack_t)DoImport, NULL );
+EXPORT void InitCmdExport(void) {
+ ButtonGroupBegin( _("Import/Export"), "cmdExportImportSetCmd", _("Import/Export") );
+ cmdGroup = BG_EXPORTIMPORT;
+ AddToolbarButton("cmdExport", wIconCreatePixMap(export_xpm),
+ IC_SELECTED | IC_ACCLKEY, (addButtonCallBack_t) DoExport, NULL);
+ AddToolbarButton("cmdExportDXF", wIconCreatePixMap(export_dxf_xpm), IC_SELECTED | IC_ACCLKEY,
+ (addButtonCallBack_t)DoExportDXF, (void*)1);
+ AddToolbarButton("cmdImport", wIconCreatePixMap(import_xpm), IC_ACCLKEY,
+ (addButtonCallBack_t) DoImport, (void*)0);
+ AddToolbarButton("cmdImportModule", wIconCreatePixMap(importmod_xpm), IC_ACCLKEY,
+ (addButtonCallBack_t) DoImport, (void*)1);
+ ButtonGroupEnd();
}
/* Give user the option to continue work after crash. This function gives the user
@@ -2514,27 +2774,34 @@ EXPORT void InitCmdExport( void )
*
*/
+
static int OfferCheckpoint( void )
{
int ret = FALSE;
/* sProdName */
- ret = wNoticeEx( NT_INFORMATION,
- _("Program was not terminated properly. Do you want to resume working on the previous trackplan?"),
- _("Resume"), _("Ignore") );
- if( ret ) {
+ ret =
+ wNotice3(
+ _(
+ "Program was not terminated properly. Do you want to resume working on the previous trackplan?"),
+ _("Resume"), _("Resume with New Name"), _("Ignore Checkpoint"));
+ //ret==1 Same, ret==-1 New, ret==0 Ignore
+ if (ret == 1)
+ printf(_("Reload Checkpoint Selected\n"));
+ else if (ret == -1)
+ printf(_("Reload Checkpoint With New Name Selected\n"));
+ else
+ printf(_("Ignore Checkpoint Selected\n"));
+ if (ret>=0) {
/* load the checkpoint file */
- LoadCheckpoint();
+ LoadCheckpoint(ret==1);
ret = TRUE;
+
}
- return ret;
+ return (ret>=0);
}
-
-EXPORT wWin_p wMain(
- int argc,
- char * argv[] )
-{
+EXPORT wWin_p wMain(int argc, char * argv[]) {
int c;
int resumeWork;
char * logFileName = NULL;
@@ -2547,12 +2814,12 @@ EXPORT wWin_p wMain(
long newToolbarMax;
char *cp;
char *oldLocale = NULL;
- char buffer[ STR_SIZE ];
+ char buffer[STR_SIZE];
unsigned int i;
- wPos_t displayWidth;
- wPos_t displayHeight;
+ wPos_t displayWidth;
+ wPos_t displayHeight;
- strcpy( buffer, sProdNameLower );
+ strcpy(buffer, sProdNameLower);
/* Initialize application name */
wInitAppName(buffer);
@@ -2563,7 +2830,7 @@ EXPORT wWin_p wMain(
/* Save user locale */
oldLocale = setlocale(LC_ALL, NULL);
if (oldLocale)
- userLocale = strdup( oldLocale );
+ userLocale = strdup(oldLocale);
/*
* ARGUMENTS
@@ -2571,89 +2838,107 @@ EXPORT wWin_p wMain(
opterr = 0;
- while ((c = getopt (argc, argv, "vl:d:c:")) != -1)
- switch (c) {
- case 'c': /* configuration name */
+ while ((c = getopt(argc, argv, "vl:d:c:m")) != -1)
+ switch (c) {
+ case 'c': /* configuration name */
/* test for valid filename */
- for( i = 0; i < strlen( optarg ); i++ ) {
- if( !isalnum( (unsigned char)optarg[ i ]) && optarg[ i ] != '.' ) {
- NoticeMessage( MSG_BAD_OPTION, _("Ok"), NULL, optarg );
- exit( 1 );
+ for (i = 0; i < strlen(optarg); i++) {
+ if (!isalnum((unsigned char) optarg[i]) && optarg[i] != '.') {
+ NoticeMessage(MSG_BAD_OPTION, _("Ok"), NULL, optarg);
+ exit(1);
}
}
/* append delimiter and argument to configuration name */
- if( strlen( optarg ) < STR_SIZE - strlen( ";" ) - strlen( buffer ) - 1 ){
- strcat( buffer, ";" );
- strcat( buffer, optarg );
- }
- else {
- NoticeMessage( MSG_BAD_OPTION, _("Ok"), NULL, optarg );
- exit( 1 );
+ if (strlen(optarg) < STR_SIZE - strlen(";") - strlen(buffer) - 1) {
+ strcat(buffer, ";");
+ strcat(buffer, optarg);
+ } else {
+ NoticeMessage(MSG_BAD_OPTION, _("Ok"), NULL, optarg);
+ exit(1);
}
break;
- case 'v': /* verbose flag */
+ case 'v': /* verbose flag */
verbose++;
- break;
- case 'd': /* define loglevel for a group */
- cp = strchr( optarg, '=' );
- if ( cp != NULL ) {
+ break;
+ case 'd': /* define loglevel for a group */
+ cp = strchr(optarg, '=');
+ if (cp != NULL) {
*cp++ = '\0';
- LogSet( optarg, atoi(cp) );
+ LogSet(optarg, atoi(cp));
} else {
- LogSet( optarg, 1 );
+ LogSet(optarg, 1);
}
break;
- case 'l': /* define log filename */
+ case 'l': /* define log filename */
logFileName = strdup(optarg);
break;
- case '?':
- NoticeMessage( MSG_BAD_OPTION, _("Ok"), NULL, argv[ optind - 1 ] );
- exit( 1 );
+ case '?':
+ NoticeMessage(MSG_BAD_OPTION, _("Ok"), NULL, argv[optind - 1]);
+ exit(1);
+ case 'm': // temporary: use MainRedraw instead of TempRedraw
+ wDrawDoTempDraw = FALSE;
+ break;
case ':':
- NoticeMessage( "Missing parameter for %s", _("Ok"), NULL, argv[ optind - 1 ] );
- exit( 1 );
+ NoticeMessage("Missing parameter for %s", _("Ok"), NULL,
+ argv[optind - 1]);
+ exit(1);
break;
- default:
- abort ();
- }
- if( optind < argc )
- initialFile = strdup( argv[ optind ] );
+ default:
+ abort();
+ }
+ if (optind < argc)
+ initialFile = strdup(argv[optind]);
- extraButtons = ( getenv(sEnvExtra) != NULL );
- LogOpen( logFileName );
- log_init = LogFindIndex( "init" );
- log_malloc = LogFindIndex( "malloc" );
- log_error = LogFindIndex( "error" );
- log_command = LogFindIndex( "command" );
+ extraButtons = (getenv(sEnvExtra) != NULL);
+ LogOpen(logFileName);
+ log_init = LogFindIndex("init");
+ log_malloc = LogFindIndex("malloc");
+ log_error = LogFindIndex("error");
+ log_command = LogFindIndex("command");
-LOG1( log_init, ( "initCustom\n" ) )
+ LOG1(log_init, ( "initCustom\n" ))
InitCustom();
/*
* MAIN WINDOW
*/
-LOG1( log_init, ( "create main window\n" ) )
- SetLayoutTitle( sProdName );
- sprintf( message, _("Unnamed Trackplan - %s(%s)"), sProdName, sVersion );
- wSetBalloonHelp( balloonHelp );
-
- wGetDisplaySize(&displayWidth, &displayHeight);
- mainW = wWinMainCreate( buffer, (displayWidth*2)/3, (displayHeight*2)/3, "xtrkcadW", message, "main",
- F_RESIZE|F_MENUBAR|F_NOTAB|F_RECALLPOS|F_HIDE,
- MainProc, NULL );
- if ( mainW == NULL )
+ LOG1(log_init, ( "create main window\n" ))
+ SetLayoutTitle(sProdName);
+ sprintf(message, _("Unnamed Trackplan - %s(%s)"), sProdName, sVersion);
+ wSetBalloonHelp(balloonHelp);
+
+ wGetDisplaySize(&displayWidth, &displayHeight);
+ mainW = wWinMainCreate(buffer, (displayWidth * 2) / 3,
+ (displayHeight * 2) / 3, "xtrkcadW", message, "main",
+ F_RESIZE | F_MENUBAR | F_NOTAB | F_RECALLPOS | F_RECALLSIZE | F_HIDE, MainProc,
+ NULL);
+ if (mainW == NULL)
return NULL;
InitAppDefaults();
-
drawColorBlack = wDrawFindColor( wRGB( 0, 0, 0) );
drawColorWhite = wDrawFindColor( wRGB(255,255,255) );
drawColorRed = wDrawFindColor( wRGB(255, 0, 0) );
drawColorBlue = wDrawFindColor( wRGB( 0, 0,255) );
drawColorGreen = wDrawFindColor( wRGB( 0,255, 0) );
drawColorAqua = wDrawFindColor( wRGB( 0,255,255) );
+
+ // Last component of spectial color must be > 3
+ drawColorPreviewSelected = wDrawFindColor( wRGB ( 6, 6, 255) ); //Special Blue
+ drawColorPreviewUnselected = wDrawFindColor( wRGB( 255, 215, 6)); //Special Yellow
+
+ drawColorPowderedBlue = wDrawFindColor( wRGB(129, 212, 250) );
drawColorPurple = wDrawFindColor( wRGB(255, 0,255) );
drawColorGold = wDrawFindColor( wRGB(255,215, 0) );
+ drawColorGrey10 = wDrawFindColor( wRGB(26,26,26) );
+ drawColorGrey20 = wDrawFindColor( wRGB(51,51,51) );
+ drawColorGrey30 = wDrawFindColor( wRGB(72,72,72) );
+ drawColorGrey40 = wDrawFindColor( wRGB(102,102,102) );
+ drawColorGrey50 = wDrawFindColor( wRGB(128,128,128) );
+ drawColorGrey60 = wDrawFindColor( wRGB(153,153,153) );
+ drawColorGrey70 = wDrawFindColor( wRGB(179,179,179) );
+ drawColorGrey80 = wDrawFindColor( wRGB(204,204,204) );
+ drawColorGrey90 = wDrawFindColor( wRGB(230,230,230) );
snapGridColor = drawColorGreen;
markerColor = drawColorRed;
borderColor = drawColorBlack;
@@ -2664,73 +2949,71 @@ LOG1( log_init, ( "create main window\n" ) )
elevColorIgnore = drawColorBlue;
elevColorDefined = drawColorGold;
profilePathColor = drawColorPurple;
- exceptionColor = wDrawFindColor( wRGB(255,0,128) );
- tieColor = wDrawFindColor( wRGB(255,128,0) );
+ exceptionColor = wDrawFindColor(wRGB(255, 89, 0 ));
+ tieColor = wDrawFindColor(wRGB(153, 89, 68));
- newToolbarMax = (1<<BG_COUNT)-1;
- wPrefGetInteger( "misc", "toolbarset", &toolbarSet, newToolbarMax );
- wPrefGetInteger( "misc", "max-toolbarset", &oldToolbarMax, 0 );
+ newToolbarMax = (1 << BG_COUNT) - 1;
+ wPrefGetInteger("misc", "toolbarset", &toolbarSet, newToolbarMax);
+ wPrefGetInteger("misc", "max-toolbarset", &oldToolbarMax, 0);
toolbarSet |= newToolbarMax & ~oldToolbarMax;
- wPrefSetInteger( "misc", "max-toolbarset", newToolbarMax );
- wPrefSetInteger( "misc", "toolbarset", toolbarSet );
+ wPrefSetInteger("misc", "max-toolbarset", newToolbarMax);
+ wPrefSetInteger("misc", "toolbarset", toolbarSet);
-LOG1( log_init, ( "fontInit\n"))
+ LOG1(log_init, ( "fontInit\n"))
wInitializeFonts();
-LOG1( log_init, ( "fileInit\n" ) )
+ LOG1(log_init, ( "fileInit\n" ))
FileInit();
- wCreateSplash( sProdName, sVersion );
+ wCreateSplash(sProdName, sVersion);
if (!initialFile) {
WDOUBLE_T tmp;
-LOG1( log_init, ( "set roomsize\n" ) )
- wPrefGetFloat( "draw", "roomsizeX", &tmp, 96.0 );
+ LOG1(log_init, ( "set roomsize\n" ))
+ wPrefGetFloat("draw", "roomsizeX", &tmp, 96.0);
roomSize.x = tmp;
- wPrefGetFloat( "draw", "roomsizeY", &tmp, 48.0 );
+ wPrefGetFloat("draw", "roomsizeY", &tmp, 48.0);
roomSize.y = tmp;
- SetRoomSize( roomSize );
+ SetRoomSize(roomSize);
}
/*
* INITIALIZE
*/
-LOG1( log_init, ( "initInfoBar\n" ) )
+ LOG1(log_init, ( "initInfoBar\n" ))
InitInfoBar();
- wSetSplashInfo( "Misc2 Init..." );
-LOG1( log_init, ( "misc2Init\n" ) )
+ wSetSplashInfo("Misc2 Init...");
+ LOG1(log_init, ( "misc2Init\n" ))
Misc2Init();
RotateDialogInit();
MoveDialogInit();
- wSetSplashInfo( _("Initializing commands") );
-LOG1( log_init, ( "paramInit\n" ) )
+ wSetSplashInfo(_("Initializing commands"));
+ LOG1(log_init, ( "paramInit\n" ))
ParamInit();
-LOG1( log_init, ( "initTrkTrack\n" ) )
+ LOG1(log_init, ( "initTrkTrack\n" ))
InitTrkTrack();
/*
* MENUS
*/
- wSetSplashInfo( _("Initializing menus") );
-LOG1( log_init, ( "createMenus\n" ) )
+ wSetSplashInfo(_("Initializing menus"));
+ LOG1(log_init, ( "createMenus\n" ))
CreateMenus();
-
-
-LOG1( log_init, ( "initialize\n" ) )
+ LOG1(log_init, ( "initialize\n" ))
if (!Initialize())
return NULL;
- ParamRegister( &menuPG );
- ParamRegister( &stickyPG );
+ ParamRegister(&menuPG);
+ ParamRegister(&stickyPG);
/* initialize the layers */
DefaultLayerProperties();
-LOG1( log_init, ( "loadFileList\n" ) )
+ LOG1(log_init, ( "loadFileList\n" ))
LoadFileList();
- AddPlaybackProc( "MENU", MenuPlayback, NULL );
+ AddPlaybackProc("MENU", MenuPlayback, NULL);
//CreateDebugW();
/*
@@ -2747,17 +3030,20 @@ LOG1( log_init, ( "loadFileList\n" ) )
} else {
HideHotBar();
}
-LOG1( log_init, ( "drawInit\n" ) )
- DrawInit( initialZoom );
+ LOG1(log_init, ( "drawInit\n" ))
+ DrawInit(initialZoom);
MacroInit();
- wSetSplashInfo( _("Reading parameter files") );
-LOG1( log_init, ( "paramFileInit\n" ) )
- if (!ParamFileInit())
+ wSetSplashInfo(_("Reading parameter files"));
+ LOG1(log_init, ( "paramFileInit\n" ))
+
+ SetParamFileDir(GetCurrentPath(LAYOUTPATHKEY)); //Set default for new parms to be the same as the layout
+
+ if (!ParamFileListInit())
return NULL;
curCommand = describeCmdInx;
-LOG1( log_init, ( "Reset\n" ) )
+ LOG1(log_init, ( "Reset\n" ))
Reset();
/*
@@ -2767,30 +3053,30 @@ LOG1( log_init, ( "Reset\n" ) )
/* Set up the data for scale and gauge description */
DoSetScaleDesc();
- // get the preferred scale from the configuration file
- pref = wPrefGetString( "misc", "scale" );
- if( !pref )
+ // get the preferred scale from the configuration file
+ pref = wPrefGetString("misc", "scale");
+ if (!pref)
// if preferred scale was not set (eg. during initial run), initialize to a default value
pref = DEFAULT_SCALE;
- strcpy( buffer, pref );
- DoSetScale( buffer );
+ strcpy(buffer, pref);
+ DoSetScale(buffer);
/* see whether last layout should be reopened on startup */
- wPrefGetInteger( "DialogItem", "pref-onstartup", &onStartup, 0 );
+ wPrefGetInteger("DialogItem", "pref-onstartup", &onStartup, 0);
/*
* THE END
*/
-LOG1( log_init, ( "the end\n" ) )
+ LOG1(log_init, ( "the end\n" ))
EnableCommands();
-LOG1( log_init, ( "Initialization complete\n" ) )
- wSetSplashInfo( _("Initialization complete") );
- RegisterChangeNotification( ToolbarChange );
- DoChangeNotification( CHANGE_MAIN|CHANGE_MAP );
+ LOG1(log_init, ( "Initialization complete\n" ))
+ wSetSplashInfo(_("Initialization complete"));
+ RegisterChangeNotification(ToolbarChange);
+ DoChangeNotification( CHANGE_MAIN | CHANGE_MAP);
- wWinShow( mainW, TRUE );
- wWinShow( mapW, mapVisible );
+ wWinShow(mainW, TRUE);
+ wWinShow(mapW, mapVisible);
wDestroySplash();
/* this has to be called before ShowTip() */
@@ -2800,20 +3086,28 @@ LOG1( log_init, ( "Initialization complete\n" ) )
/* check for existing checkpoint file */
resumeWork = FALSE;
- if (ExistsCheckpoint())
+ if (ExistsCheckpoint()) {
resumeWork = OfferCheckpoint();
+ MainRedraw();
+ }
if (!resumeWork) {
- /* if work is to be resumed and no filename was given on startup, load last layout */
+ /* if work is not to be resumed and no filename was given on startup, load last layout */
if ((onStartup == 0) && (!initialFile || !strlen(initialFile))) {
+ long iExample;
initialFile = (char*)wPrefGetString("misc", "lastlayout");
+ wPrefGetInteger("misc", "lastlayoutexample", &iExample, 0);
+ bExample = (iExample == 1);
}
if (initialFile && strlen(initialFile)) {
- DoFileList(0, NULL, initialFile);
+ DoFileList(0, NULL, initialFile); //Will load Background values, if archive
+ if (onStartup == 1)
+ LayoutBackGroundInit(TRUE); //Wipe Out Prior Background
+ else
+ LayoutBackGroundInit(FALSE); //Get Prior BackGround
}
}
inMainW = FALSE;
return mainW;
}
-
diff --git a/app/bin/misc.h b/app/bin/misc.h
index 2fb3359..2be0be2 100644
--- a/app/bin/misc.h
+++ b/app/bin/misc.h
@@ -44,6 +44,7 @@ typedef void (*addButtonCallBack_t)(void*);
#define STR_SIZE (256)
#define STR_SHORT_SIZE (80)
#define STR_LONG_SIZE (1024)
+#define STR_HUGE_SIZE (10240)
#define CAST_AWAY_CONST (char*)
@@ -68,15 +69,17 @@ extern long hideSelectionWindow;
extern long labelWhen;
extern long labelScale;
extern long labelEnable;
-extern long colorLayers;
+extern long colorTrack;
+extern long colorDraw;
extern long carHotbarModeInx;
extern DIST_T minLength;
extern DIST_T connectDistance;
extern ANGLE_T connectAngle;
extern long twoRailScale;
extern long mapScale;
-extern long zoomCorner;
+extern long constrainMain;
extern long checkPtInterval;
+extern long autosaveChkPoints;
extern long liveMap;
extern long preSelect;
extern long hideTrainsInTunnels;
@@ -91,8 +94,11 @@ extern DIST_T curScaleRatio;
extern char * curScaleName;
extern int enumerateMaxDescLen;
extern long enableBalloonHelp;
+extern long showFlexTrack;
extern long hotBarLabels;
extern long rightClickMode;
+extern long selectMode;
+extern long selectZero;
extern void * commandContext;
extern coOrd cmdMenuPos;
#define MODE_DESIGN (0)
@@ -136,6 +142,12 @@ extern long programMode;
#define C_TEXT wActionText
#define C_WUP wActionWheelUp
#define C_WDOWN wActionWheelDown
+#define C_LDOUBLE wActionLDownDouble
+#define C_MODKEY wActionModKey
+#define C_SCROLLUP wActionScrollUp
+#define C_SCROLLDOWN wActionScrollDown
+#define C_SCROLLLEFT wActionScrollLeft
+#define C_SCROLLRIGHT wActionScrollRight
#define C_INIT (wActionLast+1)
#define C_START (wActionLast+2)
#define C_REDRAW (wActionLast+3)
@@ -146,6 +158,7 @@ extern long programMode;
#define C_RCLICK (wActionLast+8)
#define C_CMDMENU (wActionLast+9)
#define C_FINISH (wActionLast+10)
+#define C_UPDATE (wActionLast+11)
#define C_CONTINUE (100)
#define C_TERMINATE (101)
@@ -180,7 +193,7 @@ extern wPos_t DlgSepFrmBottom;
extern wWin_p mainW;
extern wPos_t toolbarHeight;
extern wIndex_t changed;
-extern char message[STR_LONG_SIZE];
+extern char message[STR_HUGE_SIZE];
extern REGION_T curRegion;
extern long paramVersion;
extern coOrd zero;
@@ -189,6 +202,7 @@ extern wButton_p undoB;
extern wButton_p redoB;
extern wButton_p zoomUpB; /** ZoomUp button on toolbar */
extern wButton_p zoomDownB; /** ZoomDown button on toolbar */
+extern wButton_p backgroundB; /** background visibility control */
// extern wButton_p easementB;
extern wIndex_t checkPtMark;
extern wMenu_p demoM;
@@ -221,9 +235,11 @@ int NoticeMessage( char *, char*, char *, ... );
int NoticeMessage2( int, char *, char*, char *, ... );
void DoQuit( void );
+void FileIsChanged(void);
char * ConvertFromEscapedText(const char * text);
char * ConvertToEscapedText(const char * text);
+int MagneticSnap( int state );
void wShow( wWin_p );
void wHide( wWin_p );
void CloseDemoWindows( void );
@@ -232,28 +248,34 @@ void SelectFont();
void CheckRoomSize( BOOL_T );
const char * GetBalloonHelpStr( char* );
+const char * GetCurCommandName( void );
void EnableCommands( void );
void Reset( void );
+wIndex_t GetCurrentCommand(void);
+BOOL_T IsCurCommandSticky(void);
void ResetIfNotSticky( void );
wBool_t DoCurCommand( wAction_t, coOrd );
void ConfirmReset( BOOL_T );
void LayoutToolBar( void * );
-#define IC_STICKY (1<<0)
-#define IC_CANCEL (1<<1)
-#define IC_MENU (1<<2)
-#define IC_NORESTART (1<<3)
-#define IC_SELECTED (1<<4)
-#define IC_POPUP (1<<5)
-#define IC_LCLICK (1<<6)
-#define IC_RCLICK (1<<7)
-#define IC_CMDMENU (1<<8)
-#define IC_POPUP2 (1<<9)
-#define IC_ABUT (1<<10)
-#define IC_ACCLKEY (1<<11)
-#define IC_MODETRAIN_TOO (1<<12)
-#define IC_MODETRAIN_ONLY (1<<13)
-#define IC_WANT_MOVE (1<<14)
-#define IC_PLAYBACK_PUSH (1<<15)
+#define IC_STICKY (1<<0)
+#define IC_INITNOTSTICKY (1<<1)
+#define IC_CANCEL (1<<2)
+#define IC_MENU (1<<3)
+#define IC_NORESTART (1<<4)
+#define IC_SELECTED (1<<5)
+#define IC_POPUP (1<<6)
+#define IC_LCLICK (1<<7)
+#define IC_RCLICK (1<<8)
+#define IC_CMDMENU (1<<9)
+#define IC_POPUP2 (1<<10)
+#define IC_ABUT (1<<11)
+#define IC_ACCLKEY (1<<12)
+#define IC_MODETRAIN_TOO (1<<13)
+#define IC_MODETRAIN_ONLY (1<<14)
+#define IC_WANT_MOVE (1<<15)
+#define IC_PLAYBACK_PUSH (1<<16)
+#define IC_WANT_MODKEYS (1<<17)
+#define IC_POPUP3 (1<<18)
wIndex_t InitCommand( wMenu_p, procCommand_t, char *, char *, int, long, long );
void AddToolbarControl( wControl_p, long );
BOOL_T CommandEnabled( wIndex_t );
@@ -278,22 +300,25 @@ void InitDebug( char *, long * );
#define CHANGE_MAIN (1<<2)
#define CHANGE_MAP (1<<4)
#define CHANGE_GRID (1<<5)
+#define CHANGE_BACKGROUND (1<<6)
#define CHANGE_UNITS (1<<7)
#define CHANGE_TOOLBAR (1<<8)
#define CHANGE_CMDOPT (1<<9)
#define CHANGE_LIMITS (1<<10)
-#define CHANGE_ALL (CHANGE_SCALE|CHANGE_PARAMS|CHANGE_MAIN|CHANGE_MAP|CHANGE_UNITS|CHANGE_TOOLBAR|CHANGE_CMDOPT)
+#define CHANGE_ALL (CHANGE_SCALE|CHANGE_PARAMS|CHANGE_MAIN|CHANGE_MAP|CHANGE_UNITS|CHANGE_TOOLBAR|CHANGE_CMDOPT|CHANGE_BACKGROUND)
typedef void (*changeNotificationCallBack_t)( long );
void RegisterChangeNotification( changeNotificationCallBack_t );
void DoChangeNotification( long );
+wBool_t CheckHelpTopicExists(const char * topic);
+
/* foreign externs */
extern drawCmd_t mapD;
extern STATUS_T CmdEnumerate( wAction_t, coOrd );
-wIndex_t modifyCmdInx;
-wIndex_t joinCmdInx;
-wIndex_t tunnelCmdInx;
+extern wIndex_t modifyCmdInx;
+extern wIndex_t joinCmdInx;
+extern wIndex_t tunnelCmdInx;
/* ctodesgn.c */
void InitNewTurn( wMenu_p m );
@@ -308,7 +333,7 @@ STATUS_T ModifyRuler( wAction_t, coOrd );
/* dialogs */
void OutputBitMap( void );
-wDrawColor snapGridColor;
+extern wDrawColor snapGridColor;
addButtonCallBack_t ColorInit( void );
addButtonCallBack_t PrefInit( void );
@@ -330,9 +355,8 @@ void InitSnapGridButtons( void );
void SnapGridEnable( void );
void SnapGridShow( void );
void MapWindowShow( int state );
-wMenuToggle_p snapGridEnableMI;
-wMenuToggle_p snapGridShowMI;
-wMenuToggle_p mapShowMI;
+extern wMenuToggle_p snapGridEnableMI;
+extern wMenuToggle_p snapGridShowMI;
void ScaleLengthEnd( void );
void EnumerateList( long, FLOAT_T, char * );
@@ -343,6 +367,8 @@ void EnumerateEnd(void);
void DoNote( void );
BOOL_T WriteMainNote( FILE * );
+BOOL_T ReadMainNote(char * line);
+
/* dbench.c */
long GetBenchData( long, long );
wIndex_t GetBenchListIndex( long );
@@ -360,7 +386,7 @@ long BenchOutputOption( long );
DIST_T BenchGetWidth( long );
/* dcustmgm.c */
-FILE * customMgmF;
+extern FILE * customMgmF;
#define CUSTMGM_DO_COPYTO (1)
#define CUSTMGM_CAN_EDIT (2)
#define CUSTMGM_DO_EDIT (3)
@@ -389,6 +415,7 @@ void ContMgmLoad (wIcon_p,contMgmCallBack_p,void *);
/* dlayer.c */
void LayerSetCounts();
+int FindUnusedLayer(unsigned int start);
void DecrementLayerObjects(unsigned int index);
void IncrementLayerObjects(unsigned int index);
@@ -418,4 +445,8 @@ void InitCmdControl ( wMenu_p menu );
/* csensor.c */
void SensorMgmLoad ( void );
void InitCmdSensor ( wMenu_p menu );
+/* cmodify.c */
+STATUS_T CmdModify(wAction_t action,coOrd pos );
+
+
#endif
diff --git a/app/bin/misc2.c b/app/bin/misc2.c
index 0dbb57d..19226cc 100644
--- a/app/bin/misc2.c
+++ b/app/bin/misc2.c
@@ -53,15 +53,17 @@
EXPORT long units = 0; /**< measurement units: 0 = English, 1 = metric */
EXPORT long checkPtInterval = 10;
+EXPORT long autosaveChkPoints = 2;
EXPORT DIST_T curScaleRatio;
EXPORT char * curScaleName;
EXPORT DIST_T trackGauge;
EXPORT long labelScale = 8;
-EXPORT long labelEnable = ((1<<0)|LABELENABLE_LENGTHS|LABELENABLE_ENDPT_ELEV|LABELENABLE_CARS);
+EXPORT long labelEnable = (LABELENABLE_ENDPT_ELEV|LABELENABLE_CARS);
EXPORT long labelWhen = 2;
-EXPORT long colorLayers = 0;
-EXPORT long zoomCorner = 0;
+EXPORT long colorTrack = 0;
+EXPORT long colorDraw = 0;
+EXPORT long constrainMain = 0;
EXPORT long hideSelectionWindow = 0;
EXPORT long angleSystem = 0;
EXPORT DIST_T minLength = 0.1;
@@ -156,10 +158,6 @@ EXPORT void DoChangeNotification( long changes )
*
*/
-
-#define SCALE_ANY (-2)
-#define SCALE_DEMO (-1)
-
typedef struct {
char * scale;
DIST_T ratio;
@@ -467,7 +465,9 @@ SetScale( SCALEINX_T newScaleInx )
SetScaleDescGauge((SCALEINX_T)newScaleInx);
- wPrefSetString( "misc", "scale", curScaleName );
+
+ if (!inPlayback)
+ wPrefSetString( "misc", "scale", curScaleName );
// now load the minimum radius for the newly selected scale
LoadLayoutMinRadiusPref(curScaleName, curScale->R[0]);
diff --git a/app/bin/misc2.h b/app/bin/misc2.h
index d616ad8..966f75b 100644
--- a/app/bin/misc2.h
+++ b/app/bin/misc2.h
@@ -42,7 +42,7 @@ typedef struct {
} logTable_t;
extern dynArr_t logTable_da;
#define logTable(N) DYNARR_N( logTable_t, logTable_da, N )
-time_t logClock;
+extern time_t logClock;
void LogOpen( char * );
void LogClose( void );
void LogSet( char *, int );
@@ -85,13 +85,19 @@ void LoadGaugeList( wList_p, SCALEDESCINX_T );
BOOL_T CompatibleScale( BOOL_T, SCALEINX_T, SCALEINX_T );
BOOL_T DoSetScaleDesc( void );
-unsigned int curLayer;
-long layerCount;
+extern unsigned int curLayer;
+extern long layerCount;
+void SetCurrLayer(wIndex_t inx, const char * name, wIndex_t op,
+ void * listContext, void * arg);
wDrawColor GetLayerColor( unsigned int );
+BOOL_T GetLayerUseColor( unsigned int);
BOOL_T GetLayerVisible( unsigned int );
BOOL_T GetLayerFrozen( unsigned int );
BOOL_T GetLayerOnMap( unsigned int );
+BOOL_T GetLayerModule( unsigned int );
+void SetLayerModule(unsigned int, BOOL_T);
char * GetLayerName( unsigned int );
+void SetLayerName(unsigned int layer, char* name);
BOOL_T ReadLayers( char * );
BOOL_T WriteLayers( FILE * );
char * FormatLayerName(unsigned int layerNumber);
@@ -103,7 +109,7 @@ void SaveLayers( void );
void RestoreLayers( void );
void LoadLayerLists( void );
addButtonCallBack_t InitLayersDialog( void );
-
+void FillLayerList(wList_p layerList);
void Misc2Init( void );
#endif
diff --git a/app/bin/note.h b/app/bin/note.h
new file mode 100644
index 0000000..315823f
--- /dev/null
+++ b/app/bin/note.h
@@ -0,0 +1,110 @@
+/** \file note.h
+ * Common definitions for notes
+ */
+
+ /* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef HAVE_NOTE_H
+#define HAVE_NOTE_H
+#include <stdbool.h>
+#include "track.h"
+
+#define URLMAXIMUMLENGTH (512)
+#define PATHMAXIMUMLENGTH (2048)
+#define TITLEMAXIMUMLENGTH (81)
+
+#define MYMIN(x, y) (((x) < (y)) ? (x) : (y))
+
+#define DELIMITER "--|--"
+
+enum noteCommands {
+ OP_NOTETEXT,
+ OP_NOTELINK,
+ OP_NOTEFILE
+};
+
+/** hold the data for the note */
+struct extraDataNote {
+ coOrd pos; /**< position */
+ unsigned int layer;
+ enum noteCommands op; /**< note type */
+ track_p trk; /**< track */
+ union {
+ char * text; /**< used for text only note */
+ struct {
+ char *title;
+ char *url;
+ } linkData; /**< used for link note */
+ struct {
+ char *path;
+ char *title;
+ BOOL_T inArchive;
+ } fileData; /**< used for file note */
+ } noteData;
+};
+
+//struct noteTextData {
+// coOrd pos;
+// unsigned int layer;
+// char *text;
+// track_p trk;
+//};
+
+struct noteLinkData {
+ coOrd pos;
+ unsigned int layer;
+ char title[TITLEMAXIMUMLENGTH];
+ char url[URLMAXIMUMLENGTH];
+ track_p trk;
+};
+
+struct noteFileData {
+ coOrd pos;
+ unsigned int layer;
+ char title[TITLEMAXIMUMLENGTH];
+ char path[PATHMAXIMUMLENGTH];
+ track_p trk;
+ BOOL_T inArchive;
+};
+
+enum { OR_NOTE, LY_NOTE, TX_TEXT, OK_TEXT, TITLE_LINK, TX_LINK, OK_LINK, TITLE_FILE, OK_FILE, CANCEL_NOTE };
+
+/* linknoteui.c */
+void NewLinkNoteUI(track_p trk);
+BOOL_T IsLinkNote(track_p trk);
+void DescribeLinkNote(track_p trk, char * str, CSIZE_T len);
+void ActivateLinkNote(track_p trk);
+
+/* filenozeui.c */
+void NewFileNoteUI(track_p trk);
+BOOL_T IsFileNote(track_p trk);
+void DescribeFileNote(track_p trk, char * str, CSIZE_T len);
+void ActivateFileNote(track_p trk);
+
+/* textnoteui.c */
+void NewTextNoteUI(track_p trk);
+void DescribeTextNote(track_p trk, char * str, CSIZE_T len);
+
+/* trknote.c */
+void NoteStateSave(track_p trk);
+
+void UpdateFile(struct extraDataNote *noteUIData, int inx, BOOL_T needUndoStart);
+void UpdateText(struct extraDataNote *noteUIData, int inx, BOOL_T needUndoStart);
+void UpdateLink(struct extraDataNote *noteUIData, int inx, BOOL_T needUndoStart);
+#endif // !HAVE_NOTE_H
diff --git a/app/bin/param.c b/app/bin/param.c
index 2f54d77..27a8cf9 100644
--- a/app/bin/param.c
+++ b/app/bin/param.c
@@ -766,63 +766,100 @@ EXPORT long ParamUpdate(
}
-EXPORT void ParamLoadData(
- paramGroup_p pg )
+void ParamLoadData(
+ paramGroup_p pg)
{
- FLOAT_T floatV;
- const char * stringV;
- paramData_p p;
- BOOL_T valid;
+ FLOAT_T floatV;
+ const char * stringV;
+ paramData_p p;
+ BOOL_T valid;
+ BOOL_T inRange;
+
+ for (p=pg->paramPtr; p<&pg->paramPtr[pg->paramCnt]; p++) {
+ if ((p->option&PDO_DLGIGNORE) != 0) {
+ continue;
+ }
- for ( p=pg->paramPtr; p<&pg->paramPtr[pg->paramCnt]; p++ ) {
- if ( (p->option&PDO_DLGIGNORE) != 0 )
- continue;
- if ( p->control == NULL || p->valueP == NULL)
- continue;
- switch ( p->type ) {
- case PD_LONG:
- stringV = wStringGetValue( (wString_p)p->control );
- *(long*)p->valueP = atol( stringV );
- break;
- case PD_RADIO:
- *(long*)p->valueP = wRadioGetValue( (wChoice_p)p->control );
- break;
- case PD_TOGGLE:
- *(long*)p->valueP = wToggleGetValue( (wChoice_p)p->control );
- break;
- case PD_LIST:
- case PD_DROPLIST:
- case PD_COMBOLIST:
- *(wIndex_t*)p->valueP = wListGetIndex( (wList_p)p->control );
- break;
- case PD_COLORLIST:
- *(wDrawColor*)p->valueP = wColorSelectButtonGetColor( (wButton_p)p->control );
- break;
- case PD_FLOAT:
- if (p->option & PDO_DIM) {
- floatV = DecodeDistance( (wString_p)p->control, &valid );
- } else {
- floatV = DecodeFloat( (wString_p)p->control, &valid );
- if (valid && (p->option & PDO_ANGLE) )
- floatV = NormalizeAngle( (angleSystem==ANGLE_POLAR)?floatV:-floatV );
- }
- if ( valid )
- *(FLOAT_T*)p->valueP = floatV;
- break;
- case PD_STRING:
- stringV = wStringGetValue( (wString_p)p->control );
- strcpy( (char*)p->valueP, stringV );
- break;
- case PD_MESSAGE:
- case PD_BUTTON:
- case PD_DRAW:
- case PD_TEXT:
- case PD_MENU:
- case PD_MENUITEM:
- case PD_BITMAP:
- break;
- }
- }
+ if (p->control == NULL || p->valueP == NULL) {
+ continue;
+ }
+
+ switch (p->type) {
+ long longV;
+
+ case PD_LONG:
+ longV = atol(wStringGetValue((wString_p)p->control));
+
+ if (p->winData) {
+ inRange = (longV <= ((paramIntegerRange_t *)p->winData)->high) &&
+ (longV >= ((paramIntegerRange_t *)p->winData)->low);
+ } else {
+ inRange = TRUE;
+ }
+
+ if (inRange) {
+ *(long*)p->valueP = longV;
+ }
+
+ break;
+
+ case PD_RADIO:
+ *(long*)p->valueP = wRadioGetValue((wChoice_p)p->control);
+ break;
+
+ case PD_TOGGLE:
+ *(long*)p->valueP = wToggleGetValue((wChoice_p)p->control);
+ break;
+
+ case PD_LIST:
+ case PD_DROPLIST:
+ case PD_COMBOLIST:
+ *(wIndex_t*)p->valueP = wListGetIndex((wList_p)p->control);
+ break;
+
+ case PD_COLORLIST:
+ *(wDrawColor*)p->valueP = wColorSelectButtonGetColor((wButton_p)p->control);
+ break;
+
+ case PD_FLOAT:
+ if (p->option & PDO_DIM) {
+ floatV = DecodeDistance((wString_p)p->control, &valid);
+ } else {
+ floatV = DecodeFloat((wString_p)p->control, &valid);
+
+ if (valid && (p->option & PDO_ANGLE)) {
+ floatV = NormalizeAngle((angleSystem==ANGLE_POLAR)?floatV:-floatV);
+ }
+ }
+
+ if (p->winData) {
+ inRange = (floatV <= ((paramFloatRange_t *)p->winData)->high) &&
+ (floatV >= ((paramFloatRange_t *)p->winData)->low);
+ } else {
+ inRange = TRUE;
+ }
+
+ if (valid && inRange) {
+ *(FLOAT_T*)p->valueP = floatV;
+ }
+
+ break;
+
+ case PD_STRING:
+ stringV = wStringGetValue((wString_p)p->control);
+ strcpy((char*)p->valueP, stringV);
+ break;
+
+ case PD_MESSAGE:
+ case PD_BUTTON:
+ case PD_DRAW:
+ case PD_TEXT:
+ case PD_MENU:
+ case PD_MENUITEM:
+ case PD_BITMAP:
+ break;
+ }
+ }
}
@@ -1348,13 +1385,24 @@ static void ParamIntegerPush( const char * val, void * dp )
paramData_p p = (paramData_p)dp;
long valL;
char * cp;
+ const char * value;
paramIntegerRange_t * irangeP;
- while ( isspace((unsigned char)*val)) val++;
- valL = strtol( val, &cp, 10 );
+ if (strlen(val) == 1 && val[strlen(val)-1] == '\n' && (p->option & BO_ENTER)) {
+ value = wStringGetValue((wString_p)p->control);
+ p->enter_pressed = TRUE;
+ } else {
+ p->enter_pressed = FALSE;
+ value = CAST_AWAY_CONST val;
+ }
+
+
+ while ( isspace((unsigned char)*value)) value++;
+ valL = strtol( value, &cp, 10 );
+
//wControlSetBalloon( p->control, 0, -5, NULL );
- if ( val == cp ) {
+ if ( value == cp ) {
wControlSetBalloon( p->control, 0, -5, _("Invalid Number") );
return;
}
@@ -1396,7 +1444,15 @@ static void ParamFloatPush( const char * val, void * dp )
paramData_p p = (paramData_p)dp;
FLOAT_T valF;
BOOL_T valid;
+ const char * value;
paramFloatRange_t * frangeP;
+ if (strlen(val) == 1 && val[strlen(val)-1] == '\n' && (p->option & PDO_ENTER)) {
+ value = wStringGetValue((wString_p)p->control);
+ p->enter_pressed = TRUE;
+ } else {
+ value = val;
+ p->enter_pressed = FALSE;
+ }
if (p->option & PDO_DIM) {
valF = DecodeDistance( (wString_p)p->control, &valid );
@@ -1434,7 +1490,7 @@ static void ParamFloatPush( const char * val, void * dp )
}
if ( (p->option&PDO_NOPSHUPD)==0 && p->valueP)
*((FLOAT_T*)(p->valueP)) = valF;
- if ( (p->option&PDO_NOPSHACT)==0 && p->group->changeProc && strlen( val ))
+ if ( (p->option&PDO_NOPSHACT)==0 && p->group->changeProc && strlen( value ))
p->group->changeProc( p->group, p-p->group->paramPtr, &valF );
}
@@ -1442,14 +1498,23 @@ static void ParamFloatPush( const char * val, void * dp )
static void ParamStringPush( const char * val, void * dp )
{
paramData_p p = (paramData_p)dp;
+ const char * value;
if (recordF && (p->option&PDO_NORECORD)==0 && p->group->nameStr && p->nameStr) {
fprintf( recordF, "PARAMETER %s %s %s\n", p->group->nameStr, p->nameStr, val );
fflush( recordF );
}
+ if (strlen(val) == 1 && val[strlen(val)-1] == '\n' && (p->option & PDO_ENTER)) {
+ value = wStringGetValue((wString_p)p->control);
+ p->enter_pressed = TRUE;
+ } else {
+ p->enter_pressed = FALSE;
+ value = CAST_AWAY_CONST val;
+ }
+
if ( (p->option&PDO_NOPSHUPD)==0 && p->valueP)
- strcpy( (char*)p->valueP, val );
+ strcpy( (char*)p->valueP, value );
if ( (p->option&PDO_NOPSHACT)==0 && p->group->changeProc)
- p->group->changeProc( p->group, p-p->group->paramPtr, CAST_AWAY_CONST val );
+ p->group->changeProc( p->group, p-p->group->paramPtr, CAST_AWAY_CONST value );
}
@@ -1495,6 +1560,15 @@ EXPORT void ParamMenuPush( void * dp )
static void ParamColorSelectPush( void * dp, wDrawColor dc )
{
paramData_p p = (paramData_p)dp;
+ long rgb = wDrawGetRGB( dc );
+ while ( dc == drawColorPreviewSelected || dc == drawColorPreviewUnselected ) {
+ // The user picked a special color, tweak it
+ rgb -= 1; // Make it very close but different
+ if ( ( rgb & 0xFF ) == 0 )
+ // Ran out of room - bail
+ break;
+ dc = wDrawFindColor( rgb );
+ }
if (recordF && (p->option&PDO_NORECORD)==0 && p->group->nameStr && p->nameStr) {
fprintf( recordF, "PARAMETER %s %s %ld\n", p->group->nameStr, p->nameStr, wDrawGetRGB(dc) );
fflush( recordF );
@@ -1827,13 +1901,19 @@ static void ParamPlayback( char * line )
pg->changeProc( pg, inx, &valF );
break;
case PD_STRING:
+ case PD_TEXT:
line += len;
while ( *line == ' ' ) line++;
Stripcr( line );
if (p->valueP)
strcpy( (char*)p->valueP, line );
if (p->control) {
- wStringSetValue( (wString_p)p->control, line );
+ if (p->type == PD_STRING) {
+ wStringSetValue((wString_p)p->control, line);
+ } else {
+ wTextClear((wText_p)p->control);
+ wTextAppend((wText_p)p->control, line);
+ }
wFlush();
}
if (pg->changeProc)
@@ -1849,7 +1929,6 @@ static void ParamPlayback( char * line )
PlaybackMouse( ddp->action, ddp->d, a, pos, drawColorBlack );
break;
case PD_MESSAGE:
- case PD_TEXT:
case PD_MENU:
case PD_BITMAP:
break;
@@ -2429,7 +2508,7 @@ SkipControl:
if ( group->boxs == NULL ) {
group->boxs = (wBox_p*)MyMalloc( boxCnt * sizeof *(wBox_p*)0 );
for ( box=0; box<boxCnt; box++ ) {
- group->boxs[box] = wBoxCreate( group->win, DlgSepLeft, boxTop, NULL, wBoxBelow, columnK.term.x, boxPos[box]-boxTop );
+ group->boxs[box] = wBoxCreate( group->win, DlgSepLeft, boxTop, NULL, wBoxThickW, columnK.term.x, boxPos[box]-boxTop );
boxTop = boxPos[box] + 4;
}
} else {
@@ -2503,7 +2582,10 @@ static void ParamDlgProc(
DefaultProc( win, wClose_e, data );
break;
case wResize_e:
- LayoutControls( pg, ParamPositionControl, NULL, NULL );
+ if (win == mapW)
+ pg->changeProc(pg, wResize_e, NULL);
+ else
+ LayoutControls( pg, ParamPositionControl, NULL, NULL );
break;
default:
break;
@@ -2544,6 +2626,7 @@ wWin_p ParamCreateDialog(
group->cancelProc = cancelProc;
group->layoutProc = layoutProc;
group->changeProc = changeProc;
+ group->winOption = winOption;
if ( (winOption&F_CENTER) == 0 )
winOption |= F_RECALLPOS;
if ( (winOption&F_RESIZE) != 0 )
diff --git a/app/bin/param.h b/app/bin/param.h
index 243bd1b..414dae3 100644
--- a/app/bin/param.h
+++ b/app/bin/param.h
@@ -58,6 +58,7 @@ typedef enum {
#define PDO_MISC (1L<<7)
#define PDO_DRAW (1L<<8)
#define PDO_FILE (1L<<9)
+#define PDO_ENTER (1L<<10)
#define PDO_STRINGLIMITLENGTH (1L<<11) /**< context has maximum length for string */
#define PDO_SMALLDIM (1L<<12)
@@ -142,6 +143,7 @@ typedef struct {
wControl_p control;
paramGroup_p group;
paramOldData_t oldD, demoD;
+ wBool_t enter_pressed;
} paramData_t, *paramData_p;
diff --git a/app/bin/paramfile.c b/app/bin/paramfile.c
new file mode 100644
index 0000000..2dd9ac7
--- /dev/null
+++ b/app/bin/paramfile.c
@@ -0,0 +1,393 @@
+/** \file paramfile.c
+ * Handling of parameter files
+ */
+
+ /* XTrackkCad - Model Railroad CAD
+ * Copyright (C) 2019 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 <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+#include "compound.h"
+#include "ctrain.h"
+#include "custom.h"
+#include "fileio.h"
+#include "i18n.h"
+#include "layout.h"
+#include "messages.h"
+#include "misc2.h"
+#include "paths.h"
+#include "include/paramfile.h"
+#include "include/paramfilelist.h"
+#include "include/utf8convert.h"
+
+#if _MSC_VER >1300
+#define stricmp( a, b ) _stricmp(a, b )
+#endif
+
+static long paramCheckSum;
+
+typedef enum paramFileState(*GetCompatibilityFunction)(int index,
+ SCALEINX_T scale);
+
+GetCompatibilityFunction GetCompatibility[] = {
+ GetTrackCompatibility,
+ GetStructureCompatibility,
+ GetCarProtoCompatibility,
+ GetCarPartCompatibility
+};
+
+#define COMPATIBILITYCHECKSCOUNT (sizeof(GetCompatibility)/sizeof(GetCompatibility[0]))
+
+/**
+ * Check whether parameter file is still loaded
+ *
+ * \param fileInx
+ * \return TRUE if loaded, FALSE otherwise
+ */
+
+wBool_t IsParamValid(
+ int fileInx)
+{
+ if (fileInx == PARAM_DEMO) {
+ return (curDemo >= 0);
+ } else if (fileInx == PARAM_CUSTOM) {
+ return TRUE;
+ } else if (fileInx == PARAM_LAYOUT) {
+ return TRUE;
+ } else if (fileInx >= 0 && fileInx < paramFileInfo_da.cnt) {
+ return (!paramFileInfo(fileInx).deleted);
+ } else {
+ return FALSE;
+ }
+}
+
+char *GetParamFileDir(void)
+{
+ return (GetCurrentPath(PARAMETERPATHKEY));
+}
+
+void
+SetParamFileDir(char *fullPath)
+{
+ SetCurrentPath(PARAMETERPATHKEY, fullPath);
+}
+
+char * GetParamFileName(
+ int fileInx)
+{
+ return paramFileInfo(fileInx).name;
+}
+
+char * GetParamFileContents(
+ int fileInx)
+{
+ return paramFileInfo(fileInx).contents;
+}
+
+bool IsParamFileDeleted(int inx)
+{
+ return paramFileInfo(inx).deleted;
+}
+
+bool IsParamFileFavorite(int inx)
+{
+ return paramFileInfo(inx).favorite;
+}
+
+void SetParamFileDeleted(int fileInx, bool deleted)
+{
+ paramFileInfo(fileInx).deleted = deleted;
+}
+
+void SetParamFileFavorite(int fileInx, bool favorite)
+{
+ paramFileInfo(fileInx).favorite = favorite;
+}
+
+void ParamCheckSumLine(char * line)
+{
+ long mult = 1;
+ while (*line) {
+ paramCheckSum += (((long)(*line++)) & 0xFF)*(mult++);
+ }
+}
+
+/**
+ * Set the compatibility state of a parameter file
+ *
+ * \param index parameter file number in list
+ * \return
+ */
+
+void SetParamFileState(int index)
+{
+ enum paramFileState state = PARAMFILE_NOTUSABLE;
+ enum paramFileState newState;
+ SCALEINX_T scale = GetLayoutCurScale();
+
+ for (int i = 0; i < COMPATIBILITYCHECKSCOUNT && state < PARAMFILE_FIT &&
+ state != PARAMFILE_UNLOADED; i++) {
+ newState = (*GetCompatibility[i])(index, scale);
+ if (newState > state || newState == PARAMFILE_UNLOADED) {
+ state = newState;
+ }
+ }
+
+ paramFileInfo(index).trackState = state;
+}
+
+/**
+ * Read a single parameter file and update the parameter file list
+ *
+ * \param fileName full path for parameter file
+ * \return
+ */
+
+int
+ReadParamFile(const char *fileName)
+{
+ DYNARR_APPEND(paramFileInfo_t, paramFileInfo_da, 10);
+ curParamFileIndex = paramFileInfo_da.cnt - 1;
+ paramFileInfo(curParamFileIndex).name = MyStrdup(fileName);
+ paramFileInfo(curParamFileIndex).valid = TRUE;
+ paramFileInfo(curParamFileIndex).deleted = !ReadParams(0, NULL, fileName);
+ paramFileInfo(curParamFileIndex).contents = MyStrdup(curContents);
+
+ SetParamFileState(curParamFileIndex);
+
+ return (curParamFileIndex);
+}
+
+/**
+ * Reload a single parameter file that had been unloaded before.
+ *
+ * \param fileindex index of previously created paramFileInfo
+ *
+ * \returns
+ */
+
+int
+ReloadDeletedParamFile(int fileindex)
+{
+ curParamFileIndex = fileindex;
+ paramFileInfo(curParamFileIndex).valid = TRUE;
+ paramFileInfo(curParamFileIndex).deleted = !ReadParams(0, NULL, paramFileInfo(curParamFileIndex).name);
+ paramFileInfo(curParamFileIndex).contents = MyStrdup(curContents);
+
+ SetParamFileState(curParamFileIndex);
+
+ return (curParamFileIndex);
+}
+
+/**
+ * Parameter file reader and interpreter
+ *
+ * \param key unused
+ * \param dirName prefix for parameter file path
+ * \param fileName name of parameter file
+ * \return
+ */
+
+bool ReadParams(
+ long key,
+ const char * dirName,
+ const char * fileName)
+{
+ FILE * oldFile;
+ char *cp;
+ wIndex_t oldLineNum;
+ wIndex_t pc;
+ long oldCheckSum;
+ long checkSum = 0;
+ BOOL_T checkSummed;
+ paramVersion = -1;
+ char *oldLocale = NULL;
+
+ if (dirName) {
+ MakeFullpath(&paramFileName, dirName, fileName, NULL);
+ } else {
+ MakeFullpath(&paramFileName, fileName, NULL);
+ }
+ paramLineNum = 0;
+ curBarScale = -1;
+ curContents = MyStrdup(fileName);
+ curSubContents = curContents;
+
+ //LOG1( log_paramFile, ("ReadParam( %s )\n", fileName ) )
+
+ oldLocale = SaveLocale("C");
+
+ paramFile = fopen(paramFileName, "r");
+ if (paramFile == NULL) {
+ /* Reset the locale settings */
+ RestoreLocale(oldLocale);
+
+ NoticeMessage(MSG_OPEN_FAIL, _("Continue"), NULL, _("Parameter"), paramFileName,
+ strerror(errno));
+
+ return FALSE;
+ }
+ paramCheckSum = key;
+ paramLineNum = 0;
+ checkSummed = FALSE;
+ BOOL_T skip = false;
+ int skipLines = 0;
+ while (paramFile && (fgets(paramLine, 256, paramFile)) != NULL) {
+ paramLineNum++;
+ Stripcr(paramLine);
+ if (strncmp(paramLine, "CHECKSUM ", 9) == 0) {
+ checkSum = atol(paramLine + 9);
+ checkSummed = TRUE;
+ goto nextLine;
+ }
+ ParamCheckSumLine(paramLine);
+ if (paramLine[0] == '#') {
+ /* comment */
+ } else if (paramLine[0] == 0) {
+ /* empty paramLine */
+ } else if (strncmp(paramLine, "INCLUDE ", 8) == 0) {
+ cp = &paramLine[8];
+ while (*cp && isspace((unsigned char)*cp)) {
+ cp++;
+ }
+ if (!*cp) {
+ InputError("INCLUDE - no file name", TRUE);
+
+ /* Close file and reset the locale settings */
+ if (paramFile) {
+ fclose(paramFile);
+ }
+ RestoreLocale(oldLocale);
+
+ return FALSE;
+ }
+ oldFile = paramFile;
+ oldLineNum = paramLineNum;
+ oldCheckSum = paramCheckSum;
+ if (!ReadParams(key, dirName, cp)) {
+ RestoreLocale(oldLocale);
+ return FALSE;
+ }
+ paramFile = oldFile;
+ paramLineNum = oldLineNum;
+ paramCheckSum = oldCheckSum;
+ if (dirName) {
+ MakeFullpath(&paramFileName, dirName, fileName, NULL);
+ } else {
+ MakeFullpath(&paramFileName, fileName);
+ }
+ skip = FALSE;
+ } else if (strncmp(paramLine, "CONTENTS ", 9) == 0) {
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(paramLine + 9);
+#endif
+ curContents = MyStrdup(paramLine + 9);
+ curSubContents = curContents;
+ skip = FALSE;
+ } else if (strncmp(paramLine, "SUBCONTENTS ", 12) == 0) {
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(paramLine + 12);
+#endif // WINDOWS
+ curSubContents = MyStrdup(paramLine + 12);
+ skip = FALSE;
+ } else if (strncmp(paramLine, "PARAM ", 6) == 0) {
+ paramVersion = strtol(paramLine + 8, &cp, 10);
+ if (cp)
+ while (*cp && isspace((unsigned char)*cp)) cp++;
+ if (paramVersion > iParamVersion) {
+ if (cp && *cp) {
+ NoticeMessage(MSG_PARAM_UPGRADE_VERSION1, _("Ok"), NULL, paramVersion, iParamVersion, sProdName, cp);
+ } else {
+ NoticeMessage(MSG_PARAM_UPGRADE_VERSION2, _("Ok"), NULL, paramVersion, iParamVersion, sProdName);
+ }
+ break;
+ }
+ if (paramVersion < iMinParamVersion) {
+ NoticeMessage(MSG_PARAM_BAD_FILE_VERSION, _("Ok"), NULL, paramVersion, iMinParamVersion, sProdName);
+ break;
+ }
+ } else if (skip && (strncmp(paramLine, " ", 1) == 0)) {
+ //Always skip to next line starting in LeftHandColumn
+ skipLines++;
+ goto nextLine;
+ } else {
+ for (pc = 0; pc < paramProc_da.cnt; pc++) {
+ if (strncmp(paramLine, paramProc(pc).name,
+ strlen(paramProc(pc).name)) == 0) {
+ skip = FALSE; //Stop skip so we re-message
+ paramProc(pc).proc(paramLine);
+ goto nextLine;
+ }
+ }
+ if (!skip) {
+ if (InputError(_("Unknown param file line - skip until next good object?"), TRUE)) { //OK to carry on
+ /* SKIP until next main line we recognize */
+ skip = TRUE;
+ skipLines++;
+ goto nextLine;
+ } else {
+ if (skipLines > 0)
+ NoticeMessage(MSG_PARAM_LINES_SKIPPED, _("Ok"), NULL, paramFileName, skipLines);
+ if (paramFile) {
+ fclose(paramFile);
+ paramFile = NULL;
+ }
+ if (paramFileName) {
+ free(paramFileName);
+ paramFileName = NULL;
+ }
+ RestoreLocale(oldLocale);
+ return FALSE;
+ }
+ }
+ skipLines++;
+ }
+ nextLine:
+ ;
+ }
+ if (key) {
+ if (!checkSummed || checkSum != paramCheckSum) {
+ /* Close file and reset the locale settings */
+ if (paramFile) {
+ fclose(paramFile);
+ }
+ RestoreLocale(oldLocale);
+
+ NoticeMessage(MSG_PROG_CORRUPTED, _("Ok"), NULL, paramFileName);
+
+ return FALSE;
+ }
+ }
+ if (skipLines > 0)
+ NoticeMessage(MSG_PARAM_LINES_SKIPPED, _("Ok"), NULL, paramFileName, skipLines);
+ if (paramFile) {
+ fclose(paramFile);
+ }
+ free(paramFileName);
+ paramFileName = NULL;
+ RestoreLocale(oldLocale);
+
+ return TRUE;
+}
diff --git a/app/bin/paramfilelist.c b/app/bin/paramfilelist.c
new file mode 100644
index 0000000..199345c
--- /dev/null
+++ b/app/bin/paramfilelist.c
@@ -0,0 +1,496 @@
+/** \file paramfilelist.c
+ * Handling of the list of parameter files
+ */
+
+/* XTrackCad - Model Railroad CAD
+ * Copyright (C) 2019 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 <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+#include "compound.h"
+#include "ctrain.h"
+#include "custom.h"
+#include "dynstring.h"
+#include "fileio.h"
+#include "i18n.h"
+#include "layout.h"
+#include "messages.h"
+#include "misc2.h"
+#include "paths.h"
+#include "include/paramfile.h"
+#include "include/paramfilelist.h"
+
+
+dynArr_t paramFileInfo_da;
+
+int curParamFileIndex = PARAM_DEMO;
+
+static int log_params;
+
+static char * customPath;
+static char * customPathBak;
+
+#define FAVORITESECTION "Parameter File Favorites"
+#define FAVORITETOTALS "Total"
+#define FAVORITEKEY "Favorite%d"
+#define FAVORITEDELETED "Deleted%d"
+
+int GetParamFileCount()
+{
+ return (paramFileInfo_da.cnt);
+}
+
+
+
+
+/**
+ * Update the configuration file in case the name of a parameter file has changed.
+ * The function reads a list of new parameter filenames and gets the contents
+ * description for each file. If that contents is in use, i.e. is a loaded parameter
+ * file, the setting in the config file is updated to the new filename.
+ * First line of update file has the date of the update file.
+ * * Following lines have filenames, one per line.
+ *
+ * \return FALSE if update not possible or not necessary, TRUE if update successful
+ */
+
+static BOOL_T UpdateParamFiles(void)
+{
+ char fileName[STR_LONG_SIZE], *fileNameP;
+ const char * cp;
+ FILE * updateF;
+ long updateTime;
+ long lastTime;
+
+ MakeFullpath(&fileNameP, libDir, "xtrkcad.upd", NULL);
+ updateF = fopen(fileNameP, "r");
+ free(fileNameP);
+ if (updateF == NULL) {
+ return FALSE;
+ }
+ if (fgets(message, sizeof message, updateF) == NULL) {
+ NoticeMessage("short file: xtrkcad.upd", _("Ok"), NULL);
+ fclose(updateF);
+ return FALSE;
+ }
+ wPrefGetInteger("file", "updatetime", &lastTime, 0);
+ updateTime = atol(message);
+ if (lastTime >= updateTime) {
+ fclose(updateF);
+ return FALSE;
+ }
+
+ while ((fgets(fileName, STR_LONG_SIZE, updateF)) != NULL) {
+ FILE * paramF;
+ char * contents;
+
+ Stripcr(fileName);
+ InfoMessage(_("Updating %s"), fileName);
+ MakeFullpath(&fileNameP, libDir, "params", fileName, NULL);
+ paramF = fopen(fileNameP, "r");
+ if (paramF == NULL) {
+ NoticeMessage(MSG_PRMFIL_OPEN_NEW, _("Ok"), NULL, fileNameP);
+ free(fileNameP);
+ continue;
+ }
+ contents = NULL;
+ while ((fgets(message, sizeof message, paramF)) != NULL) {
+ if (strncmp(message, "CONTENTS", 8) == 0) {
+ Stripcr(message);
+ contents = message + 9;
+ break;
+ }
+ }
+ fclose(paramF);
+ if (contents == NULL) {
+ NoticeMessage(MSG_PRMFIL_NO_CONTENTS, _("Ok"), NULL, fileNameP);
+ free(fileNameP);
+ continue;
+ }
+ cp = wPrefGetString("Parameter File Map", contents);
+ wPrefSetString("Parameter File Map", contents, fileNameP);
+ if (cp != NULL && *cp != '\0') {
+ /* been there, done that */
+ free(fileNameP);
+ continue;
+ }
+
+ free(fileNameP);
+ }
+ fclose(updateF);
+ wPrefSetInteger("file", "updatetime", updateTime);
+ return TRUE;
+}
+
+/**
+ * Read the list of parameter files from configuration and load the files.
+ *
+ */
+void LoadParamFileList(void)
+{
+ int fileNo;
+ BOOL_T updated = FALSE;
+ long *favoriteList = NULL;
+ long favorites;
+ int nextFavorite = 0;
+
+ updated = UpdateParamFiles();
+
+ wPrefGetIntegerBasic(FAVORITESECTION, FAVORITETOTALS, &favorites, 0);
+ if (favorites) {
+ DynString topic;
+ favoriteList = MyMalloc(sizeof(long)*favorites);
+ if (!favoriteList) {
+ AbortProg("Couldn't allocate memory for favorite list!\n");
+ }
+
+ DynStringMalloc(&topic, 16);
+ for (int i = 0; i < favorites; i++) {
+ DynStringPrintf(&topic, FAVORITEKEY, i);
+ wPrefGetIntegerBasic(FAVORITESECTION, DynStringToCStr(&topic), &favoriteList[i],
+ 0);
+ }
+ DynStringFree(&topic);
+ }
+
+ for (fileNo = 1; ; fileNo++) {
+ char *fileName;
+ const char * contents;
+ enum paramFileState structState = PARAMFILE_UNLOADED;
+
+
+ sprintf(message, "File%d", fileNo);
+ contents = wPrefGetString("Parameter File Names", message);
+ if (contents == NULL || *contents == '\0') {
+ break;
+ }
+ InfoMessage("Parameters for %s", contents);
+ fileName = wPrefGetString("Parameter File Map", contents);
+ if (fileName == NULL || *fileName == '\0') {
+ NoticeMessage(MSG_PRMFIL_NO_MAP, _("Ok"), NULL, contents);
+ continue;
+ }
+ char * share;
+
+ // Rewire to the latest system level
+ if ((share= strstr(fileName,"/share/xtrkcad/params/"))) {
+ share += strlen("/share/xtrkcad/params/");
+ MakeFullpath(&fileName, wGetAppLibDir(), "params", share, NULL);
+ wPrefSetString("Parameter File Map", contents, fileName);
+ }
+
+ ReadParamFile(fileName);
+
+ if (curContents == NULL) {
+ curContents = curSubContents = MyStrdup(contents);
+ }
+ paramFileInfo(curParamFileIndex).contents = curContents;
+ if (favoriteList && fileNo == favoriteList[nextFavorite]) {
+ DynString topic;
+ long deleted;
+ DynStringMalloc(&topic, 16);
+ DynStringPrintf(&topic, FAVORITEDELETED, fileNo);
+
+ wPrefGetIntegerBasic(FAVORITESECTION, DynStringToCStr(&topic), &deleted, 0L);
+ paramFileInfo(curParamFileIndex).favorite = TRUE;
+ paramFileInfo(curParamFileIndex).deleted = deleted;
+ if (nextFavorite < favorites - 1) {
+ nextFavorite++;
+ }
+ DynStringFree(&topic);
+ }
+
+ }
+ curParamFileIndex = PARAM_CUSTOM;
+ if (updated) {
+ SaveParamFileList();
+ }
+
+ MyFree(favoriteList);
+}
+
+/**
+ * Save the currently selected parameter files. Parameter files that have been unloaded
+ * are not saved.
+ *
+ */
+
+void SaveParamFileList(void)
+{
+ int fileInx;
+ int fileNo;
+ int favorites;
+ char * contents, *cp;
+
+ for (fileInx = 0, fileNo = 1, favorites = 0; fileInx < paramFileInfo_da.cnt;
+ fileInx++) {
+ if (paramFileInfo(fileInx).valid && (!paramFileInfo(fileInx).deleted ||
+ paramFileInfo(fileInx).favorite)) {
+ sprintf(message, "File%d", fileNo);
+ contents = paramFileInfo(fileInx).contents;
+ for (cp = contents; *cp; cp++) {
+ if (*cp == '=' || *cp == '\'' || *cp == '"' || *cp == ':' || *cp == '.') {
+ *cp = ' ';
+ }
+ }
+ wPrefSetString("Parameter File Names", message, contents);
+ wPrefSetString("Parameter File Map", contents, paramFileInfo(fileInx).name);
+ if (paramFileInfo(fileInx).favorite) {
+ sprintf(message, FAVORITEKEY, favorites);
+ wPrefSetInteger(FAVORITESECTION, message, fileNo);
+ sprintf(message, FAVORITEDELETED, fileNo);
+ wPrefSetInteger(FAVORITESECTION, message, paramFileInfo(fileInx).deleted);
+ favorites++;
+ }
+ fileNo++;
+ }
+ }
+ sprintf(message, "File%d", fileNo);
+ wPrefSetString("Parameter File Names", message, "");
+ wPrefSetInteger(FAVORITESECTION, FAVORITETOTALS, favorites);
+}
+
+void
+UpdateParamFileList(void)
+{
+ for (size_t i = 0; i < (unsigned)paramFileInfo_da.cnt; i++) {
+ SetParamFileState(i);
+ }
+}
+
+/**
+ * Load the selected parameter files. This is a callback executed when the file selection dialog
+ * is closed.
+ * Steps:
+ * - the parameters are read from file
+ * - check is performed to see whether the content is already present, if yes the previously
+ * loaded content is invalidated
+ * - loaded parameter file is added to list of parameter files
+ * - if a parameter file dialog exists the list is updated. It is either rewritten in
+ * in case of an invalidated file or the new file is appended
+ * - the settings are updated
+ * These steps are repeated for every file in list
+ *
+ * \param files IN the number of filenames in the fileName array
+ * \param fileName IN an array of fully qualified filenames
+ * \param data IN ignored
+ * \return TRUE on success, FALSE on error
+ */
+
+int LoadParamFile(
+ int files,
+ char ** fileName,
+ void * data)
+{
+ wIndex_t inx;
+ int i = 0;
+
+ assert(fileName != NULL);
+ assert(files > 0);
+
+ for (i = 0; i < files; i++) {
+ enum paramFileState structState = PARAMFILE_UNLOADED;
+ int newIndex;
+
+ curContents = curSubContents = NULL;
+
+ newIndex = ReadParamFile(fileName[i]);
+
+ // in case the contents is already present, make invalid
+ for (inx = 0; inx < newIndex; inx++) {
+ if (paramFileInfo(inx).valid &&
+ strcmp(paramFileInfo(inx).contents, curContents) == 0) {
+ paramFileInfo(inx).valid = FALSE;
+ break;
+ }
+ }
+
+ wPrefSetString("Parameter File Map", curContents,
+ paramFileInfo(curParamFileIndex).name);
+ }
+ //Only set the ParamFileDir if not the system directory
+ if (!strstr(fileName[i-1],"/share/xtrkcad/params/"))
+ SetParamFileDir(fileName[i - 1]);
+ curParamFileIndex = PARAM_CUSTOM;
+ DoChangeNotification(CHANGE_PARAMS);
+ return TRUE;
+}
+
+static void ReadCustom(void)
+{
+ FILE * f;
+ MakeFullpath(&customPath, workingDir, sCustomF, NULL);
+ customPathBak = MyStrdup(customPath);
+ customPathBak[ strlen(customPathBak)-1 ] = '1';
+ f = fopen(customPath, "r");
+ if (f != NULL) {
+ fclose(f);
+ curParamFileIndex = PARAM_CUSTOM;
+ ReadParams(0, workingDir, sCustomF);
+ }
+}
+
+
+/*
+ * Open the file and then set the locale to "C". Old locale will be copied to
+ * oldLocale. After the required file I/O is done, the caller must call
+ * CloseCustom() with the same locale value that was returned in oldLocale by
+ * this function.
+ */
+
+FILE * OpenCustom(char *mode)
+{
+ FILE * ret = NULL;
+
+ if (inPlayback) {
+ return NULL;
+ }
+ if (*mode == 'w') {
+ rename(customPath, customPathBak);
+ }
+ if (customPath) {
+ ret = fopen(customPath, mode);
+ if (ret == NULL) {
+ NoticeMessage(MSG_OPEN_FAIL, _("Continue"), NULL, _("Custom"), customPath,
+ strerror(errno));
+ }
+ }
+
+ return ret;
+}
+/**
+ * Update and open the parameter files dialog box
+ *
+ * \param junk
+ */
+
+static void DoParamFileListDialog(void *junk)
+{
+ DoParamFiles(junk);
+ ParamFileListLoad(paramFileInfo_da.cnt, &paramFileInfo_da);
+
+}
+
+addButtonCallBack_t ParamFilesInit(void)
+{
+ RegisterChangeNotification(ParamFilesChange);
+ return &DoParamFileListDialog;
+}
+
+/**
+ * Get the initial parameter files. The Xtrkcad.xtq file containing scale and
+ * demo definitions is read.
+ *
+ * \return FALSE on error, TRUE otherwise
+ */
+BOOL_T ParamFileListInit(void)
+{
+ log_params = LogFindIndex("params");
+
+ // get the default definitions
+ if (ReadParams(lParamKey, libDir, sParamQF) == FALSE) {
+ return FALSE;
+ }
+
+ curParamFileIndex = PARAM_CUSTOM;
+
+ if (lParamKey == 0) {
+ LoadParamFileList();
+ ReadCustom();
+ }
+
+ return TRUE;
+
+}
+
+/**
+ * Deletes all parameter types described by index
+ *
+ * \param index Zero-based index of the.
+ */
+
+static void
+DeleteAllParamTypes(int index)
+{
+
+ DeleteTurnoutParams(index);
+ DeleteCarProto(index);
+ DeleteCarPart(index);
+ DeleteStructures(index);
+}
+
+
+/**
+ * Unload parameter file: all parameter definitions from this file are deleted
+ * from memory. Strings allocated to store the filename and contents
+ * description are free'd as well.
+ * In order to keep the overall data structures consistent, the file info
+ * structure is not removed from the array but flagged as garbage
+ *
+ * \param fileIndex Zero-based index of the file.
+ *
+ * \returns True if it succeeds, false if it fails.
+ */
+
+bool
+UnloadParamFile(wIndex_t fileIndex)
+{
+ paramFileInfo_p paramFileI = &paramFileInfo(fileIndex);
+
+ DeleteAllParamTypes(fileIndex);
+
+ MyFree(paramFileI->name);
+ MyFree(paramFileI->contents);
+
+ paramFileI->valid = FALSE;
+
+ for (int i = 0; i < paramFileInfo_da.cnt; i++) {
+ LOG1(log_params, ("UnloadParamFiles: = %s: %d\n", paramFileInfo(i).contents,
+ paramFileInfo(i).trackState))
+ }
+
+ return (true);
+}
+
+/**
+ * Reload parameter file
+ *
+ * \param index Zero-based index of the paramFileInfo struct.
+ *
+ * \returns True if it succeeds, false if it fails.
+ */
+
+bool
+ReloadParamFile(wIndex_t index)
+{
+ paramFileInfo_p paramFileI = &paramFileInfo(index);
+
+ DeleteAllParamTypes(index);
+ MyFree(paramFileI->contents);
+
+ ReloadDeletedParamFile(index);
+
+ return(true);
+}
diff --git a/app/bin/paramfilesearch_ui.c b/app/bin/paramfilesearch_ui.c
new file mode 100644
index 0000000..bf9c47a
--- /dev/null
+++ b/app/bin/paramfilesearch_ui.c
@@ -0,0 +1,426 @@
+/** \file paramfilesearch_ui.c
+ * Parameter File Search Dialog
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2019 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 <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "custom.h"
+#include "dynstring.h"
+#include "i18n.h"
+#include "messages.h"
+#include "param.h"
+#include "include/partcatalog.h"
+#include "paths.h"
+#include "include/paramfilelist.h"
+#include "fileio.h"
+#include "directory.h"
+
+#include "bitmaps/magnifier.xpm"
+
+static CatalogEntry *catalogFileBrowse; /**< current search results */
+static TrackLibrary *trackLibrary; /**< Track Library */
+static CatalogEntry *currentCat; /**< catalog being shown */
+
+/* define the search / browse dialog */
+
+static struct wFilSel_t *searchUi_fs; /**< searchdialog for parameter files */
+
+static void SearchUiBrowse(void *junk);
+static void SearchUiDefault(void * junk);
+static void SearchUiApply(wWin_p junk);
+static void SearchUiSelectAll(void *junk);
+static void SearchUiDoSearch(void *junk);
+
+static long searchUiMode = 0;
+static paramListData_t searchUiListData = { 10, 370, 0 };
+#define MAXQUERYLENGTH 250
+static char searchUiQuery[MAXQUERYLENGTH];
+static char * searchUiLabels[] = { N_("Show File Names"), NULL };
+
+static paramData_t searchUiPLs[] = {
+#define I_QUERYSTRING (0)
+ { PD_STRING, searchUiQuery, "query", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)(340), "", 0, 0, MAXQUERYLENGTH-1 },
+#define I_SEARCHBUTTON (1)
+ { PD_BUTTON, (void*)SearchUiDoSearch, "find", PDO_DLGHORZ, 0, NULL, BO_ICON, (void *)NULL },
+#define I_MESSAGE (2)
+ { PD_MESSAGE, N_("Enter at least one search word"), NULL, PDO_DLGBOXEND, (void *)370 },
+#define I_RESULTLIST (3)
+ { PD_LIST, NULL, "inx", PDO_NOPREF | PDO_DLGRESIZE, &searchUiListData, NULL, BL_DUP|BL_SETSTAY|BL_MANY },
+#define I_MODETOGGLE (4)
+ { PD_TOGGLE, &searchUiMode, "mode", PDO_DLGBOXEND, searchUiLabels, NULL, BC_HORZ|BC_NOBORDER },
+#define I_APPLYBUTTON (5)
+ { PD_BUTTON, (void *)SearchUiApply, "apply", PDO_DLGCMDBUTTON, NULL, N_("Add") },
+#define I_SELECTALLBUTTON (6)
+ { PD_BUTTON, (void*)SearchUiSelectAll, "selectall", PDO_DLGCMDBUTTON, NULL, N_("Select all") },
+ { PD_BUTTON, (void*)SearchUiDefault, "default", 0, NULL, N_("Reload Library") },
+};
+
+#define SEARCHBUTTON ((wButton_p)searchUiPLs[I_SEARCHBUTTON].control)
+#define RESULTLIST ((wList_p)searchUiPLs[I_RESULTLIST].control)
+#define APPLYBUTTON ((wButton_p)searchUiPLs[I_APPLYBUTTON].control)
+#define SELECTALLBUTTON ((wButton_p)searchUiPLs[I_SELECTALLBUTTON].control)
+#define MESSAGETEXT ((wMessage_p)searchUiPLs[I_MESSAGE].control)
+#define QUERYSTRING ((wString_p)searchUiPLs[I_QUERYSTRING].control)
+
+static paramGroup_t searchUiPG = { "searchgui", 0, searchUiPLs, sizeof searchUiPLs/sizeof searchUiPLs[0] };
+static wWin_p searchUiW;
+
+#define FILESECTION "file"
+#define PARAMDIRECTORY "paramdir"
+
+/**
+ * Reload the listbox showing the current catalog
+ */
+
+static
+void SearchFileListLoad(CatalogEntry *catalog)
+{
+ CatalogEntry *currentEntry = catalog->next;
+ DynString description;
+ DynStringMalloc(&description, STR_SHORT_SIZE);
+
+ wControlShow((wControl_p)RESULTLIST, FALSE);
+ wListClear(RESULTLIST);
+
+ while (currentEntry != currentEntry->next) {
+ for (unsigned int i=0;i<currentEntry->files;i++) {
+ DynStringClear(&description);
+ DynStringCatCStr(&description,
+ ((!searchUiMode) && currentEntry->contents) ?
+ currentEntry->contents :
+ currentEntry->fullFileName[i]);
+
+ wListAddValue(RESULTLIST,
+ DynStringToCStr(&description),
+ NULL,
+ // indicatorIcons[paramFileInfo.favorite][paramFileInfo.trackState],
+ (void*)currentEntry->fullFileName[i]);
+ }
+
+ currentEntry = currentEntry->next;
+ }
+
+ wControlShow((wControl_p)RESULTLIST, TRUE);
+ wControlActive((wControl_p)SELECTALLBUTTON,
+ wListGetCount(RESULTLIST));
+
+ DynStringFree(&description);
+
+ currentCat = catalog;
+}
+
+/**
+ * Find parameter files using the file selector
+ *
+ * \param junk
+ */
+
+static void SearchUiBrowse(void * junk)
+{
+
+ //EmptyCatalog(catalogFileBrowse);
+
+ wFilSelect(searchUi_fs, GetParamFileDir());
+
+ //SearchFileListLoad(catalogFileBrowse);
+
+ return;
+}
+
+
+/**
+ * Reload just the system files into the searchable set
+ */
+
+static void SearchUiDefault(void * junk)
+{
+
+ if (!catalogFileBrowse)
+ catalogFileBrowse = InitCatalog();
+ else {
+ EmptyCatalog(catalogFileBrowse);
+ }
+
+ if (trackLibrary)
+ DeleteLibrary(trackLibrary);
+
+ char * parms_path;
+
+ MakeFullpath(&parms_path, wGetAppLibDir(), "params", NULL);
+
+ trackLibrary = CreateLibrary(parms_path);
+
+ SearchFileListLoad(trackLibrary->catalog); //Start with system files
+
+ free(parms_path);
+
+}
+
+/**
+ * Load the selected items of search results
+ */
+
+void static
+SearchUILoadResults(void)
+{
+ char **fileNames;
+ int files = wListGetSelectedCount(RESULTLIST);
+ int found = 0;
+
+ if (files) {
+ fileNames = malloc(sizeof(char *)*files);
+ if (!fileNames) {
+ AbortProg("Couldn't allocate memory for result list: %s (%d)", __FILE__,
+ __LINE__, NULL);
+ }
+
+ for (int inx = 0; found < files; inx++) {
+ if (wListGetItemSelected(RESULTLIST, inx)) {
+ fileNames[found++] = (char *)wListGetItemContext(RESULTLIST, inx);
+ }
+ }
+
+ LoadParamFile(files, fileNames, NULL);
+ free(fileNames);
+ SearchUiOk((void *) 0);
+ }
+
+}
+
+/**
+ * Update the action buttons.
+ *
+ * If there is at least one selected file, Apply is enabled
+ * If there are entries in the list, Select All is enabled
+ *
+ * \return
+ */
+
+static void UpdateSearchUiButton(void)
+{
+ wIndex_t selCnt = wListGetSelectedCount(RESULTLIST);
+ wIndex_t cnt = wListGetCount(RESULTLIST);
+
+ wControlActive((wControl_p)APPLYBUTTON, selCnt > 0);
+ wControlActive((wControl_p)SELECTALLBUTTON, cnt > 0);
+}
+
+// Return a pointer to the (shifted) trimmed string
+char * StringTrim(char *s)
+{
+ char *original = s;
+ size_t len = 0;
+
+ while (isspace((unsigned char) *s)) {
+ s++;
+ }
+ if (*s) {
+ char *p = s;
+ while (*p) p++;
+ while (isspace((unsigned char) *(--p)));
+ p[1] = '\0';
+ len = (size_t) (p - s + 1);
+ }
+
+ return (s == original) ? s : memmove(original, s, len + 1);
+}
+
+/**
+ * Perform the search. If successful, the results are loaded into the list
+ *
+ * \param ptr INignored
+ */
+
+static void SearchUiDoSearch(void * ptr)
+{
+ unsigned result;
+
+ char * search;
+
+ search = StringTrim(searchUiQuery);
+
+ if (catalogFileBrowse) {
+ EmptyCatalog(catalogFileBrowse);
+ } else
+ catalogFileBrowse = InitCatalog();
+
+ result = SearchLibrary(trackLibrary, search, catalogFileBrowse);
+
+ if (result) {
+ DynString hitsMessage;
+ DynStringMalloc(&hitsMessage, 16);
+ DynStringPrintf(&hitsMessage, _("%d parameter files found."), result);
+ wMessageSetValue(MESSAGETEXT, DynStringToCStr(&hitsMessage));
+ DynStringFree(&hitsMessage);
+
+ SearchFileListLoad(catalogFileBrowse);
+
+ } else {
+
+ wListClear(RESULTLIST);
+ wControlActive((wControl_p)SELECTALLBUTTON, FALSE);
+ wMessageSetValue(MESSAGETEXT, _("No matches found."));
+ }
+}
+
+/**
+ * Select all files in the list
+ *
+ * \param junk IN ignored
+ * \return
+ */
+
+static void SearchUiSelectAll(void *junk)
+{
+ wListSelectAll(RESULTLIST);
+}
+
+/**
+ * Action handler for Done button. Hides the dialog.
+ *
+ * \param [in,out] junk ignored.
+ */
+
+void SearchUiOk(void * junk)
+{
+ if (searchUiW) {
+ wHide(searchUiW);
+ }
+}
+
+/**
+ * Handle the Add button: a list of selected list elements is created and
+ * passed to the parameter file list.
+ *
+ * \param junk IN/OUT ignored
+ */
+
+static void SearchUiApply(wWin_p junk)
+{
+ SearchUILoadResults();
+}
+
+/**
+ * Event handling for the Search dialog. If the 'X' decoration is pressed the
+ * dialog window is closed.
+ *
+ * \param pg IN ignored
+ * \param inx IN ignored
+ * \param valueP IN ignored
+ */
+
+static void SearchUiDlgUpdate(
+ paramGroup_p pg,
+ int inx,
+ void * valueP)
+{
+ switch (inx) {
+ case I_RESULTLIST:
+ UpdateSearchUiButton();
+ break;
+ case I_MODETOGGLE:
+ SearchFileListLoad(currentCat);
+ break;
+ case -1:
+ SearchUiOk(valueP);
+ break;
+ }
+}
+
+/**
+ * Get the system default directory for parameter files. First step is to
+ * check the configuration file for a user specific setting. If that is not
+ * found, the diretory is based derived from the installation directory.
+ * The returned string has to be free'd() when no longer needed.
+ *
+ * \return parameter file directory
+ */
+
+static char *
+GetParamsPath()
+{
+ char * params_path;
+ char *params_pref;
+ params_pref = wPrefGetString(FILESECTION, PARAMDIRECTORY);
+
+ if (!params_pref) {
+ MakeFullpath(&params_path, wGetAppLibDir(), "params", NULL);
+ } else {
+ params_path = strdup(params_pref);
+ }
+ return(params_path);
+}
+/**
+ * Create and open the search dialog.
+ *
+ * \param junk
+ */
+
+void DoSearchParams(void * junk)
+{
+ if (searchUiW == NULL) {
+ catalogFileBrowse = InitCatalog();
+
+ //Make the Find menu bound to the System Library initially
+ char *paramsDir = GetParamsPath();
+ trackLibrary = CreateLibrary(paramsDir);
+ free(paramsDir);
+
+ searchUiPLs[I_SEARCHBUTTON].winLabel = (char *)wIconCreatePixMap(magnifier_xpm);
+
+ ParamRegister(&searchUiPG);
+
+ searchUiW = ParamCreateDialog(&searchUiPG,
+ MakeWindowTitle(_("Choose parameter files")), _("Done"), NULL, wHide,
+ TRUE, NULL, F_RESIZE | F_RECALLSIZE, SearchUiDlgUpdate);
+ if (trackLibrary) {
+ SearchFileListLoad(trackLibrary->catalog); //Start with system files
+ }
+ wControlActive((wControl_p)APPLYBUTTON, FALSE);
+ wControlActive((wControl_p)SELECTALLBUTTON, FALSE);
+
+ searchUi_fs = wFilSelCreate(searchUiW, FS_LOAD, FS_MULTIPLEFILES,
+ _("Load Parameters"), _("Parameter files (*.xtp)|*.xtp"), GetParameterFileInfo,
+ (void *)catalogFileBrowse);
+ }
+
+ ParamLoadControls(&searchUiPG);
+ ParamGroupRecord(&searchUiPG);
+
+ if (!trackLibrary) {
+ wControlActive((wControl_p)SEARCHBUTTON, FALSE);
+ wControlActive((wControl_p)QUERYSTRING, FALSE);
+ wMessageSetValue(MESSAGETEXT,
+ _("No system parameter files found, search is disabled."));
+ } else {
+ wStringSetValue(QUERYSTRING, "");
+
+ SearchFileListLoad(trackLibrary->catalog); //Start with system files
+
+ }
+ wShow(searchUiW);
+}
+
+
diff --git a/app/bin/partcatalog.c b/app/bin/partcatalog.c
new file mode 100644
index 0000000..a1db09c
--- /dev/null
+++ b/app/bin/partcatalog.c
@@ -0,0 +1,846 @@
+/** \file partcatalog.c
+* Manage the catalog of track parameter files
+*/
+/* XTrkCad - Model Railroad CAD
+* Copyright (C) 2019 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 <assert.h>
+#include <ctype.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <search.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WINDOWS
+ #include "include/dirent.h"
+#else
+ #include <dirent.h>
+#endif
+#include "fileio.h"
+#include "misc.h"
+#include "include/paramfile.h"
+#include "include/partcatalog.h"
+#include "paths.h"
+#include "include/stringxtc.h"
+#include "include/utf8convert.h"
+
+#if _MSC_VER > 1300
+ #define strnicmp _strnicmp
+ #define strdup _strdup
+#endif
+
+#define PUNCTUATION "+-*/.,&%=#"
+
+
+
+/**
+ * Create and initialize the linked list for the catalog entries
+ *
+ * \return pointer to first element
+ */
+
+CatalogEntry *
+InitCatalog(void)
+{
+ CatalogEntry *head;
+ CatalogEntry *tail;
+
+ /* allocate two pseudo nodes for beginning and end of list */
+ head = (CatalogEntry *)malloc(sizeof(CatalogEntry));
+ tail = (CatalogEntry *)malloc(sizeof(CatalogEntry));
+
+ head->next = tail;
+ tail->next = tail;
+
+
+
+ return (head);
+}
+
+/**
+ * Create a new CatalogEntry and add it to the linked list. The newly
+ * created entry is inserted into the list after the given position
+ *
+ * \param entry IN insertion point
+ * \return pointer to new entry
+ */
+
+static CatalogEntry *
+InsertIntoCatalogAfter(CatalogEntry *entry)
+{
+ CatalogEntry *newEntry = (CatalogEntry *)malloc(sizeof(CatalogEntry));
+ newEntry->next = entry->next;
+ entry->next = newEntry;
+ newEntry->files = 0;
+ newEntry->contents = NULL;
+
+ return (newEntry);
+}
+
+/**
+ * Count the elements in the linked list ignoring dummy elements
+ *
+ * \param listHeader IN the linked list
+ * \return the numberof elements
+ */
+
+unsigned
+CountCatalogEntries(CatalogEntry *listHeader)
+{
+ CatalogEntry *currentEntry = listHeader->next;
+ unsigned count = 0;
+
+ while (currentEntry != currentEntry->next) {
+ count++;
+ currentEntry = currentEntry->next;
+ }
+ return (count);
+}
+
+/**
+ * Empty a catalog. All data nodes including their allocated memory are freed. On
+ *
+ * \param listHeader IN the list
+ */
+
+void
+EmptyCatalog(CatalogEntry *listHeader)
+{
+ CatalogEntry *current = listHeader;
+
+ while (current->next != current->next->next) {
+ CatalogEntry *removedElement;
+ removedElement = current->next;
+ current->next = current->next->next;
+ if (removedElement->contents) {
+ free(removedElement->contents);
+ }
+ for (unsigned int i = 0; i < removedElement->files; i++) {
+ free(removedElement->fullFileName[i]);
+ }
+ free(removedElement);
+ }
+}
+
+/**
+ * Find the position in the list and add
+ *
+ * \param listHeader IN start of list
+ * \param contents IN contents to include
+ *
+ * \return CatalogEntry if found, NULL otherwise
+ */
+
+static CatalogEntry *
+InsertInOrder(CatalogEntry *listHeader, const char *contents)
+{
+ CatalogEntry *currentEntry = listHeader;
+
+ while (currentEntry->next != currentEntry->next->next) {
+ CatalogEntry *nextEntry = currentEntry->next;
+ if (XtcStricmp(nextEntry->contents, contents)>0) {
+ return InsertIntoCatalogAfter(currentEntry);
+ }
+ currentEntry = nextEntry;
+ }
+ return InsertIntoCatalogAfter(currentEntry);
+}
+/**
+ * Get the existing list element for a content
+ *
+ * \param listHeader IN start of list
+ * \param contents IN contents to search
+ * \param Do we log error messages or not
+ *
+ * \return CatalogEntry if found, NULL otherwise
+ */
+
+static CatalogEntry *
+IsExistingContents(CatalogEntry *listHeader, const char *contents, BOOL_T silent)
+{
+ CatalogEntry *currentEntry = listHeader->next;
+
+ while (currentEntry != currentEntry->next) {
+ if (!XtcStricmp(currentEntry->contents, contents)) {
+ if (!silent)
+ printf("%s already exists in %s\n", contents, currentEntry->fullFileName[0]);
+ return (currentEntry);
+ }
+ currentEntry = currentEntry->next;
+ }
+ return (NULL);
+}
+
+/**
+ * Store information about a parameter file. The filename is added to the array
+ * of files with identical content. If not already present, in addition
+ * the content is stored
+ *
+ * \param entry existing entry to be updated
+ * \param path filename to add
+ * \param contents contents description
+ */
+
+static void
+UpdateCatalogEntry(CatalogEntry *entry, char *path, char *contents)
+{
+ if (!entry->contents) {
+ entry->contents = strdup(contents);
+ }
+
+ if (entry->files < MAXFILESPERCONTENT) {
+ entry->fullFileName[entry->files++] = strdup(path);
+ } else {
+ AbortProg("Number of file with same content too large!", NULL);
+ }
+}
+
+/**
+ * Create the list for the catalog entries
+ *
+ * \return
+ */
+
+static CatalogEntry *
+CreateCatalog()
+{
+ CatalogEntry *catalog = InitCatalog();
+
+ return (catalog);
+}
+
+
+static IndexEntry *
+CreateIndexTable(unsigned int capacity)
+{
+ IndexEntry *index = (IndexEntry *)malloc(capacity * sizeof(IndexEntry));
+
+ return (index);
+}
+
+/**
+ * Scan opened directory for the next parameter file
+ *
+ * \param dir IN opened directory handle
+ * \param dirName IN name of directory
+ * \param fileName OUT fully qualified filename
+ *
+ * \return TRUE if file found, FALSE if not
+ */
+
+static bool
+GetNextParameterFile(DIR *dir, const char *dirName, char **fileName)
+{
+ bool done = false;
+ bool res = false;
+
+ /*
+ * get all files from the directory
+ */
+ while (!done) {
+ struct stat fileState;
+ struct dirent *ent;
+
+ ent = readdir(dir);
+
+ if (ent) {
+ if (!XtcStricmp(FindFileExtension(ent->d_name), "xtp")) {
+ /* create full file name and get the state for that file */
+ MakeFullpath(fileName, dirName, ent->d_name, NULL);
+
+ if (stat(*fileName, &fileState) == -1) {
+ fprintf(stderr, "Error getting file state for %s\n", *fileName);
+ continue;
+ }
+
+ /* ignore any directories */
+ if (!(fileState.st_mode & S_IFDIR)) {
+ done = true;
+ res = true;
+ }
+ }
+ } else {
+ done = true;
+ res = false;
+ }
+ }
+ return (res);
+}
+
+/**
+ * Scan a directory for parameter files. For each file found the CONTENTS is
+ * read and added to the list *
+ *
+ * \param insertAfter IN starting point for the list of files
+ * \param dirName IN directory to be scanned
+ *
+ * \return pointer to the last element(?)
+ */
+
+static CatalogEntry *
+ScanDirectory(CatalogEntry *catalog, const char *dirName)
+{
+ DIR *d;
+ CatalogEntry *newEntry = catalog;
+
+ d = opendir(dirName);
+ if (d) {
+ char *fileName = NULL;
+
+ while (GetNextParameterFile(d, dirName, &fileName)) {
+ CatalogEntry *existingEntry;
+ char *contents = GetParameterFileContent(fileName);
+ if ((existingEntry = IsExistingContents(catalog, contents,FALSE))) {
+ printf("Duplicate CONTENTS record in parameter file %s\n", fileName);
+ if (strcmp(existingEntry->fullFileName[existingEntry->files-1],fileName))
+ UpdateCatalogEntry(existingEntry, fileName, contents);
+ } else {
+ newEntry = InsertInOrder(catalog,contents);
+ UpdateCatalogEntry(newEntry, fileName, contents);
+ }
+ free(contents);
+ free(fileName);
+ fileName = NULL;
+ }
+ closedir(d);
+ }
+
+ return (newEntry);
+}
+
+/**
+ * Comparison function for IndexEntries used by qsort()
+ *
+ * \param entry1 IN
+ * \param entry2 IN
+ * \return per C runtime conventions
+ */
+
+static int
+CompareIndex(const void *entry1, const void *entry2)
+{
+ IndexEntry index1 = *(IndexEntry *)entry1;
+ IndexEntry index2 = *(IndexEntry *)entry2;
+ return (strcoll(index1.keyWord, index2.keyWord));
+}
+
+/*!
+ * Filter keywords. Current rules:
+ * - single character string that only consist of a punctuation char
+ *
+ * \param word IN keyword
+ * \return true if any rule applies, false otherwise
+ */
+
+bool
+FilterKeyword(char *word)
+{
+ if (strlen(word) == 1 && strpbrk(word, PUNCTUATION )) {
+ return(true);
+ }
+ return(false);
+}
+
+/**
+ * Create the keyword index from a list of parameter files
+ *
+ * \param catalog IN list of parameter files
+ * \param index IN index table to be filled
+ * \param pointer IN/OUT array of words that are indexed
+ * \param capacityOfIndex IN total maximum of keywords
+ * \return number of indexed keywords
+ */
+static unsigned
+CreateContentsIndex(CatalogEntry *catalog, IndexEntry *index, void** words_array,
+ unsigned capacityOfIndex)
+{
+ CatalogEntry *currentEntry = catalog->next;
+ unsigned totalMemory = 0;
+ size_t wordCount = 0;
+ char *wordList;
+ char *wordListPtr;
+
+ while (currentEntry != currentEntry->next) {
+ totalMemory += strlen(currentEntry->contents) + 1;
+ currentEntry = currentEntry->next;
+ }
+
+ wordList = malloc((totalMemory + 1) * sizeof(char));
+ *words_array = (void*)wordList;
+
+ wordListPtr = wordList;
+ currentEntry = catalog->next;
+
+ while (currentEntry != currentEntry->next) {
+ char *word;
+ char *content = strdup(currentEntry->contents);
+
+ word = strtok(content, " \t\n\r");
+ while (word && wordCount < capacityOfIndex) {
+ strcpy(wordListPtr, word);
+
+ char *p = wordListPtr;
+ for (; *p; ++p) {
+ *p = tolower(*p);
+ }
+ if (!FilterKeyword(wordListPtr)) {
+ index[wordCount].value = currentEntry;
+ index[wordCount].keyWord = wordListPtr;
+ wordListPtr += strlen(word) + 1;
+ wordCount++;
+ if (wordCount >= capacityOfIndex) {
+ AbortProg("Too many keywords were used!", NULL);
+ }
+ }
+ word = strtok(NULL, " \t\n\r");
+ }
+ free(content);
+ currentEntry = currentEntry->next;
+ }
+ *wordListPtr = '\0';
+
+ qsort((void*)index, wordCount, sizeof(IndexEntry), CompareIndex);
+
+ return (wordCount);
+}
+
+/**
+* A recursive binary search function. It returns location of x in
+* given array arr[l..r] is present, otherwise -1
+* Taken from http://www.geeksforgeeks.org/binary-search/ and modified
+*
+* \param arr IN array to search
+* \param l IN starting index
+* \param r IN highest index in array
+* \param key IN key to search
+* \return index if found, -1 otherwise
+*/
+
+static int SearchInIndex(IndexEntry arr[], int l, int r, char *key)
+{
+ if (r >= l) {
+ int mid = l + (r - l) / 2;
+ int res = XtcStricmp(key, arr[mid].keyWord);
+
+ // If the element is present at the middle itself
+ if (!res) {
+ return mid;
+ }
+
+ // If the array size is 1
+ if (r == 0) {
+ return -1;
+ }
+
+ // If element is smaller than mid, then it can only be present
+ // in left subarray
+ if (res < 0) {
+ return SearchInIndex(arr, l, mid - 1, key);
+ }
+
+ // Else the element can only be present in right subarray
+ return SearchInIndex(arr, mid + 1, r, key);
+ }
+
+ // We reach here when element is not present in array
+ return -1;
+}
+
+/**
+ * Inserts a key in arr[] of given capacity. n is current
+ * size of arr[]. This function returns n+1 if insertion
+ * is successful, else n.
+ * Taken from http ://www.geeksforgeeks.org/search-insert-and-delete-in-a-sorted-array/ and modified
+ */
+
+int InsertSorted(CatalogEntry *arr[], int n, CatalogEntry *key, int capacity)
+{
+ // Cannot insert more elements if n is already
+ // more than or equal to capcity
+ if (n >= capacity) {
+ return n;
+ }
+
+ int i;
+ for (i = n - 1; (i >= 0 && arr[i] > key); i--) {
+ arr[i + 1] = arr[i];
+ }
+
+ arr[i + 1] = key;
+
+ return (n + 1);
+}
+
+/**
+ * Comparison function for CatalogEntries used by qsort()
+ *
+ * \param entry1 IN
+ * \param entry2 IN
+ * \return per C runtime conventions
+ */
+
+static int
+CompareResults(const void *entry1, const void *entry2)
+{
+ CatalogEntry * index1 = *(CatalogEntry **)entry1;
+ CatalogEntry * index2 = *(CatalogEntry **)entry2;
+ return (strcoll(index1->contents, index2->contents));
+}
+
+/**
+ * Search the index for a keyword. The index is assumed to be sorted. So after one entry
+ * is found, neighboring entries up and down are checked as well. The total result set
+ * is placed into an array and returned. This array has to be free'd by the caller.
+ *
+ * \param index IN index list
+ * \param length IN number of entries index
+ * \param search IN search string
+ * \param resultCount OUT count of found entries
+ * \return array of found catalog entries, NULL if none found
+ */
+
+static int findAll = 1;
+
+unsigned int
+FindWord(IndexEntry *index, int length, char *search, CatalogEntry ***entries)
+{
+ CatalogEntry **result; //Array of pointers to Catalog Entries
+ int found;
+ int foundElements = 0;
+ *entries = NULL;
+
+ //Get all the entries back for generic search or if "generic find"
+ if (findAll || !search || (search[0] == '*') || (search[0] == '\0')) {
+ result = malloc((length) * sizeof(CatalogEntry *));
+ for (int i = 0; i < length; i++) {
+ result[i] = index[i].value;
+ }
+ *entries = result;
+ return length;
+ }
+
+ found = SearchInIndex(index, 0, length, search);
+
+ if (found >= 0) {
+ int lower = found;
+ int upper = found;
+ int i;
+
+ while (lower > 0 && !XtcStricmp(index[lower-1].keyWord, search)) {
+ lower--;
+ }
+
+ while (upper < length - 1 && !XtcStricmp(index[upper + 1].keyWord, search)) {
+ upper++;
+ }
+
+ foundElements = 1 + upper - lower;
+
+ result = malloc((foundElements) * sizeof(CatalogEntry *));
+
+ for (i = 0; i < foundElements; i++) {
+ result[i] = index[i+lower].value;
+ }
+
+ qsort((void*)result, foundElements, sizeof(void *), CompareResults);
+
+ *entries = result;
+ }
+ return (foundElements);
+}
+
+/**
+ * Create and initialize the data structure for the track library
+ *
+ * \param trackLibrary OUT the newly allocated track library
+ * \return TRUE on success
+ */
+
+TrackLibrary *
+InitLibrary(void)
+{
+ TrackLibrary *trackLib = malloc(sizeof(TrackLibrary));
+
+ if (trackLib) {
+ trackLib->catalog = CreateCatalog();
+ trackLib->index = NULL;
+ trackLib->wordCount = 0;
+ trackLib->trackTypeCount = 0;
+ }
+
+ return (trackLib);
+}
+
+/**
+ * Scan directory and all parameter files found to the catalog
+ *
+ * \param trackLib IN the catalog
+ * \param directory IN directory to scan
+ * \return number of files found
+ */
+
+bool
+GetTrackFiles(TrackLibrary *trackLib, char *directory)
+{
+ ScanDirectory(trackLib->catalog, directory);
+ trackLib->trackTypeCount = CountCatalogEntries(trackLib->catalog);
+
+ return (trackLib->trackTypeCount);
+}
+/**
+ * Add a list of parameters files to a catalog. This function is
+ * called when the user selects files in the file selector.
+ *
+ * \param files IN count of files
+ * \param fileName IN array of filenames
+ * \param data IN pointer to the catalog
+ * \return alwqys TRUE
+ */
+
+int GetParameterFileInfo(
+ int files,
+ char ** fileName,
+ void * data)
+{
+ CatalogEntry *catalog = (CatalogEntry *)data;
+
+ assert(fileName != NULL);
+ assert(files > 0);
+ assert(data != NULL);
+
+ for (int i = 0; i < files; i++) {
+ CatalogEntry *newEntry;
+ char *contents = GetParameterFileContent(fileName[i]);
+
+ if (!(newEntry = IsExistingContents(catalog, contents,TRUE))) {
+ newEntry = InsertIntoCatalogAfter(catalog);
+ }
+ UpdateCatalogEntry(newEntry, fileName[i], contents);
+ free(contents);
+ }
+ return (TRUE);
+}
+
+/**
+ * Create the search index from the contents description for the whole catalog.
+ * A fixed number of words are added to the index. See ESTIMATED_CONTENTS_WORDS
+ *
+ * \param trackLib IN the catalog
+ * \return the number of words indexed
+ */
+
+unsigned
+CreateLibraryIndex(TrackLibrary *trackLib)
+{
+ trackLib->index = CreateIndexTable(trackLib->trackTypeCount *
+ ESTIMATED_CONTENTS_WORDS);
+
+ trackLib->wordCount = CreateContentsIndex(trackLib->catalog, trackLib->index,
+ &trackLib->words_array,
+ ESTIMATED_CONTENTS_WORDS * trackLib->trackTypeCount);
+
+ return (trackLib->wordCount);
+}
+
+void
+DeleteLibraryIndex(TrackLibrary *trackLib)
+{
+ free(trackLib->index);
+ trackLib->index = NULL;
+
+ free(trackLib->words_array);
+
+ trackLib->wordCount = 0;
+
+}
+
+
+/**
+ * Create the library and index of parameter files in a given directory.
+ *
+ * \param directory IN directory to scan
+ * \return NULL if error or empty directory, else library handle
+ */
+
+TrackLibrary *
+CreateLibrary(char *directory)
+{
+ TrackLibrary *library;
+
+ library = InitLibrary();
+ if (library) {
+ if (!GetTrackFiles(library, directory)) {
+ return (NULL);
+ }
+
+ CreateLibraryIndex(library);
+ }
+ return (library);
+}
+
+void
+DeleteLibrary(TrackLibrary* library)
+{
+ DeleteLibraryIndex(library);
+
+
+ free(library);
+}
+
+// Case insensitive comparison
+char* stristr( const char* haystack, const char* needle )
+{
+ int c = tolower((unsigned char)*needle);
+ if (c == '\0')
+ return (char *)haystack;
+ for (; *haystack; haystack++) {
+ if (tolower((unsigned char)*haystack) == c) {
+ for (size_t i = 0;;) {
+ if (needle[++i] == '\0')
+ return (char *)haystack;
+ if (tolower((unsigned char)haystack[i]) != tolower((unsigned char)needle[i]))
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Search the library for a keyword string and return the result list
+ *
+ * First the index is searched for the first word and then each "hit" is matched
+ * to the entire search string
+ *
+ * Null, Blank and "*" match all entries
+ *
+ * The list is de-duped of repeat of filenames as the same file might appear in
+ * more than once
+ *
+ * \param library IN the library
+ * \param searchExpression IN keyword to search for
+ * \param resultEntries IN list header for result list
+ * \return number of found entries
+ */
+unsigned
+SearchLibrary(TrackLibrary *library, char *searchExpression,
+ CatalogEntry *resultEntries)
+{
+ CatalogEntry **entries;
+ CatalogEntry * newEntry = resultEntries;
+ unsigned entryCount;
+
+ char * word;
+
+ word = strdup(searchExpression);
+
+ //word = strtok(word," \t");
+
+ if (library->index == NULL || library->wordCount == 0) {
+ return (0);
+ }
+ entryCount = FindWord(library->index, library->wordCount, word,
+ &entries);
+ int count= 0;
+ if (entryCount) {
+ unsigned int i = 0;
+ while (i < entryCount) {
+ char * match;
+ //Check if entire String Matches
+ if (!searchExpression || !word || (word[0] == '*') || (word[0] == '\0') ||
+ (match = stristr(entries[i]->contents,searchExpression))) {
+ CatalogEntry * existingEntry;
+ existingEntry = IsExistingContents(resultEntries, entries[i]->contents, TRUE);
+ //Same FileName already in one of the entries?
+ BOOL_T found = FALSE;
+ if (existingEntry) {
+ for (unsigned int j=0;j<existingEntry->files;j++) {
+ if (!strcmp(existingEntry->fullFileName[j],entries[i]->fullFileName[entries[i]->files-1])) {
+ found=TRUE;
+ break;
+ }
+ }
+ if (found == TRUE ) {
+ i++;
+ continue;
+ }
+ UpdateCatalogEntry(existingEntry, entries[i]->fullFileName[(entries[i]->files- 1)],
+ entries[i]->contents);
+ } else {
+ newEntry = InsertInOrder(resultEntries,entries[i]->contents);
+ UpdateCatalogEntry(newEntry, entries[i]->fullFileName[(entries[i]->files- 1)],
+ entries[i]->contents);
+ }
+ count++;
+ }
+ i++;
+ }
+ }
+ free(word);
+ if (entries)
+ free(entries); //Clean-up after search
+ return (count);
+}
+
+/**
+ * Get the contents description from a parameter file. Returned string has to be freed after use.
+ *
+ * \param file IN xtpfile
+ * \return pointer to found contents or NULL if not present
+ */
+
+char *
+GetParameterFileContent(char *file)
+{
+ FILE *fh;
+ char *result = NULL;
+
+ fh = fopen(file, "rt");
+ if (fh) {
+ bool found = false;
+
+ while (!found) {
+ char buffer[512];
+ if (fgets(buffer, sizeof(buffer), fh)) {
+ char *ptr = strtok(buffer, " \t");
+ if (!XtcStricmp(ptr, CONTENTSCOMMAND)) {
+ /* if found, store the rest of the line and the filename */
+ ptr = ptr+strlen(CONTENTSCOMMAND)+1;
+ ptr = strtok(ptr, "\r\n");
+ result = strdup(ptr);
+#ifdef WINDOWS
+ ConvertUTF8ToSystem(result);
+#endif // WINDOWS
+ found = true;
+ }
+ } else {
+ fprintf(stderr, "Nothing found in %s\n", file);
+ found = true;
+ }
+ }
+ fclose(fh);
+ }
+ return(result);
+}
diff --git a/app/bin/paths.c b/app/bin/paths.c
index cbd9b38..6c6bb10 100644
--- a/app/bin/paths.c
+++ b/app/bin/paths.c
@@ -69,7 +69,7 @@ FindPath(const char *type)
}
/**
- * Add a path to the table. If it already exists, the value ist updated.
+ * Add a path to the table. If it already exists, the value list updated.
*
* \param type IN type of path
* \param path IN path
@@ -162,6 +162,21 @@ char *GetCurrentPath(
}
/**
+ * Convert path to forward slash
+ *
+ * \param [in,out] string If non-null, the string.
+ */
+
+void ConvertPathForward(char *string)
+{
+ char *ptr = string;
+ while ((ptr = strchr(ptr, '\\')) != NULL) {
+ ptr[0] = '/';
+ ptr++;
+ }
+}
+
+/**
* Find the filename/extension piece in a fully qualified path
*
* \param path IN the full path
@@ -183,8 +198,28 @@ char *FindFilename(char *path)
}
/**
+ * Find file extension in a filename
+ *
+ * \param path IN full or partial path
+ * \return pointer to the file extension part, empty string if no extension present
+ */
+
+char *FindFileExtension(char *path) {
+ char *ext;
+ ext = strrchr(path, '.');
+
+ if (ext) {
+ ext++;
+ } else {
+ ext = path + strlen(path);
+ }
+
+ return ext;
+}
+
+/**
* Make a full path definition from directorys and filenames. The individual pieces are
-* concatinated. Where necessary a path delimiter is added. A pointer to the resulting
+* Concatenated. Where necessary a path delimiter is added. A pointer to the resulting
* string is returned. This memory should be free'd when no longer needed.
* Windows: to construct an absolute path, a leading backslash has to be included after
* the drive delimiter ':' or at the beginning of the first directory name.
diff --git a/app/bin/paths.h b/app/bin/paths.h
index 1e3c98a..f3f5f23 100644
--- a/app/bin/paths.h
+++ b/app/bin/paths.h
@@ -27,6 +27,8 @@
void SetCurrentPath( const char * pathType, const char * fileName );
char *GetCurrentPath(const char *pathType);
+void ConvertPathForward(char *string);
char *FindFilename(char *path);
+char *FindFileExtension(char *path);
void MakeFullpath(char **str, ...);
#endif
diff --git a/app/bin/shortentext.c b/app/bin/shortentext.c
new file mode 100644
index 0000000..6cd16e6
--- /dev/null
+++ b/app/bin/shortentext.c
@@ -0,0 +1,92 @@
+/** \file stringutils.c
+ * Some assorted string handling functions
+ */
+
+ /* XTrackCAD - Model Railroad CAD
+ * Copyright (C) 2019 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 <string.h>
+#include "shortentext.h"
+
+#define WHITESPACES "\n\r\t "
+#define ELLIPSIZE "..."
+
+/**
+ * Replace all whitespace characters with blanks. Successive occurences are reduced to a single blank.
+ *
+ * \param source IN string to convert
+ * \param dest IN buffer for converted string, minimum size is the size of the source string
+ */
+void
+RemoveFormatChars( char *source, char *dest )
+{
+ int lastChar = '\0';
+
+ while (*source) {
+ if (strchr(WHITESPACES, *source)) {
+ if (lastChar != ' ') {
+ *dest++ = ' ';
+ lastChar = ' ';
+ }
+ } else {
+ lastChar = *source;
+ *dest++ = lastChar;
+ }
+ source++;
+ }
+ if (lastChar != ' ') {
+ *dest = '\0';
+ } else {
+ *(dest - 1) = '\0';
+ }
+}
+
+void
+EllipsizeString(char *source, char *dest, size_t length)
+{
+ size_t position;
+ char *resultString = (dest ? dest: source);
+
+
+ // trivial case: nothing to do if source is shorter and no inplace
+ if( strlen(source) <= length )
+ {
+ if( dest )
+ strcpy(dest, source);
+ return;
+ }
+
+ strncpy(resultString, source, length);
+ resultString[ length ] = '\0';
+
+ position = length - 1;
+ while (position) {
+ if (resultString[position] == ' ' && position <= (length - sizeof(ELLIPSIZE))) {
+ strcpy(resultString + position, ELLIPSIZE);
+ break;
+ } else {
+ position--;
+ }
+ }
+
+ // no blank in string, replace the last n chars
+ if (!position) {
+ strcpy(resultString + (strlen(resultString) - sizeof(ELLIPSIZE) + 1), ELLIPSIZE);
+ }
+ return;
+} \ No newline at end of file
diff --git a/app/bin/shortentext.h b/app/bin/shortentext.h
new file mode 100644
index 0000000..1b71a08
--- /dev/null
+++ b/app/bin/shortentext.h
@@ -0,0 +1,28 @@
+/** \file stringutils.h
+ * String handling utilities
+ */
+
+ /* XTrackCAD - Model Railroad CAD
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef HAVE_STRINGUTILS_H
+#define HAVE_STRINGUTILS_H
+ void RemoveFormatChars(char *source, char *dest);
+ void EllipsizeString(char *source, char *dest, size_t length);
+#endif // !HAVE_STRINGUTIL_H
+
diff --git a/app/bin/smalldlg.c b/app/bin/smalldlg.c
index 7828912..1fb5965 100644
--- a/app/bin/smalldlg.c
+++ b/app/bin/smalldlg.c
@@ -36,6 +36,7 @@
#ifdef WINDOWS
#include <io.h>
#include <windows.h>
+#include <FreeImage.h>
#else
#include <sys/stat.h>
#endif
@@ -67,7 +68,7 @@ static paramData_t tipPLs[] = {
#define I_TIPTEXT (1)
#define tipT ((wText_p)tipPLs[I_TIPTEXT].control)
{ PD_MESSAGE, N_("Did you know..."), NULL, 0, NULL, NULL, BM_LARGE },
- { PD_TEXT, NULL, "text", 0, &tipTextData, NULL, BO_READONLY|BT_CHARUNITS },
+ { PD_TEXT, NULL, "text", 0, &tipTextData, NULL, BO_READONLY|BT_TOP|BT_CHARUNITS },
{ PD_BUTTON, (void*)ShowTip, "prev", PDO_DLGRESETMARGIN, NULL, N_("Previous Tip"), 0L, (void *)(SHOWTIP_FORCESHOW | SHOWTIP_PREVTIP) },
{ PD_BUTTON, (void*)ShowTip, "next", PDO_DLGHORZ, NULL, N_("Next Tip"), 0L, (void *)(SHOWTIP_FORCESHOW | SHOWTIP_NEXTTIP) },
{ PD_TOGGLE, &showTipAtStart, "showatstart", PDO_DLGCMDBUTTON, tipLabels, NULL, BC_NOBORDER }};
@@ -86,7 +87,7 @@ static void CreateTipW( void )
char *filename;
char * cp;
- tipW = ParamCreateDialog( &tipPG, MakeWindowTitle(_("Tip of the Day")), _("Ok"), (paramActionOkProc)wHide, NULL, FALSE, NULL, F_CENTER, NULL );
+ tipW = ParamCreateDialog( &tipPG, MakeWindowTitle(_("Tip of the Day")), _("Ok"), (paramActionOkProc)wHide, wHide, FALSE, NULL, F_RESIZE|F_CENTER, NULL );
/* open the tip file */
MakeFullpath(&filename, libDir, sTipF, NULL);
@@ -167,7 +168,8 @@ void ShowTip( long flags )
}
ParamLoadControls( &tipPG );
wTextClear( tipT );
- wPrefGetInteger( "misc", "tip-number", &tipNum, 0 );
+ /* initial value is -1 which gets incremented 0 below */
+ wPrefGetInteger( "misc", "tip-number", &tipNum, -1 );
if( flags & SHOWTIP_PREVTIP ) {
if(tipNum == 0 )
@@ -202,7 +204,7 @@ static paramData_t aboutPLs[] = {
{ PD_MESSAGE, NULL, NULL, PDO_DLGNEWCOLUMN, NULL, NULL, BM_LARGE },
#define I_COPYRIGHT (2)
#define COPYRIGHT_T ((wText_p)aboutPLs[I_COPYRIGHT].control)
- { PD_TEXT, NULL, NULL, PDO_DLGRESIZE, &aboutTextData, NULL, BT_CHARUNITS }
+ { PD_TEXT, NULL, NULL, PDO_DLGRESIZE, &aboutTextData, NULL, BO_READONLY|BT_TOP|BT_CHARUNITS }
};
static paramGroup_t aboutPG = { "about", 0, aboutPLs, sizeof aboutPLs/sizeof aboutPLs[0] };
@@ -217,13 +219,18 @@ void CreateAboutW( void *ptr )
if( !aboutW ) {
aboutPLs[I_ABOUTDRAW].winData = wIconCreatePixMap( xtc_xpm );
ParamRegister( &aboutPG );
- aboutW = ParamCreateDialog( &aboutPG, MakeWindowTitle(_("About")), _("Ok"), (paramActionOkProc)wHide, NULL, FALSE, NULL, F_TOP|F_CENTER, NULL );
+ aboutW = ParamCreateDialog( &aboutPG, MakeWindowTitle(_("About")), _("Ok"), (paramActionOkProc)wHide, wHide, FALSE, NULL, F_TOP|F_CENTER, NULL );
ParamLoadMessage( &aboutPG, I_ABOUTVERSION, sAboutProd );
wTextAppend( COPYRIGHT_T, DESCRIPTION );
wTextAppend( COPYRIGHT_T, "\n\nXTrackCAD is Copyright 2003 by Sillub Technology and 2017 by Bob Blackwell, Martin Fischer and Adam Richards." );
wTextAppend( COPYRIGHT_T, "\nIcons by: Tango Desktop Project (http://tango.freedesktop.org)");
+ wTextAppend(COPYRIGHT_T, "\nSome icons by Yusuke Kamiyamane. Licensed under a Creative Commons Attribution 3.0 License.");
wTextAppend( COPYRIGHT_T, "\nContributions by: Robert Heller, Mikko Nissinen, Timothy M. Shead, Daniel Luis Spagnol" );
wTextAppend( COPYRIGHT_T, "\nParameter Files by: Ralph Boyd, Dwayne Ward" );
+#ifdef WINDOWS
+ wTextAppend(COPYRIGHT_T, "\n");
+ wTextAppend(COPYRIGHT_T, FreeImage_GetCopyrightMessage());
+#endif
wTextAppend( COPYRIGHT_T, "\nCornu Algorithm and Implementation by: Raph Levien");
wTextAppend( COPYRIGHT_T, "\nuthash Copyright notice:" );
wTextAppend( COPYRIGHT_T, "\nCopyright (c) 2005-2015, Troy D. Hanson http://troydhanson.github.com/uthash/");
diff --git a/app/bin/stringxtc.c b/app/bin/stringxtc.c
new file mode 100644
index 0000000..483f1a6
--- /dev/null
+++ b/app/bin/stringxtc.c
@@ -0,0 +1,106 @@
+/** \file stringxtc.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+ /*
+ * stupid library routines.
+ */
+
+#include <ctype.h>
+#include <stddef.h>
+#include <errno.h>
+#include "include/stringxtc.h"
+
+/**
+ * strscpy - Copy a C-string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: Size of destination buffer
+ *
+ * Copy the string, or as much of it as fits, into the dest buffer. The
+ * behavior is undefined if the string buffers overlap. The destination
+ * buffer is always NUL terminated, unless it's zero-sized.
+ *
+ * Preferred to strlcpy() since the API doesn't require reading memory
+ * from the src string beyond the specified "count" bytes, and since
+ * the return value is easier to error-check than strlcpy()'s.
+ * In addition, the implementation is robust to the string changing out
+ * from underneath it, unlike the current strlcpy() implementation.
+ *
+ * Preferred to strncpy() since it always returns a valid string, and
+ * doesn't unnecessarily force the tail of the destination buffer to be
+ * zeroed. If zeroing is desired please use strscpy_pad().
+ *
+ * Return: The number of characters copied (not including the trailing
+ * %NUL) or -E2BIG if the destination buffer wasn't big enough.
+ */
+
+size_t strscpy(char *dest, const char *src, size_t count)
+{
+ long res = 0;
+
+ if (count == 0)
+ return -E2BIG;
+
+ while (count) {
+ char c;
+
+ c = src[res];
+ dest[res] = c;
+ if (!c)
+ return res;
+ res++;
+ count--;
+ }
+
+ /* Hit buffer length without finding a NUL; force NUL-termination. */
+ if (res)
+ dest[res - 1] = '\0';
+
+ return -E2BIG;
+}
+
+/**
+ * Convert a string to lower case
+ * Taken from https://stackoverflow.com/questions/23618316/undefined-reference-to-strlwr
+ *
+ * \param str IN string to convert
+ * \return pointer to converted string
+ */
+
+char *
+XtcStrlwr(char *str)
+{
+ unsigned char *p = (unsigned char *)str;
+
+ while (*p) {
+ *p = tolower((unsigned char)*p);
+ p++;
+ }
+
+ return str;
+}
+
+/**
+ * Compare two strings case insensitive
+ * Taken from https://stackoverflow.com/questions/30733786/c99-remove-stricmp-and-strnicmp
+ *
+ * \param a, b IN strings to compare
+ * \return
+ */
+
+int
+XtcStricmp(const char *a, const char *b)
+{
+ int ca, cb;
+ do {
+ ca = (unsigned char) *a++;
+ cb = (unsigned char) *b++;
+ ca = tolower(toupper(ca));
+ cb = tolower(toupper(cb));
+ } while ((ca == cb) && (ca != '\0'));
+ return ca - cb;
+}
+
+
diff --git a/app/bin/tbezier.c b/app/bin/tbezier.c
index 80feedb..fc949a2 100644
--- a/app/bin/tbezier.c
+++ b/app/bin/tbezier.c
@@ -54,7 +54,6 @@
EXPORT TRKTYP_T T_BEZIER = -1;
EXPORT TRKTYP_T T_BZRLIN = -1;
-
struct extraData {
BezierData_t bezierData;
};
@@ -134,17 +133,25 @@ static void ComputeBezierBoundingBox( track_p trk, struct extraData * xx )
DIST_T BezierDescriptionDistance(
coOrd pos,
- track_p trk )
+ track_p trk,
+ coOrd * dpos,
+ BOOL_T show_hidden,
+ BOOL_T * hidden)
{
struct extraData *xx = GetTrkExtraData(trk);
coOrd p1;
-
- if ( GetTrkType( trk ) != T_BEZIER || ( GetTrkBits( trk ) & TB_HIDEDESC ) != 0 )
+ if (hidden) *hidden = FALSE;
+ if ( GetTrkType( trk ) != T_BEZIER || ((( GetTrkBits( trk ) & TB_HIDEDESC ) != 0 ) && !show_hidden))
return 100000;
- p1.x = xx->bezierData.pos[0].x + ((xx->bezierData.pos[3].x-xx->bezierData.pos[0].x)/2) + xx->bezierData.descriptionOff.x;
- p1.y = xx->bezierData.pos[0].y + ((xx->bezierData.pos[3].y-xx->bezierData.pos[0].y)/2) + xx->bezierData.descriptionOff.y;
-
+ coOrd offset = xx->bezierData.descriptionOff;
+
+ if (( GetTrkBits( trk ) & TB_HIDEDESC ) != 0 ) offset = zero;
+
+ p1.x = xx->bezierData.pos[0].x + ((xx->bezierData.pos[3].x-xx->bezierData.pos[0].x)/2) + offset.x;
+ p1.y = xx->bezierData.pos[0].y + ((xx->bezierData.pos[3].y-xx->bezierData.pos[0].y)/2) + offset.y;
+ if (hidden) *hidden = (GetTrkBits( trk ) & TB_HIDEDESC);
+ *dpos = p1;
return FindDistance( p1, pos );
}
@@ -167,8 +174,8 @@ static void DrawBezierDescription(
pos.x += xx->bezierData.descriptionOff.x;
pos.y += xx->bezierData.descriptionOff.y;
fp = wStandardFont( F_TIMES, FALSE, FALSE );
- sprintf( message, _("Bezier Curve: length=%s min radius=%s"),
- FormatDistance(xx->bezierData.length), FormatDistance(xx->bezierData.minCurveRadius));
+ sprintf( message, _("Bezier: len=%0.2f min_rad=%0.2f"),
+ xx->bezierData.length, xx->bezierData.minCurveRadius>10000?0.0:xx->bezierData.minCurveRadius);
DrawBoxedString( BOX_BOX, d, pos, message, fp, (wFontSize_t)descriptionFontSize, color, 0.0 );
}
@@ -180,30 +187,31 @@ STATUS_T BezierDescriptionMove(
{
struct extraData *xx = GetTrkExtraData(trk);
static coOrd p0,p1;
- static BOOL_T editState;
- wDrawColor color;
+ static BOOL_T editState = FALSE;
+
if (GetTrkType(trk) != T_BEZIER) return C_TERMINATE;
p0.x = xx->bezierData.pos[0].x + ((xx->bezierData.pos[3].x - xx->bezierData.pos[0].x)/2);
p0.y = xx->bezierData.pos[0].y + ((xx->bezierData.pos[3].y - xx->bezierData.pos[0].y)/2);
switch (action) {
case C_DOWN:
+ DrawBezierDescription( trk, &mainD, wDrawColorWhite );
case C_MOVE:
case C_UP:
editState = TRUE;
p1 = pos;
- color = GetTrkColor( trk, &mainD );
- DrawLine( &mainD, p0, pos, 0, wDrawColorBlack );
xx->bezierData.descriptionOff.x = pos.x - p0.x;
xx->bezierData.descriptionOff.y = pos.y - p0.y;
if (action == C_UP) {
editState = FALSE;
+ wDrawColor color = GetTrkColor( trk, &mainD );
+ DrawBezierDescription( trk, &mainD, color );
}
- MainRedraw();
- MapRedraw();
return action==C_UP?C_TERMINATE:C_CONTINUE;
case C_REDRAW:
- if (editState)
- DrawLine( &mainD, p1, p0, 0, wDrawColorBlack );
+ if (editState) {
+ DrawBezierDescription( trk, &tempD, wDrawColorBlue );
+ DrawLine( &tempD, p1, p0, 0, wDrawColorBlue );
+ }
break;
@@ -230,8 +238,9 @@ static struct {
dynArr_t segs;
long width;
wDrawColor color;
+ long lineType;
} bezData;
-typedef enum { P0, A0, R0, C0, Z0, CP1, CP2, P1, A1, R1, C1, Z1, RA, LN, GR, LY, WI, CO } crvDesc_e;
+typedef enum { P0, A0, R0, C0, Z0, CP1, CP2, P1, A1, R1, C1, Z1, RA, LN, GR, LT, WI, CO, LY} crvDesc_e;
static descData_t bezDesc[] = {
/*P0*/ { DESC_POS, N_("End Pt 1: X,Y"), &bezData.pos[0] },
/*A0*/ { DESC_ANGLE, N_("End Angle"), &bezData.angle[0] },
@@ -248,9 +257,10 @@ static descData_t bezDesc[] = {
/*RA*/ { DESC_DIM, N_("MinRadius"), &bezData.radius },
/*LN*/ { DESC_DIM, N_("Length"), &bezData.length },
/*GR*/ { DESC_FLOAT, N_("Grade"), &bezData.grade },
-/*LY*/ { DESC_LAYER, N_("Layer"), &bezData.layerNumber },
+/*LT*/ { DESC_LIST, N_("Line Type"), &bezData.lineType},
/*WI*/ { DESC_LONG, N_("Line Width"), &bezData.width},
/*CO*/ { DESC_COLOR, N_("Line Color"), &bezData.color},
+/*LY*/ { DESC_LAYER, N_("Layer"), &bezData.layerNumber },
{ DESC_NULL } };
static void UpdateBezier( track_p trk, int inx, descData_p descUpd, BOOL_T final )
@@ -305,7 +315,7 @@ static void UpdateBezier( track_p trk, int inx, descData_p descUpd, BOOL_T final
case Z1:
ep = (inx==Z0?0:1);
UpdateTrkEndElev( trk, ep, GetTrkEndElevUnmaskedMode(trk,ep), bezData.elev[ep], NULL );
- ComputeElev( trk, 1-ep, FALSE, &bezData.elev[1-ep], NULL );
+ ComputeElev( trk, 1-ep, FALSE, &bezData.elev[1-ep], NULL, TRUE );
if ( bezData.length > minLength )
bezData.grade = fabs( (bezData.elev[0]-bezData.elev[1])/bezData.length )*100.0;
else
@@ -322,6 +332,9 @@ static void UpdateBezier( track_p trk, int inx, descData_p descUpd, BOOL_T final
case CO:
xx->bezierData.segsColor = bezData.color;
break;
+ case LT:
+ xx->bezierData.lineType = bezData.lineType;
+ break;
default:
AbortProg( "updateBezier: Bad inx %d", inx );
}
@@ -398,8 +411,8 @@ static void DescribeBezier( track_p trk, char * str, CSIZE_T len )
bezData.center[1] = params.arcP;
if (GetTrkType(trk) == T_BEZIER) {
- ComputeElev( trk, 0, FALSE, &bezData.elev[0], NULL );
- ComputeElev( trk, 1, FALSE, &bezData.elev[1], NULL );
+ ComputeElev( trk, 0, FALSE, &bezData.elev[0], NULL, FALSE );
+ ComputeElev( trk, 1, FALSE, &bezData.elev[1], NULL, FALSE );
if ( bezData.length > minLength )
bezData.grade = fabs( (bezData.elev[0]-bezData.elev[1])/bezData.length )*100.0;
@@ -415,9 +428,13 @@ static void DescribeBezier( track_p trk, char * str, CSIZE_T len )
if (GetTrkType(trk) == T_BEZIER) {
bezDesc[Z0].mode = EndPtIsDefinedElev(trk,0)?0:DESC_RO;
bezDesc[Z1].mode = EndPtIsDefinedElev(trk,1)?0:DESC_RO;
+ bezDesc[LT].mode = DESC_IGNORE;
}
- else
+ else {
bezDesc[Z0].mode = bezDesc[Z1].mode = DESC_IGNORE;
+ bezDesc[LT].mode = 0;
+ bezData.lineType = xx->bezierData.lineType;
+ }
bezDesc[A0].mode = DESC_RO;
bezDesc[A1].mode = DESC_RO;
bezDesc[C0].mode = DESC_RO;
@@ -434,11 +451,52 @@ static void DescribeBezier( track_p trk, char * str, CSIZE_T len )
if (GetTrkType(trk) == T_BEZIER)
DoDescribe( _("Bezier Track"), trk, bezDesc, UpdateBezier );
- else
+ else {
DoDescribe( _("Bezier Line"), trk, bezDesc, UpdateBezier );
+ if (bezDesc[LT].control0!=NULL) {
+ wListClear( (wList_p)bezDesc[LT].control0 );
+ wListAddValue( (wList_p)bezDesc[LT].control0, _("Solid"), NULL, (void*)0 );
+ wListAddValue( (wList_p)bezDesc[LT].control0, _("Dash"), NULL, (void*)1 );
+ wListAddValue( (wList_p)bezDesc[LT].control0, _("Dot"), NULL, (void*)2 );
+ wListAddValue( (wList_p)bezDesc[LT].control0, _("DashDot"), NULL, (void*)3 );
+ wListAddValue( (wList_p)bezDesc[LT].control0, _("DashDotDot"), NULL, (void*)4 );
+ wListAddValue( (wList_p)bezDesc[LT].control0, _("CenterDot"), NULL, (void*)5);
+ wListAddValue( (wList_p)bezDesc[LT].control0, _("PhantomDot"), NULL, (void*)6 );
+ wListSetIndex( (wList_p)bezDesc[LT].control0, bezData.lineType );
+ }
+ }
}
+EXPORT void SetBezierLineType( track_p trk, int width ) {
+ if (GetTrkType(trk) == T_BZRLIN) {
+ struct extraData * xx = GetTrkExtraData(trk);
+ switch(width) {
+ case 0:
+ xx->bezierData.lineType = DRAWLINESOLID;
+ break;
+ case 1:
+ xx->bezierData.lineType = DRAWLINEDASH;
+ break;
+ case 2:
+ xx->bezierData.lineType = DRAWLINEDOT;
+ break;
+ case 3:
+ xx->bezierData.lineType = DRAWLINEDASHDOT;
+ break;
+ case 4:
+ xx->bezierData.lineType = DRAWLINEDASHDOTDOT;
+ break;
+ case 5:
+ xx->bezierData.lineType = DRAWLINECENTER;
+ break;
+ case 6:
+ xx->bezierData.lineType = DRAWLINEPHANTOM;
+ break;
+ }
+ }
+}
+
static DIST_T DistanceBezier( track_p t, coOrd * p )
{
struct extraData *xx = GetTrkExtraData(t);
@@ -465,34 +523,30 @@ static void DrawBezier( track_p t, drawCmd_p d, wDrawColor color )
if (GetTrkType(t) == T_BZRLIN) {
+ unsigned long NotSolid = ~(DC_NOTSOLIDLINE);
+ d->options &= NotSolid;
+ if (xx->bezierData.lineType == DRAWLINESOLID) {}
+ else if (xx->bezierData.lineType == DRAWLINEDASH) d->options |= DC_DASH;
+ else if (xx->bezierData.lineType == DRAWLINEDOT) d->options |= DC_DOT;
+ else if (xx->bezierData.lineType == DRAWLINEDASHDOT) d->options |= DC_DASHDOT;
+ else if (xx->bezierData.lineType == DRAWLINEDASHDOTDOT) d->options |= DC_DASHDOTDOT;
+ else if (xx->bezierData.lineType == DRAWLINECENTER) d->options |= DC_CENTER;
+ else if (xx->bezierData.lineType == DRAWLINEPHANTOM) d->options |= DC_PHANTOM;
DrawSegsO(d,t,zero,0.0,xx->bezierData.arcSegs.ptr,xx->bezierData.arcSegs.cnt, 0.0, color, 0);
+ d->options &= NotSolid;
return;
}
- if (GetTrkWidth(t) == 2)
- widthOptions |= DTS_THICK2;
- if (GetTrkWidth(t) == 3)
- widthOptions |= DTS_THICK3;
-
-
- if ( ((d->funcs->options&wDrawOptTemp)==0) &&
+ if ( ((d->options&DC_SIMPLE)==0) &&
(labelWhen == 2 || (labelWhen == 1 && (d->options&DC_PRINT))) &&
labelScale >= d->scale &&
( GetTrkBits( t ) & TB_HIDEDESC ) == 0 ) {
DrawBezierDescription( t, d, color );
}
DIST_T scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale;
- if ( tieDrawMode!=TIEDRAWMODE_NONE &&
- d!=&mapD &&
- (d->options&DC_TIES)!=0 &&
- d->scale<scale2rail/2 )
- DrawSegsO(d,t,zero,0.0,xx->bezierData.arcSegs.ptr,xx->bezierData.arcSegs.cnt, GetTrkGauge(t), color, widthOptions|DTS_TIES);
DrawSegsO(d,t,zero,0.0,xx->bezierData.arcSegs.ptr,xx->bezierData.arcSegs.cnt, GetTrkGauge(t), color, widthOptions);
- if ( (d->funcs->options & wDrawOptTemp) == 0 &&
- (d->options&DC_QUICK) == 0 ) {
- DrawEndPt( d, t, 0, color );
- DrawEndPt( d, t, 1, color );
- }
+ DrawEndPt( d, t, 0, color );
+ DrawEndPt( d, t, 1, color );
}
static void DeleteBezier( track_p t )
@@ -505,6 +559,7 @@ static void DeleteBezier( track_p t )
if (s.bezSegs.ptr) MyFree(s.bezSegs.ptr);
s.bezSegs.max = 0;
s.bezSegs.cnt = 0;
+ s.bezSegs.ptr = NULL;
}
}
if (xx->bezierData.arcSegs.ptr && !xx->bezierData.arcSegs.max)
@@ -522,13 +577,14 @@ static BOOL_T WriteBezier( track_p t, FILE * f )
BOOL_T track =(GetTrkType(t)==T_BEZIER);
options = GetTrkWidth(t) & 0x0F;
if ( ( GetTrkBits(t) & TB_HIDEDESC ) == 0 ) options |= 0x80;
- rc &= fprintf(f, "%s %d %u %ld %ld %0.6f %s %d %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f 0 %0.6f %0.6f \n",
+ rc &= fprintf(f, "%s %d %u %ld %ld %0.6f %s %d %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %d %0.6f %0.6f \n",
track?"BEZIER":"BZRLIN",GetTrkIndex(t), GetTrkLayer(t), (long)options, wDrawGetRGB(xx->bezierData.segsColor), xx->bezierData.segsWidth,
- GetTrkScaleName(t), GetTrkVisible(t),
+ GetTrkScaleName(t), GetTrkVisible(t)|(GetTrkNoTies(t)?1<<2:0)|(GetTrkBridge(t)?1<<3:0),
xx->bezierData.pos[0].x, xx->bezierData.pos[0].y,
xx->bezierData.pos[1].x, xx->bezierData.pos[1].y,
xx->bezierData.pos[2].x, xx->bezierData.pos[2].y,
xx->bezierData.pos[3].x, xx->bezierData.pos[3].y,
+ xx->bezierData.lineType,
xx->bezierData.descriptionOff.x, xx->bezierData.descriptionOff.y )>0;
if (track) {
rc &= WriteEndPt( f, t, 0 );
@@ -538,7 +594,7 @@ static BOOL_T WriteBezier( track_p t, FILE * f )
return rc;
}
-static void ReadBezier( char * line )
+static BOOL_T ReadBezier( char * line )
{
struct extraData *xx;
track_p t;
@@ -548,20 +604,23 @@ static void ReadBezier( char * line )
char scale[10];
wIndex_t layer;
long options;
+ int lt;
char * cp = NULL;
unsigned long rgb;
DIST_T width;
- if (!GetArgs( line+6, "dLluwsdpppp0p",
- &index, &layer, &options, &rgb, &width, scale, &visible, &p0, &c1, &c2, &p1, &dp ) ) {
- return;
+ TRKTYP_T trkTyp = strncmp(line,"BEZIER",6)==0?T_BEZIER:T_BZRLIN;
+ if (!GetArgs( line+6, "dLluwsdppppdp",
+ &index, &layer, &options, &rgb, &width, scale, &visible, &p0, &c1, &c2, &p1, &lt, &dp ) ) {
+ return FALSE;
}
- if (strncmp(line,"BEZIER",6)==0)
- t = NewTrack( index, T_BEZIER, 0, sizeof *xx );
- else
- t = NewTrack( index, T_BZRLIN, 0, sizeof *xx );
+ if ( !ReadSegs() )
+ return FALSE;
+ t = NewTrack( index, trkTyp, 0, sizeof *xx );
xx = GetTrkExtraData(t);
- SetTrkVisible(t, visible);
+ SetTrkVisible(t, visible&2);
+ SetTrkNoTies(t,visible&4);
+ SetTrkBridge(t,visible&8);
SetTrkScale(t, LookupScale(scale));
SetTrkLayer(t, layer );
SetTrkWidth(t, (int)(options&0x0F));
@@ -570,15 +629,16 @@ static void ReadBezier( char * line )
xx->bezierData.pos[1] = c1;
xx->bezierData.pos[2] = c2;
xx->bezierData.pos[3] = p1;
+ xx->bezierData.lineType = lt;
xx->bezierData.descriptionOff = dp;
xx->bezierData.segsWidth = width;
xx->bezierData.segsColor = wDrawFindColor( rgb );
- ReadSegs();
FixUpBezier(xx->bezierData.pos,xx,GetTrkType(t) == T_BEZIER);
ComputeBezierBoundingBox(t,xx);
if (GetTrkType(t) == T_BEZIER) {
SetEndPts(t,2);
}
+ return TRUE;
}
static void MoveBezier( track_p trk, coOrd orig )
@@ -665,16 +725,21 @@ static BOOL_T SplitBezier( track_p trk, coOrd pos, EPINX_T ep, track_p *leftover
if (track) {
trk1 = NewBezierTrack(ep?newr:newl,NULL,0);
+ //Move elev data from ep
} else
trk1 = NewBezierLine(ep?newr:newl,NULL,0, xx->bezierData.segsColor,xx->bezierData.segsWidth);
- UndoModify(trk);
+ DIST_T height;
+ int opt;
+ GetTrkEndElev(trk,ep,&opt,&height);
+ UpdateTrkEndElev( trk1, ep, opt, height, (opt==ELEV_STATION)?GetTrkEndElevStation(trk,ep):NULL );
+ UndoModify(trk);
for (int i=0;i<4;i++) {
xx->bezierData.pos[i] = ep?newl[i]:newr[i];
}
FixUpBezier(xx->bezierData.pos,xx,track);
ComputeBezierBoundingBox(trk,xx);
SetTrkEndPoint( trk, ep, xx->bezierData.pos[ep?3:0], ep?xx->bezierData.a1:xx->bezierData.a0);
-
+ UpdateTrkEndElev( trk, ep, ELEV_NONE, 0, NULL);
*leftover = trk1;
*ep0 = 1-ep;
*ep1 = ep;
@@ -831,7 +896,6 @@ static BOOL_T MergeBezier(
}
DrawNewTrack( trk0 );
-
return TRUE;
}
@@ -842,7 +906,8 @@ static BOOL_T EnumerateBezier( track_p trk )
if (trk != NULL) {
DIST_T d;
struct extraData *xx = GetTrkExtraData(trk);
- d = xx->bezierData.length;
+ d = max(BezierOffsetLength(xx->bezierData.arcSegs,-GetTrkGauge(trk)/2.0),
+ BezierOffsetLength(xx->bezierData.arcSegs,GetTrkGauge(trk)/2.0));
ScaleLengthIncrement( GetTrkScale(trk), d );
}
return TRUE;
@@ -884,20 +949,72 @@ static BOOL_T GetParamsBezier( int inx, track_p trk, coOrd pos, trackParams_t *
params->arcA0 = segPtr->u.c.a0;
params->arcA1 = segPtr->u.c.a1;
}
- if ( inx == PARAMS_PARALLEL ) {
- params->ep = 0;
- } else if (inx == PARAMS_CORNU ){
+ if ( inx == PARAMS_NODES ) {
+ if (GetTrkType(trk) == T_BEZIER) return FALSE;
+ if (FindDistance(pos,params->bezierPoints[0]) > FindDistance(pos,params->bezierPoints[3]))
+ params->ep = 1;
+ else params->ep = 0;
+ coOrd curr_pos = params->bezierPoints[params->ep*3];
+ BOOL_T first = TRUE;
+ DYNARR_RESET(coOrd,params->nodes);
+ for (int i = 0; i<xx->bezierData.arcSegs.cnt;i++) {
+ trkSeg_p segPtr = &DYNARR_N(trkSeg_t,xx->bezierData.arcSegs,params->ep?xx->bezierData.arcSegs.cnt-1-i:i);
+ if (segPtr->type == SEG_STRLIN) {
+ BOOL_T eps = 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,1);
+ DYNARR_LAST(coOrd,params->nodes) = segPtr->u.l.pos[eps];
+ }
+ DYNARR_APPEND(coOrd,params->nodes,1);
+ DYNARR_LAST(coOrd,params->nodes) = segPtr->u.l.pos[1-eps];
+ } else {
+ coOrd start,end;
+ Translate(&start,segPtr->u.c.center,segPtr->u.c.a0,fabs(segPtr->u.c.radius));
+ Translate(&end,segPtr->u.c.center,segPtr->u.c.a0+segPtr->u.c.a1,fabs(segPtr->u.c.radius));
+ BOOL_T back = FindDistance(start,curr_pos)>FindDistance(end,curr_pos);
+ if (segPtr->u.c.radius > 0.5) {
+ double min_angle = 360*acos(1.0-(0.1/fabs(segPtr->u.c.radius)))/M_PI; //Error max is 0.1"
+ double number = 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,1);
+ if (back == params->ep)
+ 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) );
+ else
+ Translate(&DYNARR_LAST(coOrd,params->nodes),segPtr->u.c.center,segPtr->u.c.a0+(j*arc_size),fabs(segPtr->u.c.radius) );
+ }
+ first = FALSE;
+ } else {
+ if (first) {
+ first = FALSE;
+ DYNARR_APPEND(coOrd,params->nodes,1);
+ DYNARR_LAST(coOrd,params->nodes) = start;
+ }
+ DYNARR_APPEND(coOrd,params->nodes,1);
+ DYNARR_LAST(coOrd,params->nodes) = end;
+
+ }
+ }
+ curr_pos = DYNARR_LAST(coOrd,params->nodes);
+ }
+ params->lineOrig = params->bezierPoints[params->ep*3];
+ params->lineEnd = params->bezierPoints[(1-params->ep)*3];
+ return TRUE;
+ } else if ((inx == PARAMS_CORNU) || (inx == PARAMS_1ST_JOIN) || (inx == PARAMS_2ND_JOIN)){
params->ep = PickEndPoint( pos, trk);
} else {
params->ep = PickUnconnectedEndPointSilent( pos, trk);
}
if (params->ep>=0)
params->angle = GetTrkEndAngle(trk, params->ep);
+
return TRUE;
}
-static BOOL_T TrimBezier( track_p trk, EPINX_T ep, DIST_T dist ) {
+static BOOL_T TrimBezier( track_p trk, EPINX_T ep, DIST_T dist, coOrd endpos, ANGLE_T angle, DIST_T radius, coOrd center ) {
+ UndrawNewTrack( trk );
DeleteTrack(trk, TRUE);
return TRUE;
}
@@ -916,7 +1033,7 @@ static BOOL_T QueryBezier( track_p trk, int query )
return TRUE;
break;
case Q_EXCEPTION:
- return GetTrkType(trk) == T_BEZIER?xx->bezierData.minCurveRadius < (GetLayoutMinTrackRadius()-EPSILON):FALSE;
+ return GetTrkType(trk) == T_BEZIER?fabs(xx->bezierData.minCurveRadius) < (GetLayoutMinTrackRadius()-EPSILON):FALSE;
break;
case Q_CAN_MODIFY_CONTROL_POINTS:
return TRUE;
@@ -928,11 +1045,13 @@ static BOOL_T QueryBezier( track_p trk, int query )
return GetTrkType(trk) == T_BEZIER?TRUE:FALSE;
break;
case Q_CAN_PARALLEL:
- return (GetTrkType(trk) == T_BEZIER);
+ return TRUE;
break;
case Q_MODIFY_CAN_SPLIT:
case Q_CORNU_CAN_MODIFY:
return (GetTrkType(trk) == T_BEZIER);
+ case Q_GET_NODES:
+ return (GetTrkType(trk) == T_BZRLIN);
default:
return FALSE;
}
@@ -980,19 +1099,76 @@ BOOL_T GetBezierSegmentFromTrack(track_p trk, trkSeg_p seg_p) {
seg_p->bezSegs.cnt = 0;
if (seg_p->bezSegs.ptr) MyFree(seg_p->bezSegs.ptr);
seg_p->bezSegs.max = 0;
+ seg_p->bezSegs.ptr = NULL;
FixUpBezierSeg(seg_p->u.b.pos,seg_p,seg_p->type == SEG_BEZTRK);
return TRUE;
}
+BOOL_T GetTracksFromBezierSegment(trkSeg_p bezSeg, track_p newTracks[2], track_p trk) {
+ track_p trk_old = NULL;
+ newTracks[0] = NULL, newTracks[1] = NULL;
+ if (bezSeg->type != SEG_BEZTRK) return FALSE;
+ for (int i=0;i<bezSeg->bezSegs.cnt;i++) {
+ trkSeg_p seg = &DYNARR_N(trkSeg_t,bezSeg->bezSegs,i);
+ track_p new_trk;
+ if (seg->type == SEG_CRVTRK)
+ new_trk = NewCurvedTrack(seg->u.c.center,fabs(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))) {
+ ConnectTracks(trk_old,i,new_trk,ep_n);
+ break;
+ }
+ }
+ }
+ }
+ trk_old = new_trk;
+ }
+ return TRUE;
+}
+
+BOOL_T GetTracksFromBezierTrack(track_p trk, track_p newTracks[2]) {
+ trkSeg_t seg_temp;
+ struct extraData * xx = GetTrkExtraData(trk);
+ newTracks[0] = NULL, newTracks[1] = NULL;
+
+ if (!IsTrack(trk)) return FALSE;
+ seg_temp.type = SEG_BEZTRK;
+ for (int i=0;i<4;i++) seg_temp.u.b.pos[i] = xx->bezierData.pos[i];
+ seg_temp.color = xx->bezierData.segsColor;
+ seg_temp.bezSegs.cnt = 0;
+ seg_temp.bezSegs.max = 0;
+ //if (seg_temp->bezSegs.ptr) MyFree(seg_temp->bezSegs.ptr);
+ DYNARR_RESET(trkSeg_t,seg_temp.bezSegs);
+ FixUpBezierSeg(seg_temp.u.b.pos,&seg_temp,TRUE);
+ GetTracksFromBezierSegment(&seg_temp, newTracks, trk);
+ MyFree(seg_temp.bezSegs.ptr);
+ seg_temp.bezSegs.cnt = 0;
+ seg_temp.bezSegs.max = 0;
+ seg_temp.bezSegs.ptr = NULL;
+ return TRUE;
+
+}
+
static BOOL_T MakeParallelBezier(
track_p trk,
coOrd pos,
DIST_T sep,
+ DIST_T factor,
track_p * newTrkR,
coOrd * p0R,
- coOrd * p1R )
+ coOrd * p1R,
+ BOOL_T track)
{
struct extraData * xx = GetTrkExtraData(trk);
coOrd np[4], p;
@@ -1011,7 +1187,8 @@ static BOOL_T MakeParallelBezier(
for (int i =0; i<4;i++) {
np[i] = xx->bezierData.pos[i];
}
-
+ sep = sep+factor/xx->bezierData.minCurveRadius;
+ // Adjust sep based on radius and factor
if ( a2 > 180 ) {
Translate(&np[0],np[0],a+90,sep);
Translate(&np[1],np[1],a+90,sep);
@@ -1025,14 +1202,18 @@ static BOOL_T MakeParallelBezier(
}
if ( newTrkR ) {
- *newTrkR = NewBezierTrack( np, NULL, 0);
+ if (track)
+ *newTrkR = NewBezierTrack( np, NULL, 0);
+ else
+ *newTrkR = NewBezierLine( np, NULL, 0, wDrawColorBlack, 0);
} else {
DYNARR_SET( trkSeg_t, tempSegs_da, 1 );
tempSegs(0).color = wDrawColorBlack;
tempSegs(0).width = 0;
tempSegs_da.cnt = 1;
- tempSegs(0).type = SEG_BEZTRK;
+ tempSegs(0).type = track?SEG_BEZTRK:SEG_BEZLIN;
if (tempSegs(0).bezSegs.ptr) MyFree(tempSegs(0).bezSegs.ptr);
+ tempSegs(0).bezSegs.ptr = 0;
tempSegs(0).bezSegs.max = 0;
tempSegs(0).bezSegs.cnt = 0;
for (int i=0;i<4;i++) tempSegs(0).u.b.pos[i] = np[i];
@@ -1063,14 +1244,40 @@ BOOL_T MoveBezierEndPt ( track_p *trk, EPINX_T *ep, coOrd pos, DIST_T d0 ) {
track_p trk2;
struct extraData *xx;
if (SplitTrack(*trk,pos,*ep,&trk2,TRUE)) {
- if (trk2) DeleteTrack(trk2,TRUE);
+ if (trk2) {
+ UndrawNewTrack( trk2 );
+ DeleteTrack(trk2,TRUE);
+ }
+ UndrawNewTrack( *trk );
xx = GetTrkExtraData(*trk);
SetTrkEndPoint( *trk, *ep, *ep?xx->bezierData.pos[3]:xx->bezierData.pos[0], *ep?xx->bezierData.a1:xx->bezierData.a0 );
+ DrawNewTrack( *trk );
return TRUE;
}
return FALSE;
}
+static wBool_t CompareBezier( track_cp trk1, track_cp trk2 )
+{
+ struct extraData *xx1 = GetTrkExtraData( trk1 );
+ struct extraData *xx2 = GetTrkExtraData( trk2 );
+ char * cp = message + strlen(message);
+ REGRESS_CHECK_POS( "Pos[0]", xx1, xx2, bezierData.pos[0] )
+ REGRESS_CHECK_POS( "Pos[1]", xx1, xx2, bezierData.pos[1] )
+ REGRESS_CHECK_POS( "Pos[2]", xx1, xx2, bezierData.pos[2] )
+ REGRESS_CHECK_POS( "Pos[3]", xx1, xx2, bezierData.pos[3] )
+ REGRESS_CHECK_DIST( "MinCurveRadius", xx1, xx2, bezierData.minCurveRadius )
+ REGRESS_CHECK_ANGLE( "A0", xx1, xx2, bezierData.a0 )
+ REGRESS_CHECK_ANGLE( "A1", xx1, xx2, bezierData.a1 )
+ // Check arcSegs
+ REGRESS_CHECK_DIST( "Length", xx1, xx2, bezierData.length )
+ REGRESS_CHECK_POS( "DescOff", xx1, xx2, bezierData.descriptionOff )
+ REGRESS_CHECK_WIDTH( "SegsWidth", xx1, xx2, bezierData.segsWidth )
+ REGRESS_CHECK_COLOR( "SegsColor", xx1, xx2, bezierData.segsColor )
+ REGRESS_CHECK_INT( "LineType", xx1, xx2, bezierData.lineType )
+ return TRUE;
+}
+
static trackCmd_t bezlinCmds = {
"BZRLIN",
DrawBezier,
@@ -1102,7 +1309,11 @@ static trackCmd_t bezlinCmds = {
NULL,
NULL,
NULL,
- RebuildBezier
+ RebuildBezier,
+ NULL,
+ NULL,
+ NULL,
+ CompareBezier
};
static trackCmd_t bezierCmds = {
@@ -1136,7 +1347,11 @@ static trackCmd_t bezierCmds = {
NULL,
MakeParallelBezier,
NULL,
- RebuildBezier
+ RebuildBezier,
+ NULL,
+ NULL,
+ NULL,
+ CompareBezier
};
@@ -1302,8 +1517,38 @@ LOG( log_bezierSegments, 1, ( " BezTr-Exit2 --> SI%d A%0.3f P[%0.3f %0.3f] D%
}
break;
- case SEGPROC_SPLIT:
- //TODO Split
+ case SEGPROC_SPLIT: ;
+ wIndex_t subinx;
+ double t;
+ double dd;
+ coOrd split_p = data->split.pos;
+ ANGLE_T angle = GetAngleSegs(segPtr->bezSegs.cnt,(trkSeg_p)segPtr->bezSegs.ptr, &split_p, &inx, &dd, &back, &subinx, NULL);
+ coOrd current[4];
+
+ BezierMathDistance(&split_p, segPtr->u.b.pos, 500, &t); //Find t value
+
+ for (int i=0;i<4;i++) {
+ current[i] = segPtr->u.b.pos[i];
+
+ }
+ for (int i=0;i<2;i++) {
+ data->split.newSeg[i].type = segPtr->type;
+ data->split.newSeg[i].color = segPtr->color;
+ data->split.newSeg[i].width = segPtr->width;
+ data->split.newSeg[i].bezSegs.ptr = NULL;
+ data->split.newSeg[i].bezSegs.cnt = 0;
+ data->split.newSeg[i].bezSegs.max = 0;
+ }
+ BezierSplit(segPtr->u.b.pos, data->split.newSeg[0].u.b.pos, data->split.newSeg[1].u.b.pos, t);
+
+ FixUpBezierSeg(data->split.newSeg[0].u.b.pos,&data->split.newSeg[0],segPtr->type == SEG_BEZTRK);
+ FixUpBezierSeg(data->split.newSeg[1].u.b.pos,&data->split.newSeg[1],segPtr->type == SEG_BEZTRK);
+
+ data->split.length[0] = data->split.newSeg[0].u.b.length;
+ data->split.length[1] = data->split.newSeg[1].u.b.length;
+
+ data->split.pos = split_p;
+
break;
case SEGPROC_GETANGLE:
diff --git a/app/bin/tbezier.h b/app/bin/tbezier.h
index 1e8b915..823992e 100644
--- a/app/bin/tbezier.h
+++ b/app/bin/tbezier.h
@@ -32,6 +32,7 @@ typedef struct {
coOrd descriptionOff;
DIST_T segsWidth;
wDrawColor segsColor;
+ drawLineType_e lineType;
} BezierData_t;
@@ -51,7 +52,10 @@ void FixUpBezier(coOrd[4], struct extraData*, BOOL_T);
void FixUpBezierSeg(coOrd[4], trkSeg_p , BOOL_T);
void FixUpBezierSegs(trkSeg_p p,int segCnt);
BOOL_T GetBezierSegmentFromTrack(track_p, trkSeg_p);
+BOOL_T GetTracksFromBezierTrack(track_p trk, track_p newTracks[2]);
+BOOL_T GetTracksFromBezierSegment(trkSeg_p bezSeg, track_p newTracks[2], track_p old);
+void SetBezierLineType( track_p trk, int width );
-DIST_T BezierDescriptionDistance(coOrd pos,track_p trk );
+DIST_T BezierDescriptionDistance(coOrd pos,track_p trk, coOrd *, BOOL_T, BOOL_T * );
STATUS_T BezierDescriptionMove(track_p trk,wAction_t action,coOrd pos );
diff --git a/app/bin/tcornu.c b/app/bin/tcornu.c
index 74a7a5e..dd09cfa 100644
--- a/app/bin/tcornu.c
+++ b/app/bin/tcornu.c
@@ -136,8 +136,8 @@ EXPORT char * CreateSegPathList(track_p trk) {
char * cp = "\0\0";
if (GetTrkType(trk) != T_CORNU) return cp;
struct extraData *xx = GetTrkExtraData(trk);
- if (xx->cornuData.cornuPath) free(xx->cornuData.cornuPath);
- xx->cornuData.cornuPath = malloc(xx->cornuData.arcSegs.cnt+2);
+ if (xx->cornuData.cornuPath) MyFree(xx->cornuData.cornuPath);
+ xx->cornuData.cornuPath = MyMalloc(xx->cornuData.arcSegs.cnt+2);
int j= 0;
for (int i = 0;i<xx->cornuData.arcSegs.cnt;i++,j++) {
xx->cornuData.cornuPath[j] = i+1;
@@ -178,17 +178,24 @@ static void ComputeCornuBoundingBox( track_p trk, struct extraData * xx )
DIST_T CornuDescriptionDistance(
coOrd pos,
- track_p trk )
+ track_p trk,
+ coOrd * dpos,
+ BOOL_T show_hidden,
+ BOOL_T * hidden)
{
struct extraData *xx = GetTrkExtraData(trk);
coOrd p1;
-
- if ( GetTrkType( trk ) != T_CORNU || ( GetTrkBits( trk ) & TB_HIDEDESC ) != 0 )
+ if (hidden) *hidden = FALSE;
+ if ( GetTrkType( trk ) != T_CORNU || ((( GetTrkBits( trk ) & TB_HIDEDESC ) != 0) && !show_hidden) )
return 100000;
- p1.x = xx->cornuData.pos[0].x + ((xx->cornuData.pos[1].x-xx->cornuData.pos[0].x)/2) + xx->cornuData.descriptionOff.x;
- p1.y = xx->cornuData.pos[0].y + ((xx->cornuData.pos[1].y-xx->cornuData.pos[0].y)/2) + xx->cornuData.descriptionOff.y;
-
+ coOrd offset = xx->cornuData.descriptionOff;
+
+ if (( GetTrkBits( trk ) & TB_HIDEDESC ) != 0) offset = zero;
+ p1.x = xx->cornuData.pos[0].x + ((xx->cornuData.pos[1].x-xx->cornuData.pos[0].x)/2) + offset.x;
+ p1.y = xx->cornuData.pos[0].y + ((xx->cornuData.pos[1].y-xx->cornuData.pos[0].y)/2) + offset.y;
+ if (hidden) *hidden = (GetTrkBits( trk ) & TB_HIDEDESC);
+ *dpos = p1;
return FindDistance( p1, pos );
}
@@ -211,8 +218,9 @@ static void DrawCornuDescription(
pos.x += xx->cornuData.descriptionOff.x;
pos.y += xx->cornuData.descriptionOff.y;
fp = wStandardFont( F_TIMES, FALSE, FALSE );
- sprintf( message, _("Cornu Curve: length=%0.3f min radius=%0.3f"),
- xx->cornuData.length, xx->cornuData.minCurveRadius);
+
+ sprintf( message, _("Cornu: len=%0.2f min_rad=%0.2f"),
+ xx->cornuData.length, (xx->cornuData.minCurveRadius>=10000.00)?0.0:xx->cornuData.minCurveRadius);
DrawBoxedString( BOX_BOX, d, pos, message, fp, (wFontSize_t)descriptionFontSize, color, 0.0 );
}
@@ -225,7 +233,6 @@ STATUS_T CornuDescriptionMove(
struct extraData *xx = GetTrkExtraData(trk);
static coOrd p0,p1;
static BOOL_T editState;
- wDrawColor color;
if (GetTrkType(trk) != T_CORNU) return C_TERMINATE;
@@ -234,24 +241,25 @@ STATUS_T CornuDescriptionMove(
switch (action) {
case C_DOWN:
+ DrawCornuDescription( trk, &mainD, wDrawColorWhite );
case C_MOVE:
case C_UP:
editState = TRUE;
p1 = pos;
- color = GetTrkColor( trk, &mainD );
xx->cornuData.descriptionOff.x = pos.x - p0.x;
xx->cornuData.descriptionOff.y = pos.y - p0.y;
- DrawCornuDescription( trk, &mainD, color );
if (action == C_UP) {
editState = FALSE;
+ wDrawColor color = GetTrkColor( trk, &mainD );
+ DrawCornuDescription( trk, &mainD, color );
}
- MainRedraw();
- MapRedraw();
return action==C_UP?C_TERMINATE:C_CONTINUE;
case C_REDRAW:
- if (editState)
- DrawLine( &mainD, p1, p0, 0, wDrawColorBlack );
+ if (editState) {
+ DrawCornuDescription( trk, &tempD, wDrawColorBlue );
+ DrawLine( &tempD, p1, p0, 0, wDrawColorBlue );
+ }
break;
}
@@ -365,18 +373,20 @@ static void UpdateCornu( track_p trk, int inx, descData_p descUpd, BOOL_T final
case R0:
if (GetTrkEndTrk(trk,0)) break;
updateEndPts = TRUE;
- xx->cornuData.r[0] = cornData.radius[0];
- Translate(&xx->cornuData.c[0],xx->cornuData.pos[0],NormalizeAngle(xx->cornuData.a[0]+90),xx->cornuData.r[0]);
+ xx->cornuData.r[0] = fabs(cornData.radius[0]);
+ Translate(&xx->cornuData.c[0],xx->cornuData.pos[0],NormalizeAngle(xx->cornuData.a[0]+90),cornData.radius[0]);
cornData.center[0] = xx->cornuData.c[0];
+ cornData.radius[0] = fabs(cornData.radius[0]);
cornuDesc[R0].mode |= DESC_CHANGE;
cornuDesc[C0].mode |= DESC_CHANGE;
break;
case R1:
if (GetTrkEndTrk(trk,1)) break;
updateEndPts = TRUE;
- xx->cornuData.r[1]= cornData.radius[1];
- Translate(&xx->cornuData.c[1],xx->cornuData.pos[1],NormalizeAngle(xx->cornuData.a[1]-90),xx->cornuData.r[1]);
+ xx->cornuData.r[1]= fabs(cornData.radius[1]);
+ Translate(&xx->cornuData.c[1],xx->cornuData.pos[1],NormalizeAngle(xx->cornuData.a[1]-90),cornData.radius[1]);
cornData.center[1] = xx->cornuData.c[1];
+ cornData.radius[1] = fabs(cornData.radius[1]);
cornuDesc[R1].mode |= DESC_CHANGE;
cornuDesc[C1].mode |= DESC_CHANGE;
break;
@@ -384,7 +394,7 @@ static void UpdateCornu( track_p trk, int inx, descData_p descUpd, BOOL_T final
case Z1:
ep = (inx==Z0?0:1);
UpdateTrkEndElev( trk, ep, GetTrkEndElevUnmaskedMode(trk,ep), cornData.elev[ep], NULL );
- ComputeElev( trk, 1-ep, FALSE, &cornData.elev[1-ep], NULL );
+ ComputeElev( trk, 1-ep, FALSE, &cornData.elev[1-ep], NULL, TRUE );
if ( cornData.length > minLength )
cornData.grade = fabs( (cornData.elev[0]-cornData.elev[1])/cornData.length )*100.0;
else
@@ -417,7 +427,7 @@ static void UpdateCornu( track_p trk, int inx, descData_p descUpd, BOOL_T final
ts[0] = GetTrkEndTrk(trk,0);
ts[1] = GetTrkEndTrk(trk,1);
SetUpCornuParmFromTracks(ts,&cp,xx);
- CallCornu(xx->cornuData.pos, tracks, NULL, &xx->cornuData.arcSegs, &cp);
+ CallCornu0(xx->cornuData.pos, xx->cornuData.c, xx->cornuData.a, xx->cornuData.r, &xx->cornuData.arcSegs, FALSE);
//FixUpCornu(xx->bezierData.pos, xx, IsTrack(trk));
ComputeCornuBoundingBox(trk, xx);
@@ -454,8 +464,8 @@ static void DescribeCornu( track_p trk, char * str, CSIZE_T len )
cornData.radius[0] = xx->cornuData.r[0];
cornData.radius[1] = xx->cornuData.r[1];
if (GetTrkType(trk) == T_CORNU) {
- ComputeElev( trk, 0, FALSE, &cornData.elev[0], NULL );
- ComputeElev( trk, 1, FALSE, &cornData.elev[1], NULL );
+ ComputeElev( trk, 0, FALSE, &cornData.elev[0], NULL, FALSE );
+ ComputeElev( trk, 1, FALSE, &cornData.elev[1], NULL, FALSE );
if ( cornData.length > minLength )
cornData.grade = fabs( (cornData.elev[0]-cornData.elev[1])/cornData.length )*100.0;
@@ -517,30 +527,16 @@ static void DrawCornu( track_p t, drawCmd_p d, wDrawColor color )
struct extraData *xx = GetTrkExtraData(t);
long widthOptions = DTS_LEFT|DTS_RIGHT;
- if (GetTrkWidth(t) == 2)
- widthOptions |= DTS_THICK2;
- if (GetTrkWidth(t) == 3)
- widthOptions |= DTS_THICK3;
-
-
- if ( ((d->funcs->options&wDrawOptTemp)==0) &&
+ if ( ((d->options&DC_SIMPLE)==0) &&
(labelWhen == 2 || (labelWhen == 1 && (d->options&DC_PRINT))) &&
labelScale >= d->scale &&
( GetTrkBits( t ) & TB_HIDEDESC ) == 0 ) {
DrawCornuDescription( t, d, color );
}
DIST_T scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale;
- if ( tieDrawMode!=TIEDRAWMODE_NONE &&
- d!=&mapD &&
- (d->options&DC_TIES)!=0 &&
- d->scale<scale2rail/2 )
- DrawSegsO(d,t,zero,0.0,xx->cornuData.arcSegs.ptr,xx->cornuData.arcSegs.cnt, GetTrkGauge(t), color, widthOptions|DTS_TIES);
DrawSegsO(d,t,zero,0.0,xx->cornuData.arcSegs.ptr,xx->cornuData.arcSegs.cnt, GetTrkGauge(t), color, widthOptions);
- if ( (d->funcs->options & wDrawOptTemp) == 0 &&
- (d->options&DC_QUICK) == 0 ) {
- DrawEndPt( d, t, 0, color );
- DrawEndPt( d, t, 1, color );
- }
+ DrawEndPt( d, t, 0, color );
+ DrawEndPt( d, t, 1, color );
}
void FreeSubSegs(trkSeg_t* s) {
@@ -579,7 +575,7 @@ static BOOL_T WriteCornu( track_p t, FILE * f )
if ( ( GetTrkBits(t) & TB_HIDEDESC ) == 0 ) options |= 0x80;
rc &= fprintf(f, "%s %d %d %ld 0 0 %s %d %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f \n",
"CORNU",GetTrkIndex(t), GetTrkLayer(t), (long)options,
- GetTrkScaleName(t), GetTrkVisible(t),
+ GetTrkScaleName(t), GetTrkVisible(t)|(GetTrkNoTies(t)?1<<2:0)|(GetTrkBridge(t)?1<<3:0),
xx->cornuData.pos[0].x, xx->cornuData.pos[0].y,
xx->cornuData.a[0],
xx->cornuData.r[0],
@@ -593,11 +589,10 @@ static BOOL_T WriteCornu( track_p t, FILE * f )
rc &= WriteEndPt( f, t, 1 );
}
rc &= WriteSegs( f, xx->cornuData.arcSegs.cnt, xx->cornuData.arcSegs.ptr );
- //rc &= fprintf(f, "\tEND\n" )>0;
return rc;
}
-static void ReadCornu( char * line )
+static BOOL_T ReadCornu( char * line )
{
struct extraData *xx;
track_p t;
@@ -613,12 +608,16 @@ static void ReadCornu( char * line )
if (!GetArgs( line+6, "dLl00sdpffppffp",
&index, &layer, &options, scale, &visible, &p0, &a0, &r0, &c0, &p1, &a1, &r1, &c1 ) ) {
- return;
+ return FALSE;
}
+ if ( !ReadSegs() )
+ return FALSE;
t = NewTrack( index, T_CORNU, 0, sizeof *xx );
xx = GetTrkExtraData(t);
- SetTrkVisible(t, visible);
+ SetTrkVisible(t, visible&2);
+ SetTrkNoTies(t, visible&4);
+ SetTrkBridge(t, visible&8);
SetTrkScale(t, LookupScale(scale));
SetTrkLayer(t, layer );
SetTrkWidth(t, (int)(options&0x0F));
@@ -632,10 +631,10 @@ static void ReadCornu( char * line )
xx->cornuData.c[1] = c1;
xx->cornuData.r[1] = r1;
xx->cornuData.descriptionOff.x = xx->cornuData.descriptionOff.y = 0.0;
- ReadSegs();
FixUpCornu0(xx->cornuData.pos,xx->cornuData.c,xx->cornuData.a, xx->cornuData.r, xx);
ComputeCornuBoundingBox(t,xx);
SetEndPts(t,2);
+ return TRUE;
}
static void MoveCornu( track_p trk, coOrd orig )
@@ -667,6 +666,9 @@ static void RescaleCornu( track_p trk, FLOAT_T ratio )
for (int i=0;i<2;i++) {
xx->cornuData.pos[i].x *= ratio;
xx->cornuData.pos[i].y *= ratio;
+ xx->cornuData.c[i].x *= ratio;
+ xx->cornuData.c[i].y *= ratio;
+ xx->cornuData.r[i] *= ratio;
}
RebuildCornu(trk);
@@ -689,13 +691,63 @@ void GetCornuParmsNear(track_p t, int sel, coOrd * pos2, coOrd * center, ANGLE_T
coOrd pos = *pos2;
double dd = DistanceCornu(t, &pos); //Pos adjusted to be on curve
int inx;
+ *radius = 0.0;
+ *angle2 = 0.0;
+ *center = zero;
wBool_t back,neg;
ANGLE_T angle = GetAngleSegs(xx->cornuData.arcSegs.cnt,(trkSeg_t *)(xx->cornuData.arcSegs.ptr),&pos,&inx,NULL,&back,NULL,&neg);
+ if (inx == -1) {
+ return; //Error in GetAngle
+ }
+
trkSeg_p segPtr = &DYNARR_N(trkSeg_t, xx->cornuData.arcSegs, inx);
- GetAngleSegs(segPtr->bezSegs.cnt,(trkSeg_t *)(segPtr->bezSegs.ptr),&pos,&inx,NULL,&back,NULL,&neg);
- segPtr = &DYNARR_N(trkSeg_t, segPtr->bezSegs, inx);
+ if (segPtr->type == SEG_BEZTRK) {
+ GetAngleSegs(segPtr->bezSegs.cnt,(trkSeg_t *)(segPtr->bezSegs.ptr),&pos,&inx,NULL,&back,NULL,&neg);
+ if (inx ==-1) return;
+ segPtr = &DYNARR_N(trkSeg_t, segPtr->bezSegs, inx);
+ }
+
+ if (segPtr->type == SEG_STRTRK) {
+ *radius = 0.0;
+ *center = zero;
+ } else if (segPtr->type == SEG_CRVTRK) {
+ *center = segPtr->u.c.center;
+ *radius = fabs(segPtr->u.c.radius);
+ }
+ if (sel)
+ angle = NormalizeAngle(angle+(neg==back?0:180));
+ else
+ angle = NormalizeAngle(angle+(neg==back?180:0));
+ *angle2 = angle;
+ *pos2 = pos;
+}
+
+void GetCornuParmsTemp(dynArr_t * array_p, int sel, coOrd * pos2, coOrd * center, ANGLE_T * angle2, DIST_T * radius ) {
+
+ coOrd pos = *pos2;
+ int inx;
+ wBool_t back,neg;
+ *radius = 0.0;
+ *center = zero;
+ *angle2 = 0.0;
+
+ ANGLE_T angle = GetAngleSegs(array_p->cnt,(trkSeg_p)array_p->ptr,&pos,&inx,NULL,&back,NULL,&neg);
+
+ if (inx==-1) return;
+
+ trkSeg_p segPtr = &DYNARR_N(trkSeg_t, *array_p, inx);
+
+ if (segPtr->type == SEG_BEZTRK) {
+
+ GetAngleSegs(segPtr->bezSegs.cnt,(trkSeg_t *)(segPtr->bezSegs.ptr),&pos,&inx,NULL,&back,NULL,&neg);
+
+ if (inx ==-1) return;
+
+ segPtr = &DYNARR_N(trkSeg_t, segPtr->bezSegs, inx);
+
+ }
if (segPtr->type == SEG_STRTRK) {
*radius = 0.0;
@@ -734,9 +786,14 @@ static BOOL_T SplitCornu( track_p trk, coOrd pos, EPINX_T ep, track_p *leftover,
ANGLE_T angle = GetAngleSegs(xx->cornuData.arcSegs.cnt,(trkSeg_t *)(xx->cornuData.arcSegs.ptr),&pos,&inx,NULL,&back,NULL,&neg);
+ if (inx == -1) return FALSE;
+
trkSeg_p segPtr = &DYNARR_N(trkSeg_t, xx->cornuData.arcSegs, inx);
GetAngleSegs(segPtr->bezSegs.cnt,(trkSeg_t *)(segPtr->bezSegs.ptr),&pos,&inx,NULL,&back,NULL,&neg);
+
+ if (inx == -1) return FALSE;
+
segPtr = &DYNARR_N(trkSeg_t, segPtr->bezSegs, inx);
if (segPtr->type == SEG_STRTRK) {
@@ -767,6 +824,7 @@ static BOOL_T SplitCornu( track_p trk, coOrd pos, EPINX_T ep, track_p *leftover,
}
trk1 = NewCornuTrack(new.pos,new.center,new.angle,new.radius,NULL,0);
+ //Copy elevation details from old ep to new ep 0/1
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"),
@@ -779,20 +837,26 @@ static BOOL_T SplitCornu( track_p trk, coOrd pos, EPINX_T ep, track_p *leftover,
UndoEnd();
return FALSE;
}
+ DIST_T height;
+ int opt;
+ GetTrkEndElev(trk,ep,&opt,&height);
+ UpdateTrkEndElev( trk1, ep, opt, height, (opt==ELEV_STATION)?GetTrkEndElevStation(trk,ep):NULL );
UndoModify(trk);
xx->cornuData.pos[ep] = pos;
xx->cornuData.a[ep] = NormalizeAngle(new.angle[1-ep]+180);
xx->cornuData.r[ep] = new.radius[1-ep];
xx->cornuData.c[ep] = new.center[1-ep];
+ //Wipe out old elevation for ep1
RebuildCornu(trk);
SetTrkEndPoint(trk, ep, xx->cornuData.pos[ep], xx->cornuData.a[ep]);
+ UpdateTrkEndElev( trk, ep, ELEV_NONE, 0, NULL);
*leftover = trk1;
- *ep0 = 1-ep;
- *ep1 = ep;
+ *ep0 = 1-ep; //Which end is for new on pos?
+ *ep1 = ep; //Which end is for old trk?
return TRUE;
}
@@ -801,8 +865,12 @@ BOOL_T MoveCornuEndPt ( track_p *trk, EPINX_T *ep, coOrd pos, DIST_T d0 ) {
track_p trk2;
if (SplitTrack(*trk,pos,*ep,&trk2,TRUE)) {
struct extraData *xx = GetTrkExtraData(*trk);
- if (trk2) DeleteTrack(trk2,TRUE);
+ if (trk2) {
+ UndrawNewTrack( trk2 );
+ DeleteTrack(trk2,TRUE);
+ }
SetTrkEndPoint( *trk, *ep, *ep?xx->cornuData.pos[1]:xx->cornuData.pos[0], *ep?xx->cornuData.a[1]:xx->cornuData.a[0] );
+ DrawNewTrack( *trk );
return TRUE;
}
return FALSE;
@@ -923,7 +991,8 @@ static BOOL_T EnumerateCornu( track_p trk )
if (trk != NULL) {
struct extraData *xx = GetTrkExtraData(trk);
DIST_T d;
- d = xx->cornuData.length;
+ d = max(CornuOffsetLength(xx->cornuData.arcSegs,-GetTrkGauge(trk)/2.0),
+ CornuOffsetLength(xx->cornuData.arcSegs,GetTrkGauge(trk)/2.0));
ScaleLengthIncrement( GetTrkScale(trk), d );
}
return TRUE;
@@ -1004,29 +1073,63 @@ static BOOL_T MergeCornu(
DrawNewTrack( trk3 );
UndoEnd();
-
return TRUE;
}
-BOOL_T GetBezierSegmentsFromCornu(track_p trk, dynArr_t * segs) {
+BOOL_T GetBezierSegmentsFromCornu(track_p trk, dynArr_t * segs, BOOL_T track) {
struct extraData * xx = GetTrkExtraData(trk);
for (int i=0;i<xx->cornuData.arcSegs.cnt;i++) {
- DYNARR_APPEND(trkSeg_t, * segs, 10);
+ trkSeg_p p = (trkSeg_t *) xx->cornuData.arcSegs.ptr+i;
+ if (p->type == SEG_BEZTRK) {
+ if (track) {
+ DYNARR_APPEND(trkSeg_t, * segs, 10);
+ trkSeg_p segPtr = &DYNARR_N(trkSeg_t,* segs,segs->cnt-1);
+ segPtr->type = SEG_BEZTRK;
+ segPtr->color = wDrawColorBlack;
+ segPtr->width = 0;
+ if (segPtr->bezSegs.ptr) MyFree(segPtr->bezSegs.ptr);
+ segPtr->bezSegs.cnt = 0;
+ segPtr->bezSegs.max = 0;
+ segPtr->bezSegs.ptr = NULL;
+ for (int j=0;j<4;j++) segPtr->u.b.pos[j] = p->u.b.pos[j];
+ FixUpBezierSeg(segPtr->u.b.pos,segPtr,TRUE);
+ } else {
+ for (int j=0;j<p->bezSegs.cnt;j++) {
+ trkSeg_p bez_p = &DYNARR_N(trkSeg_t,p->bezSegs,j);
+ DYNARR_APPEND(trkSeg_t, * segs, 10);
+ trkSeg_p segPtr = &DYNARR_LAST(trkSeg_t,* segs);
+ if (bez_p->type == SEG_CRVTRK) segPtr->type = SEG_CRVLIN;
+ if (bez_p->type == SEG_STRTRK) segPtr->type = SEG_STRLIN;
+ segPtr->u = bez_p->u;
+ segPtr->width = bez_p->width;
+ segPtr->color = bez_p->color;
+ }
+ }
+ } else if (p->type == SEG_STRTRK) {
+ DYNARR_APPEND(trkSeg_t, * segs, 1);
+ trkSeg_p segPtr = &DYNARR_N(trkSeg_t,* segs,segs->cnt-1);
+ segPtr->type = track?SEG_STRTRK:SEG_STRLIN;
+ segPtr->color = wDrawColorBlack;
+ segPtr->width = 0;
+ for (int j=0;j<2;j++) segPtr->u.l.pos[i] = p->u.l.pos[i];
+ segPtr->u.l.angle = p->u.l.angle;
+ segPtr->u.l.option = 0;
+ } else if (p->type == SEG_CRVTRK) {
+ DYNARR_APPEND(trkSeg_t, * segs, 1);
trkSeg_p segPtr = &DYNARR_N(trkSeg_t,* segs,segs->cnt-1);
- segPtr->type = SEG_BEZTRK;
+ segPtr->type = track?SEG_CRVTRK:SEG_CRVLIN;
segPtr->color = wDrawColorBlack;
segPtr->width = 0;
- if (segPtr->bezSegs.ptr) MyFree(segPtr->bezSegs.ptr);
- segPtr->bezSegs.cnt = 0;
- segPtr->bezSegs.max = 0;
- segPtr->bezSegs.ptr = NULL;
- trkSeg_p p = (trkSeg_t *) xx->cornuData.arcSegs.ptr+i;
- for (int j=0;j<4;j++) segPtr->u.b.pos[j] = p->u.b.pos[j];
- FixUpBezierSeg(segPtr->u.b.pos,segPtr,TRUE);
+ segPtr->u.c.a0 = p->u.c.a0;
+ segPtr->u.c.a1 = p->u.c.a1;
+ segPtr->u.c.center = p->u.c.center;
+ segPtr->u.c.radius = p->u.c.radius;
+ }
}
return TRUE;
}
+
static DIST_T GetLengthCornu( track_p trk )
{
struct extraData *xx = GetTrkExtraData(trk);
@@ -1052,6 +1155,7 @@ static BOOL_T GetParamsCornu( int inx, track_p trk, coOrd pos, trackParams_t * p
params->track_angle = GetAngleSegs( //Find correct Segment and nearest point in it
xx->cornuData.arcSegs.cnt,xx->cornuData.arcSegs.ptr,
&pos, &segInx, &d , &back, &segInx2, &negative );
+ if (segInx ==-1) return FALSE;
trkSeg_p segPtr = &DYNARR_N(trkSeg_t,xx->cornuData.arcSegs,segInx);
if (negative != back) params->track_angle = NormalizeAngle(params->track_angle+180); //Cornu is in reverse
if (segPtr->type == SEG_STRTRK) {
@@ -1079,13 +1183,16 @@ static BOOL_T GetParamsCornu( int inx, track_p trk, coOrd pos, trackParams_t * p
params->cornuCenter[i] = xx->cornuData.c[i];
}
params->len = xx->cornuData.length;
- if ( inx == PARAMS_PARALLEL ) {
- params->ep = 0;
- } else if (inx == PARAMS_CORNU) {
+ if ( inx == PARAMS_NODES ) {
+ return FALSE;
+ } else if ((inx == PARAMS_CORNU) || (inx == PARAMS_1ST_JOIN) || (inx == PARAMS_2ND_JOIN) ) {
params->ep = PickEndPoint( pos, trk);
} else {
params->ep = PickUnconnectedEndPointSilent( pos, trk );
+
}
+ if (params->ep == -1) return FALSE;
+
if (params->ep>=0) {
params->angle = GetTrkEndAngle(trk,params->ep);
}
@@ -1108,7 +1215,7 @@ static BOOL_T QueryCornu( track_p trk, int query )
return TRUE;
break;
case Q_EXCEPTION:
- return xx->cornuData.minCurveRadius < (GetLayoutMinTrackRadius()-EPSILON);
+ return fabs(xx->cornuData.minCurveRadius) < (GetLayoutMinTrackRadius()-EPSILON);
break;
case Q_IS_CORNU:
return TRUE;
@@ -1122,13 +1229,12 @@ static BOOL_T QueryCornu( track_p trk, int query )
// case Q_MODIFY_CANT_SPLIT: Remove Split Restriction
// case Q_CANNOT_BE_ON_END: Remove Restriction - Can have Cornu with no ends
case Q_CANNOT_PLACE_TURNOUT:
- return TRUE;
+ return FALSE;
break;
case Q_IGNORE_EASEMENT_ON_EXTEND:
return TRUE;
break;
case Q_MODIFY_CAN_SPLIT:
- case Q_CAN_EXTEND:
return TRUE;
default:
return FALSE;
@@ -1178,8 +1284,9 @@ static ANGLE_T GetAngleCornu(
BOOL_T back, neg;
int indx;
angle = GetAngleSegs( xx->cornuData.arcSegs.cnt, (trkSeg_p)xx->cornuData.arcSegs.ptr, &pos, &indx, NULL, &back, NULL, &neg );
- if ( ep0 ) *ep0 = -1;
- if ( ep1 ) *ep1 = -1;
+ if (!back) angle = NormalizeAngle(angle+180);
+ if ( ep0 ) *ep0 = neg?1:0;
+ if ( ep1 ) *ep1 = neg?0:1;
return angle;
}
@@ -1188,14 +1295,17 @@ BOOL_T GetCornuSegmentFromTrack(track_p trk, trkSeg_p seg_p) {
return TRUE;
}
+static dynArr_t cornuSegs_da;
static BOOL_T MakeParallelCornu(
track_p trk,
coOrd pos,
DIST_T sep,
+ DIST_T factor,
track_p * newTrkR,
coOrd * p0R,
- coOrd * p1R )
+ coOrd * p1R,
+ BOOL_T track )
{
struct extraData * xx = GetTrkExtraData(trk);
coOrd np[4], p, nc[2];
@@ -1216,40 +1326,41 @@ static BOOL_T MakeParallelCornu(
BOOL_T above = FALSE;
if ( diff_a < 180 ) above = TRUE; //Above track
if (xx->cornuData.a[0] <180) above = !above;
- Translate(&np[0],xx->cornuData.pos[0],xx->cornuData.a[0]+(above?90:-90),sep);
- Translate(&np[1],xx->cornuData.pos[1],xx->cornuData.a[1]+(above?-90:90),sep);
+ DIST_T sep0 = sep+((xx->cornuData.r[0]!=0.0)?fabs(factor/xx->cornuData.r[0]):0);
+ DIST_T sep1 = sep+((xx->cornuData.r[1]!=0.0)?fabs(factor/xx->cornuData.r[1]):0);
+ Translate(&np[0],xx->cornuData.pos[0],xx->cornuData.a[0]+(above?90:-90),sep0);
+ Translate(&np[1],xx->cornuData.pos[1],xx->cornuData.a[1]+(above?-90:90),sep1);
na[0]=xx->cornuData.a[0];
na[1]=xx->cornuData.a[1];
- if (xx->cornuData.r[0]) {
+ if (xx->cornuData.r[0] != 0.0) {
//Find angle between center and end angle of track
ANGLE_T ea0 =
NormalizeAngle(FindAngle(xx->cornuData.c[0],xx->cornuData.pos[0])-xx->cornuData.a[0]);
- DIST_T sep0 = sep;
- if (ea0>180) sep0 = -sep;
+ if (ea0>180) sep0 = -sep0;
nr[0]=xx->cornuData.r[0]+(above?sep0:-sep0); //Needs adjustment
nc[0]=xx->cornuData.c[0];
} else {
- nr[0] = 0;
+ nr[0] = 0.0;
nc[0] = zero;
}
- if (xx->cornuData.r[1]) {
+ if (xx->cornuData.r[1] != 0.0) {
ANGLE_T ea1 =
NormalizeAngle(FindAngle(xx->cornuData.c[1],xx->cornuData.pos[1])-xx->cornuData.a[1]);
- DIST_T sep1 = sep;
- if (ea1<180) sep1 = -sep;
+ if (ea1<180) sep1 = -sep1;
nr[1]=xx->cornuData.r[1]+(above?sep1:-sep1); //Needs adjustment
nc[1]=xx->cornuData.c[1];
} else {
- nr[1] = 0;
+ nr[1] = 0.0;
nc[1] = zero;
}
if ( newTrkR ) {
- *newTrkR = NewCornuTrack( np, nc, na, nr, NULL, 0);
- if (*newTrkR==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"),
+ if (track) {
+ *newTrkR = NewCornuTrack( np, nc, na, nr, NULL, 0);
+ if (*newTrkR==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"),
np[0].x,np[0].y,
np[1].x,np[1].y,
nc[0].x,nc[0].y,
@@ -1258,16 +1369,75 @@ static BOOL_T MakeParallelCornu(
FormatDistance(nr[0]),FormatDistance(nr[1]));
return FALSE;
}
+ } else {
+ tempSegs_da.cnt = 0;
+ CallCornu0(np,nc,na,nr,&tempSegs_da,FALSE);
+ *newTrkR = MakePolyLineFromSegs( zero, 0.0, &tempSegs_da );
+ }
} else {
tempSegs_da.cnt = 0;
CallCornu0(np,nc,na,nr,&tempSegs_da,FALSE);
+ if (!track) {
+ for (int i=0;i<tempSegs_da.cnt;i++) {
+ trkSeg_p seg = &tempSegs(i);
+ if (seg->type == SEG_STRTRK) {
+ seg->type = SEG_STRLIN;
+ seg->color = wDrawColorBlack;
+ seg->width = 0;
+ }
+ if (seg->type == SEG_CRVTRK) {
+ seg->type = SEG_CRVLIN;
+ seg->color = wDrawColorBlack;
+ seg->width = 0;
+ }
+ if (seg->type == SEG_BEZTRK) {
+ for (int j=0;j<seg->bezSegs.cnt;j++) {
+ trkSeg_p bseg = &(((trkSeg_t *)seg->bezSegs.ptr)[j]);
+ if (bseg->type == SEG_STRTRK) {
+ bseg->type = SEG_STRLIN;
+ bseg->color = wDrawColorBlack;
+ bseg->width = 0;
+ }
+ if (bseg->type == SEG_CRVTRK) {
+ bseg->type = SEG_CRVLIN;
+ bseg->color = wDrawColorBlack;
+ bseg->width = 0;
+ }
+ }
+ seg->type = SEG_BEZLIN;
+ seg->color = wDrawColorBlack;
+ seg->width = 0;
+ }
+ }
+ }
}
if ( p0R ) *p0R = np[0];
if ( p1R ) *p1R = np[1];
return TRUE;
}
+static BOOL_T TrimCornu( track_p trk, EPINX_T ep, DIST_T dist, coOrd endpos, ANGLE_T angle, DIST_T radius, coOrd center ) {
+ UndoModify(trk);
+ if (dist>0.0 && dist<minLength) {
+ UndrawNewTrack( trk );
+ DeleteTrack(trk, TRUE);
+ return FALSE;
+ } else {
+ struct extraData *xx;
+ UndrawNewTrack( trk );
+ xx = GetTrkExtraData(trk);
+ xx->cornuData.a[ep] = angle;
+ xx->cornuData.c[ep] = center;
+ xx->cornuData.r[ep] = radius;
+ xx->cornuData.pos[ep] = endpos;
+ RebuildCornu(trk);
+ SetTrkEndPoint(trk, ep, xx->cornuData.pos[ep], xx->cornuData.a[ep]);
+ DrawNewTrack( trk );
+ }
+ return TRUE;
+}
+
/*
* When an undo is run, the array of segs is missing - they are not saved to the Undo log. So Undo calls this routine to
* ensure
@@ -1288,6 +1458,29 @@ EXPORT BOOL_T RebuildCornu (track_p trk)
}
+static wBool_t CompareCornu( track_cp trk1, track_cp trk2 )
+{
+ struct extraData *xx1 = GetTrkExtraData( trk1 );
+ struct extraData *xx2 = GetTrkExtraData( trk2 );
+ char * cp = message + strlen(message);
+ REGRESS_CHECK_POS( "Pos[0]", xx1, xx2, cornuData.pos[0] )
+ REGRESS_CHECK_POS( "Pos[1]", xx1, xx2, cornuData.pos[1] )
+ REGRESS_CHECK_POS( "C[0]", xx1, xx2, cornuData.c[0] )
+ REGRESS_CHECK_POS( "C[1]", xx1, xx2, cornuData.c[1] )
+ REGRESS_CHECK_ANGLE( "A[0]", xx1, xx2, cornuData.a[0] )
+ REGRESS_CHECK_ANGLE( "A[1]", xx1, xx2, cornuData.a[1] )
+ REGRESS_CHECK_DIST( "R[0]", xx1, xx2, cornuData.r[0] )
+ REGRESS_CHECK_DIST( "R[1]", xx1, xx2, cornuData.r[1] )
+ REGRESS_CHECK_DIST( "MinCurveRadius", xx1, xx2, cornuData.minCurveRadius )
+ REGRESS_CHECK_DIST( "MaxRateofChange", xx1, xx2, cornuData.maxRateofChange )
+ REGRESS_CHECK_DIST( "Length", xx1, xx2, cornuData.length )
+ REGRESS_CHECK_ANGLE( "WindingAngle", xx1, xx2, cornuData.windingAngle )
+ // CHECK arcSegs
+ REGRESS_CHECK_POS( "DescOff", xx1, xx2, cornuData.descriptionOff )
+ // CHECK cornuPath
+ return TRUE;
+}
+
static trackCmd_t cornuCmds = {
"CORNU",
DrawCornu,
@@ -1305,7 +1498,7 @@ static trackCmd_t cornuCmds = {
TraverseCornu,
EnumerateCornu,
NULL, /* redraw */
- NULL, /* trim */
+ TrimCornu, /* trim */
MergeCornu,
NULL, /* modify */
GetLengthCornu,
@@ -1319,7 +1512,11 @@ static trackCmd_t cornuCmds = {
NULL,
MakeParallelCornu,
NULL,
- RebuildCornu
+ RebuildCornu,
+ NULL,
+ NULL,
+ NULL,
+ CompareCornu
};
diff --git a/app/bin/tcornu.h b/app/bin/tcornu.h
index a987044..5684373 100644
--- a/app/bin/tcornu.h
+++ b/app/bin/tcornu.h
@@ -37,6 +37,7 @@ typedef struct {
DIST_T radius[2]; //0.0 if straight
ANGLE_T angle[2]; //Set if straight
coOrd center[2]; //Set if radius >0
+ dynArr_t mids; //If there are G2 points added
} cornuParm_t;
@@ -53,13 +54,14 @@ BOOL_T RebuildCornu (track_p trk);
DIST_T DistanceCornu( track_p t, coOrd * p );
STATUS_T CornuDescriptionMove(track_p trk,wAction_t action,coOrd pos );
-DIST_T CornuDescriptionDistance(coOrd pos,track_p trk );
+DIST_T CornuDescriptionDistance(coOrd pos,track_p trk, coOrd *, BOOL_T show_hidden, BOOL_T * hidden );
void GetCornuParmsNear(track_p t, int sel, coOrd * pos, coOrd * center, ANGLE_T * angle, DIST_T * radius );
+void GetCornuParmsTemp(dynArr_t *, int sel, coOrd * pos2, coOrd * center, ANGLE_T * angle2, DIST_T * radius );
BOOL_T CallCornu(coOrd[2],track_p[2],EPINX_T[2],dynArr_t *,cornuParm_t *);
BOOL_T CallCornu0(coOrd[2], coOrd[2], ANGLE_T[2], DIST_T[2], dynArr_t *,BOOL_T);
-BOOL_T GetBezierSegmentsFromCornu(track_p, dynArr_t *);
+BOOL_T GetBezierSegmentsFromCornu(track_p, dynArr_t *, BOOL_T);
char * CreateSegPathList(track_p trk);
diff --git a/app/bin/tcurve.c b/app/bin/tcurve.c
index 7233ebf..00d1ef5 100644
--- a/app/bin/tcurve.c
+++ b/app/bin/tcurve.c
@@ -22,6 +22,7 @@
#include <assert.h>
#include <math.h>
+#include <string.h>
#include "ccurve.h"
#include "cjoin.h"
@@ -172,25 +173,32 @@ BOOL_T GetCurveMiddle( track_p trk, coOrd * pos )
DIST_T CurveDescriptionDistance(
coOrd pos,
- track_p trk )
+ track_p trk,
+ coOrd * dpos,
+ BOOL_T show_hidden,
+ BOOL_T * hidden)
{
struct extraData *xx = GetTrkExtraData(trk);
coOrd p1;
FLOAT_T ratio;
ANGLE_T a, a0, a1;
-
- if ( GetTrkType( trk ) != T_CURVE || ( GetTrkBits( trk ) & TB_HIDEDESC ) != 0 )
+ if (hidden) *hidden = FALSE;
+ if ( (GetTrkType( trk ) != T_CURVE )|| ((( GetTrkBits( trk ) & TB_HIDEDESC ) != 0) && !show_hidden))
return 100000;
+ coOrd offset = xx->descriptionOff;
+ if (( GetTrkBits( trk ) & TB_HIDEDESC ) != 0) offset = zero;
if ( xx->helixTurns > 0 ) {
- p1.x = xx->pos.x + xx->descriptionOff.x;
- p1.y = xx->pos.y + xx->descriptionOff.y;
+ p1.x = xx->pos.x + offset.x;
+ p1.y = xx->pos.y + offset.y;
} else {
GetCurveAngles( &a0, &a1, trk );
- ratio = ( xx->descriptionOff.x + 1.0 ) / 2.0;
+ ratio = ( offset.x + 1.0 ) / 2.0;
a = a0 + ratio * a1;
- ratio = ( xx->descriptionOff.y + 1.0 ) / 2.0;
+ ratio = ( offset.y + 1.0 ) / 2.0;
Translate( &p1, xx->pos, a, xx->radius * ratio );
}
+ if (hidden) *hidden = (GetTrkBits( trk ) & TB_HIDEDESC);
+ *dpos = p1;
return FindDistance( p1, pos );
}
@@ -220,8 +228,8 @@ static void DrawCurveDescription(
dist = GetLengthCurve( trk );
elevValid = FALSE;
if ( (!xx->circle) &&
- ComputeElev( trk, 0, FALSE, &elev0, NULL ) &&
- ComputeElev( trk, 1, FALSE, &elev1, NULL ) ) {
+ ComputeElev( trk, 0, FALSE, &elev0, NULL, FALSE ) &&
+ ComputeElev( trk, 1, FALSE, &elev1, NULL, FALSE ) ) {
if( elev0 == elev1 )
elevValid = FALSE;
else {
@@ -232,15 +240,15 @@ static void DrawCurveDescription(
}
fp = wStandardFont( F_TIMES, FALSE, FALSE );
if (elevValid)
- sprintf( message, _("Helix: turns=%ld length=%s grade=%0.1f%% sep=%s"),
+ sprintf( message, _("Helix: turns=%ld len=%0.2f grade=%0.1f%% sep=%0.2f"),
xx->helixTurns,
- FormatDistance(dist),
+ dist,
grade*100.0,
- FormatDistance(sep) );
+ sep );
else
- sprintf( message, _("Helix: turns=%ld length=%s"),
+ sprintf( message, _("Helix: turns=%ld len=%0.2f"),
xx->helixTurns,
- FormatDistance(dist) );
+ dist );
DrawBoxedString( BOX_BOX, d, pos, message, fp, (wFontSize_t)descriptionFontSize, color, 0.0 );
} else {
dist = trackGauge/2.0;
@@ -278,6 +286,7 @@ STATUS_T CurveDescriptionMove(
switch (action) {
case C_DOWN:
+ DrawCurveDescription( trk, &mainD, wDrawColorWhite );
case C_MOVE:
case C_UP:
editMode = TRUE;
@@ -286,8 +295,6 @@ STATUS_T CurveDescriptionMove(
xx->descriptionOff.x = (pos.x-xx->pos.x);
xx->descriptionOff.y = (pos.y-xx->pos.y);
p1 = pos;
- if (action != C_UP)
- DrawLine( &tempD, p0, p1, 0, wDrawColorBlack );
} else {
p1 = pos;
GetCurveAngles( &a0, &a1, trk );
@@ -314,14 +321,16 @@ STATUS_T CurveDescriptionMove(
a = a0 + (0.5 * a1);
PointOnCircle( &p0, xx->pos, xx->radius/2, a );
}
- if (action == C_UP) editMode = FALSE;
- MainRedraw();
- MapRedraw();
+ if (action == C_UP) {
+ editMode = FALSE;
+ DrawCurveDescription( trk, &mainD, wDrawColorBlack );
+ }
return action==C_UP?C_TERMINATE:C_CONTINUE;
case C_REDRAW:
if (editMode) {
- DrawLine( &tempD, p1, p0, 0, wDrawColorBlack );
+ DrawLine( &tempD, p0, p1, 0, wDrawColorBlue );
+ DrawCurveDescription( trk, &tempD, wDrawColorBlue );
}
break;
@@ -478,7 +487,7 @@ static void UpdateCurve( track_p trk, int inx, descData_p descUpd, BOOL_T final
case Z1:
ep = (inx==Z0?0:1);
UpdateTrkEndElev( trk, ep, GetTrkEndElevUnmaskedMode(trk,ep), crvData.elev[ep], NULL );
- ComputeElev( trk, 1-ep, FALSE, &crvData.elev[1-ep], NULL );
+ ComputeElev( trk, 1-ep, FALSE, &crvData.elev[1-ep], NULL, TRUE );
if ( crvData.length > minLength )
crvData.grade = fabs( (crvData.elev[0]-crvData.elev[1])/crvData.length )*100.0;
else
@@ -575,13 +584,13 @@ static void DescribeCurve( track_p trk, char * str, CSIZE_T len )
crvData.angle = a1;
crvData.layerNumber = GetTrkLayer(trk);
if ( !xx->circle ) {
- ComputeElev( trk, 0, FALSE, &crvData.elev[0], NULL );
- ComputeElev( trk, 1, FALSE, &crvData.elev[1], NULL );
+ ComputeElev( trk, 0, FALSE, &crvData.elev[0], NULL, FALSE );
+ ComputeElev( trk, 1, FALSE, &crvData.elev[1], NULL, FALSE );
} else {
crvData.elev[0] = crvData.elev[1] = 0;
}
- ComputeElev( trk, 0, FALSE, &crvData.elev[0], NULL );
- ComputeElev( trk, 1, FALSE, &crvData.elev[1], NULL );
+ ComputeElev( trk, 0, FALSE, &crvData.elev[0], NULL, FALSE );
+ ComputeElev( trk, 1, FALSE, &crvData.elev[1], NULL, FALSE );
if ( crvData.length > minLength )
crvData.grade = fabs( (crvData.elev[0]-crvData.elev[1])/crvData.length )*100.0;
else
@@ -657,12 +666,8 @@ static void DrawCurve( track_p t, drawCmd_p d, wDrawColor color )
struct extraData *xx = GetTrkExtraData(t);
ANGLE_T a0, a1;
track_p tt = t;
- long widthOptions = DTS_LEFT|DTS_RIGHT|DTS_TIES;
+ long widthOptions = DTS_LEFT|DTS_RIGHT;
- if (GetTrkWidth(t) == 2)
- widthOptions |= DTS_THICK2;
- if (GetTrkWidth(t) == 3)
- widthOptions |= DTS_THICK3;
GetCurveAngles( &a0, &a1, t );
if (xx->circle) {
tt = NULL;
@@ -671,21 +676,18 @@ static void DrawCurve( track_p t, drawCmd_p d, wDrawColor color )
a0 = 0.0;
a1 = 360.0;
}
- if ( ((d->funcs->options&wDrawOptTemp)==0) &&
+ if ( ((d->options&(DC_SIMPLE|DC_SEGTRACK))==0) &&
(labelWhen == 2 || (labelWhen == 1 && (d->options&DC_PRINT))) &&
labelScale >= d->scale &&
( GetTrkBits( t ) & TB_HIDEDESC ) == 0 ) {
DrawCurveDescription( t, d, color );
}
+
DrawCurvedTrack( d, xx->pos, xx->radius, a0, a1,
GetTrkEndPos(t,0), GetTrkEndPos(t,1),
- t, GetTrkGauge(t), color, widthOptions );
- if ( (d->funcs->options & wDrawOptTemp) == 0 &&
- (d->options&DC_QUICK) == 0 &&
- (!IsCurveCircle(t)) ) {
- DrawEndPt( d, t, 0, color );
- DrawEndPt( d, t, 1, color );
- }
+ t, color, widthOptions );
+ DrawEndPt( d, t, 0, color );
+ DrawEndPt( d, t, 1, color );
}
static void DeleteCurve( track_p t )
@@ -702,15 +704,15 @@ static BOOL_T WriteCurve( track_p t, FILE * f )
options |= 0x80;
rc &= fprintf(f, "CURVE %d %d %ld 0 0 %s %d %0.6f %0.6f 0 %0.6f %ld %0.6f %0.6f\n",
GetTrkIndex(t), GetTrkLayer(t), (long)options,
- GetTrkScaleName(t), GetTrkVisible(t), xx->pos.x, xx->pos.y, xx->radius,
+ GetTrkScaleName(t), GetTrkVisible(t)|(GetTrkNoTies(t)?1<<2:0)|(GetTrkBridge(t)?1<<3:0), xx->pos.x, xx->pos.y, xx->radius,
xx->helixTurns, xx->descriptionOff.x, xx->descriptionOff.y )>0;
rc &= WriteEndPt( f, t, 0 );
rc &= WriteEndPt( f, t, 1 );
- rc &= fprintf(f, "\tEND\n" )>0;
+ rc &= fprintf(f, "\t%s\n", END_SEGS)>0;
return rc;
}
-static void ReadCurve( char * line )
+static BOOL_T ReadCurve( char * line )
{
struct extraData *xx;
track_p t;
@@ -723,32 +725,45 @@ static void ReadCurve( char * line )
wIndex_t layer;
long options;
char * cp = NULL;
+ long helixTurns = 0;
+ coOrd descriptionOff = { 0.0, 0.0 };
if (!GetArgs( line+6, paramVersion<3?"dXZsdpYfc":paramVersion<9?"dLl00sdpYfc":"dLl00sdpffc",
&index, &layer, &options, scale, &visible, &p, &elev, &r, &cp ) ) {
- return;
+ return FALSE;
}
+ if (cp) {
+ if ( !GetArgs( cp, "lp", &helixTurns, &descriptionOff ) )
+ return FALSE;
+ }
+ if ( !ReadSegs() )
+ return FALSE;
t = NewTrack( index, T_CURVE, 0, sizeof *xx );
xx = GetTrkExtraData(t);
- SetTrkVisible(t, visible);
+ xx->helixTurns = helixTurns;
+ xx->descriptionOff = descriptionOff;
+ if ( paramVersion < 3 ) {
+ SetTrkVisible(t, visible!=0);
+ SetTrkNoTies(t, FALSE);
+ SetTrkBridge(t, FALSE);
+ } else {
+ SetTrkVisible(t, visible&2);
+ SetTrkNoTies(t, visible&4);
+ SetTrkBridge(t, visible&8);
+ }
SetTrkScale(t, LookupScale(scale));
SetTrkLayer(t, layer );
SetTrkWidth(t, (int)(options&3));
xx->pos = p;
xx->radius = r;
- xx->helixTurns = 0;
- xx->descriptionOff.x = xx->descriptionOff.y = 0.0;
- if (cp) {
- GetArgs( cp, "lp", &xx->helixTurns, &xx->descriptionOff );
- }
if ( ( ( options & 0x80 ) != 0 ) == ( xx->helixTurns > 0 ) )
SetTrkBits(t,TB_HIDEDESC);
- ReadSegs();
SetEndPts(t,2);
if (GetTrkEndAngle( t, 0 ) == 270.0 &&
GetTrkEndAngle( t, 1 ) == 90.0 )
xx->circle = TRUE;
ComputeCurveBoundingBox( t, xx );
+ return TRUE;
}
static void MoveCurve( track_p trk, coOrd orig )
@@ -810,7 +825,12 @@ static BOOL_T SplitCurve( track_p trk, coOrd pos, EPINX_T ep, track_p *leftover,
a0 = a;
}
trk1 = NewCurvedTrack( xx->pos, xx->radius, a0, a1, 0 );
+ DIST_T height;
+ int opt;
+ GetTrkEndElev(trk,ep,&opt,&height);
+ UpdateTrkEndElev( trk1, 1-ep, opt, height, (opt==ELEV_STATION)?GetTrkEndElevStation(trk,ep):NULL );
AdjustCurveEndPt( trk, ep, a+(ep==0?-90.0:90.0) );
+ UpdateTrkEndElev( trk, ep, ELEV_NONE, 0, NULL);
*leftover = trk1;
*ep0 = 1-ep;
*ep1 = ep;
@@ -922,15 +942,15 @@ static BOOL_T EnumerateCurve( track_p trk )
if (trk != NULL) {
xx = GetTrkExtraData(trk);
GetCurveAngles( &a0, &a1, trk );
- d = xx->radius * 2.0 * M_PI * a1 / 360.0;
+ d = (xx->radius + (GetTrkGauge(trk)/2.0))* 2.0 * M_PI * a1 / 360.0;
if (xx->helixTurns > 0)
- d += (xx->helixTurns-(xx->circle?1:0)) * xx->radius * 2.0 * M_PI;
+ d += (xx->helixTurns-(xx->circle?1:0)) * (xx->radius+(GetTrkGauge(trk)/2.0)) * 2.0 * M_PI;
ScaleLengthIncrement( GetTrkScale(trk), d );
}
return TRUE;
}
-static BOOL_T TrimCurve( track_p trk, EPINX_T ep, DIST_T dist )
+static BOOL_T TrimCurve( track_p trk, EPINX_T ep, DIST_T dist, coOrd endpos, ANGLE_T angle, DIST_T endradius, coOrd endcenter )
{
DIST_T d;
DIST_T radius;
@@ -980,6 +1000,8 @@ static BOOL_T MergeCurve(
if ( xx0->helixTurns > 0 ||
xx1->helixTurns > 0 )
return FALSE;
+ if (GetTrkType(trk0) != GetTrkType(trk1))
+ return FALSE;
d = FindDistance( xx0->pos, xx1->pos );
d += fabs( xx0->radius - xx1->radius );
if ( d > connectDistance )
@@ -991,6 +1013,8 @@ static BOOL_T MergeCurve(
UndoStart( _("Merge Curves"), "MergeCurve( T%d[%d] T%d[%d] )", GetTrkIndex(trk0), ep0, GetTrkIndex(trk1), ep1 );
UndoModify( trk0 );
UndrawNewTrack( trk0 );
+ if (GetTrkEndTrk(trk0,ep0) == trk1)
+ DisconnectTracks( trk0, ep0, trk1, ep1);
trk2 = GetTrkEndTrk( trk1, 1-ep1 );
if (trk2) {
ep2 = GetEndPtConnectedToMe( trk2, trk1 );
@@ -1168,7 +1192,7 @@ static DIST_T GetLengthCurve( track_p trk )
a1 = 360.0;
else
GetCurveAngles( &a0, &a1, trk );
- dist = (rad+GetTrkGauge(trk)/2.0)*a1*2.0*M_PI/360.0;
+ dist = rad*a1*2.0*M_PI/360.0;
if (xx->helixTurns>0)
dist += (xx->helixTurns-(xx->circle?1:0)) * xx->radius * 2.0 * M_PI;
return dist;
@@ -1194,32 +1218,25 @@ static BOOL_T GetParamsCurve( int inx, track_p trk, coOrd pos, trackParams_t * p
ErrorMessage( MSG_CANT_EXTEND_HELIX );
return FALSE;
}
+ if (inx == PARAMS_NODES) return FALSE;
params->len = params->arcR * params->arcA1 *2.0*M_PI/360.0;
if (xx->helixTurns > 0)
params->len += (xx->helixTurns-(xx->circle?1:0)) * xx->radius * 2.0 * M_PI;
params->helixTurns = xx->helixTurns;
- if ( inx == PARAMS_PARALLEL ) {
- params->ep = 0;
- if (xx->helixTurns > 0) {
- params->arcA0 = 0.0;
- params->arcA1 = 360.0;
- }
+ params->circleOrHelix = FALSE;
+ if ( IsCurveCircle( trk ) ) {
+ params->ep = PickArcEndPt( params->arcP, /*Dj.inp[0].*/pos, pos );
+ params->angle = params->track_angle;
+ params->circleOrHelix = TRUE;
+ return TRUE;
+ } else if ((inx == PARAMS_CORNU) || (inx == PARAMS_1ST_JOIN) || (inx == PARAMS_2ND_JOIN) ) {
+ params->ep = PickEndPoint(pos, trk);
} else {
- params->circleOrHelix = FALSE;
- if ( IsCurveCircle( trk ) ) {
- params->ep = PickArcEndPt( params->arcP, /*Dj.inp[0].*/pos, pos );
- params->angle = params->track_angle;
- params->circleOrHelix = TRUE;
- return TRUE;
- } else if (inx == PARAMS_CORNU ) {
- params->ep = PickEndPoint(pos, trk);
- } else {
- params->ep = PickUnconnectedEndPointSilent( pos, trk );
- }
- if (params->ep == -1)
- return FALSE;
- params->angle = GetTrkEndAngle(trk,params->ep); ;
+ params->ep = PickUnconnectedEndPointSilent( pos, trk );
}
+ if (params->ep == -1)
+ return FALSE;
+ params->angle = GetTrkEndAngle(trk,params->ep); ;
return TRUE;
}
@@ -1255,10 +1272,11 @@ static BOOL_T QueryCurve( track_p trk, int query )
case Q_HAS_DESC:
case Q_CORNU_CAN_MODIFY:
case Q_MODIFY_CAN_SPLIT:
+ case Q_CAN_EXTEND:
return TRUE;
break;
case Q_EXCEPTION:
- return xx->radius < GetLayoutMinTrackRadius() - EPSILON;
+ return fabs(xx->radius) < (GetLayoutMinTrackRadius() - EPSILON);
break;
case Q_NOT_PLACE_FROGPOINTS:
return IsCurveCircle( trk );
@@ -1274,6 +1292,8 @@ static BOOL_T QueryCurve( track_p trk, int query )
if ((xx->helixTurns >0) || xx->circle) return TRUE;
return FALSE;
break;
+ case Q_NODRAWENDPT:
+ return xx->circle;
default:
return FALSE;
}
@@ -1295,9 +1315,11 @@ static BOOL_T MakeParallelCurve(
track_p trk,
coOrd pos,
DIST_T sep,
+ DIST_T factor,
track_p * newTrkR,
coOrd * p0R,
- coOrd * p1R )
+ coOrd * p1R,
+ BOOL_T track)
{
struct extraData * xx = GetTrkExtraData(trk);
struct extraData * xx1;
@@ -1305,16 +1327,32 @@ static BOOL_T MakeParallelCurve(
ANGLE_T a0, a1;
rad = FindDistance( pos, xx->pos );
+ sep = sep+factor/xx->radius;
if ( rad > xx->radius )
rad = xx->radius + sep;
else
rad = xx->radius - sep;
GetCurveAngles( &a0, &a1, trk );
if ( newTrkR ) {
- *newTrkR = NewCurvedTrack( xx->pos, rad, a0, a1, 0 );
- xx1 = GetTrkExtraData(*newTrkR);
- xx1->helixTurns = xx->helixTurns;
- xx1->circle = xx->circle;
+ if (track) {
+ *newTrkR = NewCurvedTrack( xx->pos, rad, a0, a1, 0 );
+ xx1 = GetTrkExtraData(*newTrkR);
+ xx1->helixTurns = xx->helixTurns;
+ xx1->circle = xx->circle;
+ }
+ else {
+ tempSegs(0).color = wDrawColorBlack;
+ tempSegs(0).width = 0;
+ tempSegs_da.cnt = 1;
+ tempSegs(0).type = SEG_CRVLIN;
+ tempSegs(0).u.c.center = xx->pos;
+ tempSegs(0).u.c.radius = rad;
+ tempSegs(0).u.c.a0 = a0;
+ tempSegs(0).u.c.a1 = a1;
+ *newTrkR = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) );
+ return TRUE;
+ }
+
ComputeCurveBoundingBox( *newTrkR, xx1 );
} else {
if ( xx->helixTurns > 0) {
@@ -1324,7 +1362,7 @@ static BOOL_T MakeParallelCurve(
tempSegs(0).color = wDrawColorBlack;
tempSegs(0).width = 0;
tempSegs_da.cnt = 1;
- tempSegs(0).type = SEG_CRVTRK;
+ tempSegs(0).type = track?SEG_CRVTRK:SEG_CRVLIN;
tempSegs(0).u.c.center = xx->pos;
tempSegs(0).u.c.radius = rad;
tempSegs(0).u.c.a0 = a0;
@@ -1336,6 +1374,19 @@ static BOOL_T MakeParallelCurve(
}
+static wBool_t CompareCurve( track_cp trk1, track_cp trk2 )
+{
+ struct extraData * ed1 = GetTrkExtraData( trk1 );
+ struct extraData * ed2 = GetTrkExtraData( trk2 );
+ char * cp = message+strlen(message);
+ REGRESS_CHECK_POS( "POS", ed1, ed2, pos )
+ REGRESS_CHECK_DIST( "RADIUS", ed1, ed2, radius )
+ REGRESS_CHECK_INT( "CIRCLE", ed1, ed2, circle )
+ REGRESS_CHECK_INT( "TURNS", ed1, ed2, helixTurns )
+ REGRESS_CHECK_POS( "DESCOFF", ed1, ed2, descriptionOff );
+ return TRUE;
+}
+
static trackCmd_t curveCmds = {
"CURVE",
DrawCurve,
@@ -1365,7 +1416,13 @@ static trackCmd_t curveCmds = {
NULL,
NULL,
NULL,
- MakeParallelCurve };
+ MakeParallelCurve,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CompareCurve };
EXPORT void CurveSegProc(
@@ -1524,7 +1581,7 @@ EXPORT void PlotCurve(
coOrd pos1,
coOrd pos2,
curveData_t * curveData,
- BOOL_T constrain )
+ BOOL_T constrain ) //Make the Radius be in steps of radiusGranularity (1/8)
{
DIST_T d0, d2, r;
ANGLE_T angle, a0, a1, a2;
@@ -1532,13 +1589,14 @@ EXPORT void PlotCurve(
switch ( mode ) {
case crvCmdFromCornu:
+ /* Already set curveRadius, pos1, and type */
case crvCmdFromEP1:
angle = FindAngle( pos0, pos1 );
d0 = FindDistance( pos0, pos2 )/2.0;
a0 = FindAngle( pos0, pos2 );
a1 = NormalizeAngle( a0 - angle );
LOG( log_curve, 3, ( "P1 = [%0.3f %0.3f] D=%0.3f A0=%0.3f A1=%0.3f\n", pos2.x, pos2.y, d0, a0, a1 ) )
- if ((fabs(d0*sin(D2R(a1))) < (4.0/75.0)*mainD.scale) & (mode == crvCmdFromEP1)) {
+ if ((fabs(d0*sin(D2R(a1))) < (4.0/75.0)*mainD.scale)) {
LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*mainD.scale ) )
curveData->pos1.x = pos0.x + d0*2.0*sin(D2R(angle));
curveData->pos1.y = pos0.y + d0*2.0*cos(D2R(angle));
@@ -1560,7 +1618,7 @@ LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*ma
else
curveData->curveRadius = d0/sin(D2R(-a1));
}
- if (curveData->curveRadius > 1000 && mode == crvCmdFromEP1) {
+ if (curveData->curveRadius > 1000) {
LOG( log_curve, 3, ( "Straight %0.3f > 1000\n", curveData->curveRadius ) )
curveData->pos1.x = pos0.x + d0*2.0*sin(D2R(angle));
curveData->pos1.y = pos0.y + d0*2.0*cos(D2R(angle));
@@ -1579,6 +1637,7 @@ LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*ma
curveData->a0 = NormalizeAngle( a2-180-curveData->a1 );
curveData->negative = TRUE;
}
+ Translate(&curveData->pos2,curveData->curvePos,FindAngle(curveData->curvePos,pos2),curveData->curveRadius);
curveData->type = curveTypeCurve;
}
}
@@ -1602,6 +1661,7 @@ LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*ma
curveData->a0 = a1;
curveData->a1 = NormalizeAngle(a0-a1);
}
+ Translate(&curveData->pos2,curveData->curvePos,FindAngle(curveData->curvePos,pos2),curveData->curveRadius);
curveData->type = curveTypeCurve;
break;
case crvCmdFromChord:
@@ -1611,7 +1671,7 @@ LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*ma
d0 = FindDistance( pos0, pos1 )/2.0;
Rotate( &pos2, pos1, -a0 );
pos2.x -= pos1.x;
- if ( fabs(pos2.x) < 0.01 )
+ if ( fabs(pos2.x) < 0.005 )
break;
d2 = sqrt( d0*d0 + pos2.x*pos2.x )/2.0;
r = d2*d2*2.0/pos2.x;
@@ -1634,6 +1694,7 @@ LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*ma
curveData->a1 = NormalizeAngle(a0-a1);
curveData->negative = TRUE;
}
+ Translate(&curveData->pos2,curveData->curvePos,FindAngle(curveData->curvePos,pos2),curveData->curveRadius);
curveData->type = curveTypeCurve;
break;
}
diff --git a/app/bin/tease.c b/app/bin/tease.c
index ad281df..dec0801 100644
--- a/app/bin/tease.c
+++ b/app/bin/tease.c
@@ -62,6 +62,9 @@ do 'testjoin psplot 10 10 40 1 | lpr -Ppostscript'
#include <math.h>
+#include "common.h"
+#include "track.h"
+#include "tcornu.h"
#include "ccurve.h"
#include "cselect.h"
#include "cstraigh.h"
@@ -72,7 +75,6 @@ do 'testjoin psplot 10 10 40 1 | lpr -Ppostscript'
#include "layout.h"
#include "messages.h"
#include "param.h"
-#include "track.h"
#include "utility.h"
static TRKTYP_T T_EASEMENT = -1;
@@ -483,6 +485,20 @@ static DIST_T GetLengthJoint( track_p trk )
return fabs( d0-d1 );
}
+static DIST_T GetFlexLengthJoint( track_p trk )
+{
+ struct extraData *xx;
+ DIST_T d0, d1, d3;
+ xx = GetTrkExtraData(trk);
+ d0 = JoinD( xx->l0, xx->R+(GetTrkGauge(trk)/2.0), xx->L );
+ d1 = JoinD( xx->l1, xx->R+(GetTrkGauge(trk)/2.0), xx->L );
+ d3 = JoinD( xx->l1, xx->R-(GetTrkGauge(trk)/2.0), xx->L );
+ if (xx->Scurve) {
+ return d0+d3;
+ } else
+ return fabs( d0-d1 );
+}
+
static struct {
coOrd endPt[2];
@@ -523,7 +539,7 @@ static void UpdateJoint( track_p trk, int inx, descData_p descUpd, BOOL_T final
case Z1:
ep = (inx==Z0?0:1);
UpdateTrkEndElev( trk, ep, GetTrkEndElevUnmaskedMode(trk,ep), jointData.elev[ep], NULL );
- ComputeElev( trk, 1-ep, FALSE, &jointData.elev[1-ep], NULL );
+ ComputeElev( trk, 1-ep, FALSE, &jointData.elev[1-ep], NULL, TRUE );
if ( jointData.length > minLength )
jointData.grade = fabs( (jointData.elev[0]-jointData.elev[1])/jointData.length )*100.0;
else
@@ -570,8 +586,8 @@ static void DescribeJoint(
jointData.l0 = xx->l0;
jointData.l1 = xx->l1;
jointData.layerNumber = GetTrkLayer(trk);
- ComputeElev( trk, 0, FALSE, &jointData.elev[0], NULL );
- ComputeElev( trk, 1, FALSE, &jointData.elev[1], NULL );
+ ComputeElev( trk, 0, FALSE, &jointData.elev[0], NULL, FALSE );
+ ComputeElev( trk, 1, FALSE, &jointData.elev[1], NULL, FALSE );
if ( jointData.length > minLength )
jointData.grade = fabs( (jointData.elev[0]-jointData.elev[1])/jointData.length )*100.0;
else
@@ -670,48 +686,6 @@ static DIST_T DistanceJoint(
}
-#ifdef LATER
-static void DrawJointSegment1(
- drawCmd_p d,
- wIndex_t cnt,
- DIST_T l0,
- DIST_T l1,
- DIST_T R,
- DIST_T L,
- coOrd P,
- ANGLE_T A,
- BOOL_T N,
- track_p trk,
- DIST_T trackGauge,
- wDrawColor color )
-/*
- * Draw a transition-curve from (l0) to (l1),
- * at angle (A) from origin (P).
- */
-{
- DIST_T l, lincr;
- wIndex_t i;
- coOrd p0, p1;
- long widthOptions = DTS_RIGHT|DTS_LEFT|DTS_TIES;
-
- if (GetTrkWidth(trk) == 2)
- widthOptions |= DTS_THICK2;
- if (GetTrkWidth(trk) == 3)
- widthOptions |= DTS_THICK3;
-
- l = l0;
- lincr = (l1-l0)/cnt;
- GetJointPos( &p0, NULL, l0, R, L, P, A, N );
- for (i=1; i<=cnt; i++) {
- l += lincr;
- GetJointPos( &p1, NULL, l, R, L, P, A, N );
- DrawStraightTrack( d, p0, p1,
- FindAngle( p1, p0 ), trk, trackGauge, color, widthOptions );
- p0 = p1;
- }
-}
-#endif
-
static void DrawJointSegment(
drawCmd_p d,
wIndex_t cnt,
@@ -740,20 +714,16 @@ static void DrawJointSegment(
ComputeJoinPos( l0, R, L, NULL, &a0, NULL, NULL );
ComputeJoinPos( l1, R, L, NULL, &a1, NULL, NULL );
a1 = a1-a0;
- if ( (d->options&DC_QUICK) ) {
- cnt1 = 1;
- } else {
- cnt1 = (int)floor(a1/JOINT_ANGLE_INCR) + 1;
- a1 /= cnt1;
- }
+ cnt1 = (int)floor(a1/JOINT_ANGLE_INCR) + 1;
+ a1 /= cnt1;
- widthOptions |= DTS_RIGHT|DTS_LEFT|DTS_TIES;
+ widthOptions |= DTS_RIGHT|DTS_LEFT;
GetJointPos( &p0, NULL, l0, R, L, P, A, N );
for (i=1; i<=cnt1; i++) {
a0 += a1;
ll = sqrt( sin(D2R(a0)) * 2 * R * L );
GetJointPos( &p1, NULL, ll, R, L, P, A, N );
- DrawStraightTrack( d, p0, p1, FindAngle( p1, p0 ), trk, trackGauge,
+ DrawStraightTrack( d, p0, p1, FindAngle( p1, p0 ), trk,
color, widthOptions );
p0 = p1;
}
@@ -834,10 +804,6 @@ LOG( log_ease, 4, ( "DJT( (X%0.3f Y%0.3f A%0.3f) \n", pos.x, pos.y, angle ) )
#ifdef LATER
scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale;
- if (options&DTS_THICK2)
- width = 2;
- if (options&DTS_THICK3)
- width = 3;
#ifdef WINDOWS
width *= (wDrawWidth)(d->dpi/mainD.dpi);
#else
@@ -851,24 +817,22 @@ LOG( log_ease, 4, ( "DJT( (X%0.3f Y%0.3f A%0.3f) \n", pos.x, pos.y, angle ) )
/* print segments about 0.20" long */
len = (l0-l1)/(0.20*d->scale);
cnt = (int)ceil(fabs(len));
- if (cnt == 0 || (d->options&DC_QUICK)) cnt = 1;
+ if (cnt == 0) cnt = 1;
DrawJointSegment( d, cnt, l0, l1, R, L, pos,
angle, negate, trackGauge, color, options, trk );
} else {
/* print segments about 0.20" long */
cnt = (int)ceil((l0)/(0.20*d->scale));
- if (cnt == 0 || (d->options&DC_QUICK)) cnt = 1;
+ if (cnt == 0) cnt = 1;
DrawJointSegment( d, cnt, 0, l0, R, L, pos,
angle, negate, trackGauge, color, options, trk );
cnt = (int)ceil((l1)/(0.20*d->scale));
- if (cnt == 0 || (d->options&DC_QUICK)) cnt = 1;
+ if (cnt == 0) cnt = 1;
DrawJointSegment( d, cnt, 0, l1, R, L, pos,
angle+180, negate, trackGauge, color, options, trk );
}
- if ( (d->funcs->options & wDrawOptTemp) == 0 && (d->options&DC_QUICK) == 0 ) {
- DrawEndPt( d, trk, ep0, color );
- DrawEndPt( d, trk, ep1, color );
- }
+ DrawEndPt( d, trk, ep0, color );
+ DrawEndPt( d, trk, ep1, color );
}
@@ -883,10 +847,6 @@ static void DrawJoint(
struct extraData * xx = GetTrkExtraData(trk);
long widthOptions = 0;
- if (GetTrkWidth(trk) == 2)
- widthOptions = DTS_THICK2;
- if (GetTrkWidth(trk) == 3)
- widthOptions = DTS_THICK3;
DrawJointTrack( d, xx->pos, xx->angle, xx->l0, xx->l1, xx->R, xx->L, xx->negate, xx->flip, xx->Scurve, trk, 0, 1, GetTrkGauge(trk), color, widthOptions );
}
@@ -912,11 +872,11 @@ static BOOL_T WriteJoint(
xx->flip, xx->negate, xx->Scurve, xx->pos.x, xx->pos.y, xx->angle )>0;
rc &= WriteEndPt( f, t, 0 );
rc &= WriteEndPt( f, t, 1 );
- rc &= fprintf(f, "\tEND\n" )>0;
+ rc &= fprintf(f, "\t%s\n", END_SEGS )>0;
return rc;
}
-static void ReadJoint(
+static BOOL_T ReadJoint(
char * line )
/*
* Read track data from a file (f).
@@ -934,17 +894,27 @@ static void ReadJoint(
if ( !GetArgs( line+6, paramVersion<3?"dXZsdffffdddpYf":paramVersion<9?"dLl00sdffffdddpYf":"dLl00sdffffdddpff",
&index, &layer, &options, scale, &visible, &e.l0, &e.l1, &e.R, &e.L,
&e.flip, &e.negate, &e.Scurve, &e.pos, &elev, &e.angle) )
- return;
+ return FALSE;
+ if ( !ReadSegs() )
+ return FALSE;
trk = NewTrack( index, T_EASEMENT, 0, sizeof e );
xx = GetTrkExtraData(trk);
- SetTrkVisible(trk, visible);
+ if ( paramVersion < 3 ) {
+ SetTrkVisible(trk, visible!=0);
+ SetTrkNoTies(trk, FALSE);
+ SetTrkBridge(trk, FALSE);
+ } else {
+ SetTrkVisible(trk, visible&2);
+ SetTrkNoTies(trk, visible&4);
+ SetTrkBridge(trk, visible&8);
+ }
SetTrkScale(trk, LookupScale(scale));
SetTrkLayer(trk, layer);
SetTrkWidth(trk, (int)(options&3));
*xx = e;
- ReadSegs();
SetEndPts( trk, 2 );
ComputeBoundingBox( trk );
+ return TRUE;
}
static void MoveJoint(
@@ -1225,12 +1195,12 @@ static BOOL_T TraverseJointTrack(
static BOOL_T EnumerateJoint( track_p trk )
{
if (trk != NULL) {
- ScaleLengthIncrement( GetTrkScale(trk), GetLengthJoint(trk) );
+ ScaleLengthIncrement( GetTrkScale(trk), GetFlexLengthJoint(trk) );
}
return TRUE;
}
-static BOOL_T TrimJoint( track_p trk, EPINX_T ep, DIST_T maxX )
+static BOOL_T TrimJoint( track_p trk, EPINX_T ep, DIST_T maxX, coOrd endpos, ANGLE_T angle, DIST_T radius, coOrd center )
{
DeleteTrack( trk, FALSE );
return TRUE;
@@ -1294,13 +1264,16 @@ static BOOL_T MergeJoint(
static BOOL_T GetParamsJoint( int inx, track_p trk, coOrd pos, trackParams_t * params )
{
params->type = curveTypeStraight;
- params->ep = PickUnconnectedEndPointSilent( pos, trk );
+ if ((inx == PARAMS_CORNU) || (inx == PARAMS_1ST_JOIN) || (inx == PARAMS_2ND_JOIN))\
+ params->ep = PickEndPoint(pos, trk);
+ else
+ params->ep = PickUnconnectedEndPointSilent( pos, trk );
if (params->ep == -1)
return FALSE;
params->lineOrig = GetTrkEndPos(trk,params->ep);
params->lineEnd = params->lineOrig;
params->angle = GetTrkEndAngle(trk,params->ep);
- params->len = 0.0;
+ params->len = GetLengthJoint(trk);
params->arcR = 0.0;
return TRUE;
}
@@ -1354,9 +1327,11 @@ static BOOL_T MakeParallelJoint(
track_p trk,
coOrd pos,
DIST_T sep,
+ DIST_T factor,
track_p * newTrkR,
coOrd * p0R,
- coOrd * p1R )
+ coOrd * p1R,
+ BOOL_T track)
{
struct extraData * xx = GetTrkExtraData(trk), *xx1;
ANGLE_T angle, A;
@@ -1378,13 +1353,13 @@ static BOOL_T MakeParallelJoint(
p0 = GetTrkEndPos(trk,0);
p1 = GetTrkEndPos(trk,1);
d0 = FindDistance( p0, p1 );
+ sep = sep+factor/(xx->R);
Translate( &p0, p0, GetTrkEndAngle(trk,0)+angle, sep );
Translate( &p1, p1, GetTrkEndAngle(trk,1)-angle, sep );
d = FindDistance( p0, p1 );
angle = R2D(asin(xx->L/2/xx->R));
A = xx->angle;
R = xx->R + sep*sin(D2R(angle));
-
dl = JoinD( xx->l1, xx->R, xx->L ) - JoinD( xx->l0, xx->R, xx->L );
/*printf( "D = %0.3f %0.3f\n", d, dl );*/
d /= d0;
@@ -1408,30 +1383,53 @@ static BOOL_T MakeParallelJoint(
}
if ( newTrkR ) {
- *newTrkR = NewTrack( 0, T_EASEMENT, 2, sizeof *xx );
- xx1 = GetTrkExtraData( *newTrkR );
- *xx1 = *xx;
- xx1->angle = A;
- xx1->R = R;
- xx1->L = L;
- xx1->l0 = l0;
- xx1->l1 = l1;
- xx1->pos = P;
- SetTrkEndPoint( *newTrkR, 0, p0, GetTrkEndAngle(trk,0) );
- SetTrkEndPoint( *newTrkR, 1, p1, GetTrkEndAngle(trk,1) );
- ComputeBoundingBox( *newTrkR );
+ if (track) {
+ *newTrkR = NewTrack( 0, T_EASEMENT, 2, sizeof *xx );
+ xx1 = GetTrkExtraData( *newTrkR );
+ *xx1 = *xx;
+ xx1->angle = A;
+ xx1->R = R;
+ xx1->L = L;
+ xx1->l0 = l0;
+ xx1->l1 = l1;
+ xx1->pos = P;
+ SetTrkEndPoint( *newTrkR, 0, p0, GetTrkEndAngle(trk,0) );
+ SetTrkEndPoint( *newTrkR, 1, p1, GetTrkEndAngle(trk,1) );
+ ComputeBoundingBox( *newTrkR );
+ } else {
+ dl = fabs(l0-l1);
+ len = dl/(0.20*mainD.scale);
+ cnt = (int)ceil(len);
+ if (cnt == 0) cnt = 1;
+ dl /= cnt;
+ DYNARR_SET( trkSeg_t, tempSegs_da, cnt );
+ for ( inx=0; inx<cnt; inx++ ) {
+ tempSegs(inx).color = wDrawColorBlack;
+ tempSegs(inx).width = 0;
+ tempSegs(inx).type = track?SEG_STRTRK:SEG_STRLIN;
+ if ( inx == 0 ) {
+ GetJointPos( &tempSegs(inx).u.l.pos[0], NULL, l0, R, L, P, A, xx->negate );
+ } else {
+ tempSegs(inx).u.l.pos[0] = tempSegs(inx-1).u.l.pos[1];
+ }
+ l0 += dl;
+ GetJointPos( &tempSegs(inx).u.l.pos[1], NULL, l0, R, L, P, A, xx->negate );
+ *newTrkR = MakeDrawFromSeg( zero, 0.0, &tempSegs(inx) );
+ }
+ tempSegs_da.cnt = cnt;
+ }
} else {
/* print segments about 0.20" long */
dl = fabs(l0-l1);
len = dl/(0.20*mainD.scale);
cnt = (int)ceil(len);
- if (cnt == 0 || (mainD.options&DC_QUICK)) cnt = 1;
+ if (cnt == 0) cnt = 1;
dl /= cnt;
DYNARR_SET( trkSeg_t, tempSegs_da, cnt );
for ( inx=0; inx<cnt; inx++ ) {
tempSegs(inx).color = wDrawColorBlack;
tempSegs(inx).width = 0;
- tempSegs(inx).type = SEG_STRTRK;
+ tempSegs(inx).type = track?SEG_STRTRK:SEG_STRLIN;
if ( inx == 0 ) {
GetJointPos( &tempSegs(inx).u.l.pos[0], NULL, l0, R, L, P, A, xx->negate );
} else {
@@ -1447,6 +1445,21 @@ static BOOL_T MakeParallelJoint(
return TRUE;
}
+static wBool_t CompareJoint( track_cp trk1, track_cp trk2 )
+{
+ struct extraData *xx1 = GetTrkExtraData( trk1 );
+ struct extraData *xx2 = GetTrkExtraData( trk2 );
+ char * cp = message + strlen(message);
+ REGRESS_CHECK_DIST( "L0", xx1, xx2, l0 );
+ REGRESS_CHECK_DIST( "L1", xx1, xx2, l1 );
+ REGRESS_CHECK_INT( "Flip", xx1, xx2, flip );
+ REGRESS_CHECK_INT( "Negate", xx1, xx2, negate );
+ REGRESS_CHECK_INT( "Scurve", xx1, xx2, Scurve );
+ REGRESS_CHECK_POS( "Pos", xx1, xx2, pos );
+ REGRESS_CHECK_ANGLE( "Angle", xx1, xx2, angle );
+ return TRUE;
+}
+
static trackCmd_t easementCmds = {
"JOINT",
@@ -1477,7 +1490,13 @@ static trackCmd_t easementCmds = {
NULL,
NULL,
NULL,
- MakeParallelJoint };
+ MakeParallelJoint,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CompareJoint };
EXPORT void JointSegProc(
@@ -1703,9 +1722,28 @@ LOG( log_ease, 1, ( " EASE R%0.3f..%0.3f L%0.3f..%0.3f\n",
ConnectTracks( trk0, ep0, trk1, ep1 );
} else {
/* Connect with transition-curve */
- joint = NewJoint( GetTrkEndPos(trk0,ep0), GetTrkEndAngle(trk0,ep0),
+ if (easementVal<0.0) { //Cornu Easements
+ coOrd pos[2];
+ pos[0] = GetTrkEndPos(trk0,ep0);
+ pos[1] = GetTrkEndPos(trk1,ep1);
+ DIST_T radius[2];
+ trackParams_t params0, params1;
+ GetTrackParams(PARAMS_CORNU,trk0,pos0,&params0);
+ GetTrackParams(PARAMS_CORNU,trk1,pos1,&params1);
+ radius[0] = params0.arcR;
+ radius[1] = params1.arcR;
+ coOrd center[2];
+ center[0] = params0.arcP;
+ center[1] = params1.arcP;
+ ANGLE_T angle[2];
+ angle[0] = NormalizeAngle(GetTrkEndAngle(trk0,ep0)+180.0);
+ angle[1] = NormalizeAngle(GetTrkEndAngle(trk1,ep1)+180.0);
+ joint = NewCornuTrack(pos,center,angle,radius, NULL, 0);
+ } else {
+ joint = NewJoint( GetTrkEndPos(trk0,ep0), GetTrkEndAngle(trk0,ep0),
GetTrkEndPos(trk1,ep1), GetTrkEndAngle(trk1,ep1),
GetTrkGauge(trk0), easeR, easeL, e );
+ }
CopyAttributes( trk0, joint );
ConnectTracks( trk1, ep1, joint, 1 );
ConnectTracks( trk0, ep0, joint, 0 );
@@ -1782,7 +1820,7 @@ track_p NewTrack( TRKINX_T a, TRKTYP_T b, EPINX_T c, TRKTYP_T d )
}
void DrawStraightTrack( drawCmd_p a, coOrd b, coOrd c, ANGLE_T d,
- DIST_T trackGauge, wDrawColor color, int opts )
+ track_p trk, wDrawColor color, int opts )
{
}
diff --git a/app/bin/textnoteui.c b/app/bin/textnoteui.c
new file mode 100644
index 0000000..331cfb5
--- /dev/null
+++ b/app/bin/textnoteui.c
@@ -0,0 +1,243 @@
+/** \file textnoteui.c
+ * View for the text note
+ */
+
+ /* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2018 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 <string.h>
+#include <stdbool.h>
+
+#include "custom.h"
+#include "dynstring.h"
+#include "i18n.h"
+#include "misc.h"
+#include "note.h"
+#include "param.h"
+#include "shortentext.h"
+#include "track.h"
+#include "wlib.h"
+
+static struct extraDataNote noteDataInUI;
+
+static paramTextData_t noteTextData = { 300, 150 };
+static paramFloatRange_t r_1000_1000 = { -1000.0, 1000.0, 80 };
+static paramData_t textEditPLs[] = {
+#define I_ORIGX (0)
+ /*0*/ { PD_FLOAT, &noteDataInUI.pos.x, "origx", PDO_DIM, &r_1000_1000, N_("Position X") },
+#define I_ORIGY (1)
+ /*1*/ { PD_FLOAT, &noteDataInUI.pos.y, "origy", PDO_DIM, &r_1000_1000, N_("Position Y") },
+#define I_LAYER (2)
+ /*2*/ { PD_DROPLIST, &noteDataInUI.layer, "layer", 0, (void*)150, "Layer", 0 },
+#define I_TEXT (3)
+ /*3*/ { PD_TEXT, NULL, "text", PDO_NOPREF, &noteTextData, N_("Note") }
+};
+
+static paramGroup_t textEditPG = { "textEdit", 0, textEditPLs, sizeof textEditPLs / sizeof textEditPLs[0] };
+static wWin_p textEditW;
+
+#define textEntry ((wText_p)textEditPLs[I_TEXT].control)
+
+extern BOOL_T inDescribeCmd;
+
+/**
+ * Return the current text
+ *
+ */
+static void GetNoteTextData()
+{
+ int len;
+
+ if (noteDataInUI.noteData.text ) {
+ MyFree(noteDataInUI.noteData.text);
+ }
+ len = wTextGetSize(textEntry);
+ noteDataInUI.noteData.text = (char*)MyMalloc(len + 2);
+ wTextGetText(textEntry, noteDataInUI.noteData.text, len);
+ return;
+}
+
+/**
+ * Check validity of entered text
+ *
+ * \return always TRUE for testing
+ */
+BOOL_T
+IsValidText(char * text)
+{
+ return(TRUE);
+}
+
+
+/**
+ * Callback for text note dialog
+ *
+ * \param pg IN unused
+ * \param inx IN index into dialog template
+ * \param valueP IN unused
+ */
+static void
+TextDlgUpdate(
+ paramGroup_p pg,
+ int inx,
+ void * valueP)
+{
+ switch (inx) {
+ case I_ORIGX:
+ case I_ORIGY:
+ UpdateText(&noteDataInUI, OR_NOTE, FALSE);
+ break;
+ case I_LAYER:
+ UpdateText(&noteDataInUI, LY_NOTE, FALSE);
+ break;
+ case I_TEXT:
+ /** TODO: this is never called, why doesn't text update trigger this callback? */
+ GetNoteTextData();
+ if (IsValidText(noteDataInUI.noteData.text)) {
+ ParamDialogOkActive(&textEditPG, TRUE);
+ } else {
+ ParamDialogOkActive(&textEditPG, FALSE);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+* Handle Cancel button: restore old values for layer and position
+*/
+
+static void
+TextEditCancel( wWin_p junk )
+{
+ if (inDescribeCmd) {
+ UpdateText(&noteDataInUI, CANCEL_NOTE, FALSE);
+ }
+ ResetIfNotSticky();
+ wHide(textEditW);
+}
+
+/**
+ * Handle OK button: make sure the entered URL is syntactically valid, update
+ * the layout and close the dialog
+ *
+ * \param junk
+ */
+
+static void
+TextEditOK(void *junk)
+{
+ GetNoteTextData();
+ UpdateText(&noteDataInUI, OK_TEXT, FALSE);
+ wHide(textEditW);
+ ResetIfNotSticky();
+ FileIsChanged();
+}
+
+
+
+/**
+ * Create the edit dialog for text notes.
+ *
+ * \param trk IN selected note
+ * \param title IN dialog title
+ */
+static void
+CreateEditTextNote(track_p trk, char *title)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ // create the dialog if necessary
+ if (!textEditW) {
+ ParamRegister(&textEditPG);
+ textEditW = ParamCreateDialog(&textEditPG,
+ "",
+ _("Done"), TextEditOK,
+ TextEditCancel, TRUE, NULL,
+ F_BLOCK,
+ TextDlgUpdate);
+ }
+
+ wWinSetTitle(textEditPG.win, MakeWindowTitle(title));
+
+ // initialize the dialog fields
+ noteDataInUI.pos = xx->pos;
+ noteDataInUI.layer = xx->layer;
+ noteDataInUI.trk = trk;
+
+ wTextClear(textEntry);
+ wTextAppend(textEntry, xx->noteData.text );
+ wTextSetReadonly(textEntry, FALSE);
+ FillLayerList((wList_p)textEditPLs[I_LAYER].control);
+ ParamLoadControls(&textEditPG);
+
+ // and show the dialog
+ wShow(textEditW);
+}
+
+/**
+ * Show details in statusbar. If running in Describe mode, the describe dialog is opened for editing the note
+ *
+ * \param trk IN the selected track (note)
+ * \param str IN the buffer for the description string
+ * \param len IN length of string buffer str
+*/
+
+void DescribeTextNote(track_p trk, char * str, CSIZE_T len)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ char *noteText;
+ DynString statusLine;
+
+ noteText = MyMalloc(strlen(xx->noteData.text) + 1);
+ RemoveFormatChars(xx->noteData.text, noteText);
+ EllipsizeString(noteText, NULL, 80);
+ DynStringMalloc(&statusLine, 100);
+
+ DynStringPrintf(&statusLine,
+ _("Note: Layer=%d %-.80s"),
+ GetTrkLayer(trk)+1,
+ noteText );
+ strcpy(str, DynStringToCStr(&statusLine));
+
+ DynStringFree(&statusLine);
+ MyFree(noteText);
+
+ if (inDescribeCmd) {
+ NoteStateSave(trk);
+
+ CreateEditTextNote(trk, _("Update comment"));
+ }
+}
+
+/**
+ * Show the UI for entering new text notes
+ *
+ * \param xx Note object data
+ */
+
+void NewTextNoteUI(track_p trk) {
+ struct extraDataNote * xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ char *tmpPtrText = _("Replace this text with your note");
+
+ xx->noteData.text = MyStrdup(tmpPtrText);
+
+ CreateEditTextNote(trk, _("Create Text Note"));
+}
+
diff --git a/app/bin/tocornu.src b/app/bin/tocornu.src
new file mode 100644
index 0000000..6184300
--- /dev/null
+++ b/app/bin/tocornu.src
@@ -0,0 +1,21 @@
+CURVE, 25, 100, 325, 80, 1700,
+CURVE, 25, 100, 300, 40, 600,
+LINE, 25, 10, 25, 140,
+LINE, 75, 70, 75, 120,
+ARROW, 25, 70, 50, 70,
+ARROW, 75, 70, 50, 70,
+ARROW, 25, 20, 125, 20,
+ARROW, 300, 20, 225, 20,
+LINE, 300, 40, 300, 10,
+LINE, 300, 40, 400, 40,
+ARROW, 25, 130, 125, 130,
+ARROW, 325, 130, 225, 130,
+LINE, 325, 80, 325, 130,
+LINE, 325, 80, 425, 80,
+LINE, 25, 100, 425, 100,
+ARROW, 315, 40, 315, 60,
+ARROW, 315, 100, 315, 60,
+ARROW, 340, 80, 340, 90,
+ARROW, 340, 100, 340, 90,
+LINE, 300, 40, 368, 10,
+LINE, 325, 80, 400, 67,
diff --git a/app/bin/tocornu3way.src b/app/bin/tocornu3way.src
new file mode 100644
index 0000000..3185e49
--- /dev/null
+++ b/app/bin/tocornu3way.src
@@ -0,0 +1,33 @@
+CURVE, 25, 100, 305, 90, 1200
+CURVE, 45, 100, 290, 50, 500
+CURVE, 65, 100, 280, 145, -600
+LINE, 294, 35, 306, 65,
+LINE, 294, 165, 306, 135,
+ARROW, 25, 100, 70, 100,
+ARROW, 322, 100, 150, 100,
+ARROW, 25, 20, 120, 20,
+ARROW, 300, 20, 200, 20,
+ARROW, 25, 180, 125, 180,
+ARROW, 290, 180, 225, 180,
+ARROW, 25, 70, 35, 70,
+ARROW, 45, 70, 35, 70,
+ARROW, 25, 140, 45, 140,
+ARROW, 65, 140, 45, 140,
+LINE, 45, 70, 45, 100
+LINE, 65, 140, 65, 100
+LINE, 25, 10, 25, 190,
+LINE, 300, 50, 300, 10,
+LINE, 300, 50, 425, 50,
+LINE, 300, 150, 300, 190,
+LINE, 300, 150, 425, 150,
+LINE, 320, 75, 325, 105,
+LINE, 325, 90, 425, 90,
+LINE, 325, 90, 425, 70,
+ARROW, 350, 100, 350, 85,
+ARROW, 350, 50, 350, 65,
+ARROW, 350, 100, 350, 115,
+ARROW, 350, 150, 350, 135,
+LINE, 300, 50, 425, 10,
+LINE, 300, 150, 425, 190,
+LINE, 322, 100, 425, 100,
+LINE, 322, 100, 322, 90,
diff --git a/app/bin/tocornuwye.src b/app/bin/tocornuwye.src
new file mode 100644
index 0000000..82a411c
--- /dev/null
+++ b/app/bin/tocornuwye.src
@@ -0,0 +1,24 @@
+STRAIGHT, 25, 100, 75, 100,
+CURVE, 75, 100, 300, 50, 600,
+CURVE, 75, 100, 300, 150, -600,
+LINE, 294, 35, 306, 65,
+LINE, 294, 165, 306, 135,
+ARROW, 25, 20, 125, 20,
+ARROW, 300, 20, 225, 20,
+ARROW, 25, 180, 125, 180,
+ARROW, 300, 180, 225, 180,
+LINE, 25, 10, 25, 190,
+LINE, 300, 50, 300, 10,
+LINE, 300, 50, 425, 50,
+LINE, 300, 150, 300, 190,
+LINE, 300, 150, 425, 150,
+LINE, 25, 100, 425, 100,
+ARROW, 350, 100, 350, 85,
+ARROW, 350, 50, 350, 65,
+ARROW, 350, 100, 350, 115,
+ARROW, 350, 150, 350, 135,
+LINE, 300, 50, 425, 10,
+LINE, 300, 150, 425, 190,
+LINE, 75, 70, 75, 120,
+ARROW, 25, 70, 50, 70,
+ARROW, 75, 70, 50, 70,
diff --git a/app/bin/track.c b/app/bin/track.c
index 0660d7d..c9ec7db 100644
--- a/app/bin/track.c
+++ b/app/bin/track.c
@@ -43,6 +43,8 @@
#include "paths.h"
#include "track.h"
#include "utility.h"
+#include "misc.h"
+#include "ctrain.h"
#ifndef TRACKDEP
#ifndef FASTTRACK
@@ -59,6 +61,8 @@
#endif
#endif
+EXPORT char tempSpecial[4096];
+
static int log_track = 0;
static int log_endPt = 0;
static int log_readTracks = 0;
@@ -110,6 +114,8 @@ EXPORT BOOL_T onTrackInSplit = FALSE;
static BOOL_T inDrawTracks;
+static wBool_t bWriteEndPtDirectIndex = FALSE;
+
#ifndef TRACKDEP
/*****************************************************************************
@@ -117,10 +123,17 @@ static BOOL_T inDrawTracks;
*
*
*/
+EXPORT void ActivateTrack( track_cp trk) {
+ int inx = GetTrkType(trk);
+ if (trackCmds( inx )->activate != NULL)
+ trackCmds( inx )->activate (trk);
+
+}
EXPORT void DescribeTrack( track_cp trk, char * str, CSIZE_T len )
{
+
trackCmds( GetTrkType(trk) )->describe ( trk, str, len );
/*epCnt = GetTrkEndPtCnt(trk);
if (debugTrack >= 2)
@@ -131,7 +144,7 @@ EXPORT void DescribeTrack( track_cp trk, char * str, CSIZE_T len )
EXPORT DIST_T GetTrkDistance( track_cp trk, coOrd * pos )
{
- return trackCmds( GetTrkType(trk) )->distance( trk, pos );
+ return fabs(trackCmds( GetTrkType(trk) )->distance( trk, pos ));
}
/**
@@ -176,13 +189,14 @@ EXPORT track_p OnTrack2( coOrd * fp, BOOL_T complain, BOOL_T track, BOOL_T ignor
}
p = *fp;
distance = trackCmds( GetTrkType(trk) )->distance( trk, &p );
- if (distance < closestDistance) {
+ if (fabs(distance) <= fabs(closestDistance)) { //Make the last (highest) preferred
closestDistance = distance;
closestTrack = trk;
closestPos = p;
}
}
- if (closestTrack && (closestDistance <= mainD.scale*0.25 || closestDistance <= trackGauge*2.0) ) {
+ if (closestTrack && closestDistance <0 ) closestDistance = 0.0; //Turntable was closest - inside well
+ if (closestTrack && ((closestDistance <= mainD.scale*0.25) || (closestDistance <= trackGauge*2.0) )) {
*fp = closestPos;
return closestTrack;
}
@@ -214,9 +228,21 @@ EXPORT BOOL_T CheckTrackLayer( track_p trk )
if (GetLayerFrozen( GetTrkLayer( trk ) ) ) {
ErrorMessage( MSG_CANT_MODIFY_FROZEN_TRK );
return FALSE;
- } else {
+ } else if (GetLayerModule( GetTrkLayer( trk ) ) ) {
+ ErrorMessage( MSG_CANT_MODIFY_MODULE_TRK );
+ return FALSE;
+ } else
+ return TRUE;
+}
+
+EXPORT BOOL_T CheckTrackLayerSilent( track_p trk )
+{
+ if (GetLayerFrozen( GetTrkLayer( trk ) ) ) {
+ return FALSE;
+ } else if (GetLayerModule( GetTrkLayer( trk ) ) ) {
+ return FALSE;
+ } else
return TRUE;
- }
}
/******************************************************************************
@@ -249,7 +275,6 @@ EXPORT void EnumerateTracks( void )
trackCmds(inx)->enumerate( NULL );
EnumerateEnd();
- Reset();
}
/*****************************************************************************
@@ -327,7 +352,9 @@ EXPORT TRKTYP_T GetTrkType( track_p trk )
EXPORT SCALEINX_T GetTrkScale( track_p trk )
{
- return (SCALEINX_T)trk->scale;
+ if ( trk )
+ return (SCALEINX_T)trk->scale;
+ return 0;
}
EXPORT void SetTrkScale( track_p trk, SCALEINX_T si )
@@ -369,6 +396,7 @@ EXPORT struct extraData * GetTrkExtraData( track_cp trk )
EXPORT void SetTrkEndPoint( track_p trk, EPINX_T ep, coOrd pos, ANGLE_T angle )
{
+ ASSERT( ep < trk->endCnt );
if (trk->endPt[ep].track != NULL) {
AbortProg( "setTrkEndPoint: endPt is connected" );
}
@@ -378,29 +406,43 @@ EXPORT void SetTrkEndPoint( track_p trk, EPINX_T ep, coOrd pos, ANGLE_T angle )
EXPORT coOrd GetTrkEndPos( track_p trk, EPINX_T e )
{
+ ASSERT( e < trk->endCnt );
return trk->endPt[e].pos;
}
EXPORT ANGLE_T GetTrkEndAngle( track_p trk, EPINX_T e )
{
+ ASSERT( e < trk->endCnt );
return trk->endPt[e].angle;
}
EXPORT track_p GetTrkEndTrk( track_p trk, EPINX_T e )
{
+ ASSERT( e < trk->endCnt );
return trk->endPt[e].track;
}
EXPORT long GetTrkEndOption( track_p trk, EPINX_T e )
{
+ ASSERT( e < trk->endCnt );
return trk->endPt[e].option;
}
EXPORT long SetTrkEndOption( track_p trk, EPINX_T e, long option )
{
+ ASSERT( e < trk->endCnt );
return trk->endPt[e].option = option;
}
+EXPORT DIST_T GetTrkGauge(
+ track_cp trk )
+{
+ if (trk)
+ return GetScaleTrackGauge( GetTrkScale( trk ) );
+ else
+ return trackGauge;
+}
+
EXPORT int GetTrkWidth( track_p trk )
{
return (int)trk->width;
@@ -441,6 +483,7 @@ EXPORT void SetTrkEndElev( track_p trk, EPINX_T ep, int option, DIST_T height, c
track_p trk1;
EPINX_T ep1;
trk->endPt[ep].elev.option = option;
+ trk->endPt[ep].elev.cacheSet = FALSE;
if (EndPtIsDefinedElev(trk,ep)) {
trk->endPt[ep].elev.u.height = height;
} else if (EndPtIsStationElev(trk,ep)) {
@@ -487,6 +530,23 @@ EXPORT DIST_T GetTrkEndElevHeight( track_p trk, EPINX_T e )
return trk->endPt[e].elev.u.height;
}
+EXPORT BOOL_T GetTrkEndElevCachedHeight (track_p trk, EPINX_T e, DIST_T * height, DIST_T * length)
+{
+ if (trk->endPt[e].elev.cacheSet) {
+ *height = trk->endPt[e].elev.cachedElev;
+ *length = trk->endPt[e].elev.cachedLength;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+EXPORT void SetTrkEndElevCachedHeight ( track_p trk, EPINX_T e, DIST_T height, DIST_T length)
+{
+ trk->endPt[e].elev.cachedElev = height;
+ trk->endPt[e].elev.cachedLength = length;
+ trk->endPt[e].elev.cacheSet = TRUE;
+}
+
EXPORT char * GetTrkEndElevStation( track_p trk, EPINX_T e )
{
@@ -531,13 +591,21 @@ void SetTrkLayer( track_p trk, int layer )
EXPORT int ClrAllTrkBits( int bits )
{
+ return ClrAllTrkBitsRedraw( bits, FALSE );
+}
+
+
+EXPORT int ClrAllTrkBitsRedraw( int bits, wBool_t bRedraw )
+{
track_p trk;
- int cnt;
- cnt = 0;
+ int cnt = 0;
TRK_ITERATE( trk ) {
- if (trk->bits&bits)
+ if (trk->bits&bits) {
cnt++;
- trk->bits &= ~bits;
+ trk->bits &= ~bits;
+ if ( bRedraw )
+ DrawNewTrack( trk );
+ }
}
return cnt;
}
@@ -549,6 +617,9 @@ EXPORT void SetTrkElev( track_p trk, int mode, DIST_T elev )
SetTrkBits( trk, TB_ELEVPATH );
trk->elev = elev;
trk->elevMode = mode;
+ for (int i=0;i<trk->endCnt;i++) {
+ trk->endPt[i].elev.cacheSet = FALSE;
+ }
}
@@ -606,7 +677,9 @@ EXPORT BOOL_T WriteEndPt( FILE * f, track_cp trk, EPINX_T ep )
long option;
assert ( endPt != NULL );
- if (endPt->track == NULL ||
+ if (bWriteEndPtDirectIndex && endPt->index > 0) {
+ rc &= fprintf( f, "\tT4 %d ", endPt->index )>0;
+ } else if (endPt->track == NULL ||
( exportingTracks && !GetTrkSelected(endPt->track) ) ) {
rc &= fprintf( f, "\tE4 " )>0;
} else {
@@ -651,7 +724,7 @@ EXPORT EPINX_T PickEndPoint( coOrd p, track_cp trk )
if (trk->endCnt <= 0)
return -1;
if ( onTrackInSplit && trk->endCnt > 2 ) {
- if (GetTrkType(trk) != T_TURNOUT)
+ if (GetTrkType(trk) == T_TURNOUT)
return TurnoutPickEndPt( p, trk );
}
d = FindDistance( p, trk->endPt[0].pos );
@@ -875,12 +948,14 @@ EXPORT BOOL_T MakeParallelTrack(
track_p trk,
coOrd pos,
DIST_T dist,
+ DIST_T factor,
track_p * newTrkR,
coOrd * p0R,
- coOrd * p1R )
+ coOrd * p1R,
+ BOOL_T track)
{
if ( trackCmds(trk->type)->makeParallel )
- return trackCmds(trk->type)->makeParallel( trk, pos, dist, newTrkR, p0R, p1R );
+ return trackCmds(trk->type)->makeParallel( trk, pos, dist, factor, newTrkR, p0R, p1R, track);
return FALSE;
}
@@ -1011,7 +1086,7 @@ EXPORT void ClearTracks( void )
to_first = NULL;
to_last = &to_first;
max_index = 0;
- changed = 0;
+ changed = checkPtMark = 0;
trackCount = 0;
ClearCars();
InfoCount( trackCount );
@@ -1033,11 +1108,14 @@ EXPORT void ResolveIndex( void )
track_p trk;
EPINX_T ep;
TRK_ITERATE(trk) {
+ LOG (log_track, 1, ( "ResNextTrack( T%d, t%d, E%d, X%ld)\n", trk->index, trk->type, trk->endCnt, trk->extraSize ));
for (ep=0; ep<trk->endCnt; ep++)
if (trk->endPt[ep].index >= 0) {
trk->endPt[ep].track = FindTrack( trk->endPt[ep].index );
if (trk->endPt[ep].track == NULL) {
- NoticeMessage( MSG_RESOLV_INDEX_BAD_TRK, _("Continue"), NULL, trk->index, ep, trk->endPt[ep].index );
+ int rc = NoticeMessage( MSG_RESOLV_INDEX_BAD_TRK, _("Continue"), _("Quit"), trk->index, ep, trk->endPt[ep].index );
+ if ( rc != 1 )
+ return;
}
}
ResolveBlockTrack (trk);
@@ -1063,29 +1141,21 @@ LOG( log_track, 4, ( "DeleteTrack(T%d)\n", GetTrkIndex(trk) ) )
}
}
}
- UndrawNewTrack( trk );
for (i=0;i<trk->endCnt;i++) {
if ((trk2=trk->endPt[i].track) != NULL) {
ep2 = GetEndPtConnectedToMe( trk2, trk );
- /*UndrawNewTrack( trk2 );*/
- DrawEndPt( &mainD, trk2, ep2, wDrawColorWhite );
DisconnectTracks( trk2, ep2, trk, i );
- /*DrawNewTrack( trk2 );*/
- if (!QueryTrack(trk2,Q_DONT_DRAW_ENDPOINT))
- DrawEndPt( &mainD, trk2, ep2, wDrawColorBlack );
if ( QueryTrack(trk,Q_CANNOT_BE_ON_END) )
UndoJoint( trk2, ep2, trk, i );
- ClrTrkElev( trk2 );
}
}
- CheckDeleteSwitchmotor( trk );
- CheckDeleteBlock( trk );
+ CheckDeleteSwitchmotor( trk );
+ CheckDeleteBlock( trk );
+ CheckCarTraverse( trk );
DecrementLayerObjects(trk->layer);
trackCount--;
AuditTracks( "deleteTrack T%d", trk->index);
UndoDelete(trk); /**< Attention: trk is invalidated during that call */
- MainRedraw();
- MapRedraw();
InfoCount( trackCount );
return TRUE;
}
@@ -1130,6 +1200,98 @@ BOOL_T TrackIterate( track_p * trk )
*trk = trk1;
return trk1 != NULL;
}
+
+
+wBool_t IsPosClose( coOrd pos1, coOrd pos2 ) {
+ DIST_T d = FindDistance( pos1, pos2 );
+ return d < 0.1;
+}
+
+
+wBool_t IsAngleClose( ANGLE_T angle1, ANGLE_T angle2 )
+{
+ ANGLE_T angle = NormalizeAngle( angle1 - angle2 );
+ if (angle > 180)
+ angle = 360-angle;
+ return angle < 0.01;
+}
+
+
+wBool_t IsDistClose( DIST_T dist1, DIST_T dist2 )
+{
+ DIST_T dist = fabs( dist1 - dist2 );
+ return dist < 0.01;
+}
+
+wBool_t IsWidthClose( DIST_T dist1, DIST_T dist2 )
+{
+ // width is computed by pixels/dpi
+ // problem is when widths are computed on platforms with differing dpi
+ DIST_T dist = fabs( dist1 - dist2 );
+ if ( dist < 0.01 )
+ return TRUE;
+#ifdef WINDOWS
+ dist1 *= 96.0/72.0;
+#else
+ dist1 *= 72.0/96.0;
+#endif
+ dist = fabs( dist1 - dist2 );
+ if ( dist < 0.01 )
+ return TRUE;
+ return FALSE;
+}
+
+wBool_t IsColorClose( wDrawColor color1, wDrawColor color2 )
+{
+ long rgb1 = wDrawGetRGB( color1 );
+ long rgb2 = wDrawGetRGB( color2 );
+ int r1 = (rgb1 >> 16) & 0xff;
+ int g1 = (rgb1 >> 8) & 0xff;
+ int b1 = rgb1 & 0xff;
+ int r2 = (rgb2 >> 16) & 0xff;
+ int g2 = (rgb2 >> 8) & 0xff;
+ int b2 = rgb2 & 0xff;
+ long diff = abs(r1-r2) + abs(g1-g2) + abs(b1-b2);
+ return (diff < 7);
+}
+
+wBool_t CompareTrack( track_cp trk1, track_cp trk2 )
+{
+ wBool_t rc = FALSE;
+ if ( trk1 == NULL ) {
+ sprintf( message, "Compare: T%d not found\n", trk2->index );
+ return FALSE;
+ }
+ sprintf( message, "Compare T:%d - ", GetTrkIndex(trk1) );
+ char * cp = message+strlen(message);
+ REGRESS_CHECK_INT( "Type", trk1, trk2, type )
+ REGRESS_CHECK_INT( "Index", trk1, trk2, index )
+ REGRESS_CHECK_INT( "Layer", trk1, trk2, layer )
+ REGRESS_CHECK_INT( "Scale", trk1, trk2, scale )
+ REGRESS_CHECK_INT( "EndPtCnt", trk1, trk2, endCnt )
+ char * cq = cp-2;
+ for ( int inx=0; inx<GetTrkEndPtCnt( trk1 ); inx++ ) {
+ cp = cq;
+ sprintf( cp, "EP:%d - ", inx );
+ cp += strlen(cp);
+ REGRESS_CHECK_POS( "Pos", trk1, trk2, endPt[inx].pos )
+ REGRESS_CHECK_ANGLE( "Angle", trk1, trk2, endPt[inx].angle )
+ int inx1 = trk1->endPt[inx].index;
+ track_cp trk1x = GetTrkEndTrk( trk1, inx );
+ if ( trk1x )
+ inx1 = GetTrkIndex( trk1x );
+ int inx2 = trk2->endPt[inx].index;
+ if ( inx1 != inx2 ) {
+ sprintf( cp, "Index: Actual` %d, Expected %d\n", inx1, inx2 );
+ return FALSE;
+ }
+ REGRESS_CHECK_INT( "Option", trk1, trk2, endPt[inx].option )
+ }
+ if ( trackCmds( GetTrkType( trk1 ) )->compare == NULL )
+ return TRUE;
+ return trackCmds( GetTrkType( trk1 ) )->compare( trk1, trk2 );
+}
+
/*****************************************************************************
*
@@ -1221,9 +1383,9 @@ EXPORT void InitCmdAboveBelow( void )
{
wIcon_p bm_p;
bm_p = wIconCreatePixMap( above_xpm );
- AddToolbarButton( "cmdAbove", bm_p, IC_SELECTED, (addButtonCallBack_t)SelectAbove, NULL );
+ AddToolbarButton( "cmdAbove", bm_p, IC_SELECTED|IC_POPUP, (addButtonCallBack_t)SelectAbove, NULL );
bm_p = wIconCreatePixMap( below_xpm );
- AddToolbarButton( "cmdBelow", bm_p, IC_SELECTED, (addButtonCallBack_t)SelectBelow, NULL );
+ AddToolbarButton( "cmdBelow", bm_p, IC_SELECTED|IC_POPUP, (addButtonCallBack_t)SelectBelow, NULL );
}
/*****************************************************************************
@@ -1244,6 +1406,15 @@ EXPORT BOOL_T ReadTrack( char * line )
{
TRKINX_T inx, lo, hi;
int cmp;
+ if (strncmp( paramLine, "TABLEEDGE ", 10 ) == 0) {
+ ReadTableEdge( paramLine+10 );
+ return TRUE;
+ }
+ if (strncmp( paramLine, "TEXT ", 5 ) == 0) {
+ ReadText( paramLine+5 );
+ return TRUE;
+ }
+
if (bsearchRead) {
if (sortedCmds == NULL) {
sortedCmds = (trackCmd_t**)MyMalloc( (trackCmds_da.cnt-1) * sizeof *(trackCmd_t*)0 );
@@ -1258,8 +1429,7 @@ if (bsearchRead) {
inx = (lo+hi)/2;
cmp = strncmp( line, sortedCmds[inx]->name, strlen(sortedCmds[inx]->name) );
if (cmp == 0) {
- sortedCmds[inx]->read(line);
- return TRUE;
+ return sortedCmds[inx]->read(line);
} else if (cmp < 0) {
hi = inx-1;
} else {
@@ -1269,28 +1439,33 @@ if (bsearchRead) {
} else {
for (inx=1; inx<trackCmds_da.cnt; inx++) {
if (strncmp( line, trackCmds(inx)->name, strlen(trackCmds(inx)->name) ) == 0 ) {
- trackCmds(inx)->read( line );
- return TRUE;
+ trackCmds(inx)->read( line );
+ // Return TRUE means we found the object type and processed it
+ // Any errors will be handled by the callee's:
+ // Either skip the definition (ReadSegs) or skip the remainder of the file (InputError)
+ return TRUE;
}
}
}
- if (strncmp( paramLine, "TABLEEDGE ", 10 ) == 0)
- return ReadTableEdge( paramLine+10 );
- if (strncmp( paramLine, "TEXT ", 5 ) == 0)
- return ReadText( paramLine+5 );
+ // Object type not found
return FALSE;
}
-EXPORT BOOL_T WriteTracks( FILE * f )
+EXPORT BOOL_T WriteTracks( FILE * f, wBool_t bFull )
{
track_p trk;
BOOL_T rc = TRUE;
- RenumberTracks();
+ if ( bFull )
+ RenumberTracks();
+ if ( !bFull )
+ bWriteEndPtDirectIndex = TRUE;
TRK_ITERATE( trk ) {
rc &= trackCmds(GetTrkType(trk))->write( trk, f );
}
- rc &= WriteCars( f );
+ bWriteEndPtDirectIndex = FALSE;
+ if ( bFull )
+ rc &= WriteCars( f );
return rc;
}
@@ -1302,7 +1477,9 @@ EXPORT void ImportStart( void )
}
-EXPORT void ImportEnd( void )
+
+
+EXPORT void ImportEnd( coOrd offset, wBool_t import, wBool_t inPlace )
{
track_p to_firstOld;
wIndex_t trackCountOld;
@@ -1310,51 +1487,98 @@ EXPORT void ImportEnd( void )
coOrd pos;
wPos_t x, y;
wPos_t ww, hh;
+ wBool_t offscreen = FALSE;
+
+ double xmin = 0.0;
+ double xmax = 0.0;
+ double ymin = 0.0;
double ymax = 0.0;
// get the current mouse position
GetMousePosition( &x, &y );
mainD.Pix2CoOrd( &mainD, x, y, &pos );
+
// get the size of the drawing area
wDrawGetSize( mainD.d, &ww, &hh );
- // in case the pointer is close to the edge or above the drawing area
- // recalculate the destination position so the pasted part remains visible
- if( abs( y - hh ) < CLOSETOTHEEDGE ) {
- for ( trk=*importTrack; trk; trk=trk->next ) {
- if (!IsTrackDeleted(trk) && trk->hi.y > ymax ) {
- ymax = trk->hi.y;
- }
+ coOrd middle_screen;
+ wPos_t mx,my;
+
+ mx = ww/2;
+ my = hh/2;
+
+ mainD.Pix2CoOrd( &mainD, mx, my, &middle_screen );
+
+
+ for ( trk=*importTrack; trk; trk=trk->next ) {
+ if (!IsTrackDeleted(trk)) {
+ if (trk->hi.y > ymax ) ymax = trk->hi.y;
+ if (trk->lo.y < ymin ) ymin = trk->lo.y;
+ if (trk->hi.x > xmax ) xmax = trk->hi.x;
+ if (trk->lo.x < xmin ) xmin = trk->lo.x;
}
- pos.y -= ymax;
}
-
+
+ coOrd size = {xmax-xmin,ymax-ymin};
+
+
+
+ if (import) {
+ offset = zero;
+ } else if (!inPlace) {
+ //If cursor is off drawing area - cursor is in middle screen
+ if ((x<LBORDER) || (x>(ww-RBORDER)) || (y<BBORDER) || (y>(hh-TBORDER))) {
+ pos.x = middle_screen.x;
+ pos.y = middle_screen.y;
+ }
+ offset.x += pos.x;
+ offset.y += pos.y;
+ }
+
+ coOrd middle_object;
+
+ middle_object.x = offset.x + (size.x/2);
+ middle_object.y = offset.y + (size.y/2);
+
+ wPos_t ox,oy;
+ mainD.CoOrd2Pix( &mainD, middle_object, &ox, &oy );
+
+ if ((ox<0) || (ox>ww) || (oy<0) || (oy>hh) ) offscreen = TRUE;
+
to_firstOld = to_first;
to_first = *importTrack;
trackCountOld = trackCount;
ResolveIndex();
to_first = to_firstOld;
RenumberTracks();
- DrawMapBoundingBox( FALSE );
// move the imported track into place
for ( trk=*importTrack; trk; trk=trk->next ) if (!IsTrackDeleted(trk)) {
- MoveTrack( trk, pos );// mainD.orig );
+ coOrd move;
+ move.x = offset.x;
+ move.y = offset.y;
+ MoveTrack( trk, move );// mainD.orig );
trk->bits |= TB_SELECTED;
DrawTrack( trk, &mainD, wDrawColorBlack );
}
- DrawMapBoundingBox( TRUE );
importTrack = NULL;
trackCount = trackCountOld;
InfoCount( trackCount );
+ // Pan screen if needed to center of new
+ if (offscreen) {
+ panCenter = middle_object;
+ PanHere((void*)0);
+ }
}
-
-EXPORT BOOL_T ExportTracks( FILE * f )
+/*******
+ * Move Selected Tracks to origin zero and write out
+ *******/
+EXPORT BOOL_T ExportTracks( FILE * f, coOrd * offset)
{
track_p trk;
- coOrd xlat, orig;
+ coOrd xlat,orig;
exportingTracks = TRUE;
orig = mapD.size;
@@ -1368,8 +1592,9 @@ EXPORT BOOL_T ExportTracks( FILE * f )
trk->index = ++max_index;
}
}
- orig.x -= trackGauge;
- orig.y -= trackGauge;
+
+ *offset = orig;
+
xlat.x = - orig.x;
xlat.y = - orig.y;
TRK_ITERATE( trk ) {
@@ -1527,13 +1752,13 @@ nextEndPt:;
if (auditStop)
if (NoticeMessage( MSG_AUDIT_WRITE_FILE, _("Yes"), _("No"))) {
fprintf( auditFile, "# before undo\n" );
- WriteTracks(auditFile);
+ WriteTracks(auditFile, TRUE);
Rdump( auditFile );
if (strcmp("undoUndo",event)==0) {
fprintf( auditFile, "# failure in undo\n" );
} else if (UndoUndo()) {
fprintf( auditFile, "# after undo\n" );
- WriteTracks(auditFile);
+ WriteTracks(auditFile, TRUE);
Rdump( auditFile );
} else {
fprintf( auditFile, "# undo stack is empty\n" );
@@ -1584,21 +1809,33 @@ EXPORT void ComputeBoundingBox( track_p trk )
EXPORT DIST_T EndPtDescriptionDistance(
coOrd pos,
track_p trk,
- EPINX_T ep )
+ EPINX_T ep,
+ coOrd *dpos,
+ BOOL_T show_hidden,
+ BOOL_T * hidden)
{
elev_t *e;
coOrd pos1;
track_p trk1;
+ *dpos = pos;
+ if (hidden) *hidden = FALSE;
e = &trk->endPt[ep].elev;
- if ((e->option&ELEV_MASK)==ELEV_NONE ||
- (e->option&ELEV_VISIBLE)==0 )
+ if ((e->option&ELEV_MASK)==ELEV_NONE)
+ return 100000;
+ if (((e->option&ELEV_VISIBLE)==0) && !show_hidden)
return 100000;
if ((trk1=GetTrkEndTrk(trk,ep)) && GetTrkIndex(trk1)<GetTrkIndex(trk))
return 100000;
+ if ((e->option&ELEV_VISIBLE)==0) { //Hidden - disregard offset
+ if (hidden) *hidden = TRUE;
+ return FindDistance( GetTrkEndPos(trk,ep), pos );
+ }
/*REORIGIN( pos1, e->doff, GetTrkEndPos(trk,ep), GetTrkEndAngle(trk,ep) );*/
pos1 = GetTrkEndPos(trk,ep);
pos1.x += e->doff.x;
pos1.y += e->doff.y;
+ *dpos = pos1;
+ if (hidden) *hidden = !(e->option&ELEV_VISIBLE);
return FindDistance( pos1, pos );
}
@@ -1610,22 +1847,21 @@ EXPORT STATUS_T EndPtDescriptionMove(
coOrd pos )
{
static coOrd p0, p1;
+ static BOOL_T editState = FALSE;
elev_t *e, *e1;
- wDrawColor color;
track_p trk1;
e = &trk->endPt[ep].elev;
switch (action) {
case C_DOWN:
p0 = GetTrkEndPos(trk,ep);
- /*REORIGIN( p0, e->doff, GetTrkEndPos(trk,ep), GetTrkEndAngle(trk,ep) );*/
-
+ p1 = pos;
+ e->option |= ELEV_VISIBLE; //Make sure we make visible
+ DrawEndElev( &mainD, trk, ep, wDrawColorWhite );
+ /*no break*/
case C_MOVE:
case C_UP:
- if (action != C_DOWN)
- DrawLine( &tempD, p0, p1, 0, wDrawColorBlack );
- color = GetTrkColor( trk, &mainD );
- DrawEndElev( &tempD, trk, ep, color );
+ editState = TRUE;
p1 = pos;
e->doff.x = (pos.x-p0.x);
e->doff.y = (pos.y-p0.y);
@@ -1633,15 +1869,18 @@ EXPORT STATUS_T EndPtDescriptionMove(
e1 = &trk1->endPt[GetEndPtConnectedToMe(trk1,trk)].elev;
e1->doff = e->doff;
}
- DrawEndElev( &tempD, trk, ep, color );
- if (action != C_UP)
- DrawLine( &tempD, p0, p1, 0, wDrawColorBlack );
- MainRedraw();
- MapRedraw();
+ if ( action == C_UP ) {
+ editState = FALSE;
+ wDrawColor color = GetTrkColor( trk, &mainD );
+ DrawEndElev( &mainD, trk, ep, color );
+ }
return action==C_UP?C_TERMINATE:C_CONTINUE;
case C_REDRAW:
- DrawLine( &tempD, p0, p1, 0, wDrawColorBlack );
+ DrawEndElev( &tempD, trk, ep, wDrawColorBlue );
+ if ( editState ) {
+ DrawLine( &tempD, p0, p1, 0, wDrawColorBlue );
+ }
break;
}
return C_CONTINUE;
@@ -1692,12 +1931,12 @@ EXPORT void LoosenTracks( void )
}
}
if (count)
- MainRedraw();
+ MainRedraw(); // LoosenTracks
else
InfoMessage(_("No tracks loosened"));
}
-EXPORT void ConnectTracks( track_p trk0, EPINX_T inx0, track_p trk1, EPINX_T inx1 )
+EXPORT int ConnectTracks( track_p trk0, EPINX_T inx0, track_p trk1, EPINX_T inx1 )
{
DIST_T d;
ANGLE_T a;
@@ -1705,31 +1944,23 @@ EXPORT void ConnectTracks( track_p trk0, EPINX_T inx0, track_p trk1, EPINX_T inx
if ( !IsTrack(trk0) ) {
NoticeMessage( _("Connecting a non-track(%d) to (%d)"), _("Continue"), NULL, GetTrkIndex(trk0), GetTrkIndex(trk1) );
- return;
+ return -1;
}
if ( !IsTrack(trk1) ) {
NoticeMessage( _("Connecting a non-track(%d) to (%d)"), _("Continue"), NULL, GetTrkIndex(trk1), GetTrkIndex(trk0) );
- return;
+ return -1;
}
pos0 = trk0->endPt[inx0].pos;
pos1 = trk1->endPt[inx1].pos;
LOG( log_track, 3, ( "ConnectTracks( T%d[%d] @ [%0.3f, %0.3f] = T%d[%d] @ [%0.3f %0.3f]\n", trk0->index, inx0, pos0.x, pos0.y, trk1->index, inx1, pos1.x, pos1.y ) )
d = FindDistance( pos0, pos1 );
- a = NormalizeAngle( trk0->endPt[inx0].angle -
- trk1->endPt[inx1].angle + 180.0 );
- if (d > connectDistance || (a > connectAngle && a < 360.0 - connectAngle) || (log_endPt>0 && logTable(log_endPt).level>=1)) {
-#ifndef WINDOWS
- LogPrintf( "connectTracks: T%d[%d] T%d[%d] d=%0.3f a=%0.3f\n %d ",
- trk0->index, inx0, trk1->index, inx1, d, a, trk0->index );
- /*PrintEndPt( logFile, trk0, 0 );
- PrintEndPt( logFile, trk0, 1 );???*/
- LogPrintf( "\n %d ", trk1->index );
- /*PrintEndPt( logFile, trk1, 0 );
- PrintEndPt( logFile, trk1, 1 );???*/
- LogPrintf("\n");
-#endif
- if (d > connectDistance || (a > connectAngle && a < 360.0 - connectAngle))
- NoticeMessage( MSG_CONNECT_TRK, _("Continue"), NULL, trk0->index, inx0, trk1->index, inx1, d, a );
+ a = fabs(DifferenceBetweenAngles( trk0->endPt[inx0].angle,
+ trk1->endPt[inx1].angle + 180.0 ));
+ if (d > connectDistance || (a > connectAngle ) ) {
+ LOG( log_endPt, 1, ( "connectTracks: T%d[%d] T%d[%d] d=%0.3f a=%0.3f\n",
+ trk0->index, inx0, trk1->index, inx1, d, a ) );
+ NoticeMessage( MSG_CONNECT_TRK, _("Continue"), NULL, trk0->index, inx0, trk1->index, inx1, d, a );
+ return -1; /* Stop connecting out of alignment tracks! */
}
UndoModify( trk0 );
UndoModify( trk1 );
@@ -1738,6 +1969,7 @@ LOG( log_track, 3, ( "ConnectTracks( T%d[%d] @ [%0.3f, %0.3f] = T%d[%d] @ [%0.3f
trk0->endPt[inx0].track = trk1;
trk1->endPt[inx1].track = trk0;
AuditTracks( "connectTracks T%d[%d], T%d[%d]", trk0->index, inx0, trk1->index, inx1 );
+ return 0;
}
@@ -1834,7 +2066,6 @@ LOG( log_track, 2, ( "SplitTrack( T%d[%d], (%0.3f %0.3f)\n", trk->index, ep, pos
} else {
LOG( log_track, 2, ( " at endPt (no connection)\n") )
}
- *leftover = trk2;
DrawNewTrack( trk );
@@ -1855,7 +2086,6 @@ LOG( log_track, 2, ( "SplitTrack( T%d[%d], (%0.3f %0.3f)\n", trk->index, ep, pos
LOG( log_track, 2, ( " at endPt (no connection)\n") )
}
DrawNewTrack( trk );
-
} else {
/* TODO circle's don't have ep's */
trk2 = GetTrkEndTrk( trk, ep );
@@ -1878,13 +2108,13 @@ LOG( log_track, 2, ( "SplitTrack( T%d[%d], (%0.3f %0.3f)\n", trk->index, ep, pos
trkl = *leftover;
ep0 = epl;
if ( !disconnect )
- ConnectTracks( trk, ep, trkl, ep0 );
- ep0 = 1-ep0;
+ ConnectTracks( trk, ep, trkl, epl );
+ ep0 = 1-epl;
while ( 1 ) {
CopyAttributes( trk, trkl );
ClrTrkElev( trkl );
trk0 = GetTrkEndTrk(trkl,ep0);
- if ( trk0 == NULL )
+ if ( trk0 == NULL || trk0->type == T_TURNOUT )
break;
ep0 = 1-GetEndPtConnectedToMe(trk0,trkl);
trkl = trk0;
@@ -1901,7 +2131,7 @@ LOG( log_track, 2, ( "SplitTrack( T%d[%d], (%0.3f %0.3f)\n", trk->index, ep, pos
while ( 1 ) {
DrawNewTrack( trkl );
trk0 = GetTrkEndTrk(trkl,ep0);
- if ( trk0 == NULL || trk0 == trk2 )
+ if ( trk0 == NULL || trk0 == trk2 || trk0->type == T_TURNOUT)
break;
ep0 = 1-GetEndPtConnectedToMe(trk0,trkl);
trkl = trk0;
@@ -1970,14 +2200,14 @@ EXPORT BOOL_T RemoveTrack( track_p * trk, EPINX_T * ep, DIST_T *dist )
}
dist1 = *dist;
*dist = 0.0;
- return TrimTrack( *trk, *ep, dist1 );
+ return TrimTrack( *trk, *ep, dist1, zero, 0.0, 0.0, zero );
}
-EXPORT BOOL_T TrimTrack( track_p trk, EPINX_T ep, DIST_T dist )
+EXPORT BOOL_T TrimTrack( track_p trk, EPINX_T ep, DIST_T dist, coOrd pos, ANGLE_T angle, DIST_T radius, coOrd center )
{
if (trackCmds(trk->type)->trim)
- return trackCmds(trk->type)->trim( trk, ep, dist );
+ return trackCmds(trk->type)->trim( trk, ep, dist, pos, angle, radius, center );
else
return FALSE;
}
@@ -1992,6 +2222,130 @@ EXPORT BOOL_T MergeTracks( track_p trk0, EPINX_T ep0, track_p trk1, EPINX_T ep1
return FALSE;
}
+EXPORT STATUS_T ExtendTrackFromOrig( track_p trk, wAction_t action, coOrd pos )
+{
+ static EPINX_T ep;
+ static coOrd end_pos;
+ static BOOL_T valid;
+ DIST_T d;
+ track_p trk1;
+ trackParams_t params;
+ static wBool_t curved;
+ static ANGLE_T end_angle;
+
+ switch ( action ) {
+ case C_DOWN:
+ ep = PickUnconnectedEndPoint( pos, trk );
+ if ( ep == -1 )
+ return C_ERROR;
+ pos = GetTrkEndPos(trk,ep);
+ if (!GetTrackParams(PARAMS_CORNU,trk,pos,&params)) return C_ERROR;
+ end_pos = pos;
+ if (params.type == curveTypeCurve) {
+ curved = TRUE;
+ tempSegs(0).type = SEG_CRVTRK;
+ tempSegs(0).width = 0;
+ tempSegs(0).u.c.radius = params.arcR;
+ tempSegs(0).u.c.center = params.arcP;
+ tempSegs(0).u.c.a0 = FindAngle(params.arcP,GetTrkEndPos(trk,ep));
+ tempSegs(0).u.c.a1 = 0;
+ } else {
+ curved = FALSE;
+ tempSegs(0).type = SEG_STRTRK;
+ tempSegs(0).width = 0;
+ tempSegs(0).u.l.pos[0] = tempSegs(0).u.l.pos[1] = GetTrkEndPos( trk, ep );
+ }
+ valid = FALSE;
+ InfoMessage( _("Drag to change track length") );
+ return C_CONTINUE;
+ /*no break*/
+ case C_MOVE:
+ if (curved) {
+ //Normalize pos
+ PointOnCircle( &pos, tempSegs(0).u.c.center, tempSegs(0).u.c.radius, FindAngle(tempSegs(0).u.c.center,pos) );
+ ANGLE_T a = FindAngle(tempSegs(0).u.c.center,pos)-FindAngle(tempSegs(0).u.c.center,end_pos);
+ d = fabs(a)*2*M_PI/360*tempSegs(0).u.c.radius;
+ if ( d <= minLength ) {
+ if (action == C_MOVE)
+ ErrorMessage( MSG_TRK_TOO_SHORT, _("Connecting "), PutDim(fabs(minLength-d)) );
+ valid = FALSE;
+ return C_CONTINUE;
+ }
+ //Restrict to outside track
+ ANGLE_T diff = NormalizeAngle(GetTrkEndAngle(trk, ep)-FindAngle(end_pos,pos));
+ if (diff>90.0 && diff<270.0) {
+ valid = FALSE;
+ tempSegs(0).u.c.a1 = 0;
+ tempSegs(0).u.c.a0 = end_angle;
+ InfoMessage( _("Inside turnout track"));
+ return C_CONTINUE;
+ }
+ end_angle = GetTrkEndAngle( trk, ep );
+ a = FindAngle(tempSegs(0).u.c.center, pos );
+ PointOnCircle( &pos, tempSegs(0).u.c.center, tempSegs(0).u.c.radius, a );
+ ANGLE_T a2 = FindAngle(tempSegs(0).u.c.center,end_pos);
+ if ((end_angle > 180 && (a2>90 && a2 <270)) ||
+ (end_angle < 180 && (a2<90 || a2 >270))) {
+ tempSegs(0).u.c.a0 = a2;
+ tempSegs(0).u.c.a1 = NormalizeAngle(a-a2);
+ } else {
+ tempSegs(0).u.c.a0 = a;
+ tempSegs(0).u.c.a1 = NormalizeAngle(a2-a);
+ }
+ tempSegs_da.cnt = 1;
+ valid = TRUE;
+ if (action == C_MOVE)
+ InfoMessage( _("Curve: Length=%s Radius=%0.3f Arc=%0.3f"),
+ FormatDistance( d ), FormatDistance(tempSegs(0).u.c.radius), PutAngle( fabs(a) ) );
+ return C_CONTINUE;
+ } else {
+ d = FindDistance( end_pos, pos );
+ valid = TRUE;
+ if ( d <= minLength ) {
+ if (action == C_MOVE)
+ ErrorMessage( MSG_TRK_TOO_SHORT, _("Connecting "), PutDim(fabs(minLength-d)) );
+ valid = FALSE;
+ return C_CONTINUE;
+ }
+ ANGLE_T diff = NormalizeAngle(GetTrkEndAngle( trk, ep )-FindAngle(end_pos, pos));
+ if (diff>=90.0 && diff<=270.0) {
+ valid = FALSE;
+ tempSegs(0).u.c.a1 = 0;
+ tempSegs(0).u.c.a0 = end_angle;
+ InfoMessage( _("Inside turnout track"));
+ return C_CONTINUE;
+ }
+ Translate( &tempSegs(0).u.l.pos[1], tempSegs(0).u.l.pos[0], GetTrkEndAngle( trk, ep ), d );
+ tempSegs_da.cnt = 1;
+ if (action == C_MOVE)
+ InfoMessage( _("Straight: Length=%s Angle=%0.3f"),
+ FormatDistance( d ), PutAngle( GetTrkEndAngle( trk, ep ) ) );
+ }
+ return C_CONTINUE;
+
+ case C_UP:
+ if (!valid)
+ return C_TERMINATE;
+ UndrawNewTrack( trk );
+ EPINX_T jp;
+ if (curved) {
+ trk1 = NewCurvedTrack(tempSegs(0).u.c.center, tempSegs(0).u.c.radius, tempSegs(0).u.c.a0, tempSegs(0).u.c.a1, 0);
+ jp = PickUnconnectedEndPoint(end_pos,trk1);
+ } else {
+ trk1 = NewStraightTrack( tempSegs(0).u.l.pos[0], tempSegs(0).u.l.pos[1] );
+ jp = 0;
+ }
+ CopyAttributes( trk, trk1 );
+ ConnectTracks( trk, ep, trk1, jp );
+ DrawNewTrack( trk );
+ DrawNewTrack( trk1 );
+ return C_TERMINATE;
+
+ default:
+ ;
+ }
+ return C_ERROR;
+}
EXPORT STATUS_T ExtendStraightFromOrig( track_p trk, wAction_t action, coOrd pos )
{
@@ -2106,6 +2460,9 @@ EXPORT char * GetTrkTypeName( track_p trk )
return trackCmds(trk->type)->name;
}
+/*
+ * Note Misnomer - this function also gets the normal length - enumerate deals with flextrack length
+ */
EXPORT DIST_T GetFlexLength( track_p trk0, EPINX_T ep, coOrd * pos )
{
@@ -2153,9 +2510,33 @@ EXPORT DIST_T GetTrkLength( track_p trk, EPINX_T ep0, EPINX_T ep1 )
} else {
pos0 = GetTrkEndPos(trk,ep0);
if (ep1==-1) {
+ // Usual case for asking about distance to center of turnout for grades
+ if (trk->type==T_TURNOUT) {
+ trackParams_t trackParamsData;
+ trackParamsData.ep = ep0;
+ if (trackCmds(trk->type)->getTrackParams != NULL) {
+ //Find distance to centroid of end points * 2 or actual length if epCnt < 3
+ trackCmds(trk->type)->getTrackParams(PARAMS_TURNOUT,trk,pos0,&trackParamsData);
+ return trackParamsData.len/2.0;
+ }
+ }
pos1.x = (trk->hi.x+trk->lo.x)/2.0;
pos1.y = (trk->hi.y+trk->lo.y)/2.0;
} else {
+ if (trk->type==T_TURNOUT) {
+ pos1 = GetTrkEndPos(trk,ep1);
+ trackParams_t trackParamsData;
+ trackParamsData.ep = ep0;
+ if (trackCmds(trk->type)->getTrackParams != NULL) {
+ //Find distance via centroid of end points or actual length if epCnt < 3
+ trackCmds(trk->type)->getTrackParams(PARAMS_TURNOUT,trk,pos0,&trackParamsData);
+ d = trackParamsData.len/2.0;
+ trackParamsData.ep = ep1;
+ trackCmds(trk->type)->getTrackParams(PARAMS_TURNOUT,trk,pos1,&trackParamsData);
+ d += trackParamsData.len/2.0;
+ return d;
+ }
+ }
pos1 = GetTrkEndPos(trk,ep1);
}
pos1.x -= pos0.x;
@@ -2169,6 +2550,8 @@ EXPORT DIST_T GetTrkLength( track_p trk, EPINX_T ep0, EPINX_T ep1 )
#define DRAW_TUNNEL_DASH (1)
#define DRAW_TUNNEL_SOLID (2)
EXPORT long drawTunnel = DRAW_TUNNEL_DASH;
+EXPORT long colorTrack;
+EXPORT long colorDraw;
/******************************************************************************
*
@@ -2179,6 +2562,24 @@ EXPORT long drawTunnel = DRAW_TUNNEL_DASH;
EXPORT long tieDrawMode = TIEDRAWMODE_SOLID;
EXPORT wDrawColor tieColor;
+static wBool_t DoDrawTies( drawCmd_p d, track_cp trk )
+{
+ DIST_T scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale;
+ if ( !trk )
+ return FALSE;
+ if (GetTrkNoTies(trk))
+ return FALSE; //No Ties for this Track
+ if ( tieDrawMode == TIEDRAWMODE_NONE )
+ return FALSE;
+ if ( d == &mapD )
+ return FALSE;
+ if ( d->scale >= scale2rail )
+ return FALSE;
+ if ( !(GetTrkVisible(trk) || drawTunnel==DRAW_TUNNEL_SOLID) )
+ return FALSE;
+ return TRUE;
+}
+
EXPORT void DrawTie(
drawCmd_p d,
coOrd pos,
@@ -2188,7 +2589,9 @@ EXPORT void DrawTie(
wDrawColor color,
BOOL_T solid )
{
- coOrd p[4], lo, hi;
+ coOrd lo, hi;
+ coOrd p[4];
+ int t[4];
length /= 2;
width /= 2;
@@ -2198,6 +2601,7 @@ EXPORT void DrawTie(
hi.x += length;
hi.y += length;
angle += 90;
+
Translate( &p[0], pos, angle, length );
Translate( &p[1], p[0], angle+90, width );
Translate( &p[0], p[0], angle-90, width );
@@ -2205,6 +2609,10 @@ EXPORT void DrawTie(
Translate( &p[3], p[2], angle-90, width );
Translate( &p[2], p[2], angle+90, width );
+ for (int i=0;i<4;i++) {
+ t[i] = 0;
+ }
+
if ( d == &mainD ) {
lo.x -= RBORDER/mainD.dpi*mainD.scale;
lo.y -= TBORDER/mainD.dpi*mainD.scale;
@@ -2214,19 +2622,16 @@ EXPORT void DrawTie(
return;
}
if ( solid ) {
- DrawFillPoly( d, 4, p, color );
+ DrawPoly( d, 4, p, t, color, 0, 1, 0 );
} else {
- DrawLine( d, p[0], p[1], 0, color );
- DrawLine( d, p[1], p[2], 0, color );
- DrawLine( d, p[2], p[3], 0, color );
- DrawLine( d, p[3], p[0], 0, color );
+ DrawPoly( d, 4, p, t, color, 0, 0, 0);
}
}
-EXPORT void DrawCurvedTies(
+static void DrawCurvedTies(
drawCmd_p d,
- track_p trk,
+ SCALEINX_T scaleInx,
coOrd p,
DIST_T r,
ANGLE_T a0,
@@ -2239,27 +2644,27 @@ EXPORT void DrawCurvedTies(
coOrd pos;
int cnt;
- if ( (d->funcs->options&wDrawOptTemp) != 0 )
+ if ( (d->options&DC_SIMPLE) != 0 )
return;
- if ( trk == NULL )
- return;
-
- td = GetScaleTieData(GetTrkScale(trk));
- if ( (!GetTrkVisible(trk)) && drawTunnel!=DRAW_TUNNEL_SOLID )
+ if ( scaleInx < 0 )
return;
+ td = GetScaleTieData( scaleInx );
+
if (color == wDrawColorBlack)
color = tieColor;
len = 2*M_PI*r*a1/360.0;
- cnt = (int)(len/td->spacing);
- if ( len-td->spacing*cnt-td->width > (td->spacing-td->width)/2 )
+ cnt = (int)floor(len/td->spacing+0.5);
+ if ( len-td->spacing*cnt-(td->width/2) > (td->spacing-td->width)/2 ) {
cnt++;
+ }
if ( cnt != 0 ) {
- dang = a1/cnt;
+ dang = (360.0*(len)/cnt)/(2*M_PI*r);
for ( ang=a0+dang/2; cnt; cnt--,ang+=dang ) {
PointOnCircle( &pos, p, r, ang );
DrawTie( d, pos, ang+90, td->length, td->width, color, tieDrawMode==TIEDRAWMODE_SOLID );
}
+
}
}
@@ -2273,11 +2678,11 @@ EXPORT void DrawCurvedTrack(
coOrd p0,
coOrd p1,
track_p trk,
- DIST_T trackGauge,
wDrawColor color,
long options )
{
DIST_T scale2rail;
+ DIST_T trackGauge = GetTrkGauge(trk);
wDrawWidth width=0;
trkSeg_p segPtr;
@@ -2295,9 +2700,10 @@ EXPORT void DrawCurvedTrack(
}
scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale;
- if (options&DTS_THICK2)
- width = 2;
- if (options&DTS_THICK3)
+ width = trk ? GetTrkWidth( trk ): 0;
+ if ( d->options&DC_THICK )
+ width = 3;
+ if ( color == wDrawColorPreviewSelected || color == wDrawColorPreviewUnselected )
width = 3;
#ifdef WINDOWS
width *= (wDrawWidth)(d->dpi/mainD.dpi);
@@ -2308,21 +2714,15 @@ EXPORT void DrawCurvedTrack(
LOG( log_track, 4, ( "DST( (%0.3f %0.3f) R%0.3f A%0.3f..%0.3f)\n",
p.x, p.y, r, a0, a1 ) )
- if ( (options&DTS_TIES) != 0 && trk &&
- tieDrawMode!=TIEDRAWMODE_NONE &&
- d!=&mapD &&
- (d->options&DC_TIES)!=0 &&
- d->scale<scale2rail/2 )
- DrawCurvedTies( d, trk, p, r, a0, a1, color );
+ if ( DoDrawTies( d, trk ) )
+ DrawCurvedTies( d, GetTrkScale(trk), p, r, a0, a1, color );
if (color == wDrawColorBlack)
color = normalColor;
if ( d->scale >= scale2rail ) {
DrawArc( d, p, r, a0, a1, ((d->scale<32) && centerDrawMode && !(options&DTS_NOCENTER)) ? 1 : 0, width, color );
- } else if (d->options & DC_QUICK) {
- DrawArc( d, p, r, a0, a1, ((d->scale<32) && centerDrawMode && !(options&DTS_NOCENTER)) ? 1 : 0, 0, color );
} else {
if ( (d->scale <= 1 && (d->options&DC_SIMPLE)==0) || (d->options&DC_CENTERLINE)!=0
- || (d->scale <= scale2rail/2 && d->options&DC_PRINT && printCenterLines)) { // if printing two rails respect print CenterLine option
+ || (d->scale <= scale2rail/2 && ((d->options&DC_PRINT) && printCenterLines))) { // if printing two rails respect print CenterLine option
long options = d->options;
d->options |= DC_DASH;
DrawArc( d, p, r, a0, a1, 0, 0, color );
@@ -2340,12 +2740,44 @@ LOG( log_track, 4, ( "DST( (%0.3f %0.3f) R%0.3f A%0.3f..%0.3f)\n",
}
}
}
+ if (trk && GetTrkBridge( trk ) ) {
+
+ ANGLE_T a2,a3;
+ coOrd pp0,pp1,pp2,pp3;
+
+ a2 = a0+R2D(trackGauge*1.0/r);
+ a3 = a1-R2D(trackGauge*2.0/r);
+
+ wDrawWidth width2 = (wDrawWidth)round((2.0 * d->dpi)/75.0);
+
+ DrawArc( d, p, r+(trackGauge*1.5), a2, a3, 0, width2, color );
+
+ PointOnCircle(&pp0,p,r+(trackGauge*1.5),a2);
+ PointOnCircle(&pp1,p,r+(trackGauge*1.5),a3+a2);
+
+ Translate( &pp2,pp0, a2-90+45, trackGauge);
+ DrawLine( d, pp0, pp2, width2, color );
+ Translate( &pp3,pp1, a2+a3+90-45, trackGauge);
+ DrawLine( d, pp1, pp3, width2, color );
+
+ DrawArc( d, p, r-(trackGauge*1.5), a2, a3, 0, width2, color );
+
+ PointOnCircle(&pp0,p,r-(trackGauge*1.5),a2);
+ PointOnCircle(&pp1,p,r-(trackGauge*1.5),a3+a2);
+
+ Translate( &pp2,pp0, a2-90-45, trackGauge);
+ DrawLine( d, pp0, pp2, width2, color );
+ Translate( &pp3,pp1, a2+a3+90+45, trackGauge);
+ DrawLine( d, pp1, pp3, width2, color );
+
+ }
+
}
-EXPORT void DrawStraightTies(
+static void DrawStraightTies(
drawCmd_p d,
- track_p trk,
+ SCALEINX_T scaleInx,
coOrd p0,
coOrd p1,
wDrawColor color )
@@ -2357,25 +2789,24 @@ EXPORT void DrawStraightTies(
int cnt;
ANGLE_T angle;
- if ( (d->funcs->options&wDrawOptTemp) != 0 )
- return;
- if ( trk == NULL )
+ if ( (d->options&DC_SIMPLE) != 0 )
return;
- td = GetScaleTieData(GetTrkScale(trk));
- if ( (!GetTrkVisible(trk)) && drawTunnel!=DRAW_TUNNEL_SOLID )
- return;
if ( color == wDrawColorBlack )
color = tieColor;
- td = GetScaleTieData( GetTrkScale(trk) );
+ if ( scaleInx < 0 )
+ return;
+ td = GetScaleTieData( scaleInx );
len = FindDistance( p0, p1 );
len -= tieOff0+tieOff1;
angle = FindAngle( p0, p1 );
- cnt = (int)(len/td->spacing);
- if ( len-td->spacing*cnt-td->width > (td->spacing-td->width)/2 )
+ cnt = (int)floor(len/td->spacing+0.5);
+ if ( len-td->spacing*cnt-td->width > (td->spacing-td->width)/2 ) {
cnt++;
+ }
if ( cnt != 0 ) {
- dlen = len/cnt;
+ dlen = FindDistance( p0, p1 )/cnt;
+ double endsize = FindDistance( p0, p1 )-cnt*dlen-td->width;
for ( len=dlen/2; cnt; cnt--,len+=dlen ) {
Translate( &pos, p0, angle, len );
DrawTie( d, pos, angle, td->length, td->width, color, tieDrawMode==TIEDRAWMODE_SOLID );
@@ -2389,13 +2820,13 @@ EXPORT void DrawStraightTrack(
coOrd p0,
coOrd p1,
ANGLE_T angle,
- track_p trk,
- DIST_T trackGauge,
+ track_cp trk,
wDrawColor color,
long options )
{
coOrd pp0, pp1;
DIST_T scale2rail;
+ DIST_T trackGauge = GetTrkGauge(trk);
wDrawWidth width=0;
trkSeg_p segPtr;
@@ -2414,9 +2845,10 @@ EXPORT void DrawStraightTrack(
scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale;
- if (options&DTS_THICK2)
- width = 2;
- if (options&DTS_THICK3)
+ width = trk ? GetTrkWidth( trk ): 0;
+ if ( d->options&DC_THICK )
+ width = 3;
+ if ( color == wDrawColorPreviewSelected || color == wDrawColorPreviewUnselected )
width = 3;
#ifdef WINDOWS
width *= (wDrawWidth)(d->dpi/mainD.dpi);
@@ -2426,21 +2858,15 @@ EXPORT void DrawStraightTrack(
#endif
LOG( log_track, 4, ( "DST( (%0.3f %0.3f) .. (%0.3f..%0.3f)\n",
p0.x, p0.y, p1.x, p1.y ) )
- if ( (options&DTS_TIES) != 0 && trk &&
- tieDrawMode!=TIEDRAWMODE_NONE &&
- d!=&mapD &&
- (d->options&DC_TIES)!=0 &&
- d->scale<scale2rail/2 )
- DrawStraightTies( d, trk, p0, p1, color );
+ if ( DoDrawTies( d, trk ) )
+ DrawStraightTies( d, GetTrkScale(trk), p0, p1, color );
if (color == wDrawColorBlack)
color = normalColor;
if ( d->scale >= scale2rail ) {
DrawLine( d, p0, p1, width, color );
- } else if (d->options&DC_QUICK) {
- DrawLine( d, p0, p1, 0, color );
} else {
if ( (d->scale <= 1 && (d->options&DC_SIMPLE)==0) || (d->options&DC_CENTERLINE)!=0
- || (d->scale <= scale2rail/2 && d->options&DC_PRINT && printCenterLines)) { // if printing two rails respect print CenterLine option
+ || (d->scale <= scale2rail/2 && ((d->options&DC_PRINT) && printCenterLines))) { // if printing two rails respect print CenterLine option
long options = d->options;
d->options |= DC_DASH;
DrawLine( d, p0, p1, 0, color );
@@ -2466,37 +2892,68 @@ LOG( log_track, 4, ( "DST( (%0.3f %0.3f) .. (%0.3f..%0.3f)\n",
}
}
}
+ if (trk && GetTrkBridge( trk ) ) {
+
+ coOrd pp2,pp3;
+ wDrawWidth width2 = (wDrawWidth)round((2.0 * d->dpi)/75.0);
+
+ Translate( &pp0, p0, angle+90, trackGauge*1.5 );
+ Translate( &pp1, p1, angle+90, trackGauge*1.5 );
+ Translate( &pp0, pp0, angle+180, trackGauge*1.5 );
+ Translate( &pp1, pp1, angle, trackGauge*1.5 );
+ DrawLine( d, pp0, pp1, width2, color );
+ Translate( &pp2,pp0, angle+90-45, trackGauge);
+ DrawLine( d, pp0, pp2, width2, color );
+ Translate( &pp3,pp1, angle+90+45, trackGauge);
+ DrawLine( d, pp1, pp3, width2, color );
+
+ Translate( &pp0, p0, angle-90, trackGauge*1.5 );
+ Translate( &pp1, p1, angle-90, trackGauge*1.5 );
+ Translate( &pp0, pp0, angle+180, trackGauge*1.5 );
+ Translate( &pp1, pp1, angle, trackGauge*1.5 );
+ DrawLine( d, pp0, pp1, width2, color );
+ Translate( &pp2,pp0, angle-90+45, trackGauge);
+ DrawLine( d, pp0, pp2, width2, color );
+ Translate( &pp3,pp1, angle-90-45, trackGauge);
+ DrawLine( d, pp1, pp3, width2, color );
+
+ }
}
EXPORT wDrawColor GetTrkColor( track_p trk, drawCmd_p d )
{
- DIST_T len, elev0, elev1;
+ DIST_T len, len1, elev0, elev1;
ANGLE_T grade = 0.0;
if ( IsTrack( trk ) && GetTrkEndPtCnt(trk) == 2 ) {
- len = GetTrkLength( trk, 0, 1 );
- if (len>0.1) {
- ComputeElev( trk, 0, FALSE, &elev0, NULL );
- ComputeElev( trk, 1, FALSE, &elev1, NULL );
- grade = fabs( (elev1-elev0)/len )*100.0;
+ if (GetTrkEndElevCachedHeight(trk,0,&elev0,&len) && GetTrkEndElevCachedHeight(trk,1,&elev1,&len1)) {
+ grade = fabs( (elev1-elev0)/(len+len1))*100.0;
+ } else {
+ len = GetTrkLength( trk, 0, 1 );
+ if (len>0.1) {
+ ComputeElev( trk, 0, FALSE, &elev0, NULL, FALSE );
+ ComputeElev( trk, 1, FALSE, &elev1, NULL, FALSE );
+ grade = fabs( (elev1-elev0)/len )*100.0;
+ }
}
}
- if ( (d->options&(DC_GROUP)) == 0 ) {
- if ( grade > GetLayoutMaxTrackGrade())
- return exceptionColor;
- if ( QueryTrack( trk, Q_EXCEPTION ) )
- return exceptionColor;
- }
- if ( (d->options&(DC_PRINT|DC_GROUP)) == 0 ) {
+ if ( (d->options&(DC_SIMPLE|DC_SEGTRACK)) != 0 )
+ return wDrawColorBlack;
+ if ( grade > GetLayoutMaxTrackGrade())
+ return exceptionColor;
+ if ( QueryTrack( trk, Q_EXCEPTION ) )
+ return exceptionColor;
+ if ( (d->options&(DC_PRINT)) == 0 ) {
if (GetTrkBits(trk)&TB_PROFILEPATH)
return profilePathColor;
if ((d->options&DC_PRINT)==0 && GetTrkSelected(trk))
return selectedColor;
}
- if ( (d->options&(DC_GROUP)) == 0 ) {
- if ( (IsTrack(trk)?(colorLayers&1):(colorLayers&2)) )
- return GetLayerColor((unsigned int)curTrackLayer);
+ if ( (IsTrack(trk)?(colorTrack):(colorDraw)) ) {
+ unsigned int iLayer = GetTrkLayer( trk );
+ if (GetLayerUseColor( iLayer ) )
+ return GetLayerColor( iLayer );
}
return wDrawColorBlack;
}
@@ -2504,9 +2961,11 @@ EXPORT wDrawColor GetTrkColor( track_p trk, drawCmd_p d )
EXPORT void DrawTrack( track_cp trk, drawCmd_p d, wDrawColor color )
{
- DIST_T scale2rail;
TRKTYP_T trkTyp;
+ // Hack for WINDOWS
+ if ( trk->bits & TB_UNDRAWN )
+ return;
trkTyp = GetTrkType(trk);
curTrackLayer = GetTrkLayer(trk);
if (d != &mapD ) {
@@ -2519,48 +2978,43 @@ EXPORT void DrawTrack( track_cp trk, drawCmd_p d, wDrawColor color )
if (color == wDrawColorBlack) {
color = GetTrkColor( trk, d );
}
+ if (color == wDrawColorPreviewSelected || color == wDrawColorPreviewUnselected ) {
+ d->options |= DC_THICK;
+ }
}
+
if (d == &mapD && !GetLayerOnMap(curTrackLayer))
return;
- if ( (IsTrack(trk)?(colorLayers&1):(colorLayers&2)) &&
+ if ( (IsTrack(trk)?(colorTrack):(colorDraw)) &&
d != &mapD && color == wDrawColorBlack )
- color = GetLayerColor((unsigned int)curTrackLayer);
- scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale;
- if ( (!inDrawTracks) &&
- tieDrawMode!=TIEDRAWMODE_NONE &&
- d != &mapD &&
- d->scale<scale2rail/2 &&
- QueryTrack(trk, Q_ISTRACK) &&
- (GetTrkVisible(trk) || drawTunnel==DRAW_TUNNEL_SOLID) ) {
- d->options |= DC_TIES;
- }
+ if (GetLayerUseColor((unsigned int)curTrackLayer))
+ color = GetLayerColor((unsigned int)curTrackLayer);
trackCmds(trkTyp)->draw( trk, d, color );
- if ( (!inDrawTracks) ) {
- d->options &= ~DC_TIES;
- }
d->options &= ~DC_DASH;
+ d->options &= ~DC_THICK;
+
DrawTrackElev( trk, d, color!=wDrawColorWhite );
}
static void DrawATrack( track_cp trk, wDrawColor color )
{
- DrawMapBoundingBox( FALSE );
DrawTrack( trk, &mapD, color );
DrawTrack( trk, &mainD, color );
- DrawMapBoundingBox( TRUE );
}
EXPORT void DrawNewTrack( track_cp t )
{
+ t->bits &= ~TB_UNDRAWN;
DrawATrack( t, wDrawColorBlack );
}
EXPORT void UndrawNewTrack( track_cp t )
{
DrawATrack( t, wDrawColorWhite );
+ t->bits |= TB_UNDRAWN;
}
EXPORT int doDrawPositionIndicator = 1;
@@ -2610,7 +3064,7 @@ static void DrawUnconnectedEndPt( drawCmd_p d, coOrd p, ANGLE_T a, DIST_T trackG
Translate( &p, p, a+90.0, 0.2 );
Translate( &p0, p, a, trackGauge );
Translate( &p1, p, a-180.0, trackGauge );
- DrawLine( d, p0, p1, (drawUnconnectedEndPt>0)?4:0, (drawUnconnectedEndPt>1)?exceptionColor:color );
+ DrawLine( d, p0, p1, (drawUnconnectedEndPt>0)?4:0, (color==wDrawColorWhite)?color:(drawUnconnectedEndPt>1)?exceptionColor:color );
}
}
@@ -2643,7 +3097,7 @@ EXPORT void DrawEndElev( drawCmd_p d, track_p trk, EPINX_T ep, wDrawColor color
case ELEV_GRADE:
if ( color == wDrawColorWhite ) {
elev0 = grade = elev->u.height;
- } else if ( !ComputeElev( trk, ep, FALSE, &elev0, &grade ) ) {
+ } else if ( !ComputeElev( trk, ep, FALSE, &elev0, &grade, FALSE ) ) {
elev0 = grade = 0;
gradeOk = FALSE;
}
@@ -2651,7 +3105,7 @@ EXPORT void DrawEndElev( drawCmd_p d, track_p trk, EPINX_T ep, wDrawColor color
elevStr = FormatDistance(elev0);
elev->u.height = elev0;
} else if (gradeOk) {
- sprintf( message, "%0.1f%%", fabs(grade*100.0) );
+ sprintf( message, "%0.1f%%", round(fabs(grade*100.0)*10)/10 );
elevStr = message;
a = GetTrkEndAngle( trk, ep );
style = BOX_ARROW;
@@ -2704,16 +3158,16 @@ EXPORT void DrawEndPt(
wDrawWidth width;
wDrawWidth width2;
- // line width for the tunnel portal, make sure it is rounded correctly
- width2 = (wDrawWidth)round((2.0 * d->dpi)/75.0);
- if (d->funcs->options&wDrawOptTemp)
+ if ( (d->options & (DC_SIMPLE|DC_SEGTRACK)) != 0)
return;
if ( trk && QueryTrack( trk, Q_NODRAWENDPT ) )
return;
-
if (trk == NULL || ep < 0)
return;
+ // line width for the tunnel portal, make sure it is rounded correctly
+ width2 = (wDrawWidth)round((2.0 * d->dpi)/75.0);
+
if (color == wDrawColorBlack)
color = normalColor;
@@ -2734,17 +3188,20 @@ EXPORT void DrawEndPt(
return;
sepBoundary = FALSE;
- if ((d->options&DC_PRINT)==0 && importTrack == NULL && GetTrkSelected(trk) && (!GetTrkSelected(trk1))) {
+ if ( inDrawTracks && (d->options&DC_PRINT)==0 && importTrack == NULL && GetTrkSelected(trk) && (!GetTrkSelected(trk1))) {
DIST_T len;
len = trackGauge*2.0;
if (len < 0.10*d->scale)
len = 0.10*d->scale;
+ long oldOptions = d->options;
+ d->options &= ~DC_NOTSOLIDLINE;
Translate( &p0, p, a+45, len );
Translate( &p1, p, a+225, len );
- DrawLine( &tempD, p0, p1, 0, selectedColor );
+ DrawLine( d, p0, p1, 2, selectedColor );
Translate( &p0, p, a-45, len );
Translate( &p1, p, a-225, len );
- DrawLine( &tempD, p0, p1, 0, selectedColor );
+ DrawLine( d, p0, p1, 2, selectedColor );
+ d->options = oldOptions;
sepBoundary = TRUE;
} else if ((d->options&DC_PRINT)==0 && importTrack == NULL && (!GetTrkSelected(trk)) && GetTrkSelected(trk1)) {
sepBoundary = TRUE;
@@ -2831,7 +3288,6 @@ EXPORT void DrawTracks( drawCmd_p d, DIST_T scale, coOrd orig, coOrd size )
inDrawTracks = TRUE;
InfoCount( 0 );
- d->options |= DC_TIES;
TRK_ITERATE( trk ) {
if ( (d->options&DC_PRINT) != 0 &&
wPrintQuit() ) {
@@ -2854,7 +3310,6 @@ EXPORT void DrawTracks( drawCmd_p d, DIST_T scale, coOrd orig, coOrd size )
if (count%10 == 0)
InfoCount( count );
}
- d->options &= ~DC_TIES;
if (d == &mainD) {
for (inx=1; inx<trackCmds_da.cnt; inx++)
@@ -2868,14 +3323,6 @@ EXPORT void DrawTracks( drawCmd_p d, DIST_T scale, coOrd orig, coOrd size )
}
-EXPORT void RedrawLayer( unsigned int l, BOOL_T draw )
-{
- MainRedraw();
- MapRedraw();
-
-}
-
-
EXPORT void DrawSelectedTracks( drawCmd_p d )
{
track_cp trk;
@@ -2899,8 +3346,6 @@ EXPORT void DrawSelectedTracks( drawCmd_p d )
EXPORT void HilightElevations( BOOL_T hilight )
{
- static long lastRedraw = -1;
- static BOOL_T lastHilight = FALSE;
track_p trk, trk1;
EPINX_T ep;
int mode;
@@ -2908,12 +3353,6 @@ EXPORT void HilightElevations( BOOL_T hilight )
coOrd pos;
DIST_T radius;
- if (currRedraw > lastRedraw) {
- lastRedraw = currRedraw;
- lastHilight = FALSE;
- }
- if (lastHilight == hilight)
- return;
radius = 0.05*mainD.scale;
if ( radius < trackGauge/2.0 )
radius = trackGauge/2.0;
@@ -2937,25 +3376,20 @@ EXPORT void HilightElevations( BOOL_T hilight )
}
}
}
- lastHilight = hilight;
}
EXPORT void HilightSelectedEndPt( BOOL_T show, track_p trk, EPINX_T ep )
{
- static BOOL_T lastShow = FALSE;
- static long lastRedraw = -1;
coOrd pos;
- if (trk == NULL)
- return;
- if (currRedraw > lastRedraw) {
- lastRedraw = currRedraw;
- lastShow = FALSE;
- }
- if (lastShow != show) {
+ if (!trk || (ep==-1)) return;
+ pos = GetTrkEndPos( trk, ep );
+ if ( show == TRUE ) {
pos = GetTrkEndPos( trk, ep );
DrawFillCircle( &tempD, pos, 0.10*mainD.scale, selectedColor );
- lastShow = show;
+ } else {
+ pos = GetTrkEndPos( trk, ep );
+ DrawFillCircle( &tempD, pos, 0.10*mainD.scale, wDrawColorWhite );
}
}
diff --git a/app/bin/track.h b/app/bin/track.h
index 7485730..4e24280 100644
--- a/app/bin/track.h
+++ b/app/bin/track.h
@@ -23,6 +23,7 @@
#ifndef TRACK_H
#define TRACK_H
+#include <string.h>
#include "common.h"
#include "draw.h"
#include "misc2.h"
@@ -34,6 +35,8 @@ typedef struct track_t * track_p;
typedef struct track_t * track_cp;
extern track_p tempTrack;
extern wIndex_t trackCount;
+extern long colorTrack;
+extern long colorDraw;
extern long drawTunnel;
extern long drawEndPtV;
extern long drawUnconnectedEndPt;
@@ -71,13 +74,16 @@ typedef enum { curveTypeNone, curveTypeCurve, curveTypeStraight, curveTypeBezier
#define PARAMS_1ST_JOIN (0)
#define PARAMS_2ND_JOIN (1)
#define PARAMS_EXTEND (2)
-#define PARAMS_PARALLEL (3)
+#define PARAMS_NODES (3)
#define PARAMS_BEZIER (4) //Not used (yet)
#define PARAMS_CORNU (5) //Called to get end characteristics
+#define PARAMS_TURNOUT (6)
+#define PARAMS_LINE (7) //Called on Lines
typedef struct {
curveType_e type; //Straight, Curve, Bezier, Cornu
EPINX_T ep; //End point that is nearby pos
+ dynArr_t nodes; //Array of nodes -> PARAMS_PARALLEL only
DIST_T len; //Length of track
ANGLE_T angle; //Angle at end of track
coOrd lineOrig; //Start of straight
@@ -95,6 +101,7 @@ typedef struct {
coOrd cornuCenter[2]; //Center at Cornu Ends
coOrd ttcenter; //Turntable
DIST_T ttradius; //Turntable
+ coOrd centroid; //Turnout
} trackParams_t;
@@ -102,7 +109,6 @@ typedef struct {
#define Q_IGNORE_EASEMENT_ON_EXTEND (2)
#define Q_REFRESH_JOIN_PARAMS_ON_MOVE (3)
#define Q_CANNOT_PLACE_TURNOUT (4)
-#define Q_DONT_DRAW_ENDPOINT (5)
#define Q_DRAWENDPTV_1 (6)
#define Q_CAN_PARALLEL (7)
#define Q_CAN_MODIFYRADIUS (8)
@@ -122,6 +128,14 @@ typedef struct {
#define Q_CAN_ADD_ENDPOINTS (22) // Is T_TURNTABLE
#define Q_HAS_VARIABLE_ENDPOINTS (23) // Is Helix or Circle
#define Q_CORNU_CAN_MODIFY (24) // can be modified by CORNU MODIFY
+#define Q_ISTRAIN (25)
+#define Q_IS_POLY (26)
+#define Q_IS_DRAW (27)
+#define Q_IS_TEXT (28)
+#define Q_IS_ACTIVATEABLE (29)
+#define Q_IS_STRUCTURE (30)
+#define Q_IS_TURNOUT (31)
+#define Q_GET_NODES (32)
typedef struct {
track_p trk; // IN Current Track OUT Next Track
@@ -139,7 +153,7 @@ typedef struct {
void (*describe)( track_p, char * line, CSIZE_T len );
void (*delete)( track_p );
BOOL_T (*write)( track_p, FILE * );
- void (*read)( char * );
+ BOOL_T (*read)( char * );
void (*move)( track_p, coOrd );
void (*rotate)( track_p, coOrd, ANGLE_T );
void (*rescale)( track_p, FLOAT_T );
@@ -149,7 +163,7 @@ typedef struct {
BOOL_T (*traverse)( traverseTrack_p, DIST_T * );
BOOL_T (*enumerate)( track_p );
void (*redraw)( void );
- BOOL_T (*trim)( track_p, EPINX_T, DIST_T );
+ BOOL_T (*trim)( track_p, EPINX_T, DIST_T, coOrd endpos, ANGLE_T angle, DIST_T endradius, coOrd endcenter );
BOOL_T (*merge)( track_p, EPINX_T, track_p, EPINX_T );
STATUS_T (*modify)( track_p, wAction_t, coOrd );
DIST_T (*getLength)( track_p );
@@ -161,11 +175,13 @@ typedef struct {
void (*drawPositionIndicator)( track_p, wDrawColor );
void (*advancePositionIndicator)( track_p, coOrd, coOrd *, ANGLE_T * );
BOOL_T (*checkTraverse)( track_p, coOrd );
- BOOL_T (*makeParallel)( track_p, coOrd, DIST_T, track_p *, coOrd *, coOrd * );
+ BOOL_T (*makeParallel)( track_p, coOrd, DIST_T, DIST_T, track_p *, coOrd *, coOrd *, BOOL_T );
void (*drawDesc)( track_p, drawCmd_p, wDrawColor );
BOOL_T (*rebuildSegs)(track_p);
BOOL_T (*replayData)(track_p, void *,long );
BOOL_T (*storeData)(track_p, void **,long *);
+ void (*activate)(track_p);
+ wBool_t (*compare)( track_cp, track_cp );
} trackCmd_t;
@@ -180,6 +196,9 @@ typedef struct {
DIST_T height;
char * name;
} u;
+ BOOL_T cacheSet;
+ double cachedElev;
+ double cachedLength;
} elev_t;
#define EPOPT_GAPPED (1L<<0)
typedef struct {
@@ -191,12 +210,13 @@ typedef struct {
long option;
} trkEndPt_t, * trkEndPt_p;
-dynArr_t tempEndPts_da;
+extern dynArr_t tempEndPts_da;
#define tempEndPts(N) DYNARR_N( trkEndPt_t, tempEndPts_da, N )
-typedef enum { FREEFORM, RECTANGLE
+typedef enum { FREEFORM, RECTANGLE, POLYLINE
} PolyType_e;
+
typedef struct {
char type;
wDrawColor color;
@@ -236,11 +256,12 @@ typedef struct {
ANGLE_T angle;
wFont_p fontP;
FONTSIZE_T fontSize;
+ BOOL_T boxed;
char * string;
} t;
struct {
int cnt;
- coOrd * pts;
+ pts_t * pts;
coOrd orig;
ANGLE_T angle;
PolyType_e polyType;
@@ -271,11 +292,12 @@ typedef struct {
#define IsSegTrack( S ) ( (S)->type == SEG_STRTRK || (S)->type == SEG_CRVTRK || (S)->type == SEG_JNTTRK || (S)->type == SEG_BEZTRK)
-dynArr_t tempSegs_da;
+extern dynArr_t tempSegs_da;
+
#define tempSegs(N) DYNARR_N( trkSeg_t, tempSegs_da, N )
-char tempSpecial[4096];
-char tempCustom[4096];
+extern char tempSpecial[4096];
+extern char tempCustom[4096];
void ComputeCurvedSeg(
trkSeg_p s,
@@ -396,6 +418,7 @@ void JointSegProc( segProc_e, trkSeg_p, segProcData_p );
void BezierSegProc( segProc_e, trkSeg_p, segProcData_p ); //Used in Cornu join
void CleanSegs( dynArr_t *);
void CopyPoly(trkSeg_p seg_p, wIndex_t segCnt);
+wBool_t CompareSegs( trkSeg_p, int, trkSeg_p, int );
/* debug.c */
void SetDebug( char * );
@@ -408,7 +431,12 @@ void SetDebug( char * );
#define TB_SHRTPATH (1<<5)
#define TB_HIDEDESC (1<<6)
#define TB_CARATTACHED (1<<7)
-#define TB_TEMPBITS (TB_PROFILEPATH|TB_PROCESSED)
+#define TB_NOTIES (1<<8)
+#define TB_BRIDGE (1<<9)
+#define TB_SELREDRAW (1<<10)
+// Track has been undrawn, don't draw it on Redraw
+#define TB_UNDRAWN (1<<11)
+#define TB_TEMPBITS (TB_PROFILEPATH|TB_PROCESSED|TB_UNDRAWN)
/* track.c */
#ifdef FASTTRACK
@@ -473,14 +501,21 @@ BOOL_T IsTrackDeleted( track_p );
#define GetTrkSelected(T) (GetTrkBits(T)&TB_SELECTED)
#define GetTrkVisible(T) (GetTrkBits(T)&TB_VISIBLE)
+#define GetTrkNoTies(T) (GetTrkBits(T)&TB_NOTIES)
+#define GetTrkBridge(T) (GetTrkBits(T)&TB_BRIDGE)
#define SetTrkVisible(T,V) ((V)?SetTrkBits(T,TB_VISIBLE):ClrTrkBits(T,TB_VISIBLE))
+#define SetTrkNoTies(T,V) ((V)?SetTrkBits(T,TB_NOTIES):ClrTrkBits(T,TB_NOTIES))
+#define SetTrkBridge(T,V) ((V)?SetTrkBits(T,TB_BRIDGE):ClrTrkBits(T,TB_BRIDGE))
int ClrAllTrkBits( int );
+int ClrAllTrkBitsRedraw( int, wBool_t );
void GetTrkEndElev( track_p trk, EPINX_T e, int *option, DIST_T *height );
void SetTrkEndElev( track_p, EPINX_T, int, DIST_T, char * );
int GetTrkEndElevMode( track_p, EPINX_T );
int GetTrkEndElevUnmaskedMode( track_p, EPINX_T );
DIST_T GetTrkEndElevHeight( track_p, EPINX_T );
+BOOL_T GetTrkEndElevCachedHeight (track_p trk, EPINX_T e, DIST_T *height, DIST_T *length);
+void SetTrkEndElevCachedHeight ( track_p trk, EPINX_T e, DIST_T height, DIST_T length);
char * GetTrkEndElevStation( track_p, EPINX_T );
#define EndPtIsDefinedElev( T, E ) (GetTrkEndElevMode(T,E)==ELEV_DEF)
#define EndPtIsIgnoredElev( T, E ) (GetTrkEndElevMode(T,E)==ELEV_IGNORE)
@@ -492,9 +527,10 @@ void ClearElevPath( void );
BOOL_T GetTrkOnElevPath( track_p, DIST_T * elev );
void SetTrkLayer( track_p, int );
BOOL_T CheckTrackLayer( track_p );
+BOOL_T CheckTrackLayerSilent(track_p);
void CopyAttributes( track_p, track_p );
-#define GetTrkGauge( T ) GetScaleTrackGauge(GetTrkScale(T))
+DIST_T GetTrkGauge( track_cp );
#define GetTrkScaleName( T ) GetScaleName(GetTrkScale(T))
void SetTrkEndPtCnt( track_p, EPINX_T );
BOOL_T WriteEndPt( FILE *, track_cp, EPINX_T );
@@ -506,11 +542,56 @@ void AuditTracks( char *, ... );
void CheckTrackLength( track_cp );
track_p NewTrack( wIndex_t, TRKTYP_T, EPINX_T, CSIZE_T );
void DescribeTrack( track_cp, char *, CSIZE_T );
+void ActivateTrack( track_cp );
EPINX_T GetEndPtConnectedToMe( track_p, track_p );
EPINX_T GetNearestEndPtConnectedToMe( track_p, track_p, coOrd);
void SetEndPts( track_p, EPINX_T );
BOOL_T DeleteTrack( track_p, BOOL_T );
+#define REGRESS_CHECK_POS( TITLE, P1, P2, FIELD ) \
+ if ( ! IsPosClose( P1->FIELD, P2->FIELD ) ) { \
+ sprintf( cp, TITLE ": Actual [%0.3f %0.3f], Expected [%0.3f %0.3f]\n", \
+ P1->FIELD.x, P1->FIELD.y, \
+ P2->FIELD.x, P2->FIELD.y ); \
+ return FALSE; \
+ }
+#define REGRESS_CHECK_DIST( TITLE, P1, P2, FIELD ) \
+ if ( ! IsDistClose( P1->FIELD, P2->FIELD ) ) { \
+ sprintf( cp, TITLE ": Actual %0.3f, Expected %0.3f\n", \
+ P1->FIELD, P2->FIELD ); \
+ return FALSE; \
+ }
+#define REGRESS_CHECK_WIDTH( TITLE, P1, P2, FIELD ) \
+ if ( ! IsWidthClose( P1->FIELD, P2->FIELD ) ) { \
+ sprintf( cp, TITLE ": Actual %0.3f, Expected %0.3f\n", \
+ P1->FIELD, P2->FIELD ); \
+ return FALSE; \
+ }
+#define REGRESS_CHECK_ANGLE( TITLE, P1, P2, FIELD ) \
+ if ( ! IsAngleClose( P1->FIELD, P2->FIELD ) ) { \
+ sprintf( cp, TITLE ": Actual %0.3f , Expected %0.3f\n", \
+ P1->FIELD, P2->FIELD ); \
+ return FALSE; \
+ }
+#define REGRESS_CHECK_INT( TITLE, P1, P2, FIELD ) \
+ if ( P1->FIELD != P2->FIELD ) { \
+ sprintf( cp, TITLE ": Actual %d, Expected %d\n", \
+ (int)(P1->FIELD), (int)(P2->FIELD) ); \
+ return FALSE; \
+ }
+#define REGRESS_CHECK_COLOR( TITLE, P1, P2, FIELD ) \
+ if ( ! IsColorClose(P1->FIELD, P2->FIELD) ) { \
+ sprintf( cp, TITLE ": Actual %6x, Expected %6x\n", \
+ (int)wDrawGetRGB(P1->FIELD), (int)wDrawGetRGB(P2->FIELD) ); \
+ return FALSE; \
+ }
+wBool_t IsPosClose( coOrd, coOrd );
+wBool_t IsAngleClose( ANGLE_T, ANGLE_T );
+wBool_t IsDistClose( DIST_T, DIST_T );
+wBool_t IsWidthClose( DIST_T, DIST_T );
+wBool_t IsColorClose( wDrawColor, wDrawColor );
+wBool_t CompareTrack( track_cp, track_cp );
+
void MoveTrack( track_p, coOrd );
void RotateTrack( track_p, coOrd, ANGLE_T );
void RescaleTrack( track_p, FLOAT_T, coOrd );
@@ -523,19 +604,18 @@ EPINX_T GetNextTrkOnPath( track_p, EPINX_T );
#define FDE_UDF 1
#define FDE_END 2
int FindDefinedElev( track_p, EPINX_T, int, BOOL_T, DIST_T *, DIST_T *);
-BOOL_T ComputeElev( track_p, EPINX_T, BOOL_T, DIST_T *, DIST_T * );
+BOOL_T ComputeElev( track_p trk, EPINX_T ep, BOOL_T on_path, DIST_T * elev, DIST_T * grade, BOOL_T force);
#define DTS_LEFT (1<<0)
#define DTS_RIGHT (1<<1)
-#define DTS_THICK2 (1<<2)
-#define DTS_THICK3 (1<<3)
-#define DTS_TIES (1<<4)
#define DTS_NOCENTER (1<<5)
+#define DTS_DOT (1<<7)
+#define DTS_DASH (1<<8)
+#define DTS_DASHDOT (1<<9)
+#define DTS_DASHDOTDOT (1<<10)
-void DrawCurvedTies( drawCmd_p, track_p, coOrd, DIST_T, ANGLE_T, ANGLE_T, wDrawColor );
-void DrawCurvedTrack( drawCmd_p, coOrd, DIST_T, ANGLE_T, ANGLE_T, coOrd, coOrd, track_p, DIST_T, wDrawColor, long );
-void DrawStraightTies( drawCmd_p, track_p, coOrd, coOrd, wDrawColor );
-void DrawStraightTrack( drawCmd_p, coOrd, coOrd, ANGLE_T, track_p, DIST_T, wDrawColor, long );
+void DrawCurvedTrack( drawCmd_p, coOrd, DIST_T, ANGLE_T, ANGLE_T, coOrd, coOrd, track_cp, wDrawColor, long );
+void DrawStraightTrack( drawCmd_p, coOrd, coOrd, ANGLE_T, track_cp, wDrawColor, long );
ANGLE_T GetAngleAtPoint( track_p, coOrd, EPINX_T *, EPINX_T * );
DIST_T GetTrkDistance( track_cp, coOrd *);
@@ -551,24 +631,23 @@ void DrawEndElev( drawCmd_p, track_p, EPINX_T, wDrawColor );
wDrawColor GetTrkColor( track_p, drawCmd_p );
void DrawTrack( track_cp, drawCmd_p, wDrawColor );
void DrawTracks( drawCmd_p, DIST_T, coOrd, coOrd );
-void RedrawLayer( unsigned int, BOOL_T );
void DrawNewTrack( track_cp );
void DrawOneTrack( track_cp, drawCmd_p );
void UndrawNewTrack( track_cp );
void DrawSelectedTracks( drawCmd_p );
void HilightElevations( BOOL_T );
void HilightSelectedEndPt( BOOL_T, track_p, EPINX_T );
-DIST_T EndPtDescriptionDistance( coOrd, track_p, EPINX_T );
+DIST_T EndPtDescriptionDistance( coOrd, track_p, EPINX_T, coOrd *, BOOL_T show_hidden, BOOL_T * hidden );
STATUS_T EndPtDescriptionMove( track_p, EPINX_T, wAction_t, coOrd );
track_p FindTrack( TRKINX_T );
void ResolveIndex( void );
void RenumberTracks( void );
BOOL_T ReadTrack( char * );
-BOOL_T WriteTracks( FILE * );
-BOOL_T ExportTracks( FILE * );
+BOOL_T WriteTracks( FILE *, wBool_t );
+BOOL_T ExportTracks( FILE * , coOrd *);
void ImportStart( void );
-void ImportEnd( void );
+void ImportEnd( coOrd , wBool_t, wBool_t);
void FreeTrack( track_p );
void ClearTracks( void );
BOOL_T TrackIterate( track_p * );
@@ -581,7 +660,7 @@ void SaveCarState( void );
void RestoreCarState( void );
TRKTYP_T InitObject( trackCmd_t* );
-void ConnectTracks( track_p, EPINX_T, track_p, EPINX_T );
+int ConnectTracks( track_p, EPINX_T, track_p, EPINX_T );
BOOL_T ReconnectTrack( track_p, EPINX_T, track_p, EPINX_T );
void DisconnectTracks( track_p, EPINX_T, track_p, EPINX_T );
BOOL_T ConnectAbuttingTracks( track_p, EPINX_T, track_p, EPINX_T );
@@ -589,9 +668,10 @@ BOOL_T ConnectTurntableTracks(track_p, EPINX_T, track_p, EPINX_T );
BOOL_T SplitTrack( track_p, coOrd, EPINX_T, track_p *leftover, BOOL_T );
BOOL_T TraverseTrack( traverseTrack_p, DIST_T * );
BOOL_T RemoveTrack( track_p*, EPINX_T*, DIST_T* );
-BOOL_T TrimTrack( track_p, EPINX_T, DIST_T );
+BOOL_T TrimTrack( track_p, EPINX_T, DIST_T, coOrd pos, ANGLE_T angle, DIST_T radius, coOrd center);
BOOL_T MergeTracks( track_p, EPINX_T, track_p, EPINX_T );
STATUS_T ExtendStraightFromOrig( track_p, wAction_t, coOrd );
+STATUS_T ExtendTrackFromOrig( track_p, wAction_t, coOrd );
STATUS_T ModifyTrack( track_p, wAction_t, coOrd );
BOOL_T GetTrackParams( int, track_p, coOrd, trackParams_t* );
BOOL_T MoveEndPt( track_p *, EPINX_T *, coOrd, DIST_T );
@@ -616,12 +696,11 @@ void FlipTrack( track_p, coOrd, ANGLE_T );
void DrawPositionIndicators( void );
void AdvancePositionIndicator( track_p, coOrd, coOrd *, ANGLE_T * );
-BOOL_T MakeParallelTrack( track_p, coOrd, DIST_T, track_p *, coOrd *, coOrd * );
-
+BOOL_T MakeParallelTrack( track_p, coOrd, DIST_T, DIST_T, track_p *, coOrd *, coOrd * , BOOL_T);
/* cmisc.c */
wIndex_t describeCmdInx;
-typedef enum { DESC_NULL, DESC_POS, DESC_FLOAT, DESC_ANGLE, DESC_LONG, DESC_COLOR, DESC_DIM, DESC_PIVOT, DESC_LAYER, DESC_STRING, DESC_TEXT, DESC_LIST, DESC_EDITABLELIST } descType;
+typedef enum { DESC_NULL, DESC_POS, DESC_FLOAT, DESC_ANGLE, DESC_LONG, DESC_COLOR, DESC_DIM, DESC_PIVOT, DESC_LAYER, DESC_STRING, DESC_TEXT, DESC_LIST, DESC_EDITABLELIST, DESC_BOXED } descType;
#define DESC_RO (1<<0)
#define DESC_IGNORE (1<<1)
#define DESC_NOREDRAW (1<<2)
@@ -647,10 +726,11 @@ typedef void (*descUpdate_t)( track_p, int, descData_p, BOOL_T );
void DoDescribe( char *, track_p, descData_p, descUpdate_t );
void DescribeCancel( void );
BOOL_T UpdateDescStraight( int, int, int, int, int, descData_p, long );
+STATUS_T CmdDescribe(wAction_t,coOrd);
/* compound.c */
-DIST_T CompoundDescriptionDistance( coOrd, track_p );
+DIST_T CompoundDescriptionDistance( coOrd, track_p, coOrd *, BOOL_T, BOOL_T * );
STATUS_T CompoundDescriptionMove( track_p, wAction_t, coOrd );
/* elev.c */
@@ -659,10 +739,10 @@ STATUS_T CompoundDescriptionMove( track_p, wAction_t, coOrd );
#define ELEV_ISLAND (1)
#define ELEV_ALONE (0)
-long oldElevationEvaluation;
+extern long oldElevationEvaluation;
EPINX_T GetNextTrkOnPath( track_p trk, EPINX_T ep );
int FindDefinedElev( track_p, EPINX_T, int, BOOL_T, DIST_T *, DIST_T * );
-BOOL_T ComputeElev( track_p, EPINX_T, BOOL_T, DIST_T *, DIST_T * );
+BOOL_T ComputeElev( track_p, EPINX_T, BOOL_T, DIST_T *, DIST_T *, BOOL_T );
void RecomputeElevations( void );
void UpdateAllElevations( void );
DIST_T GetElevation( track_p );
@@ -672,11 +752,22 @@ void UpdateTrkEndElev( track_p, EPINX_T, int, DIST_T, char * );
void DrawTrackElev( track_p, drawCmd_p, BOOL_T );
/* cdraw.c */
+typedef enum {DRAWLINESOLID,
+ DRAWLINEDASH,
+ DRAWLINEDOT,
+ DRAWLINEDASHDOT,
+ DRAWLINEDASHDOTDOT,
+ DRAWLINECENTER,
+ DRAWLINEPHANTOM } drawLineType_e;
track_p MakeDrawFromSeg( coOrd, ANGLE_T, trkSeg_p );
+track_p MakePolyLineFromSegs( coOrd, ANGLE_T, dynArr_t * );
+void DrawOriginAnchor(track_p);
BOOL_T OnTableEdgeEndPt( track_p, coOrd * );
BOOL_T GetClosestEndPt( track_p, coOrd * );
BOOL_T ReadTableEdge( char * );
BOOL_T ReadText( char * );
+void SetLineType( track_p trk, int width );
+void MenuMode(int );
/* chotbar.c */
extern DIST_T curBarScale;
@@ -685,7 +776,7 @@ void HideHotBar( void );
void LayoutHotBar ( void *);
typedef enum { HB_SELECT, HB_DRAW, HB_LISTTITLE, HB_BARTITLE, HB_FULLTITLE } hotBarProc_e;
typedef char * (*hotBarProc_t)( hotBarProc_e, void *, drawCmd_p, coOrd * );
-void AddHotBarElement( char *, coOrd, coOrd, BOOL_T, DIST_T, void *, hotBarProc_t );
+void AddHotBarElement( char *, coOrd, coOrd, BOOL_T, BOOL_T, DIST_T, void *, hotBarProc_t );
void HotBarCancel( void );
void AddHotBarTurnouts( void );
void AddHotBarStructures( void );
diff --git a/app/bin/trackx.h b/app/bin/trackx.h
index 9f24e7c..50fda1d 100644
--- a/app/bin/trackx.h
+++ b/app/bin/trackx.h
@@ -40,7 +40,7 @@ typedef struct track_t {
BOOL_T new:1;
unsigned int width:2;
unsigned int elevMode:2;
- unsigned int bits:9;
+ unsigned int bits:12;
EPINX_T endCnt;
trkEndPt_p endPt;
struct { float x; float y; } lo, hi;
diff --git a/app/bin/trknote.c b/app/bin/trknote.c
new file mode 100644
index 0000000..f27cf2e
--- /dev/null
+++ b/app/bin/trknote.c
@@ -0,0 +1,720 @@
+/** \file trknote.c
+ * Track notes "postits"
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis, 2018 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 <stdint.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "cundo.h"
+#include "custom.h"
+#include "dynstring.h"
+#include "fileio.h"
+#include "i18n.h"
+#include "misc.h"
+#include "note.h"
+#include "param.h"
+#include "track.h"
+#include "include/utf8convert.h"
+#include "utility.h"
+
+extern BOOL_T inDescribeCmd;
+extern descData_t noteDesc[];
+
+static TRKTYP_T T_NOTE = -1;
+
+static wDrawBitMap_p note_bm, link_bm, document_bm;
+
+typedef struct {
+ char **xpm;
+ int OP;
+ char * shortName;
+ char * cmdName;
+ char * helpKey;
+ long acclKey;
+} trknoteData_t;
+
+#include "bitmaps/sticky-note-text.xpm"
+#include "bitmaps/sticky-note-chain.xpm"
+#include "bitmaps/sticky-note-clip.xpm"
+
+static trknoteData_t noteTypes[] = {
+ { sticky_note_text_bits, OP_NOTETEXT, N_("Note"), N_("Comment"), "cmdTextNote", 0L },
+ { sticky_note_chain_bits, OP_NOTELINK, N_("Link"), N_("Weblink"), "cmdLinkNote", 0L },
+ { sticky_note_clip_bits, OP_NOTEFILE, N_("Document"), N_("Document"), "cmdFileNote", 0L },
+};
+
+static long curNoteType;
+
+static unsigned layerSave;
+static coOrd posSave;
+
+#define NOTETYPESCOUNT (sizeof(noteTypes)/sizeof(trknoteData_t))
+
+
+/*****************************************************************************
+ * NOTE OBJECT
+ */
+
+static track_p NewNote(wIndex_t index, coOrd p, enum noteCommands command )
+{
+ track_p t;
+ struct extraDataNote * xx;
+ t = NewTrack(index, T_NOTE, 0, sizeof *xx);
+ xx = (struct extraDataNote *)GetTrkExtraData(t);
+ xx->pos = p;
+ xx->op = command;
+ SetBoundingBox(t, p, p);
+ return t;
+}
+
+/**
+ * Draw the icon for a note into the drawing area
+ *
+ * \param t IN note
+ * \param d IN drawing environment
+ * \param color IN color for ico
+ */
+
+static void DrawNote(track_p t, drawCmd_p d, wDrawColor color)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(t);
+ coOrd p[4];
+
+ if (d->scale >= 16) {
+ return;
+ }
+ if ((d->options & DC_SIMPLE)) {
+ //while the icon is moved, draw a square
+ //because CmdMove draws all selected object into tempSeg and
+ //tempSegDrawFuncs doesn't have a BitMap drawing func
+ DIST_T dist;
+ dist = 0.1*mainD.scale;
+ p[0].x = p[1].x = xx->pos.x - dist;
+ p[2].x = p[3].x = xx->pos.x + dist;
+ p[1].y = p[2].y = xx->pos.y - dist;
+ p[3].y = p[0].y = xx->pos.y + dist;
+ DrawLine(d, p[0], p[1], 0, color);
+ DrawLine(d, p[1], p[2], 0, color);
+ DrawLine(d, p[2], p[3], 0, color);
+ DrawLine(d, p[3], p[0], 0, color);
+ } else {
+ // draw a bitmap for static object
+ wDrawBitMap_p bm;
+
+ if (xx->op == OP_NOTELINK ||(inDescribeCmd && curNoteType == OP_NOTELINK)) {
+ bm = link_bm;
+ } else {
+ if (xx->op == OP_NOTEFILE || (inDescribeCmd && curNoteType == OP_NOTEFILE)) {
+ bm = document_bm;
+ } else {
+ bm = note_bm;
+ }
+ }
+ DrawBitMap(d, xx->pos, bm, color);
+ }
+}
+
+static DIST_T DistanceNote(track_p t, coOrd * p)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(t);
+ DIST_T d;
+ d = FindDistance(*p, xx->pos);
+
+ if (d < 3.0*(mainD.scale/12.0)) {
+ return d;
+ }
+
+ return 100000.0;
+}
+
+static void DeleteNote(track_p t)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(t);
+
+ switch (xx->op) {
+ case OP_NOTETEXT:
+ if (xx->noteData.text) {
+ MyFree(xx->noteData.text);
+ }
+ break;
+ case OP_NOTEFILE:
+ if (xx->noteData.fileData.path) {
+ MyFree(xx->noteData.fileData.path);
+ }
+ if (xx->noteData.fileData.title) {
+ MyFree(xx->noteData.fileData.title);
+ }
+ break;
+ case OP_NOTELINK:
+ if (xx->noteData.linkData.title) {
+ MyFree(xx->noteData.linkData.title);
+ }
+ if (xx->noteData.linkData.url) {
+ MyFree(xx->noteData.linkData.url);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
+NoteStateSave(track_p trk)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ layerSave = GetTrkLayer(trk);
+ posSave = xx->pos;
+}
+
+/**
+* Handle Cancel button: restore old values for layer and position
+*/
+
+void
+CommonCancelNote(track_p trk)
+{
+ if (inDescribeCmd) {
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ xx->layer = layerSave;
+ xx->pos = posSave;
+ SetBoundingBox(trk, xx->pos, xx->pos);
+ }
+}
+
+static void
+CommonUpdateNote(track_p trk, int inx, struct extraDataNote *noteData )
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ switch (inx) {
+ case OR_NOTE:
+ xx->pos = noteData->pos;
+ SetBoundingBox(trk, xx->pos, xx->pos);
+ break;
+ case LY_NOTE:
+ SetTrkLayer(trk, noteData->layer);
+ break;
+ case CANCEL_NOTE:
+ CommonCancelNote(trk);
+ break;
+ }
+}
+
+
+void UpdateFile(struct extraDataNote *noteUIData, int inx, BOOL_T needUndoStart)
+{
+ track_p trk = noteUIData->trk;
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ switch (inx) {
+ case OR_NOTE:
+ case LY_NOTE:
+ case CANCEL_NOTE:
+ CommonUpdateNote(trk, inx, noteUIData);
+ break;
+ case OK_FILE:
+ {
+ DeleteNote(trk);
+ xx->noteData.fileData.path = MyStrdup(noteUIData->noteData.fileData.path);
+ xx->noteData.fileData.title = MyStrdup(noteUIData->noteData.fileData.title);
+ //result = malloc( maximumSize );
+ //resultSize = File2URI(noteFileData->path, maximumSize, result);
+ //xx->text = (char*)MyMalloc(resultSize + strlen(noteFileData->title) + 2);
+ //sprintf(xx->text, "%s %s", result, noteFileData->title);
+ //if (noteFileData->inArchive) {
+ // CopyFile(noteFileData->path, archiveDirectory);
+
+ //}
+ //free(result);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void UpdateLink(struct extraDataNote *noteUIData, int inx, BOOL_T needUndoStart)
+{
+ track_p trk = noteUIData->trk;
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ switch (inx) {
+ case OR_NOTE:
+ case LY_NOTE:
+ case CANCEL_NOTE:
+ CommonUpdateNote(trk, inx, noteUIData);
+ break;
+
+ case OK_LINK:
+ DeleteNote(trk);
+ xx->noteData.linkData.title = MyStrdup(noteUIData->noteData.linkData.title);
+ xx->noteData.linkData.url = MyStrdup(noteUIData->noteData.linkData.url);
+ break;
+ default:
+ break;
+ }
+}
+
+void UpdateText(struct extraDataNote *noteUIData, int inx, BOOL_T needUndoStart)
+{
+ track_p trk = noteUIData->trk;
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(trk);
+
+ switch (inx) {
+ case OR_NOTE:
+ case LY_NOTE:
+ case CANCEL_NOTE:
+ CommonUpdateNote(trk, inx, noteUIData);
+ break;
+
+ case OK_TEXT:
+ DeleteNote(trk);
+ xx->noteData.text = MyStrdup(noteUIData->noteData.text);
+ break;
+ default:
+ break;
+ }
+ changed++;
+}
+
+/**
+ * Get the delimited marker for the current note. Markers start and end with
+ * a delimiter. The marker itself is a single digit number. For plain text notes
+ * no marker is used for backwards compatibility
+ *
+ * \param command IN the note's command code
+ * \return a pointer to the marker string.
+ */
+
+static char *
+GetNoteMarker(enum noteCommands command )
+{
+ static char marker[2 * sizeof(DELIMITER) + 3];
+
+ switch (command) {
+ case OP_NOTEFILE:
+ case OP_NOTELINK:
+ sprintf(marker, DELIMITER "%d" DELIMITER, command);
+ break;
+ case OP_NOTETEXT:
+ default:
+ *marker = '\0';
+ break;
+ }
+ return(marker);
+}
+
+/**
+ * Write the note to file. Handles the complete syntax for a note statement
+ *
+ * \param t IN pointer to the note track element
+ * \param f IN file handle for writing
+ * \return TRUE for success
+ */
+
+static BOOL_T WriteNote(track_p t, FILE * f)
+{
+ struct extraDataNote *xx = (struct extraDataNote *)GetTrkExtraData(t);
+ BOOL_T rc = TRUE;
+
+ rc &= fprintf(f, "NOTE %d %u 0 0 %0.6f %0.6f 0 %d", GetTrkIndex(t),
+ GetTrkLayer(t),
+ xx->pos.x, xx->pos.y, xx->op )>0;
+
+ char *s[2] = { NULL, NULL };
+ switch (xx->op) {
+ case OP_NOTETEXT:
+ s[0]=ConvertToEscapedText( xx->noteData.text );
+ break;
+ case OP_NOTELINK:
+ s[0]=ConvertToEscapedText( xx->noteData.linkData.url );
+ s[1]=ConvertToEscapedText( xx->noteData.linkData.title );
+ break;
+ case OP_NOTEFILE:
+ s[0]=ConvertToEscapedText( xx->noteData.fileData.path );
+ s[1]=ConvertToEscapedText( xx->noteData.fileData.title );
+ break;
+ default:
+ AbortProg( "WriteNote: %d", xx->op );
+ }
+#ifdef WINDOWS
+ for ( int inx = 0; inx < 2; inx++ ) {
+ if ( RequiresConvToUTF8( s[inx] ) ) {
+ wSystemToUTF8 ( s[inx], message, sizeof message );
+ MyFree( s[inx] );
+ s[inx] = MyStrdup( message );
+ }
+ }
+#endif
+ rc &= fprintf( f, " \"%s\"", s[0] )>0;
+ MyFree(s[0]);
+ if ( s[1] ) {
+ rc &= fprintf( f, " \"%s\"", s[1] )>0;
+ MyFree( s[1] );
+ }
+ rc &= fprintf( f, "\n" )>0;
+
+ return rc;
+}
+
+/**
+ * Read a track note aka postit
+ *
+ * \param line
+ */
+
+static BOOL_T
+ReadTrackNote(char *line)
+{
+ track_p t;
+ int size;
+ char * cp;
+ struct extraDataNote *xx;
+ wIndex_t index;
+ wIndex_t layer;
+ coOrd pos;
+ DIST_T elev;
+ char *noteText;
+ enum noteCommands noteType;
+ char * sText;
+
+ if (!GetArgs(line + 5, paramVersion < 3 ? "XXpYdc" : paramVersion < 9 ?
+ "dL00pYdc" : "dL00pfdc",
+ &index, &layer, &pos, &elev, &size, &cp)) {
+ return FALSE;
+ }
+
+ if ( paramVersion >= 12 ) {
+ noteType = size;
+ t = NewNote(index, pos, noteType);
+ SetTrkLayer(t, layer);
+
+ xx = (struct extraDataNote *)GetTrkExtraData(t);
+ switch (noteType) {
+ case OP_NOTETEXT:
+ if ( !GetArgs( cp, "qc", &sText, &cp ) )
+ return FALSE;
+#ifdef WINDOWS
+ ConvertUTF8ToSystem( sText );
+#endif
+ xx->noteData.text = sText;
+ break;
+ case OP_NOTELINK:
+ if ( !GetArgs( cp, "qc", &sText, &cp ) )
+ return FALSE;
+#ifdef WINDOWS
+ ConvertUTF8ToSystem( sText );
+#endif
+ xx->noteData.linkData.url = sText;
+ if ( !GetArgs( cp, "qc", &sText, &cp ) )
+ return FALSE;
+#ifdef WINDOWS
+ ConvertUTF8ToSystem( sText );
+#endif
+ xx->noteData.linkData.title = sText;
+ break;
+ case OP_NOTEFILE:
+ if ( !GetArgs( cp, "qc", &sText, &cp ) )
+ return FALSE;
+#ifdef WINDOWS
+ ConvertUTF8ToSystem( sText );
+#endif
+ xx->noteData.fileData.path = sText;
+ if ( !GetArgs( cp, "qc", &sText, &cp ) )
+ return FALSE;
+#ifdef WINDOWS
+ ConvertUTF8ToSystem( sText );
+#endif
+ xx->noteData.fileData.title = sText;
+ xx->noteData.fileData.inArchive = FALSE;
+ break;
+ default:
+ AbortProg( "ReadNote: %d", noteType );
+ }
+ } else {
+ noteText = ReadMultilineText();
+
+ noteType = OP_NOTETEXT;
+
+ if( !strncmp(noteText, DELIMITER, strlen( DELIMITER )) &&
+ !strncmp(noteText + strlen(DELIMITER) + 1, DELIMITER, strlen(DELIMITER)) &&
+ noteText[strlen(DELIMITER)] - '0' > 0 &&
+ noteText[strlen(DELIMITER)] - '0' <= OP_NOTEFILE)
+ {
+ noteType = noteText[strlen(DELIMITER)] - '0';
+ }
+
+ t = NewNote(index, pos, noteType);
+ SetTrkLayer(t, layer);
+
+ xx = (struct extraDataNote *)GetTrkExtraData(t);
+
+ switch (noteType) {
+ case OP_NOTETEXT:
+ xx->noteData.text = MyStrdup(noteText);
+ break;
+ case OP_NOTELINK:
+ {
+ char *ptr;
+ ptr = strtok(noteText, " ");
+ xx->noteData.linkData.url = MyStrdup(ptr + 2 * strlen(DELIMITER) + 1);
+ xx->noteData.linkData.title = MyStrdup(noteText + strlen(ptr) + 1);
+ break;
+ }
+ case OP_NOTEFILE:
+ {
+ char *ptr;
+ ptr = strtok(noteText + 2 * strlen(DELIMITER) + 1, "\"");
+ xx->noteData.fileData.path = MyStrdup(ptr);
+ xx->noteData.fileData.title = MyStrdup(ptr + strlen(ptr) + 2 );
+ xx->noteData.fileData.inArchive = FALSE;
+ break;
+ }
+
+ }
+ MyFree(noteText);
+ }
+ return TRUE;
+}
+
+/**
+ * Handle reading of NOTE
+ *
+ * \param line IN complete line with NOTE statement
+ */
+
+static BOOL_T
+ReadNote(char * line)
+{
+ if (strncmp(line, "NOTE MAIN", 9) == 0) {
+ return ReadMainNote(line);
+ } else {
+ return ReadTrackNote(line);
+ }
+}
+
+static void MoveNote(track_p trk, coOrd orig)
+{
+ struct extraDataNote * xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ xx->pos.x += orig.x;
+ xx->pos.y += orig.y;
+ SetBoundingBox(trk, xx->pos, xx->pos);
+}
+
+
+static void RotateNote(track_p trk, coOrd orig, ANGLE_T angle)
+{
+ struct extraDataNote * xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ Rotate(&xx->pos, orig, angle);
+ SetBoundingBox(trk, xx->pos, xx->pos);
+}
+
+static void RescaleNote(track_p trk, FLOAT_T ratio)
+{
+ struct extraDataNote * xx = (struct extraDataNote *)GetTrkExtraData(trk);
+ xx->pos.x *= ratio;
+ xx->pos.y *= ratio;
+}
+
+static void DescribeNote(track_p trk, char * str, CSIZE_T len)
+{
+ if (IsLinkNote(trk)) {
+ DescribeLinkNote(trk, str, len);
+ }
+ else {
+ if (IsFileNote(trk)) {
+ DescribeFileNote(trk, str, len);
+ } else {
+ DescribeTextNote(trk, str, len);
+ }
+ }
+}
+
+static void ActivateNote(track_p trk) {
+ if (IsLinkNote(trk) ) {
+ ActivateLinkNote(trk);
+ }
+ if (IsFileNote(trk)) {
+ ActivateFileNote(trk);
+ }
+}
+
+static BOOL_T QueryNote( track_p trk, int query )
+{
+ switch ( query ) {
+ case Q_IS_ACTIVATEABLE:;
+ if (IsFileNote(trk)) return TRUE;
+ if (IsLinkNote(trk)) return TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+ return FALSE;
+}
+
+static wBool_t CompareNote( track_cp trk1, track_cp trk2 )
+{
+ struct extraDataNote *xx1 = (struct extraDataNote *)GetTrkExtraData( trk1 );
+ struct extraDataNote *xx2 = (struct extraDataNote *)GetTrkExtraData( trk2 );
+ char * cp = message + strlen(message);
+ REGRESS_CHECK_POS( "Pos", xx1, xx2, pos )
+ REGRESS_CHECK_INT( "Layer", xx1, xx2, layer )
+ REGRESS_CHECK_INT( "Op", xx1, xx2, op )
+ return TRUE;
+}
+
+static trackCmd_t noteCmds = {
+ "NOTE",
+ DrawNote,
+ DistanceNote,
+ DescribeNote,
+ DeleteNote,
+ WriteNote,
+ ReadNote,
+ MoveNote,
+ RotateNote,
+ RescaleNote,
+ NULL, /* audit */
+ NULL, /* getAngle */
+ NULL, /* split */
+ NULL, /* traverse */
+ NULL, /* enumerate */
+ NULL, /* redraw */
+ NULL, /*trim*/
+ NULL, /*merge*/
+ NULL, /*modify*/
+ NULL, /*getLength*/
+ NULL, /*getTrackParams*/
+ NULL, /*moveEndPt*/
+ QueryNote, /*query*/
+ NULL, /*ungroup*/
+ NULL, /*flip*/
+ NULL, /*drawPositionIndicator*/
+ NULL, /*advancePositionIndicator*/
+ NULL, /*checkTraverse*/
+ NULL, /*makeParallel*/
+ NULL, /*drawDesc*/
+ NULL, /*rebuildSegs*/
+ NULL, /*replayData*/
+ NULL, /*storeData*/
+ ActivateNote,
+ CompareNote
+};
+
+/*****************************************************************************
+ * NOTE COMMAND
+ */
+
+
+
+static STATUS_T CmdNote(wAction_t action, coOrd pos)
+{
+ static coOrd oldPos;
+ static int state_on = FALSE;
+ track_p trk;
+
+ switch (action) {
+ case C_START:
+ InfoMessage(_("Place a note on the layout"));
+ curNoteType = (long)commandContext;
+ return C_CONTINUE;
+
+ case C_DOWN:
+ state_on = TRUE;
+ oldPos = pos;
+ return C_CONTINUE;
+
+ case C_MOVE:
+ oldPos = pos;
+ return C_CONTINUE;
+
+ case C_UP:
+ UndoStart(_("New Note"), "New Note");
+ state_on = FALSE;
+ trk = NewNote(-1, pos, curNoteType );
+ inDescribeCmd = TRUE;
+ DrawNewTrack(trk);
+
+ switch (curNoteType)
+ {
+ case OP_NOTETEXT:
+ NewTextNoteUI(trk);
+ break;
+ case OP_NOTELINK:
+ NewLinkNoteUI(trk);
+ break;
+ case OP_NOTEFILE:
+ NewFileNoteUI(trk);
+ break;
+ }
+
+ inDescribeCmd = FALSE;
+
+ return C_CONTINUE;
+
+ case C_REDRAW:
+ if (state_on) {
+ switch (curNoteType) {
+ case OP_NOTETEXT:
+ DrawBitMap(&tempD, oldPos, note_bm, normalColor);
+ break;
+ case OP_NOTELINK:
+ DrawBitMap(&tempD, oldPos, link_bm, normalColor);
+ break;
+ }
+ }
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ DescribeCancel();
+ state_on = FALSE;
+ return C_CONTINUE;
+ }
+
+ return C_INFO;
+}
+
+#include "bitmaps/note.xbm"
+#include "bitmaps/link.xbm"
+#include "bitmaps/clip.xbm"
+#include "bitmaps/cnote.xpm"
+
+void InitTrkNote(wMenu_p menu)
+{
+ note_bm = wDrawBitMapCreate(mainD.d, note_width, note_width, 8, 8, note_bits);
+ link_bm = wDrawBitMapCreate(mainD.d, note_width, note_width, 8, 8, link_bits);
+ document_bm = wDrawBitMapCreate(mainD.d, note_width, note_width, 8, 8, clip_bits);
+
+ ButtonGroupBegin(_("Notes"), "cmdNoteCmd", _("Add notes"));
+ for (int i = 0; i < NOTETYPESCOUNT; i++) {
+ trknoteData_t *nt;
+ wIcon_p icon;
+
+ nt = noteTypes + i;
+ icon = wIconCreatePixMap(nt->xpm);
+ AddMenuButton(menu, CmdNote, nt->helpKey, _(nt->cmdName), icon, LEVEL0_50, IC_STICKY | IC_POPUP2, nt->acclKey, (void *)(intptr_t)nt->OP);
+ }
+ ButtonGroupEnd();
+
+ T_NOTE = InitObject(&noteCmds);
+}
diff --git a/app/bin/trkseg.c b/app/bin/trkseg.c
index ab4b5a8..3e38933 100644
--- a/app/bin/trkseg.c
+++ b/app/bin/trkseg.c
@@ -142,8 +142,14 @@ EXPORT coOrd GetSegEndPt(
break;
case SEG_BEZTRK:
case SEG_BEZLIN:
- if (ep ==1) pos = segPtr->u.b.pos[3]; //For Bezier, use the End Points of the overall curve
- else pos = segPtr->u.b.pos[0];
+ if (ep ==1) {
+ pos = segPtr->u.b.pos[3]; //For Bezier, use the End Points of the overall curve
+ angle = FindAngle(segPtr->u.b.pos[2],segPtr->u.b.pos[3]);
+ } else {
+ pos = segPtr->u.b.pos[0];
+ angle = FindAngle(segPtr->u.b.pos[1],segPtr->u.b.pos[0]);
+ }
+
break;
default:
AbortProg("GetSegCntPt(%c)", segPtr->type );
@@ -172,8 +178,8 @@ EXPORT void GetTextBounds(
coOrd * hiR )
{
- coOrd size;
- POS_T descent = 0.0;
+ coOrd size, size2;
+ POS_T descent = 0.0, ascent = 0.0;
coOrd lo, hi;
coOrd p[4];
coOrd lastL;
@@ -183,9 +189,9 @@ EXPORT void GetTextBounds(
// set up the corners of the rectangle
p[0].x = p[3].x = 0.0;
p[1].x = p[2].x = size.x;
- DrawTextSize2(&mainD, "A", NULL, fs, FALSE, &size, &descent);
+ DrawTextSize2(&mainD, "A", NULL, fs, FALSE, &size2, &descent, &ascent);
p[0].y = p[1].y = lastL.y - descent;
- p[2].y = p[3].y = size.y;
+ p[2].y = p[3].y = size2.y;
lo = hi = zero;
@@ -239,24 +245,10 @@ static void Get1SegBounds( trkSeg_p segPtr, coOrd xlat, ANGLE_T angle, coOrd *lo
case SEG_TBLEDGE:
case SEG_CRVLIN:
case SEG_JNTTRK:
- REORIGIN( p0, GetSegEndPt( segPtr, 0, FALSE, NULL ), angle, xlat )
- REORIGIN( p1, GetSegEndPt( segPtr, 1, FALSE, NULL ), angle, xlat )
- if (p0.x < p1.x) {
- lo->x = p0.x;
- hi->x = p1.x;
- } else {
- lo->x = p1.x;
- hi->x = p0.x;
- }
- if (p0.y < p1.y) {
- lo->y = p0.y;
- hi->y = p1.y;
- } else {
- lo->y = p1.y;
- hi->y = p0.y;
- }
- if ( segPtr->type == SEG_CRVTRK ||
- segPtr->type == SEG_CRVLIN ) {
+ if ( (segPtr->type == SEG_CRVTRK) ||
+ (segPtr->type == SEG_CRVLIN) ) {
+ /* TODO: be more precise about curved line width */
+ width.x = width.y = segPtr->width/2.0;
REORIGIN( pc, segPtr->u.c.center, angle, xlat );
a0 = NormalizeAngle( segPtr->u.c.a0 + angle );
a1 = segPtr->u.c.a1;
@@ -266,7 +258,7 @@ static void Get1SegBounds( trkSeg_p segPtr, coOrd xlat, ANGLE_T angle, coOrd *lo
lo->y = pc.y - radius;
hi->x = pc.x + radius;
hi->y = pc.y + radius;
- return;
+ break;
}
if ( a0 + a1 >= 360.0 )
hi->y = pc.y + radius;
@@ -277,12 +269,25 @@ static void Get1SegBounds( trkSeg_p segPtr, coOrd xlat, ANGLE_T angle, coOrd *lo
if ( a0 < 270.0 && a0+a1 >= 270.0 )
lo->x = pc.x - radius;
}
+ REORIGIN( p0, GetSegEndPt( segPtr, 0, FALSE, NULL ), angle, xlat )
+ REORIGIN( p1, GetSegEndPt( segPtr, 1, FALSE, NULL ), angle, xlat )
+ if (p0.x < p1.x) {
+ lo->x = p0.x;
+ hi->x = p1.x;
+ } else {
+ lo->x = p1.x;
+ hi->x = p0.x;
+ }
+ if (p0.y < p1.y) {
+ lo->y = p0.y;
+ hi->y = p1.y;
+ } else {
+ lo->y = p1.y;
+ hi->y = p0.y;
+ }
if ( segPtr->type == SEG_STRLIN ) {
width.x = segPtr->width * fabs(cos( D2R( FindAngle(p0, p1) ) ) ) / 2.0;
width.y = segPtr->width * fabs(sin( D2R( FindAngle(p0, p1) ) ) ) / 2.0;
- } else if ( segPtr->type == SEG_CRVLIN ) {
- /* TODO: be more precise about curved line width */
- width.x = width.y = segPtr->width/2.0;
} else if ( segPtr->type == SEG_BENCH ) {
width.x = BenchGetWidth( segPtr->u.l.option ) * fabs(cos( D2R( FindAngle(p0, p1) ) ) ) / 2.0;
width.y = BenchGetWidth( segPtr->u.l.option ) * fabs(sin( D2R( FindAngle(p0, p1) ) ) ) / 2.0;
@@ -293,7 +298,7 @@ static void Get1SegBounds( trkSeg_p segPtr, coOrd xlat, ANGLE_T angle, coOrd *lo
width.x = width.y = segPtr->width/2.0;
case SEG_FILPOLY:
for (inx=0; inx<segPtr->u.p.cnt; inx++ ) {
- REORIGIN( p0, segPtr->u.p.pts[inx], angle, xlat )
+ REORIGIN( p0, segPtr->u.p.pts[inx].pt, angle, xlat )
if (inx==0) {
*lo = *hi = p0;
} else {
@@ -431,8 +436,8 @@ EXPORT void MoveSegs(
case SEG_POLY:
case SEG_FILPOLY:
for (inx=0; inx<s->u.p.cnt; inx++) {
- s->u.p.pts[inx].x += orig.x;
- s->u.p.pts[inx].y += orig.y;
+ s->u.p.pts[inx].pt.x += orig.x;
+ s->u.p.pts[inx].pt.y += orig.y;
}
break;
case SEG_JNTTRK:
@@ -484,7 +489,7 @@ EXPORT void RotateSegs(
case SEG_POLY:
case SEG_FILPOLY:
for (inx=0; inx<s->u.p.cnt; inx++) {
- Rotate( &s->u.p.pts[inx], orig, angle );
+ Rotate( &s->u.p.pts[inx].pt, orig, angle );
}
break;
case SEG_JNTTRK:
@@ -511,7 +516,7 @@ EXPORT void FlipSegs(
{
trkSeg_p s;
int inx;
- coOrd * pts;
+ pts_t * pts;
for (s=segs; s<&segs[segCnt]; s++) {
switch (s->type) {
@@ -537,11 +542,11 @@ EXPORT void FlipSegs(
break;
case SEG_POLY:
case SEG_FILPOLY:
- pts = (coOrd*)MyMalloc( s->u.p.cnt * sizeof (coOrd) );
- memcpy( pts, s->u.p.pts, s->u.p.cnt * sizeof (coOrd) );
+ pts = (pts_t*)MyMalloc( s->u.p.cnt * sizeof (pts_t) );
+ memcpy( pts, s->u.p.pts, s->u.p.cnt * sizeof (pts_t) );
s->u.p.pts = pts;
for (inx=0; inx<s->u.p.cnt; inx++) {
- s->u.p.pts[inx].y = -s->u.p.pts[inx].y;
+ s->u.p.pts[inx].pt.y = -s->u.p.pts[inx].pt.y;
}
/* Don't Free - we only just got! ALso can't free other copy as that may be a template */
//MyFree(pts);
@@ -602,8 +607,8 @@ EXPORT void RescaleSegs(
case SEG_POLY:
case SEG_FILPOLY:
for (inx=0; inx<s->u.p.cnt; inx++) {
- s->u.p.pts[inx].x *= scale_x;
- s->u.p.pts[inx].y *= scale_y;
+ s->u.p.pts[inx].pt.x *= scale_x;
+ s->u.p.pts[inx].pt.y *= scale_y;
}
break;
case SEG_JNTTRK:
@@ -638,7 +643,7 @@ EXPORT void CloneFilledDraw(
trkSeg_p segs,
BOOL_T reorigin )
{
- coOrd * newPts;
+ pts_t * newPts;
trkSeg_p sp;
wIndex_t inx;
@@ -646,21 +651,20 @@ EXPORT void CloneFilledDraw(
switch (sp->type) {
case SEG_POLY:
case SEG_FILPOLY:
- newPts = (coOrd*)MyMalloc( sp->u.p.cnt * sizeof (coOrd) );
+ newPts = (pts_t*)MyMalloc( sp->u.p.cnt * sizeof (pts_t) );
+ memcpy( newPts, sp->u.p.pts, sp->u.p.cnt * sizeof (pts_t) );
if ( reorigin ) {
for ( inx = 0; inx<sp->u.p.cnt; inx++ )
- REORIGIN( newPts[inx], sp->u.p.pts[inx], sp->u.p.angle, sp->u.p.orig );
+ REORIGIN( newPts[inx].pt, sp->u.p.pts[inx].pt, sp->u.p.angle, sp->u.p.orig );
sp->u.p.angle = 0;
sp->u.p.orig = zero;
- } else {
- memcpy( newPts, sp->u.p.pts, sp->u.p.cnt * sizeof (coOrd) );
}
//if (sp->u.p.pts) Can't do this a pts could be pointing at static
// free(sp->u.p.pts);
sp->u.p.pts = newPts;
break;
case SEG_TEXT:
- sp->u.t.string = strdup( sp->u.t.string);
+ sp->u.t.string = MyStrdup( sp->u.t.string);
break;
case SEG_BEZTRK:
case SEG_BEZLIN:
@@ -753,9 +757,9 @@ EXPORT DIST_T DistanceSegs(
for (lin=0;lin<segPtr->u.p.cnt;lin++) {
pt = p0;
if (lin < segPtr->u.p.cnt-1 )
- ddd = LineDistance( &pt, segPtr->u.p.pts[lin], segPtr->u.p.pts[lin+1] );
+ ddd = LineDistance( &pt, segPtr->u.p.pts[lin].pt, segPtr->u.p.pts[lin+1].pt );
else
- ddd = LineDistance( &pt, segPtr->u.p.pts[lin], segPtr->u.p.pts[0] );
+ ddd = LineDistance( &pt, segPtr->u.p.pts[lin].pt, segPtr->u.p.pts[0].pt );
if ( ddd < dd ) {
dd = ddd;
p1 = pt;
@@ -846,7 +850,7 @@ EXPORT ANGLE_T GetAngleSegs(
{
wIndex_t inx;
ANGLE_T angle = 0.0;
- coOrd p0;
+ coOrd p0,p1;
DIST_T d, dd;
segProcData_t segProcData;
coOrd pos2 = * pos1;
@@ -889,15 +893,17 @@ EXPORT ANGLE_T GetAngleSegs(
break;
case SEG_POLY:
case SEG_FILPOLY:
- p0 = pos2;
- dd = LineDistance( &p0, segPtr->u.p.pts[segPtr->u.p.cnt-1], segPtr->u.p.pts[0] );
- angle = FindAngle( segPtr->u.p.pts[segPtr->u.p.cnt-1], segPtr->u.p.pts[0] );
+ p0 = p1 = pos2;
+ dd = LineDistance( &p0, segPtr->u.p.pts[segPtr->u.p.cnt-1].pt, segPtr->u.p.pts[0].pt );
+ angle = FindAngle( segPtr->u.p.pts[segPtr->u.p.cnt-1].pt, segPtr->u.p.pts[0].pt );
for ( inx=0; inx<segPtr->u.p.cnt-1; inx++ ) {
- p0 = pos2;
- d = LineDistance( &p0, segPtr->u.p.pts[inx], segPtr->u.p.pts[inx+1] );
+ p0 = p1;
+ d = LineDistance( &p0, segPtr->u.p.pts[inx].pt, segPtr->u.p.pts[inx+1].pt );
if ( d < dd ) {
dd = d;
- angle = FindAngle( segPtr->u.p.pts[inx], segPtr->u.p.pts[inx+1] );
+ angle = FindAngle( segPtr->u.p.pts[inx].pt, segPtr->u.p.pts[inx+1].pt );
+ if (subSegInxR) *subSegInxR = inx;
+ pos2 = p0;
}
}
break;
@@ -1125,14 +1131,14 @@ static void AppendPath( signed char c )
EXPORT BOOL_T ReadSegs( void )
{
char *cp, *cpp;
- BOOL_T rc=FALSE;
+ BOOL_T rc=TRUE;
trkSeg_p s;
trkEndPt_p e;
long rgb;
int i;
DIST_T elev0, elev1;
BOOL_T hasElev;
- BOOL_T isPolyV2, noVersion;
+ BOOL_T isPolyV1, isPolyV2;
BOOL_T improvedEnds;
FLOAT_T ignoreFloat;
char type;
@@ -1146,14 +1152,13 @@ EXPORT BOOL_T ReadSegs( void )
DYNARR_RESET( trkSeg_t, tempSegs_da );
DYNARR_RESET( trkEndPt_t, tempEndPts_da );
pathCnt = 0;
- while ( (cp = GetNextLine()) != NULL ) {
+ AppendPath(0); // End of all paths
+ while ( rc && ((cp = GetNextLine()) != NULL) ) {
while (isspace(*cp)) cp++;
hasElev = FALSE;
improvedEnds = FALSE;
- if ( strncmp( cp, "END", 3 ) == 0 ) {
- rc = TRUE;
- subsegs = FALSE;
- break;
+ if ( IsEND( END_SEGS ) ) {
+ return TRUE;
}
if ( strncmp(cp, "SUBSEGS", 7) == 0) {
subsegs = TRUE;
@@ -1163,24 +1168,22 @@ EXPORT BOOL_T ReadSegs( void )
subsegs = FALSE;
continue;
}
- if ( *cp == '\n' || *cp == '#' ) {
+ if ( *cp == '\0' || *cp == '\n' || *cp == '#' ) {
continue;
}
+ if (subsegs) continue;
type = *cp++;
- hasElev = FALSE;
- noVersion = TRUE;
- if ( *cp != ' ')
- noVersion = FALSE;
- if ( *cp == '3' ) {
- cp++;
- hasElev = TRUE;
- }
- isPolyV2 = FALSE;
- if (*cp == '4') {
- cp++;
- hasElev = TRUE;
- isPolyV2 = TRUE;
- improvedEnds = TRUE;
+ improvedEnds = isPolyV2 = hasElev = isPolyV1 = FALSE;
+ if ( isdigit( *cp ) ) {
+ long iVersion = strtol( cp, &cp, 10 );
+ if ( iVersion >= 3 )
+ hasElev = isPolyV1 = TRUE;
+ if ( iVersion >= 4 )
+ improvedEnds = isPolyV2 = TRUE;
+ if ( iVersion > 4 ) {
+ InputError( "Invalid segment version number, maximum is %d", TRUE, 4 );
+ break;
+ }
}
switch (type) {
case SEG_STRLIN:
@@ -1341,34 +1344,28 @@ EXPORT BOOL_T ReadSegs( void )
s = &tempSegs(tempSegs_da.cnt-1);
s->type = type;
s->u.p.polyType = FREEFORM;
- if (isPolyV2) {
- if ( !GetArgs( cp, "lwdd",
- &rgb, &s->width,
- &s->u.p.cnt, &s->u.p.polyType) ) {
- rc = FALSE;
- /*??*/break;
- }
- } else {
- if ( !GetArgs( cp, "lwd",
- &rgb, &s->width,
- &s->u.p.cnt) ) {
- rc = FALSE;
- /*??*/break;
- }
+ if ( !GetArgs( cp,
+ isPolyV2?"lwdd":"lwdX",
+ &rgb,
+ &s->width,
+ &s->u.p.cnt,
+ &s->u.p.polyType) ) {
+ rc = FALSE;
+ /*??*/break;
}
s->color = wDrawFindColor( rgb );
- s->u.p.pts = (coOrd*)MyMalloc( s->u.p.cnt * sizeof (coOrd) );
+ s->u.p.pts = (pts_t*)MyMalloc( s->u.p.cnt * sizeof (pts_t) );
for ( i=0; i<s->u.p.cnt; i++ ) {
cp = GetNextLine();
- if (cp == NULL || !GetArgs( cp, "p", &s->u.p.pts[i])) {
+ if (cp == NULL ||
+ !GetArgs( cp,
+// TODO: does elev belong here instead of the seg header?
+ isPolyV2?"pdY":isPolyV1?"pXf":"pXY",
+ &s->u.p.pts[i].pt,
+ &s->u.p.pts[i].pt_type,
+ &elev0 )) {
rc = FALSE;
}
- if (!noVersion) {
- if (cp == NULL || !GetArgs( cp, hasElev?"f":"Y", &elev0 ) ) {
- rc = FALSE;
- /*??*/break;
- }
- }
}
s->u.p.angle = 0.0;
s->u.p.orig = zero;
@@ -1378,14 +1375,11 @@ EXPORT BOOL_T ReadSegs( void )
s = &tempSegs(tempSegs_da.cnt-1);
s->type = type;
s->u.t.fontP = NULL;
- char * expandedText;
- if ( !GetArgs( cp, "lpf0fq", &rgb, &s->u.t.pos, &s->u.t.angle, &s->u.t.fontSize, &expandedText ) ) {
+ if ( !GetArgs( cp, "lpfdfq", &rgb, &s->u.t.pos, &s->u.t.angle, &s->u.t.boxed, &s->u.t.fontSize, &plain_text ) ) {
rc = FALSE;
/*??*/break;
}
- plain_text = ConvertFromEscapedText(expandedText);
- s->u.t.string = plain_text;
- MyFree(expandedText);
+ s->u.t.string = MyStrdup(plain_text);
s->color = wDrawFindColor( rgb );
break;
case SEG_UNCEP:
@@ -1455,18 +1449,20 @@ EXPORT BOOL_T ReadSegs( void )
case SEG_PATH:
while (isspace(*cp)) cp++;
if (*cp == '\"') cp++;
- while ( *cp != '\"') AppendPath((signed char)*cp++);
- AppendPath(0);
+ pathCnt--; // Overwrite previous terminator
+ while ( *cp != '\"') AppendPath((signed char)*cp++); // Name of path
+ AppendPath(0); // End of name
cp++;
while (1) {
i = (int)strtol(cp, &cpp, 10);
if (cp == cpp)
/*??*/break;
cp = cpp;
- AppendPath( (signed char)i );
+ AppendPath( (signed char)i ); // Segment # of path component
}
- AppendPath( 0 );
- AppendPath( 0 );
+ AppendPath( 0 ); // End of last path components
+ AppendPath( 0 ); // End of path
+ AppendPath( 0 ); // End of all paths
break;
case SEG_SPEC:
strncpy( tempSpecial, cp+1, sizeof tempSpecial - 1 );
@@ -1481,11 +1477,18 @@ EXPORT BOOL_T ReadSegs( void )
}
break;
default:
+ InputError( "Unknown segment type: %c", TRUE, type );
+ rc = FALSE;
break;
}
}
- AppendPath( 0 );
- return rc;
+// We've hit an InputError.
+// The user may have chosen to not continue (paramFile == NULL)
+// Otherwise we have to flush until we see END$SEGS
+
+ while ( GetNextLine() && !IsEND( END_SEGS ) ); // Chomp, Chomp
+
+ return FALSE;
}
EXPORT BOOL_T WriteSegs(
@@ -1559,7 +1562,8 @@ EXPORT BOOL_T WriteSegsEnd(
case SEG_BEZTRK:
case SEG_BEZLIN:
rc &= fprintf( f, "\t%c3 %ld %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f\n",
- segs[i].type, wDrawGetRGB(segs[i].color), segs[i].width,
+ segs[i].type, wDrawGetRGB(segs[i].color),
+ segs[i].width,
segs[i].u.l.pos[0].x, segs[i].u.l.pos[0].y,
segs[i].u.l.pos[1].x, segs[i].u.l.pos[1].y,
segs[i].u.l.pos[2].x, segs[i].u.l.pos[2].y,
@@ -1584,24 +1588,26 @@ EXPORT BOOL_T WriteSegsEnd(
break;
case SEG_POLY:
case SEG_FILPOLY:
+// TODO: to be consistent, we should add a dummy 0 for elev. See ReadSegs/SEG_POLY
rc &= fprintf( f, "\t%c4 %ld %0.6f %d %d \n",
segs[i].type, wDrawGetRGB(segs[i].color), segs[i].width,
segs[i].u.p.cnt, segs[i].u.p.polyType ) > 0;
for ( j=0; j<segs[i].u.p.cnt; j++ )
- rc &= fprintf( f, "\t\t%0.6f %0.6f 0\n",
- segs[i].u.p.pts[j].x, segs[i].u.p.pts[j].y ) > 0;
+ rc &= fprintf( f, "\t\t%0.6f %0.6f %d\n",
+ segs[i].u.p.pts[j].pt.x, segs[i].u.p.pts[j].pt.y, segs[i].u.p.pts[j].pt_type ) > 0;
break;
case SEG_TEXT: /* 0pf0fq */
escaped_text = ConvertToEscapedText(segs[i].u.t.string);
- rc &= fprintf( f, "\t%c %ld %0.6f %0.6f %0.6f 0 %0.6f \"%s\"\n",
+ rc &= fprintf( f, "\t%c %ld %0.6f %0.6f %0.6f %d %0.6f \"%s\"\n",
segs[i].type, wDrawGetRGB(segs[i].color),
segs[i].u.t.pos.x, segs[i].u.t.pos.y, segs[i].u.t.angle,
+ segs[i].u.t.boxed,
segs[i].u.t.fontSize, escaped_text ) > 0;
MyFree(escaped_text);
break;
}
}
- if (writeEnd) rc &= fprintf( f, "\tEND\n" )>0;
+ if (writeEnd) rc &= fprintf( f, "\t%s\n", END_SEGS )>0;
return rc;
}
@@ -1664,15 +1670,15 @@ EXPORT void DrawDimLine(
if ( ( option & 0x10 ) == 0 ) {
Translate( &p, p0, a0-45, dist );
- DrawLine( d, p0, p, 0, color );
+ DrawLine( d, p0, p, width, color );
Translate( &p, p0, a0+45, dist );
- DrawLine( d, p0, p, 0, color );
+ DrawLine( d, p0, p, width, color );
}
if ( ( option & 0x20 ) == 0 ) {
Translate( &p, p1, a0-135, dist );
- DrawLine( d, p1, p, 0, color );
+ DrawLine( d, p1, p, width, color );
Translate( &p, p1, a0+135, dist );
- DrawLine( d, p1, p, 0, color );
+ DrawLine( d, p1, p, width, color );
}
if ( fs < 2*d->scale ) {
@@ -1686,7 +1692,7 @@ EXPORT void DrawDimLine(
size.y = textsize.y/2.0;
dist1 = FindDistance( zero, size );
if ( dist <= dist1*2 ) {
- DrawLine( d, p0, p1, 0, color );
+ DrawLine( d, p0, p1, width, color );
return;
}
a1 = FindAngle( zero, size );
@@ -1715,11 +1721,11 @@ EXPORT void DrawDimLine(
p = pc;
p.x -= fx*x;
p.y -= fy*y;
- DrawLine( d, p0, p, 0, color );
+ DrawLine( d, p0, p, width, color );
p = pc;
p.x += fx*x;
p.y += fy*y;
- DrawLine( d, p, p1, 0, color );
+ DrawLine( d, p, p1, width, color );
}
/*
@@ -1747,6 +1753,8 @@ EXPORT void DrawSegsO(
long option;
wFontSize_t fs;
+ wBool_t bFill;
+
for (i=0; i<segCnt; i++,segPtr++ ) {
if (color == wDrawColorBlack) {
color1 = segPtr->color;
@@ -1754,60 +1762,10 @@ EXPORT void DrawSegsO(
} else {
color1 = color2 = color;
}
- if ( (options&DTS_TIES)!=0 ) {
- if ( segPtr->color == wDrawColorWhite )
- continue;
- switch (segPtr->type) {
- case SEG_STRTRK:
- REORIGIN( p0, segPtr->u.l.pos[0], angle, orig )
- REORIGIN( p1, segPtr->u.l.pos[1], angle, orig )
- DrawStraightTies( d, trk, p0, p1, color );
- break;
- case SEG_CRVTRK:
- a0 = NormalizeAngle(segPtr->u.c.a0 + angle);
- REORIGIN( c, segPtr->u.c.center, angle, orig );
- DrawCurvedTies( d, trk, c, fabs(segPtr->u.c.radius), a0, segPtr->u.c.a1, color );
- break;
- case SEG_JNTTRK:
- REORIGIN( p0, segPtr->u.j.pos, angle, orig );
- DrawJointTrack( d, p0, NormalizeAngle(segPtr->u.j.angle+angle), segPtr->u.j.l0, segPtr->u.j.l1, segPtr->u.j.R, segPtr->u.j.L, segPtr->u.j.negate, segPtr->u.j.flip, segPtr->u.j.Scurve, trk, -1, -1, trackGauge, color1, options );
- break;
- case SEG_BEZTRK:
- REORIGIN(p0, segPtr->u.b.pos[0], angle, orig);
- REORIGIN(p1, segPtr->u.b.pos[1], angle, orig);
- REORIGIN(p2, segPtr->u.b.pos[2], angle, orig);
- REORIGIN(p3, segPtr->u.b.pos[3], angle, orig);
- tempPtr = segPtr->bezSegs.ptr;
- for(int j=0;j<segPtr->bezSegs.cnt;j++,tempPtr++) { //Loop through sub parts (only Trks supported)
- if (tempPtr->type == SEG_CRVTRK) {
- a0 = NormalizeAngle(tempPtr->u.c.a0 + angle);
- REORIGIN( c, tempPtr->u.c.center, angle, orig );
- DrawCurvedTies( d, trk, c, fabs(tempPtr->u.c.radius), a0, tempPtr->u.c.a1, color );
- }
- if (tempPtr->type == SEG_STRTRK) {
- REORIGIN( p0, tempPtr->u.l.pos[0], angle, orig )
- REORIGIN( p1, tempPtr->u.l.pos[1], angle, orig )
- DrawStraightTies( d, trk, p0, p1, color );
- }
- }
- break;
- }
- continue;
- }
- switch (segPtr->type) {
- case SEG_STRTRK:
- case SEG_CRVTRK:
- case SEG_JNTTRK:
- case SEG_BEZTRK:
- case SEG_TEXT:
- break;
- default:
- if (d->options&DC_QUICK)
- return;
- if ((d->options&DC_SIMPLE) != 0 &&
- trackGauge != 0.0)
- return;
- }
+ wDrawWidth thick = 3;
+#ifdef WINDOWS
+ thick *= (wDrawWidth)(d->dpi/mainD.dpi);
+#endif
switch (segPtr->type) {
case SEG_STRLIN:
case SEG_DIMLIN:
@@ -1824,17 +1782,16 @@ EXPORT void DrawSegsO(
break;
DrawStraightTrack( d,
p0, p1,
- FindAngle(p0, p1 ),
- NULL, trackGauge, color1, options );
+ FindAngle(p1, p0 ),
+ trk, color1, options );
break;
case SEG_STRLIN:
- DrawLine( d, p0, p1, (wDrawWidth)floor(segPtr->width*factor+0.5), color1 );
+ DrawLine( d, p0, p1, (d->options&DC_THICK)?thick:(wDrawWidth)floor(segPtr->width*factor+0.5), color1 );
break;
case SEG_DIMLIN:
case SEG_BENCH:
case SEG_TBLEDGE:
- if ( (d->options&DC_GROUP) ||
- (segPtr->type == SEG_DIMLIN && d->funcs == &tempSegDrawFuncs) ) {
+ if ( (d->options&DC_SEGTRACK) ) {
DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 );
tempPtr = &tempSegs(tempSegs_da.cnt-1);
memcpy( tempPtr, segPtr, sizeof segPtr[0] );
@@ -1848,7 +1805,7 @@ EXPORT void DrawSegsO(
fs /= (option==0?8:option==1?4:option==2?2:1);
if ( fs < 2 )
fs = 2;
- DrawDimLine( d, p0, p1, FormatDistance(FindDistance(p0,p1)), fs, 0.5, 0, color, option & 0x00 );
+ DrawDimLine( d, p0, p1, FormatDistance(FindDistance(p0,p1)), fs, 0.5, (d->options&DC_THICK)?thick:0, color, option & 0x00 );
break;
case SEG_BENCH:
DrawBench( d, p0, p1, color1, color2, options, segPtr->u.l.option );
@@ -1876,10 +1833,10 @@ EXPORT void DrawSegsO(
fabs(segPtr->u.c.radius),
a0, segPtr->u.c.a1,
p0, p1,
- NULL, trackGauge, color1, options );
+ trk, color1, options );
} else {
DrawArc( d, c, fabs(segPtr->u.c.radius), a0, segPtr->u.c.a1,
- FALSE, (wDrawWidth)floor(segPtr->width*factor+0.5), color1 );
+ FALSE, (d->options&DC_THICK)?thick:(wDrawWidth)floor(segPtr->width*factor+0.5), color1 );
}
break;
case SEG_BEZTRK:
@@ -1889,7 +1846,7 @@ EXPORT void DrawSegsO(
color1 = normalColor;
if ( segPtr->color == wDrawColorWhite )
break;
- }
+ } else
REORIGIN(p0, segPtr->u.b.pos[0], angle, orig);
REORIGIN(p1, segPtr->u.b.pos[1], angle, orig);
REORIGIN(p2, segPtr->u.b.pos[2], angle, orig);
@@ -1911,10 +1868,10 @@ EXPORT void DrawSegsO(
fabs(tempPtr->u.c.radius),
a0, tempPtr->u.c.a1,
p0, p1,
- NULL, trackGauge, color1, options );
+ trk, color1, options );
} else if (tempPtr->type == SEG_CRVLIN) {
DrawArc( d, c, fabs(tempPtr->u.c.radius), a0, tempPtr->u.c.a1,
- FALSE, (wDrawWidth)floor(tempPtr->width*factor+0.5), color1 );
+ FALSE, (d->options&DC_THICK)?thick:(wDrawWidth)floor(tempPtr->width*factor+0.5), color1 );
}
break;
case SEG_STRTRK:
@@ -1922,15 +1879,14 @@ EXPORT void DrawSegsO(
if ( tempPtr->color == wDrawColorWhite ) break;
REORIGIN(p0,tempPtr->u.l.pos[0], angle, orig);
REORIGIN(p1,tempPtr->u.l.pos[1], angle, orig);
- DrawStraightTrack( d,
- p0, p1,
- FindAngle(p0, p1 ),
- NULL, trackGauge, color1, options );
+ DrawStraightTrack( d, p0, p1,
+ FindAngle(p1, p0 ),
+ trk, color1, options );
break;
case SEG_STRLIN:
REORIGIN(p0,tempPtr->u.l.pos[0], angle, orig);
REORIGIN(p1,tempPtr->u.l.pos[1], angle, orig);
- DrawLine( d, p0, p1, (wDrawWidth)floor(tempPtr->width*factor+0.5), color1 );
+ DrawLine( d, p0, p1, (d->options&DC_THICK)?thick:(wDrawWidth)floor(tempPtr->width*factor+0.5), color1 );
break;
}
}
@@ -1941,48 +1897,37 @@ EXPORT void DrawSegsO(
break;
case SEG_TEXT:
REORIGIN( p0, segPtr->u.t.pos, angle, orig )
- DrawMultiString( d, p0, segPtr->u.t.string, segPtr->u.t.fontP, segPtr->u.t.fontSize, color1, NormalizeAngle(angle + segPtr->u.t.angle), NULL, NULL );
+ DrawMultiString( d, p0, segPtr->u.t.string, segPtr->u.t.fontP, segPtr->u.t.fontSize, color1, NormalizeAngle(angle + segPtr->u.t.angle), NULL, NULL, segPtr->u.t.boxed );
break;
case SEG_FILPOLY:
- if ( (d->options&DC_GROUP) == 0 &&
- d->funcs != &tempSegDrawFuncs ) {
- /* Note: if we call tempSegDrawFillPoly we get a nasty bug
- /+ because we don't make a private copy of p.pts */
- coOrd *tempPts = malloc(sizeof(coOrd)*segPtr->u.p.cnt);
-// coOrd tempPts[segPtr->u.p.cnt];
- for (j=0;j<segPtr->u.p.cnt;j++) {
- REORIGIN( tempPts[j], segPtr->u.p.pts[j], angle, orig );
- }
- DrawFillPoly( d, segPtr->u.p.cnt, tempPts, color1 );
- free(tempPts);
- break;
- } /* else fall thru */
case SEG_POLY:
- if ( (d->options&DC_GROUP) ) {
- DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 );
- tempPtr = &tempSegs(tempSegs_da.cnt-1);
- memcpy( tempPtr, segPtr, sizeof segPtr[0] );
- tempPtr->u.p.orig = orig;
- tempPtr->u.p.angle = angle;
- break;
- }
- REORIGIN( p0, segPtr->u.p.pts[0], angle, orig )
- c = p0;
- for (j=1; j<segPtr->u.p.cnt; j++) {
- REORIGIN( p1, segPtr->u.p.pts[j], angle, orig );
- DrawLine( d, p0, p1, (wDrawWidth)floor(segPtr->width*factor+0.5), color1 );
- p0 = p1;
+ ;
+ /* Note: if we call tempSegDrawFillPoly we get a nasty bug
+ /+ because we don't make a private copy of p.pts */
+ coOrd *tempPts = malloc(sizeof(coOrd)*segPtr->u.p.cnt);
+ int *tempTypes = malloc(sizeof(int)*segPtr->u.p.cnt);
+// coOrd tempPts[segPtr->u.p.cnt];
+ for (j=0;j<segPtr->u.p.cnt;j++) {
+ REORIGIN( tempPts[j], segPtr->u.p.pts[j].pt, angle, orig );
+ tempTypes[j] = segPtr->u.p.pts[j].pt_type;
}
- DrawLine( d, p0, c, (wDrawWidth)floor(segPtr->width*factor+0.5), color1 );
+ bFill = (segPtr->type == SEG_FILPOLY);
+ if ( (d->options&DC_SIMPLE) && programMode != MODE_TRAIN )
+ bFill = FALSE;
+ DrawPoly( d, segPtr->u.p.cnt, tempPts, tempTypes, color1, (d->options&DC_THICK)?thick:(wDrawWidth)floor(segPtr->width*factor+0.5), bFill?1:0, segPtr->u.p.polyType==POLYLINE?1:0);
+ free(tempPts);
+ free(tempTypes);
break;
case SEG_FILCRCL:
REORIGIN( c, segPtr->u.c.center, angle, orig )
- if ( (d->options&DC_GROUP) != 0 ||
- d->funcs != &tempSegDrawFuncs ) {
+ bFill = TRUE;
+ if ( (d->options&DC_SIMPLE) && programMode != MODE_TRAIN )
+ bFill = FALSE;
+ if ( bFill ) {
DrawFillCircle( d, c, fabs(segPtr->u.c.radius), color1 );
} else {
DrawArc( d, c, fabs(segPtr->u.c.radius), 0, 360,
- FALSE, (wDrawWidth)0, color1 );
+ FALSE, (d->options&DC_THICK)?thick:(wDrawWidth)0, color1 );
}
break;
}
@@ -2003,7 +1948,8 @@ EXPORT void DrawSegs(
DIST_T trackGauge,
wDrawColor color )
{
- DrawSegsO( d, NULL, orig, angle, segPtr, segCnt, trackGauge, color, 0 );
+
+ DrawSegsO( d, NULL, orig, angle, segPtr, segCnt, trackGauge, color, DTS_LEFT|DTS_RIGHT );
}
/*
@@ -2031,16 +1977,170 @@ EXPORT void CleanSegs(dynArr_t * seg_p) {
seg_p->max = 0;
}
+/*
+ * Copy Segs from one array to another
+ */
+EXPORT void AppendSegsToArray(dynArr_t * seg_to, dynArr_t * seg_from) {
+ if (seg_from->cnt ==0) return;
+ int j = 0;
+ DYNARR_APPEND(trkSeg_t, * seg_to, seg_from->cnt);
+ for (int i=0; i<seg_from->cnt;i++,j++) {
+ trkSeg_p from_p = &DYNARR_N(trkSeg_t, * seg_from,j);
+ trkSeg_p to_p = &DYNARR_N(trkSeg_t, * seg_to,i);
+ memcpy((void *)to_p,(void *)from_p,sizeof( trkSeg_t));
+ if (from_p->type == SEG_BEZLIN || from_p->type == SEG_BEZTRK) {
+ if (from_p->bezSegs.ptr) {
+ to_p->bezSegs.ptr = memdup(from_p->bezSegs.ptr,from_p->bezSegs.cnt*sizeof(trkSeg_t));
+ }
+ }
+ if (from_p->type == SEG_POLY || from_p->type == SEG_FILPOLY) {
+ if (from_p->u.p.pts) {
+ to_p->u.p.pts = memdup(from_p->u.p.pts,from_p->u.p.cnt*sizeof(pts_t));
+ }
+ }
+ }
+}
+
+EXPORT void AppendTransformedSegs(dynArr_t * seg_to, dynArr_t * seg_from, coOrd orig, coOrd rotateOrig, ANGLE_T angle) {
+ if (seg_from->cnt ==0) return;
+ int j = 0;
+ DYNARR_APPEND(trkSeg_t, * seg_to, seg_from->cnt);
+ for (int i=0; i<seg_from->cnt;i++,j++) {
+ trkSeg_p from_p = &DYNARR_N(trkSeg_t, * seg_from,j);
+ trkSeg_p to_p = &DYNARR_N(trkSeg_t, * seg_to,i);
+ memcpy((void *)to_p,(void *)from_p,sizeof( trkSeg_t));
+ if (from_p->type == SEG_BEZLIN || from_p->type == SEG_BEZTRK) {
+ if (from_p->bezSegs.ptr) {
+ to_p->bezSegs.ptr = memdup(from_p->bezSegs.ptr,from_p->bezSegs.cnt*sizeof(trkSeg_t));
+ }
+ }
+ if (from_p->type == SEG_POLY || from_p->type == SEG_FILPOLY) {
+ if (from_p->u.p.pts) {
+ to_p->u.p.pts = memdup(from_p->u.p.pts,from_p->u.p.cnt*sizeof(pts_t));
+ }
+ }
+ RotateSegs(1,to_p,rotateOrig,angle);
+ coOrd move;
+ move.x = orig.x - rotateOrig.x;
+ move.y = orig.y - rotateOrig.y;
+ MoveSegs(1,to_p,move);
+ }
+}
+
EXPORT void CopyPoly(trkSeg_p p, wIndex_t segCnt) {
- coOrd * newPts;
+ pts_t * newPts;
for (int i=0;i<segCnt;i++,p++) {
- if (p->type == SEG_POLY || p->type == SEG_FILPOLY) {
- newPts = memdup( p->u.p.pts, p->u.p.cnt*sizeof (coOrd) );
+ if ((p->type == SEG_POLY) || (p->type == SEG_FILPOLY)) {
+ newPts = memdup( p->u.p.pts, p->u.p.cnt*sizeof (pts_t) );
p->u.p.pts = newPts;
}
+ if ( p->type == SEG_TEXT ) {
+ p->u.t.string = MyStrdup( p->u.t.string );
+ }
}
}
-
-
+EXPORT wBool_t CompareSegs(
+ trkSeg_p segPtr1,
+ int segCnt1,
+ trkSeg_p segPtr2,
+ int segCnt2 )
+{
+ char * cp = message+strlen(message);
+ if ( segCnt1 != segCnt2 ) {
+ sprintf( cp, "SegCnt %d %d\n", segCnt1, segCnt2 );
+ return FALSE;
+ }
+ char * cq = cp-2;;
+ for ( int segInx = 0; segInx < segCnt1; segInx++ ) {
+ cp = cq;
+ sprintf( cp, "SEG:%d - ", segInx );
+ cp += strlen( cp );
+ trkSeg_p segP1 = &segPtr1[segInx];
+ trkSeg_p segP2 = &segPtr2[segInx];
+ REGRESS_CHECK_INT( "Type", segP1, segP2, type );
+ REGRESS_CHECK_COLOR( "Color", segP1, segP2, color );
+ switch( segP1->type ) {
+ case SEG_DIMLIN:
+ case SEG_TBLEDGE:
+ case SEG_BENCH:
+ // These don't have widths
+ break;
+ default:
+ REGRESS_CHECK_WIDTH( "Width", segP1, segP2, width );
+ }
+ switch( segP1->type ) {
+ case SEG_DIMLIN:
+ case SEG_TBLEDGE:
+ // These don't have color
+ break;
+ default:
+ REGRESS_CHECK_COLOR( "Color", segP1, segP2, color );
+ }
+ switch( segP1->type ) {
+ case SEG_STRTRK:
+ case SEG_STRLIN:
+ case SEG_DIMLIN:
+ case SEG_BENCH:
+ case SEG_TBLEDGE:
+ REGRESS_CHECK_POS( "Pos[0]", segP1, segP2, u.l.pos[0] )
+ REGRESS_CHECK_POS( "Pos[1]", segP1, segP2, u.l.pos[1] )
+// REGRESS_CHECK_POS( "Pos[2]", segP1, segP2, u.l.pos[2] )
+// REGRESS_CHECK_POS( "Pos[3]", segP1, segP2, u.l.pos[3] )
+ REGRESS_CHECK_ANGLE( "Angle", segP1, segP2, u.l.angle )
+ REGRESS_CHECK_INT( "Option", segP1, segP2, u.l.option )
+ break;
+ case SEG_BEZTRK:
+ case SEG_BEZLIN:
+ break; // u.b
+ case SEG_CRVLIN:
+ case SEG_CRVTRK:
+ case SEG_FILCRCL:
+ REGRESS_CHECK_POS( "Center", segP1, segP2, u.c.center )
+ REGRESS_CHECK_ANGLE( "A0", segP1, segP2, u.c.a0 )
+ REGRESS_CHECK_ANGLE( "A1", segP1, segP2, u.c.a1 )
+ REGRESS_CHECK_DIST( "Radius", segP1, segP2, u.c.radius )
+ break; // u.c
+ case SEG_JNTTRK:
+ REGRESS_CHECK_POS( "Pos", segP1, segP2, u.j.pos )
+ REGRESS_CHECK_ANGLE( "Angle", segP1, segP2, u.j.angle )
+ REGRESS_CHECK_DIST( "R", segP1, segP2, u.j.R )
+ REGRESS_CHECK_DIST( "L", segP1, segP2, u.j.L )
+ REGRESS_CHECK_DIST( "L0", segP1, segP2, u.j.l0 )
+ REGRESS_CHECK_DIST( "L1", segP1, segP2, u.j.l1 );
+ REGRESS_CHECK_INT( "Flip", segP1, segP2, u.j.flip )
+ REGRESS_CHECK_INT( "Negate", segP1, segP2, u.j.negate )
+ REGRESS_CHECK_INT( "Scurve", segP1, segP2, u.j.Scurve )
+ break; // u.j
+ case SEG_TEXT:
+ REGRESS_CHECK_POS( "Pos", segP1, segP2, u.t.pos )
+ REGRESS_CHECK_ANGLE( "Angle", segP1, segP2, u.t.angle )
+ // CHECK fontP
+ REGRESS_CHECK_DIST( "Fontsize", segP1, segP2, u.t.fontSize )
+ REGRESS_CHECK_INT( "Boxed", segP1, segP2, u.t.boxed )
+ // CHECK string
+ break; // u.t
+ case SEG_POLY:
+ case SEG_FILPOLY:
+ REGRESS_CHECK_INT( "Cnt", segP1, segP2, u.p.cnt )
+ // CHECK pts
+ REGRESS_CHECK_POS( "Orig", segP1, segP2, u.p.orig )
+ REGRESS_CHECK_ANGLE( "Angle", segP1, segP2, u.p.angle )
+ break; // u.p
+ // EndPts
+ case SEG_UNCEP:
+ case SEG_CONEP:
+ break;
+ // Turnout/Struct
+ case SEG_PATH:
+ case SEG_SPEC:
+ case SEG_CUST:
+ case SEG_DOFF:
+ break;
+ default:
+ break;
+ }
+ }
+ return TRUE;
+}
diff --git a/app/bin/tstraigh.c b/app/bin/tstraigh.c
index 5cf1cda..f9b666f 100644
--- a/app/bin/tstraigh.c
+++ b/app/bin/tstraigh.c
@@ -163,7 +163,7 @@ static void UpdateStraight( track_p trk, int inx, descData_p descUpd, BOOL_T fin
case Z1:
ep = (inx==Z0?0:1);
UpdateTrkEndElev( trk, ep, GetTrkEndElevUnmaskedMode(trk,ep), strData.elev[ep], NULL );
- ComputeElev( trk, 1-ep, FALSE, &strData.elev[1-ep], NULL );
+ ComputeElev( trk, 1-ep, FALSE, &strData.elev[1-ep], NULL, TRUE );
if ( strData.length > minLength )
strData.grade = fabs( (strData.elev[0]-strData.elev[1])/strData.length )*100.0;
else
@@ -242,8 +242,8 @@ static void DescribeStraight( track_p trk, char * str, CSIZE_T len )
fix1 = GetTrkEndTrk(trk,1)!=NULL;
strData.endPt[0] = GetTrkEndPos(trk,0);
strData.endPt[1] = GetTrkEndPos(trk,1);
- ComputeElev( trk, 0, FALSE, &strData.elev[0], NULL );
- ComputeElev( trk, 1, FALSE, &strData.elev[1], NULL );
+ ComputeElev( trk, 0, FALSE, &strData.elev[0], NULL, FALSE );
+ ComputeElev( trk, 1, FALSE, &strData.elev[1], NULL, FALSE );
strData.length = FindDistance( strData.endPt[0], strData.endPt[1] );
strData.layerNumber = GetTrkLayer(trk);
if ( strData.length > minLength )
@@ -274,18 +274,12 @@ static DIST_T DistanceStraight( track_p t, coOrd * p )
static void DrawStraight( track_p t, drawCmd_p d, wDrawColor color )
{
- long widthOptions = DTS_LEFT|DTS_RIGHT|DTS_TIES;
- if (GetTrkWidth(t) == 2)
- widthOptions |= DTS_THICK2;
- if (GetTrkWidth(t) == 3)
- widthOptions |= DTS_THICK3;
+ long widthOptions = DTS_LEFT|DTS_RIGHT;
DrawStraightTrack( d, GetTrkEndPos(t,0), GetTrkEndPos(t,1),
GetTrkEndAngle(t,0),
- t, GetTrkGauge(t), color, widthOptions );
- if ( (d->funcs->options & wDrawOptTemp) == 0 && (d->options & DC_QUICK) == 0 ) {
- DrawEndPt( d, t, 0, color );
- DrawEndPt( d, t, 1, color );
- }
+ t, color, widthOptions );
+ DrawEndPt( d, t, 0, color );
+ DrawEndPt( d, t, 1, color );
}
static void DeleteStraight( track_p t )
@@ -297,14 +291,14 @@ static BOOL_T WriteStraight( track_p t, FILE * f )
BOOL_T rc = TRUE;
rc &= fprintf(f, "STRAIGHT %d %d %ld 0 0 %s %d\n",
GetTrkIndex(t), GetTrkLayer(t), (long)GetTrkWidth(t),
- GetTrkScaleName(t), GetTrkVisible(t) )>0;
+ GetTrkScaleName(t), GetTrkVisible(t)|(GetTrkNoTies(t)?1<<2:0)|(GetTrkBridge(t)?1<<3:0) )>0;
rc &= WriteEndPt( f, t, 0 );
rc &= WriteEndPt( f, t, 1 );
- rc &= fprintf(f, "\tEND\n" )>0;
+ rc &= fprintf(f, "\t%s\n", END_SEGS)>0;
return rc;
}
-static void ReadStraight( char * line )
+static BOOL_T ReadStraight( char * line )
{
track_p trk;
wIndex_t index;
@@ -314,15 +308,25 @@ static void ReadStraight( char * line )
long options;
if ( !GetArgs( line+8, paramVersion<3?"dXZsd":"dLl00sd", &index, &layer, &options, scale, &visible ) )
- return;
+ return FALSE;
+ if ( !ReadSegs() )
+ return FALSE;
trk = NewTrack( index, T_STRAIGHT, 0, 0 );
SetTrkScale( trk, LookupScale(scale) );
- SetTrkVisible(trk, visible);
+ if ( paramVersion < 3 ) {
+ SetTrkVisible(trk, visible!=0);
+ SetTrkNoTies(trk, FALSE);
+ SetTrkBridge(trk, FALSE);
+ } else {
+ SetTrkVisible(trk, visible&2);
+ SetTrkNoTies(trk, visible&4);
+ SetTrkBridge(trk, visible&8);
+ }
SetTrkLayer(trk, layer);
SetTrkWidth( trk, (int)(options&3) );
- ReadSegs();
SetEndPts( trk, 2 );
ComputeBoundingBox( trk );
+ return TRUE;
}
static void MoveStraight( track_p trk, coOrd orig )
@@ -362,11 +366,16 @@ static BOOL_T SplitStraight( track_p trk, coOrd pos, EPINX_T ep, track_p *leftov
{
track_p trk1;
- trk1 = NewStraightTrack( GetTrkEndPos(trk,ep), pos );
+ trk1 = NewStraightTrack( 1-ep?GetTrkEndPos(trk,ep):pos, 1-ep?pos:GetTrkEndPos(trk,ep) );
+ DIST_T height;
+ int opt;
+ GetTrkEndElev(trk,ep,&opt,&height);
+ UpdateTrkEndElev( trk1, ep, opt, height, (opt==ELEV_STATION)?GetTrkEndElevStation(trk,ep):NULL );
AdjustStraightEndPt( trk, ep, pos );
+ UpdateTrkEndElev( trk, ep, ELEV_NONE, 0, NULL);
*leftover = trk1;
- *ep0 = 1;
- *ep1 = 0;
+ *ep0 = 1-ep;
+ *ep1 = ep;
return TRUE;
}
@@ -413,7 +422,7 @@ static BOOL_T EnumerateStraight( track_p trk )
return TRUE;
}
-static BOOL_T TrimStraight( track_p trk, EPINX_T ep, DIST_T dist )
+static BOOL_T TrimStraight( track_p trk, EPINX_T ep, DIST_T dist, coOrd endpos, ANGLE_T angle, DIST_T radius, coOrd center )
{
DIST_T d;
ANGLE_T a;
@@ -427,8 +436,10 @@ static BOOL_T TrimStraight( track_p trk, EPINX_T ep, DIST_T dist )
UndrawNewTrack( trk );
AdjustStraightEndPt( trk, ep, pos );
DrawNewTrack( trk );
- } else
+ } else {
+ UndrawNewTrack( trk );
DeleteTrack( trk, TRUE );
+ }
return TRUE;
}
@@ -493,6 +504,7 @@ BOOL_T ExtendStraightToJoin(
DisconnectTracks( trk1, 1-ep1, trk1x, ep1x );
}
if (trk2) {
+ UndrawNewTrack( trk1 );
DeleteTrack( trk1, TRUE );
} else {
trk2 = trk1;
@@ -555,17 +567,13 @@ static STATUS_T ModifyStraight( track_p trk, wAction_t action, coOrd pos )
if (action == C_MOVE)
InfoMessage( _("Straight: Length=%s Angle=%0.3f"),
FormatDistance( d ), PutAngle( GetTrkEndAngle( trk, ep ) ) );
- MainRedraw();
- MapRedraw();
return C_CONTINUE;
case C_UP:
if (valid)
AdjustStraightEndPt( trk, ep, tempSegs(0).u.l.pos[1] );
tempSegs_da.cnt = 0;
- DrawNewTrack( trk );
- MainRedraw();
- MapRedraw();
+ DrawNewTrack( trk );
return C_TERMINATE;
default:
@@ -584,9 +592,8 @@ static DIST_T GetLengthStraight( track_p trk )
static BOOL_T GetParamsStraight( int inx, track_p trk, coOrd pos, trackParams_t * params )
{
params->type = curveTypeStraight;
- if ( inx == PARAMS_PARALLEL ) {
- params->ep = 0;
- } else if (inx == PARAMS_CORNU ){
+ if ( inx == PARAMS_NODES ) return FALSE;
+ if ((inx == PARAMS_CORNU) || (inx == PARAMS_1ST_JOIN) || (inx == PARAMS_2ND_JOIN) ){
params->ep = PickEndPoint( pos, trk);
params->arcP = zero;
params->arcR = 0.0;
@@ -627,6 +634,7 @@ static BOOL_T QueryStraight( track_p trk, int query )
case Q_ISTRACK:
case Q_CORNU_CAN_MODIFY:
case Q_MODIFY_CAN_SPLIT:
+ case Q_CAN_EXTEND:
return TRUE;
default:
return FALSE;
@@ -647,9 +655,11 @@ static BOOL_T MakeParallelStraight(
track_p trk,
coOrd pos,
DIST_T sep,
+ DIST_T factor,
track_p * newTrkR,
coOrd * p0R,
- coOrd * p1R )
+ coOrd * p1R,
+ BOOL_T track)
{
ANGLE_T angle = GetTrkEndAngle(trk,1);
coOrd p0, p1;
@@ -660,12 +670,23 @@ static BOOL_T MakeParallelStraight(
Translate( &p0, GetTrkEndPos(trk,0), angle, sep );
Translate( &p1, GetTrkEndPos(trk,1), angle, sep );
if ( newTrkR ) {
- *newTrkR = NewStraightTrack( p0, p1 );
+ if (track)
+ *newTrkR = NewStraightTrack( p0, p1 );
+ else {
+ tempSegs(0).color = wDrawColorBlack;
+ tempSegs(0).width = 0;
+ tempSegs_da.cnt = 1;
+ tempSegs(0).type = SEG_STRLIN;
+ tempSegs(0).u.l.pos[0] = p0;
+ tempSegs(0).u.l.pos[1] = p1;
+ *newTrkR = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) );
+ }
+
} else {
tempSegs(0).color = wDrawColorBlack;
tempSegs(0).width = 0;
tempSegs_da.cnt = 1;
- tempSegs(0).type = SEG_STRTRK;
+ tempSegs(0).type = track?SEG_STRTRK:SEG_STRLIN;
tempSegs(0).u.l.pos[0] = p0;
tempSegs(0).u.l.pos[1] = p1;
}
@@ -675,6 +696,12 @@ static BOOL_T MakeParallelStraight(
}
+static wBool_t CompareStraight( track_cp trk1, track_cp trk2 )
+{
+ return TRUE;
+}
+
+
static trackCmd_t straightCmds = {
"STRAIGHT",
DrawStraight,
@@ -704,8 +731,13 @@ static trackCmd_t straightCmds = {
NULL,
NULL,
NULL,
- MakeParallelStraight };
-
+ MakeParallelStraight,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CompareStraight };
EXPORT void StraightSegProc(
segProc_e cmd,
@@ -810,6 +842,8 @@ EXPORT void StraightSegProc(
*/
+
+
track_p NewStraightTrack( coOrd p0, coOrd p1 )
{
track_p t;
diff --git a/app/bin/unittest/CMakeLists.txt b/app/bin/unittest/CMakeLists.txt
index 32e2ddb..7055d0b 100644
--- a/app/bin/unittest/CMakeLists.txt
+++ b/app/bin/unittest/CMakeLists.txt
@@ -1,10 +1,10 @@
# build unit tests for the xtrkcad library
-add_executable(dxfformattest
+add_executable(dxfformattest
dxfformattest.c
../dxfformat.c
)
-
+
target_link_libraries(dxfformattest
dynstring
${LIBS})
@@ -29,3 +29,35 @@ target_link_libraries(defaultstest
${LIBS})
add_test(DefaultsTest defaultstest)
+
+add_executable(shortentest
+ shortentest.c
+ ../shortentext.c
+ )
+
+target_link_libraries(shortentest
+ ${LIBS})
+
+add_test(ShortenTest shortentest)
+
+add_test(CatalogTest catalogtest)
+
+set (TESTXTP
+ "atl83ho.xtp" "atlasn.xtp" "HO-Peco-Code83.xtp"
+ )
+
+foreach(testfile IN LISTS TESTXTP )
+ configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/testfiles/${testfile}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ COPYONLY )
+endforeach()
+
+add_executable(catalogtest
+ catalogtest.c
+ ../partcatalog.c
+ ../paths.c
+ )
+
+target_link_libraries(catalogtest
+ dynstring
+ ${LIBS}) \ No newline at end of file
diff --git a/app/bin/unittest/catalogtest.c b/app/bin/unittest/catalogtest.c
new file mode 100644
index 0000000..6025990
--- /dev/null
+++ b/app/bin/unittest/catalogtest.c
@@ -0,0 +1,124 @@
+/** \file catalog.c
+* Unit tests for part catalog management
+*/
+
+#include <malloc.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "../include/partcatalog.h"
+
+TrackLibrary *trackLib;
+CatalogEntry *catalog;
+
+
+// some dummy functions to suppress linking problems
+wGetUserHomeDir()
+{
+
+}
+
+wPrefSetString()
+{
+
+}
+
+wPrefGetString()
+{
+
+}
+
+AbortProg()
+{
+
+}
+
+static void
+CreateLib(void **state)
+{
+ (void)state;
+ trackLib = CreateLibrary(".");
+ assert_non_null((void *)trackLib);
+}
+
+static void ScanEmptyDir(void **state)
+{
+ (void)state;
+ bool success;
+ EmptyCatalog(trackLib->catalog);
+ success = GetTrackFiles(trackLib, "//");
+ assert_false(success);
+}
+
+static void ScanTestFiles(void **state)
+{
+ (void)state;
+ bool success;
+ EmptyCatalog(trackLib->catalog);
+ success = GetTrackFiles(trackLib, ".");
+ assert_true(success);
+}
+
+static void CreateIndex(void **state)
+{
+ (void)state;
+ unsigned int words = CreateLibraryIndex(trackLib);
+ assert_true(words > 0);
+}
+
+static void SearchNothing(void **state)
+{
+ (void)state;
+ unsigned int files = SearchLibrary(trackLib, "djfhdkljhf", catalog);
+ assert_true(files == 0);
+ EmptyCatalog(catalog);
+}
+
+static void SearchSingle(void **state)
+{
+ (void)state;
+ int files = SearchLibrary(trackLib, "peco", catalog );
+ assert_true(files==1);
+ EmptyCatalog(catalog);
+}
+
+static void SearchMultiple(void **state)
+{
+ (void)state;
+ int files = SearchLibrary(trackLib, "atlas", catalog);
+ assert_true(files == 2);
+ EmptyCatalog(catalog);
+}
+
+static void FilterTest(void **state)
+{
+ (void)state;
+ bool res;
+
+ res = FilterKeyword("test");
+ assert_false(res);
+ assert_true(FilterKeyword("&"));
+ assert_false(FilterKeyword("n"));
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(CreateLib),
+ cmocka_unit_test(ScanEmptyDir),
+ cmocka_unit_test(ScanTestFiles),
+ cmocka_unit_test(CreateIndex),
+ cmocka_unit_test(SearchNothing),
+ cmocka_unit_test(SearchSingle),
+ cmocka_unit_test(SearchMultiple),
+ cmocka_unit_test(FilterTest),
+ };
+
+ catalog = InitCatalog();
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+} \ No newline at end of file
diff --git a/app/bin/unittest/defaultstest.c b/app/bin/unittest/defaultstest.c
index d877f46..e930468 100644
--- a/app/bin/unittest/defaultstest.c
+++ b/app/bin/unittest/defaultstest.c
@@ -56,11 +56,17 @@ wPrefGetFloatBasic(const char *section, const char *name, double *result, double
return(TRUE);
}
-const char * wPrefGetStringBasic(const char *section, const char *name)
+char * wPrefGetStringBasic(const char *section, const char *name)
{
return(NULL);
}
+/* dummy to make the linker happy */
+void
+wPrefSetInteger(const char *section, const char *name, long value)
+{
+ return;
+}
static void BinarySearch(void **state)
{
int result;
diff --git a/app/bin/unittest/pathstest.c b/app/bin/unittest/pathstest.c
index b7e792e..3ee830e 100644
--- a/app/bin/unittest/pathstest.c
+++ b/app/bin/unittest/pathstest.c
@@ -41,6 +41,11 @@ char *wPrefGetStringExt(const char *section, const char *key)
return(NULL);
}
+char *wPrefGetString(const char *section, const char *key)
+{
+ return(DEFAULTPATH);
+}
+
const char *wGetUserHomeDir(void)
{
return(DEFAULTPATH);
diff --git a/app/bin/unittest/shortentest.c b/app/bin/unittest/shortentest.c
new file mode 100644
index 0000000..4d24b84
--- /dev/null
+++ b/app/bin/unittest/shortentest.c
@@ -0,0 +1,152 @@
+/** \file stringutiltest.c
+* Unit tests for the dxfformat module
+*/
+
+#include <malloc.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <shortentext.h>
+
+#define RESULTSTRING "This is a test!"
+
+
+static void NoRemoveBlanks(void **state)
+{
+ char *result = malloc(strlen(RESULTSTRING) + 20);
+ (void)state;
+
+ RemoveFormatChars(RESULTSTRING, result);
+ assert_string_equal(result, RESULTSTRING);
+
+ RemoveFormatChars(" " RESULTSTRING, result);
+ assert_string_equal(result, " " RESULTSTRING);
+}
+
+static void RemoveMultipleBlanks(void **state)
+{
+ char *result = malloc(strlen(RESULTSTRING) + 20);
+ (void)state;
+
+ RemoveFormatChars("This is a test!", result);
+ assert_string_equal(result, RESULTSTRING);
+
+ RemoveFormatChars("This is a test!", result);
+ assert_string_equal(result, RESULTSTRING);
+}
+
+
+static void RemoveTabs(void **state)
+{
+ char *result = malloc(strlen(RESULTSTRING) + 20);
+ (void)state;
+
+ RemoveFormatChars("This \tis\ta test!", result);
+ assert_string_equal(result, RESULTSTRING);
+
+ RemoveFormatChars("This\t\tis a\ttest!", result);
+ assert_string_equal(result, RESULTSTRING);
+
+ RemoveFormatChars("\tThis is a test!", result);
+ assert_string_equal(result, " " RESULTSTRING);
+}
+
+static void RemoveCRs(void **state)
+{
+ char *result = malloc(strlen(RESULTSTRING) + 20);
+ (void)state;
+
+ RemoveFormatChars("This\r is a test!", result);
+ assert_string_equal(result, RESULTSTRING);
+
+ RemoveFormatChars("This\ris a test!", result);
+ assert_string_equal(result, RESULTSTRING);
+
+ RemoveFormatChars("This is a test!\r", result);
+ assert_string_equal(result, RESULTSTRING);
+}
+
+static void RemoveLFs(void **state)
+{
+ char *result = malloc(strlen(RESULTSTRING) + 20);
+ (void)state;
+
+ RemoveFormatChars("This\n is a test!", result);
+ assert_string_equal(result, RESULTSTRING);
+
+ RemoveFormatChars("This\nis a test!", result);
+ assert_string_equal(result, RESULTSTRING);
+
+ RemoveFormatChars("\nThis is a test!", result);
+ assert_string_equal(result, " " RESULTSTRING);
+
+ RemoveFormatChars("This is a test!\r\n", result);
+ assert_string_equal(result, RESULTSTRING);
+}
+
+#define LONGSTRING "The strrchr() function in C/C++ locates the last occurrence of a character in a string. It returns a pointer to the last occurrence in the string. The terminating null character is considered part of the C string. ... str : specifies the pointer to the null terminated string to be searched for."
+
+static void NoEllipsizeText(void **state)
+{
+ char *result = malloc(strlen(RESULTSTRING) + 20);
+
+ (void)state;
+
+ EllipsizeString(RESULTSTRING, result, strlen(RESULTSTRING) + 10);
+ assert_string_equal(result, RESULTSTRING);
+
+ EllipsizeString(RESULTSTRING, NULL, strlen(RESULTSTRING) + 10);
+ assert_string_equal(result, RESULTSTRING);
+}
+
+static void EllipsizeText(void **state)
+{
+ char *result = malloc(sizeof(LONGSTRING));
+ (void)state;
+
+ EllipsizeString(LONGSTRING, result, strlen(LONGSTRING));
+ assert_string_equal(result, LONGSTRING);
+
+ EllipsizeString(LONGSTRING, result, 40);
+ assert_string_equal(result, "The strrchr() function in C/C++...");
+
+ EllipsizeString(LONGSTRING, result, 23);
+ assert_string_equal(result, "The strrchr()...");
+
+ strcpy(result, LONGSTRING);
+ EllipsizeString(result, NULL, 23);
+ assert_string_equal(result, "The strrchr()...");
+
+}
+
+static void LongText(void **state)
+{
+ char *result = malloc(sizeof(LONGSTRING));
+ (void)state;
+
+ strcpy(result, "abcdefghijklmnopqrstuvwxyz");
+ EllipsizeString(result, NULL, 23);
+ assert_string_equal(result, "abcdefghijklmnopqrst...");
+
+ EllipsizeString("abcdefghijklmnopqrstuvwxyz", result, 10);
+ assert_string_equal(result, "abcdefg...");
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(NoRemoveBlanks),
+ cmocka_unit_test(RemoveMultipleBlanks),
+ cmocka_unit_test(RemoveTabs),
+ cmocka_unit_test(RemoveCRs),
+ cmocka_unit_test(RemoveLFs),
+ cmocka_unit_test(NoEllipsizeText),
+ cmocka_unit_test(EllipsizeText),
+ cmocka_unit_test(LongText),
+ };
+ return cmocka_run_group_tests(tests, NULL, NULL);
+} \ No newline at end of file
diff --git a/app/bin/unittest/testfiles/HO-Peco-Code83.xtp b/app/bin/unittest/testfiles/HO-Peco-Code83.xtp
new file mode 100644
index 0000000..09bf426
--- /dev/null
+++ b/app/bin/unittest/testfiles/HO-Peco-Code83.xtp
@@ -0,0 +1,236 @@
+CONTENTS Peco North American Code 83 HO Scale Turnouts
+#Updated based on PECO Website and PDF's
+SUBCONTENTS Peco Code 83 HO Turnouts
+TURNOUT HO "PECO Code 83 #5 Left Hand Turnout SL-8352/SLE-8352"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 8.259842 0.000000 90.000000
+ E 8.259842 1.000000 78.600000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 8.259842 0.000000
+ C 0 0.000000 -26.558075 0.649635 26.558075 168.599924 11.400152
+ S 0 0.000000 5.899063 0.523973 8.259842 1.000000
+END
+TURNOUT HO "PECO Code 83 #5 Right Hand Turnout SL-8351/SLE-8351"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 8.259842 0.000000 90.000000
+ E 8.259842 -1.000000 101.400000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 8.259842 0.000000
+ C 0 0.000000 26.558075 0.649494 -26.558075 0.000076 11.400152
+ S 0 0.000000 5.899063 -0.523973 8.259842 -1.000000
+END
+TURNOUT HO "PECO Code 83 #6 Left Hand Turnout SL-8362/SLE-8362"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 9.192913 0.000000 90.000000
+ E 9.192913 1.000000 80.500000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 9.192913 0.000000
+ C 0 0.000000 -30.900336 0.649641 30.900336 170.499924 9.500152
+ S 0 0.000000 5.749703 0.423792 9.192913 1.000000
+END
+TURNOUT HO "PECO Code 83 #6 Right Hand Turnout SL-8361/SLE-8361"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 9.192913 0.000000 90.000000
+ E 9.192913 -1.000000 99.500000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 9.192913 0.000000
+ C 0 0.000000 30.900336 0.649477 -30.900336 0.000076 9.500152
+ S 0 0.000000 5.749703 -0.423792 9.192913 -1.000000
+END
+TURNOUT HO "PECO Code 83 #8 Left Hand Turnout SL-8382/SLE-8382"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 12.649606 0.000000 90.000000
+ E 12.649606 1.000000 82.850000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 12.649606 0.000000
+ C 0 0.000000 -64.478236 0.649686 64.478236 172.849924 7.150152
+ S 0 0.000000 8.675202 0.501423 12.649606 1.000000
+END
+TURNOUT HO "PECO Code 83 #8 Right Hand Turnout SL-8381/SLE-8381"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 12.649606 0.000000 90.000000
+ E 12.649606 -1.000000 97.150000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 12.649606 0.000000
+ C 0 0.000000 64.478236 0.649343 -64.478236 0.000076 7.150152
+ S 0 0.000000 8.675202 -0.501423 12.649606 -1.000000
+END
+
+SUBCONTENTS Peco Code 83 HO Wye Turnouts
+TURNOUT HO "PECO Code 83 #4 WYE Turnout SL-8348/SLE-8348"
+ P "Left" 1 2 3
+ P "Right" 1 4 5
+ E 0.000000 0.000000 270.000000
+ E 7.159055 0.500000 82.850000
+ E 7.159055 -0.500000 97.150000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ C 0 0.000000 -40.393551 0.649654 40.393551 172.849924 7.150152
+ S 0 0.000000 5.677382 0.314125 7.159055 0.500000
+ C 0 0.000000 40.393551 0.649439 -40.393551 0.000076 7.150152
+ S 0 0.000000 5.677382 -0.314125 7.159055 -0.500000
+END
+
+SUBCONTENTS Peco Code 83 HO Crossings
+TURNOUT HO "PECO Code 83 #6 Diamond Crossing SL-8364/SLE-8364"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 12.035433 0.000000 90.000000
+ E 0.082528 0.993201 279.500000
+ E 11.952905 -0.993201 99.500000
+ S 0 0.000000 0.000000 0.000000 12.035433 0.000000
+ S 0 0.000000 0.082528 0.993201 11.952905 -0.993201
+END
+TURNOUT HO "PECO Code 83 90d Crossing SL-8390"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 2.000000 0.000000 90.000000
+ E 1.000000 -1.000000 180.000000
+ E 1.000000 1.000000 0.000000
+ S 0 0.000000 0.000000 0.000000 2.000000 0.000000
+ S 0 0.000000 1.000000 1.000000 1.000000 -1.000000
+END
+
+SUBCONTENTS Peco Code 83 HO Curved Turnouts
+TURNOUT HO "Peco Code 83 #7 Curved Left Turnout SL-8377/SLE-8377"
+ P "Normal" 1 4 5
+ P "Reverse" 1 2 3
+ E 0.000000 0.000000 270.000000
+ E 11.106693 0.984252 81.000000
+ E 10.865748 1.968504 72.000000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ C 0 0.000000 -26.251070 0.649635 26.251070 161.999924 18.000152
+ S 0 0.000000 8.761686 1.284838 10.865748 1.968504
+ C 0 0.000000 -53.910688 0.649672 53.910688 170.999924 9.000152
+ S 0 0.000000 9.083224 0.663751 11.106693 0.984252
+END
+TURNOUT HO "Peco Code 83 #7 Curved Right Turnout SL-8376/SLE-8376"
+ P "Normal" 1 4 5
+ P "Reverse" 1 2 3
+ E 0.000000 0.000000 270.000000
+ E 11.106693 -0.984252 99.000000
+ E 10.865748 -1.968504 108.000000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ C 0 0.000000 26.251070 0.649496 -26.251070 0.000076 18.000152
+ S 0 0.000000 8.761686 -1.284838 10.865748 -1.968504
+ C 0 0.000000 53.910688 0.649385 -53.910688 0.000076 9.000152
+ S 0 0.000000 9.083224 -0.663751 11.106693 -0.984252
+END
+
+SUBCONTENTS Peco Code 83 HO Slip Turnouts
+TURNOUT HO "Peco Code 83 #6 Double Slip Switch SL-U8363"
+ P "Normal" 1 2 3 0 4 5 6
+ P "Reverse" 1 7 6 0 4 8 3
+ E 0.000000 0.000000 270.000000
+ E 12.035433 0.000000 90.000000
+ E 0.082528 0.993201 279.500000
+ E 11.952905 -0.993201 99.500000
+ S 0 0.000000 0.000000 0.000000 1.299468 0.000000
+ S 0 0.000000 1.299468 0.000000 10.735965 0.000000
+ S 0 0.000000 10.735965 0.000000 12.035433 0.000000
+ S 0 0.000000 0.082528 0.993201 1.363761 0.778782
+ S 0 0.000000 1.363761 0.778782 10.671672 -0.778782
+ S 0 0.000000 10.671672 -0.778782 11.952905 -0.993201
+ C 0 0.000000 56.784006 1.299241 -56.784006 0.000076 9.500152
+ C 0 0.000000 -56.784006 10.736040 56.783993 180.000076 9.500152
+END
+
+SUBCONTENTS Peco Code 83 HO Inspection Pit
+TURNOUT HO "Peco Code 83 Inspection Pit SL-8356"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 11.692913 0.000000 90.000000
+ S 0 0.000000 0.000000 0.000000 11.692913 0.000000
+ F 15720651 0.000000 4
+ 0.000000 0.551091 0
+ 11.692913 0.551091 0
+ 11.692913 -0.551091 0
+ 0.000000 -0.551091 0
+ F 12632256 0.000000 4
+ 0.000000 0.280000 0
+ 0.560000 0.280000 0
+ 0.560000 -0.280000 0
+ 0.000000 -0.280000 0
+ L 0 0.020000 0.000000 0.280000 0.000000 -0.280000
+ L 0 0.020000 0.112000 0.280000 0.112000 -0.280000
+ L 0 0.020000 0.224000 0.280000 0.224000 -0.280000
+ L 0 0.020000 0.336000 0.280000 0.336000 -0.280000
+ L 0 0.020000 0.448000 0.280000 0.448000 -0.280000
+ L 0 0.020000 0.560000 0.280000 0.560000 -0.280000
+ F 12632256 0.000000 4
+ 11.132913 0.280000 0
+ 11.692913 0.280000 0
+ 11.692913 -0.280000 0
+ 11.132913 -0.280000 0
+ L 0 0.020000 11.132913 0.280000 11.132913 -0.280000
+ L 0 0.020000 11.244913 0.280000 11.244913 -0.280000
+ L 0 0.020000 11.356913 0.280000 11.356913 -0.280000
+ L 0 0.020000 11.468913 0.280000 11.468913 -0.280000
+ L 0 0.020000 11.580913 0.280000 11.580913 -0.280000
+ L 0 0.020000 11.692913 0.280000 11.692913 -0.280000
+ A 0 0.020000 0.062500 0.974409 0.000000 0.000000 360.000000
+ A 0 0.020000 0.062500 2.923228 0.000000 0.000000 360.000000
+ A 0 0.020000 0.062500 4.872047 0.000000 0.000000 360.000000
+ A 0 0.020000 0.062500 6.820866 0.000000 0.000000 360.000000
+ A 0 0.020000 0.062500 8.769685 0.000000 0.000000 360.000000
+ A 0 0.020000 0.062500 10.718504 0.000000 0.000000 360.000000
+ L 0 0.020000 0.000000 0.551091 11.692913 0.551091
+ L 0 0.020000 0.000000 0.280000 11.692913 0.28000
+ L 0 0.020000 0.000000 -0.280000 11.692913 -0.280000
+ L 0 0.020000 0.000000 -0.551091 11.692913 -0.551091
+END
+TURNOUT HO "Peco Code 83 Inspection Pit(Stair End) SL-8356A"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 1.948819 0.000000 90.000000
+ S 0 0.000000 0.000000 0.000000 1.948819 0.000000
+ F 15720651 0.000000 4
+ 0.000000 0.551091 0
+ 1.948819 0.551091 0
+ 1.948819 -0.551091 0
+ 0.000000 -0.551091 0
+ F 12632256 0.000000 4
+ 0.000000 0.280000 0
+ 0.560000 0.280000 0
+ 0.560000 -0.280000 0
+ 0.000000 -0.280000 0
+ L 0 0.020000 0.000000 0.280000 0.000000 -0.280000
+ L 0 0.020000 0.112000 0.280000 0.112000 -0.280000
+ L 0 0.020000 0.224000 0.280000 0.224000 -0.280000
+ L 0 0.020000 0.336000 0.280000 0.336000 -0.280000
+ L 0 0.020000 0.448000 0.280000 0.448000 -0.280000
+ L 0 0.020000 0.560000 0.280000 0.560000 -0.280000
+ A 0 0.020000 0.062500 0.974409 0.000000 0.000000 360.000000
+ L 0 0.020000 0.000000 0.551091 1.948819 0.551091
+ L 0 0.020000 0.000000 0.280000 1.948819 0.28000
+ L 0 0.020000 0.000000 -0.280000 1.948819 -0.280000
+ L 0 0.020000 0.000000 -0.551091 1.948819 -0.551091
+
+END
+TURNOUT HO "Peco Code 83 Inspection Pit(Mid Section) SL-8356B"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 1.948819 0.000000 90.000000
+ S 0 0.000000 0.000000 0.000000 1.948819 0.000000
+ F 15720651 0.000000 4
+ 0.000000 0.551091 0
+ 1.948819 0.551091 0
+ 1.948819 -0.551091 0
+ 0.000000 -0.551091 0
+ A 0 0.020000 0.062500 0.974409 0.000000 0.000000 360.000000
+ L 0 0.020000 0.000000 0.551091 1.948819 0.551091
+ L 0 0.020000 0.000000 0.280000 1.948819 0.28000
+ L 0 0.020000 0.000000 -0.280000 1.948819 -0.280000
+ L 0 0.020000 0.000000 -0.551091 1.948819 -0.551091
+END \ No newline at end of file
diff --git a/app/bin/unittest/testfiles/atl83ho.xtp b/app/bin/unittest/testfiles/atl83ho.xtp
new file mode 100644
index 0000000..02452da
--- /dev/null
+++ b/app/bin/unittest/testfiles/atl83ho.xtp
@@ -0,0 +1,561 @@
+CONTENTS Atlas Code 83 - HO Scale
+SUBCONTENTS Atlas HO-Scale C83 - Switched
+TURNOUT HO "Atlas #6 Left C83 Super 505"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 11.613000 0.000000 90.000000
+ E 11.613000 1.335000 80.500000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 11.613000 0.000000
+ C 0 0.000000 -35.933506 0.649648 35.933506 170.499924 9.500152
+ S 0 0.000000 6.580428 0.492821 11.613000 1.335000
+ END
+TURNOUT HO "Atlas #6 Right C83 Super 506"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 11.613000 0.000000 90.000000
+ E 11.613000 -1.335000 99.500000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 11.613000 0.000000
+ C 0 0.000000 35.933506 0.649457 -35.933506 0.000076 9.500152
+ S 0 0.000000 6.580428 -0.492821 11.613000 -1.335000
+ END
+TURNOUT HO "Atlas C83 Left Remote/Manual Snap Switch 540/542"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ E 7.656300 1.085500 70.000000
+ S 0 0.000000 0.000000 0.000000 2.149777 0.000000
+ S 0 0.000000 2.149777 0.000000 9.000000 0.000000
+ C 0 0.000000 -14.315249 2.149796 14.315249 159.999924 20.000152
+ S 0 0.000000 7.045913 0.863327 7.656300 1.085500
+ END
+TURNOUT HO "Atlas C83 Right Remote/Manual Snap Switch 541/543"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ E 7.656300 -1.085500 110.000000
+ S 0 0.000000 0.000000 0.000000 2.149777 0.000000
+ S 0 0.000000 2.149777 0.000000 9.000000 0.000000
+ C 0 0.000000 14.315249 2.149720 -14.315249 0.000076 20.000152
+ S 0 0.000000 7.045913 -0.863327 7.656300 -1.085500
+ END
+TURNOUT HO "Atlas C83 Left Remote/Manual 22in Snap Switch 546/544"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 10.500000 0.000000 90.000000
+ E 10.500000 1.674650 67.500000
+ S 0 0.000000 0.000000 0.000000 2.730631 0.000000
+ S 0 0.000000 2.730631 0.000000 10.500000 0.000000
+ C 0 0.000000 -18.734087 2.730656 18.734087 157.500000 22.500000
+ S 0 0.000000 9.899897 1.451414 10.500000 1.674650
+ END
+TURNOUT HO "Atlas C83 Right Remote/Manual 22in Snap Switch 547/545"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 10.500000 0.000000 90.000000
+ E 10.500000 -1.674650 112.500000
+ S 0 0.000000 0.000000 0.000000 2.730631 0.000000
+ S 0 0.000000 2.730631 0.000000 10.500000 0.000000
+ C 0 0.000000 18.734087 2.730656 -18.734087 0.000000 22.500000
+ S 0 0.000000 9.899897 -1.451414 10.500000 -1.674650
+ END
+TURNOUT HO "Atlas C83 Wye Switch 560"
+ P "Left" 1 2 3
+ P "Right" 1 4 5
+ E 0.000000 0.000000 270.000000
+ E 7.805900 0.655500 81.000000
+ E 7.805900 -0.655500 99.000000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ C 0 0.000000 -38.343529 0.649651 38.343529 170.999924 9.000152
+ S 0 0.000000 6.647945 0.472088 7.805900 0.655500
+ C 0 0.000000 38.343529 0.649447 -38.343529 0.000076 9.000152
+ S 0 0.000000 6.647945 -0.472088 7.805900 -0.655500
+ END
+TURNOUT HO "Atlas #6 Left C83 Customline 563"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 12.000000 0.000000 90.000000
+ E 9.999000 0.874800 81.000000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 12.000000 0.000000
+ C 0 0.000000 -48.616653 0.649665 48.616653 170.999924 9.000152
+ S 0 0.000000 8.255041 0.598571 9.999000 0.874800
+ END
+TURNOUT HO "Atlas #6 Right C83 Customline 564"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 12.000000 0.000000 90.000000
+ E 9.999000 -0.874800 99.000000
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 12.000000 0.000000
+ C 0 0.000000 48.616653 0.649406 -48.616653 0.000076 9.000152
+ S 0 0.000000 8.255041 -0.598571 9.999000 -0.874800
+ END
+TURNOUT HO "Atlas #4 Left C83 Customline 561"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ E 8.000000 1.000000 75.522476
+ S 0 0.000000 0.000000 0.000000 0.776702 0.000000
+ S 0 0.000000 0.776702 0.000000 9.000000 0.000000
+ C 0 0.000000 -26.377309 0.776737 26.377309 165.522400 14.477676
+ S 0 0.000000 7.371097 0.837607 8.000000 1.000000
+ END
+TURNOUT HO "Atlas #4 Right C83 Customline 562"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ E 8.000000 -1.000000 104.477524
+ S 0 0.000000 0.000000 0.000000 0.776702 0.000000
+ S 0 0.000000 0.776702 0.000000 9.000000 0.000000
+ C 0 0.000000 26.377309 0.776597 -26.377309 0.000076 14.477676
+ S 0 0.000000 7.371097 -0.837607 8.000000 -1.000000
+ END
+TURNOUT HO "Atlas #8 Left C83 Customline 565"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 13.500000 0.000000 90.000000
+ E 11.400000 0.900000 82.819238
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 13.500000 0.000000
+ C 0 0.000000 -57.485559 0.649676 57.485559 172.819162 7.180914
+ S 0 0.000000 7.835446 0.450893 11.400000 0.900000
+ END
+TURNOUT HO "Atlas #8 Right C83 Customline 566"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 13.500000 0.000000 90.000000
+ E 11.400000 -0.900000 97.180762
+ S 0 0.000000 0.000000 0.000000 0.649600 0.000000
+ S 0 0.000000 0.649600 0.000000 13.500000 0.000000
+ C 0 0.000000 57.485559 0.649371 -57.485559 0.000076 7.180914
+ S 0 0.000000 7.835446 -0.450893 11.400000 -0.900000
+ END
+TURNOUT HO "Atlas Curve Left C83 Customline 595"
+ P "Normal" 1
+ P "Reverse" 2
+ E 0.000000 0.000000 270.000000
+ E 15.000000 4.019238 60.000000
+ E 13.392751 4.546227 52.500000
+ C 0 0.000000 30.000000 0.000000 30.000000 150.000000 30.000000
+ C 0 0.000000 22.000000 0.000000 22.000000 142.500000 37.500000
+ END
+TURNOUT HO "Atlas Curve Right C83 Customline 596"
+ P "Normal" 1
+ P "Reverse" 2
+ E 0.000000 0.000000 270.000000
+ E 15.000000 -4.019238 120.000000
+ E 13.392751 -4.546227 127.500000
+ C 0 0.000000 30.000000 0.000000 -30.000000 0.000000 30.000000
+ C 0 0.000000 22.000000 0.000000 -22.000000 0.000000 37.500000
+ END
+
+
+
+SUBCONTENTS Atlas HO-Scale C83 - Crossings
+TURNOUT HO "Atlas 12.5D Crossing 571"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ E 0.106666 0.973972 282.500000
+ E 8.893334 -0.973972 102.500000
+ S 0 0.000000 0.000000 0.000000 9.000000 0.000000
+ S 0 0.000000 0.106666 0.973972 8.893334 -0.973972
+ END
+TURNOUT HO "Atlas 571 Fitter Piece 571a"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 0.100000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 0.100000 0.000000
+ END
+TURNOUT HO "Atlas 19D Crossing 572"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 6.082500 0.000000 90.000000
+ E 0.165690 0.990130 289.000000
+ E 5.916810 -0.990130 109.000000
+ S 0 0.000000 0.000000 0.000000 6.082500 0.000000
+ S 0 0.000000 0.165690 0.990130 5.916810 -0.990130
+ END
+TURNOUT HO "Atlas 30D Crossing 573"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 4.000000 0.000000 90.000000
+ E 0.267947 0.999997 300.000000
+ E 3.732053 -0.999997 120.000000
+ S 0 0.000000 0.000000 0.000000 4.000000 0.000000
+ S 0 0.000000 0.267947 0.999997 3.732053 -0.999997
+ END
+TURNOUT HO "Atlas 25D Crossing 574"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 4.608100 0.000000 90.000000
+ E 0.215870 0.973730 295.000000
+ E 4.392230 -0.973730 115.000000
+ S 0 0.000000 0.000000 0.000000 4.608100 0.000000
+ S 0 0.000000 0.215870 0.973730 4.392230 -0.973730
+ END
+TURNOUT HO "Atlas 45D Crossing 575"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 3.000000 0.000000 90.000000
+ E 0.439338 1.060658 315.000000
+ E 2.560662 -1.060658 135.000000
+ S 0 0.000000 0.000000 0.000000 3.000000 0.000000
+ S 0 0.000000 0.439338 1.060658 2.560662 -1.060658
+ END
+TURNOUT HO "Atlas 60D Crossing 576"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 3.000000 0.000000 90.000000
+ E 0.749997 1.299036 330.000000
+ E 2.250003 -1.299036 150.000000
+ S 0 0.000000 0.000000 0.000000 3.000000 0.000000
+ S 0 0.000000 0.749997 1.299036 2.250003 -1.299036
+ END
+TURNOUT HO "Atlas 90D Crossing 577"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 2.000000 0.000000 90.000000
+ E 1.000003 1.000000 360.000000
+ E 0.999997 -1.000000 180.000000
+ S 0 0.000000 0.000000 0.000000 2.000000 0.000000
+ S 0 0.000000 1.000003 1.000000 0.999997 -1.000000
+ END
+
+SUBCONTENTS Atlas HO-Scale C83 - Straight Track
+TURNOUT HO "Atlas C83 9"" Straight 510/520"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 9.000000 0.000000
+ END
+TURNOUT HO "Atlas C83 6"" Straight 521"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 6.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 6.000000 0.000000
+ END
+TURNOUT HO "Atlas C83 3"" Straight 522"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 3.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 3.000000 0.000000
+ END
+TURNOUT HO "Atlas C83 1.5"" Straight 523"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 1.500000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 1.500000 0.000000
+ END
+TURNOUT HO "Atlas C83 2.0"" Straight 525"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 2.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 2.000000 0.000000
+ END
+TURNOUT HO "Atlas C83 0.75"" Straight 524a"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 0.750000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 0.750000 0.000000
+ END
+TURNOUT HO "Atlas C83 1"" Straight 524b"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 1.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 1.000000 0.000000
+ END
+TURNOUT HO "Atlas C83 1.25"" Straight 524c"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 1.250000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 1.250000 0.000000
+ END
+TURNOUT HO "Atlas C83 1.5"" Straight 524d"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 1.500000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 1.500000 0.000000
+ END
+TURNOUT HO "Atlas C83 2.0"" Straight 524e"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 2.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 2.000000 0.000000
+ END
+TURNOUT HO "Atlas C83 2.5"" Straight 524f"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 2.500000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 2.500000 0.000000
+ END
+
+SUBCONTENTS Atlas HO-Scale C83 - Curve Track
+TURNOUT HO "Atlas C83 15"" 30D Curve 511/530"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 7.499994 -2.009616 120.000000
+ C 0 0 15.000000 0.000000 -15.000000 0.000000 30.000000
+ END
+TURNOUT HO "Atlas C83 15"" 15D Curve 531"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 3.882282 0.511112 75.000000
+ C 0 0 -15.000000 0.000020 15.000000 165.000076 15.000000
+ END
+TURNOUT HO "Atlas C83 18"" 30D Curve 512/532"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 8.999993 -2.411539 120.000000
+ C 0 0 18.000000 0.000000 -18.000000 0.000000 30.000000
+ END
+TURNOUT HO "Atlas C83 18"" 15D Curve 533"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 4.658739 -0.613334 105.000000
+ C 0 0 18.000000 0.000000 -18.000000 0.000000 15.000000
+ END
+TURNOUT HO "Atlas C83 18"" 10D Curve 534"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 3.125665 -0.273460 100.000000
+ C 0 0 18.000000 0.000000 -18.000000 0.000000 10.000000
+ END
+TURNOUT HO "Atlas C83 22"" 22.5D Curve 513/535"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 8.419029 -1.674647 112.500000
+ C 0 0 22.000000 0.000000 -22.000000 0.000000 22.500000
+ END
+TURNOUT HO "Atlas C83 22"" 7.5D Curve 537"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 2.871574 0.188213 82.500000
+ C 0 0.000000 -22.000000 0.000029 22.000000 172.500076 7.500000
+ END
+TURNOUT HO "Atlas C83 24"" 22.5D Curve 536"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 9.184395 1.826888 67.500000
+ C 0 0.000000 -24.000000 0.000032 24.000000 157.500076 22.500000
+ END
+
+
+SUBCONTENTS Atlas HO-Scale C83 - Misc Track
+TURNOUT HO "Atlas C83 9"" Straight Rerailer 519"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 9.000000 0.000000
+ F 12566463 0.000000 4
+ 0.500000 0.584375 0
+ 1.000000 0.334375 0
+ 8.000000 0.334375 0
+ 8.500000 0.584375 0
+ F 12566463 0.000000 6
+ 0.500000 0.000000 0
+ 1.000000 -0.250000 0
+ 8.000000 -0.250000 0
+ 8.500000 0.000000 0
+ 8.000000 0.250000 0
+ 1.000000 0.250000 0
+ F 12566463 0.000000 4
+ 0.500000 -0.584375 0
+ 1.000000 -0.334375 0
+ 8.000000 -0.334375 0
+ 8.500000 -0.584375 0
+ END
+TURNOUT HO "Atlas C83 Bumper 518"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ S 0 0 0.000000 0.000000 3.750000 0.000000
+ END
+
+SUBCONTENTS Atlas HO-Scale C83 - Bridges
+TURNOUT HO "Atlas C83 9"" Warren Truss Bridge 590"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 9.000000 0.000000
+ F 11579568 0.000000 4
+ 0.000000 1.200000 0
+ 9.000000 1.200000 0
+ 9.000000 0.625000 0
+ 0.000000 0.625000 0
+ F 11579568 0.000000 4
+ 0.000000 -1.200000 0
+ 9.000000 -1.200000 0
+ 9.000000 -0.625000 0
+ 0.000000 -0.625000 0
+ L 8421504 0.100000 0.000000 1.200000 9.000000 1.200000
+ L 8421504 0.100000 0.000000 -1.200000 9.000000 -1.200000
+END
+TURNOUT HO "Atlas C83 9"" Deck Truss Bridge 591"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 9.000000 0.000000
+ L 11579568 0.050000 0.000000 0.700000 9.000000 0.700000
+ L 11579568 0.050000 0.000000 0.600000 0.000000 0.700000
+ L 11579568 0.050000 9.000000 0.600000 9.000000 0.700000
+ L 11579568 0.050000 0.000000 -0.700000 9.000000 -0.700000
+ L 11579568 0.050000 0.000000 -0.600000 0.000000 -0.700000
+ L 11579568 0.050000 9.000000 -0.600000 9.000000 -0.700000
+END
+TURNOUT HO "Atlas C83 9"" Plate Girder Bridge 592"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 9.000000 0.000000
+ F 11579568 0.000000 4
+ 0.000000 1.300000 0
+ 9.000000 1.300000 0
+ 9.000000 0.625000 0
+ 0.000000 0.625000 0
+ F 11579568 0.000000 4
+ 0.000000 -1.300000 0
+ 9.000000 -1.300000 0
+ 9.000000 -0.625000 0
+ 0.000000 -0.625000 0
+ L 8421504 0.100000 0.000000 1.300000 9.000000 1.300000
+ L 8421504 0.050000 0.900000 1.000000 0.900000 1.300000
+ L 8421504 0.050000 2.700000 1.000000 2.700000 1.300000
+ L 8421504 0.050000 4.500000 1.000000 4.500000 1.300000
+ L 8421504 0.050000 6.300000 1.000000 6.300000 1.300000
+ L 8421504 0.050000 8.100000 1.000000 8.100000 1.300000
+ L 8421504 0.100000 0.000000 -1.300000 9.000000 -1.300000
+ L 8421504 0.050000 0.900000 -1.000000 0.900000 -1.300000
+ L 8421504 0.050000 2.700000 -1.000000 2.700000 -1.300000
+ L 8421504 0.050000 4.500000 -1.000000 4.500000 -1.300000
+ L 8421504 0.050000 6.300000 -1.000000 6.300000 -1.300000
+ L 8421504 0.050000 8.100000 -1.000000 8.100000 -1.300000
+END
+TURNOUT HO "Atlas C83 18"" Through Truss Bridge 593/594"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 18.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 18.000000 0.000000
+ L 11579568 0.050000 0.000000 1.200000 18.000000 1.200000
+ L 11579568 0.050000 0.000000 0.750000 0.000000 1.200000
+ L 11579568 0.050000 18.000000 0.750000 18.000000 1.200000
+ L 11579568 0.050000 0.000000 -1.200000 18.000000 -1.200000
+ L 11579568 0.050000 0.000000 -0.750000 0.000000 -1.200000
+ L 11579568 0.050000 18.000000 -0.750000 18.000000 -1.200000
+ L 11579568 0.050000 3.000000 -1.200000 3.000000 1.200000
+ L 11579568 0.050000 6.000000 -1.200000 6.000000 1.200000
+ L 11579568 0.050000 9.000000 -1.200000 9.000000 1.200000
+ L 11579568 0.050000 12.000000 -1.200000 12.000000 1.200000
+ L 11579568 0.050000 15.000000 -1.200000 15.000000 1.200000
+ L 11579568 0.050000 3.000000 -1.200000 6.000000 1.200000
+ L 11579568 0.050000 3.000000 1.200000 6.000000 -1.200000
+ L 11579568 0.050000 6.000000 -1.200000 9.000000 1.200000
+ L 11579568 0.050000 6.000000 1.200000 9.000000 -1.200000
+ L 11579568 0.050000 9.000000 -1.200000 12.000000 1.200000
+ L 11579568 0.050000 9.000000 1.200000 12.000000 -1.200000
+ L 11579568 0.050000 12.000000 -1.200000 15.000000 1.200000
+ L 11579568 0.050000 12.000000 1.200000 15.000000 -1.200000
+END
+TURNOUT HO "Atlas C83 9"" Single-Track Thru-Girder Bridge 70000027"
+ P "P0" 1
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ S 0 0.000000 0.000000 0.000000 9.000000 0.000000
+ L 11579568 0.100000 0.500000 1.000000 8.500000 1.000000
+ L 11579568 0.050000 0.750000 1.000000 0.750000 0.625000
+ L 11579568 0.050000 2.000000 1.000000 2.000000 0.625000
+ L 11579568 0.050000 3.250000 1.000000 3.250000 0.625000
+ L 11579568 0.050000 4.500000 1.000000 4.500000 0.625000
+ L 11579568 0.050000 5.750000 1.000000 5.750000 0.625000
+ L 11579568 0.050000 7.000000 1.000000 7.000000 0.625000
+ L 11579568 0.050000 8.250000 1.000000 8.250000 0.625000
+ L 11579568 0.100000 0.500000 -1.000000 8.500000 -1.000000
+ L 11579568 0.050000 0.750000 -1.000000 0.750000 -0.625000
+ L 11579568 0.050000 2.000000 -1.000000 2.000000 -0.625000
+ L 11579568 0.050000 3.250000 -1.000000 3.250000 -0.625000
+ L 11579568 0.050000 4.500000 -1.000000 4.500000 -0.625000
+ L 11579568 0.050000 5.750000 -1.000000 5.750000 -0.625000
+ L 11579568 0.050000 7.000000 -1.000000 7.000000 -0.625000
+ L 11579568 0.050000 8.250000 -1.000000 8.250000 -0.625000
+END
+TURNOUT HO "Atlas C83 9"" Double-Track Thru-Girder Bridge 70000028"
+ P "P0" 1 0 1
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ E 0.000000 -2.000000 270.000000
+ E 9.000000 -2.000000 90.000000
+ S 0 0.000000 0.000000 0.000000 9.000000 0.000000
+ S 0 0.000000 0.000000 -2.000000 9.000000 -2.000000
+ L 11579568 0.100000 0.500000 1.000000 8.500000 1.000000
+
+ L 11579568 0.050000 0.750000 1.000000 0.750000 0.625000
+ L 11579568 0.050000 2.000000 1.000000 2.000000 0.625000
+ L 11579568 0.050000 3.250000 1.000000 3.250000 0.625000
+ L 11579568 0.050000 4.500000 1.000000 4.500000 0.625000
+ L 11579568 0.050000 5.750000 1.000000 5.750000 0.625000
+ L 11579568 0.050000 7.000000 1.000000 7.000000 0.625000
+ L 11579568 0.050000 8.250000 1.000000 8.250000 0.625000
+
+ L 11579568 0.050000 0.750000 -1.000000 0.750000 -0.625000
+ L 11579568 0.050000 2.000000 -1.000000 2.000000 -0.625000
+ L 11579568 0.050000 3.250000 -1.000000 3.250000 -0.625000
+ L 11579568 0.050000 4.500000 -1.000000 4.500000 -0.625000
+ L 11579568 0.050000 5.750000 -1.000000 5.750000 -0.625000
+ L 11579568 0.050000 7.000000 -1.000000 7.000000 -0.625000
+ L 11579568 0.050000 8.250000 -1.000000 8.250000 -0.625000
+
+ L 11579568 0.100000 0.500000 -1.000000 8.500000 -1.000000
+
+ L 11579568 0.050000 0.750000 -1.000000 0.750000 -1.375000
+ L 11579568 0.050000 2.000000 -1.000000 2.000000 -1.375000
+ L 11579568 0.050000 3.250000 -1.000000 3.250000 -1.375000
+ L 11579568 0.050000 4.500000 -1.000000 4.500000 -1.375000
+ L 11579568 0.050000 5.750000 -1.000000 5.750000 -1.375000
+ L 11579568 0.050000 7.000000 -1.000000 7.000000 -1.375000
+ L 11579568 0.050000 8.250000 -1.000000 8.250000 -1.375000
+
+ L 11579568 0.050000 0.750000 -3.000000 0.750000 -2.625000
+ L 11579568 0.050000 2.000000 -3.000000 2.000000 -2.625000
+ L 11579568 0.050000 3.250000 -3.000000 3.250000 -2.625000
+ L 11579568 0.050000 4.500000 -3.000000 4.500000 -2.625000
+ L 11579568 0.050000 5.750000 -3.000000 5.750000 -2.625000
+ L 11579568 0.050000 7.000000 -3.000000 7.000000 -2.625000
+ L 11579568 0.050000 8.250000 -3.000000 8.250000 -2.625000
+
+ L 11579568 0.100000 0.500000 -3.000000 8.500000 -3.000000
+END
+TURNOUT HO "Atlas C83 9"" Single-Track Add-On Thru-Girder Bridge 70000029"
+ P "P0" 1
+ E 0.000000 0.000000 270.000000
+ E 9.000000 0.000000 90.000000
+ S 0 0.000000 0.000000 0.000000 9.000000 0.000000
+ #L 11579568 0.100000 0.500000 1.000000 8.500000 1.000000
+ L 11579568 0.050000 0.750000 1.000000 0.750000 0.625000
+ L 11579568 0.050000 2.000000 1.000000 2.000000 0.625000
+ L 11579568 0.050000 3.250000 1.000000 3.250000 0.625000
+ L 11579568 0.050000 4.500000 1.000000 4.500000 0.625000
+ L 11579568 0.050000 5.750000 1.000000 5.750000 0.625000
+ L 11579568 0.050000 7.000000 1.000000 7.000000 0.625000
+ L 11579568 0.050000 8.250000 1.000000 8.250000 0.625000
+ L 11579568 0.100000 0.500000 -1.000000 8.500000 -1.000000
+ L 11579568 0.050000 0.750000 -1.000000 0.750000 -0.625000
+ L 11579568 0.050000 2.000000 -1.000000 2.000000 -0.625000
+ L 11579568 0.050000 3.250000 -1.000000 3.250000 -0.625000
+ L 11579568 0.050000 4.500000 -1.000000 4.500000 -0.625000
+ L 11579568 0.050000 5.750000 -1.000000 5.750000 -0.625000
+ L 11579568 0.050000 7.000000 -1.000000 7.000000 -0.625000
+ L 11579568 0.050000 8.250000 -1.000000 8.250000 -0.625000
+END
diff --git a/app/bin/unittest/testfiles/atlasn.xtp b/app/bin/unittest/testfiles/atlasn.xtp
new file mode 100644
index 0000000..882e94c
--- /dev/null
+++ b/app/bin/unittest/testfiles/atlasn.xtp
@@ -0,0 +1,697 @@
+CONTENTS Atlas N-Scale Track
+SUBCONTENTS Atlas N-Scale Track - Straight
+TURNOUT N "Atlas 5in Straight 2501"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 4.910000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 4.910000 0.000000
+ END
+TURNOUT N "Atlas 2 1/2in Straight XXX"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 2.455000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 2.455000 0.000000
+ END
+TURNOUT N "Atlas 1 1/4in Straight XXX"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 1.227500 0.000000 90.000000
+ S 0 0 0.000000 0.000000 1.227500 0.000000
+ END
+TURNOUT N "Atlas 5/8in Straight XXX"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 0.613750 0.000000 90.000000
+ S 0 0 0.000000 0.000000 0.613750 0.000000
+ END
+
+SUBCONTENTS Atlas N-Scale Track - Curved
+TURNOUT N "Atlas 9 3/4R full section 2510"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 4.875000 -1.306000 120.000000
+ C 0 0 9.750000 0.000000 -9.750000 0.000000 30.000000
+ END
+TURNOUT N "Atlas 9 3/4R half section 2511"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 2.523400 -0.332300 105.000000
+ C 0 0 9.750000 0.000000 -9.750000 0.002000 15.000000
+ END
+TURNOUT N "Atlas 11R full section 2520"
+ P "Normal" 1
+ E 0.000000 1.473718 270.000000
+ E 5.499996 0.000000 120.000000
+ C 0 0.000000 11.000000 0.000000 -9.526282 0.000000 30.000000
+ END
+TURNOUT N "Atlas 11R half section 2521"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 2.847000 -0.375000 105.000000
+ C 0 0 11.000000 0.000000 -11.000000 0.000000 15.000000
+ END
+TURNOUT N "Atlas 19R section 2526"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 4.917000 -0.646414 105.000000
+ C 0 0 19.000000 0.000000 -19.000000 0.000000 15.000000
+ END
+
+SUBCONTENTS Atlas N-Scale Track - Bumper / Rerailer
+# Bumper Track Design by Bob Blackwell
+TURNOUT N "Atlas Bumper Track 2536"
+ P "Normal" 1
+ E 0.000000 0.312508 270.000000
+ S 0 0.000000 0.000000 0.312508 2.750000 0.312512
+ F3 0 0.000000 4
+ 1.625000 0.625000 0
+ 2.500000 0.625000 0
+ 2.500000 0.000000 0
+ 1.625000 0.000000 0
+ END
+# Rerailer Track Design by Bob Blackwell
+TURNOUT N "Atlas Rerailer Track 2532"
+ P "NORMAL" 1
+ E 0.000000 0.479167 270.000000
+ E 4.906250 0.479167 90.000000
+ S 0 0.000000 0.000000 0.479167 4.906250 0.479167
+ L3 0 0.020833 1.609375 0.729169 0 3.292817 0.729169 0
+ L3 0 0.020833 1.000000 0.947917 0 3.914062 0.947917 0
+ L3 0 0.020833 3.906248 0.010417 0 3.906249 0.947917 0
+ L3 0 0.020833 3.914062 0.010417 0 1.000000 0.010417 0
+ L3 0 0.020833 0.999998 0.947917 0 1.000001 0.010417 0
+ L3 0 0.020833 1.609375 0.229170 0 3.296875 0.229172 0
+ L3 0 0.020833 1.609375 0.229167 0 1.000000 0.010417 0
+ L3 0 0.020833 3.296875 0.229167 0 3.906250 0.010417 0
+ L3 0 0.020833 1.609375 0.729167 0 1.000000 0.947917 0
+ L3 0 0.020833 3.296875 0.729167 0 3.906250 0.947917 0
+ L3 0 0.020833 1.734375 0.604167 0 3.171875 0.604169 0
+ L3 0 0.020833 1.734375 0.354167 0 3.171875 0.354169 0
+ L3 0 0.020833 1.312500 0.479167 0 1.734375 0.604167 0
+ L3 0 0.020833 1.312500 0.479167 0 1.734375 0.354167 0
+ L3 0 0.020833 3.171875 0.604167 0 3.593750 0.479167 0
+ L3 0 0.020833 3.171875 0.354167 0 3.593750 0.479167 0
+ END
+
+SUBCONTENTS Atlas N-Scale Track - Bridges
+# Warren Truss Bridge Design by Bob Blackwell
+TURNOUT N "Atlas Warren Truss Bridge 2546"
+ P "Normal" 1
+ E 0.010420 0.744792 269.999848
+ E 4.916670 0.744798 89.999848
+ S 0 0.000000 0.010420 0.744792 4.916670 0.744798
+ L3 0 0.020833 0.010420 0.010417 0 4.916670 0.010417 0
+ L3 0 0.020833 4.916665 0.010417 0 4.916669 1.479167 0
+ L3 0 0.020833 4.916670 1.479167 0 0.010420 1.479167 0
+ L3 0 0.020833 0.010419 1.479167 0 0.010417 0.010417 0
+ L3 0 0.020833 4.916670 0.104167 0 0.010420 0.104167 0
+ L3 0 0.020833 4.916670 1.385417 0 0.010420 1.385417 0
+ L3 0 0.020833 0.713545 1.479167 0 0.713545 1.385417 0
+ L3 0 0.020833 4.197920 1.479167 0 4.197920 1.385417 0
+ L3 0 0.020833 0.713545 0.104167 0 0.713545 0.010417 0
+ L3 0 0.020833 4.197920 0.104167 0 4.197920 0.010417 0
+ END
+# Deck Truss Bridge Design by Bob Blackwell
+TURNOUT N "Atlas Deck Truss Bridge 2547"
+ P "Normal" 1
+ E 0.010418 0.385417 269.999854
+ E 4.916668 0.385423 89.999854
+ S 0 0.000000 0.010418 0.385417 4.916668 0.385423
+ L3 0 0.020833 0.010418 0.010417 0 4.916668 0.010417 0
+ L3 0 0.020833 4.916667 0.010417 0 4.916668 0.760417 0
+ L3 0 0.020833 4.916668 0.760417 0 0.010418 0.760417 0
+ L3 0 0.020833 0.010418 0.760417 0 0.010417 0.010417 0
+ L3 0 0.020833 4.916668 0.072917 0 0.010418 0.072917 0
+ L3 0 0.020833 4.916668 0.697917 0 0.010418 0.697917 0
+ END
+# Plate Girder Bridge Design by Bob Blackwell
+TURNOUT N "Atlas Plate Girder Bridge 2548"
+ P "Normal" 1
+ E 0.010417 0.760417 269.999848
+ E 4.916667 0.760423 89.999848
+ S 0 0.000000 0.010417 0.760417 4.916667 0.760423
+ L3 0 0.020833 0.010417 0.010417 0 4.916667 0.010417 0
+ L3 0 0.020833 4.916667 0.010417 0 4.916667 1.510417 0
+ L3 0 0.020833 4.916667 1.510417 0 0.010417 1.510417 0
+ L3 0 0.020833 0.010417 1.510417 0 0.010417 0.010417 0
+ L3 0 0.020833 4.916667 0.104180 0 0.010417 0.104173 0
+ L3 0 0.020833 4.916667 1.416667 0 0.010417 1.416667 0
+ END
+TURNOUT N "Atlas Through Truss Bridge 10in 2570/71"
+ P "Normal" 1
+ E 0.000000 0.000000 270.000000
+ E 10.000000 0.000000 90.000000
+ S 0 0 0.000000 0.000000 10.000000 0.000000
+ L 0 0.053333 0.000000 0.84375 10.000000 0.84375
+ L 0 0.053333 0.000000 -0.84375 10.000000 -0.84375
+ L 0 0.053333 1.625000 -0.84375 1.625000 0.84375
+ L 0 0.053333 1.625000 -0.84375 3.312500 0.84375
+ L 0 0.053333 3.312500 -0.84375 1.625000 0.84375
+ L 0 0.053333 3.312500 -0.84375 3.312500 0.84375
+ L 0 0.053333 3.312500 -0.84375 5.000000 0.84375
+ L 0 0.053333 5.000000 -0.84375 3.312500 0.84375
+ L 0 0.053333 5.000000 -0.84375 5.000000 0.84375
+ L 0 0.053333 5.000000 -0.84375 6.687500 0.84375
+ L 0 0.053333 6.687500 -0.84375 5.000000 0.84375
+ L 0 0.053333 6.687500 -0.84375 6.687500 0.84375
+ L 0 0.053333 6.687500 -0.84375 8.375000 0.84375
+ L 0 0.053333 8.375000 -0.84375 6.687500 0.84375
+ L 0 0.053333 8.375000 -0.84375 8.375000 0.84375
+ END
+
+SUBCONTENTS Atlas N-Scale Track - Crossings
+# 90 Degree Crossing Design by Bob Blackwell
+TURNOUT N "Atlas 90 Degree Crossing 2569"
+ P "Normal" 1 0 2
+ E 0.000000 0.000000 270.000000
+ E 4.910000 0.000000 90.000000
+ E 2.455000 2.455000 0.000000
+ E 2.455000 -2.455000 180.000000
+ S 0 0 0.000000 0.000000 4.910000 0.000000
+ S 0 0 2.455000 2.455000 2.455000 -2.455000
+ END
+# 60 Degree Crossing Design by Bob Blackwell
+TURNOUT N "Atlas 60 Degree Crossing 2568"
+ P "Normal" 1 0 2
+ E 0.000000 1.650872 270.000000
+ E 2.859358 3.301727 29.999802
+ E 3.812500 1.650872 90.000000
+ E 0.953116 0.000000 209.999802
+ S 0 0.000000 0.000000 1.650872 3.812500 1.650872
+ S 0 0.000000 2.859358 3.301727 0.953116 0.000000
+ END
+# 45 Degree Crossing Design by Bob Blackwell
+TURNOUT N "Atlas 45 Degree Crossing 2567"
+ P "Normal" 1 0 2
+ E 0.000000 1.414217 270.000000
+ E 3.414208 2.828431 44.999886
+ E 4.000000 1.414217 90.000000
+ E 0.585785 0.000000 224.999886
+ S 0 0.000000 0.000000 1.414217 4.000000 1.414217
+ S 0 0.000000 3.414208 2.828431 0.585785 0.000000
+ END
+# 30 Degree Crossing Design by Bob Blackwell
+TURNOUT N "Atlas 30 Degree Crossing 2566"
+ P "Normal" 1 0 2
+ E 0.000000 0.648442 270.000000
+ E 2.419997 1.296881 59.999819
+ E 2.593750 0.648442 90.000000
+ E 0.173747 0.000000 239.999819
+ S 0 0.000000 0.000000 0.648442 2.593750 0.648442
+ S 0 0.000000 2.419997 1.296881 0.173747 0.000000
+ END
+# 20 Degree Crossing Design by Bob Blackwell
+TURNOUT N "Atlas 20 Degree Crossing 2565"
+ P "Normal" 1 0 2
+ E 0.000000 0.849704 270.000007
+ E 4.818923 1.699405 70.000081
+ E 4.968750 0.849703 90.000007
+ E 0.149822 0.000000 250.000081
+ S 0 0.000000 0.149822 0.000000 4.818923 1.699405
+ S 0 0.000000 0.000000 0.849704 4.968750 0.849703
+ END
+# 15 Degree Crossing Design by Bob Blackwell
+TURNOUT N "Atlas 15 Degree Crossover 2564"
+ P "Normal" 1 0 2
+ E 0.085186 0.000000 255.000000
+ E 4.914815 1.294094 75.000000
+ E 0.000000 0.647044 270.000000
+ E 5.000001 0.647050 90.000000
+ S 0 0.000000 0.085186 0.000000 4.914815 1.294094
+ S 0 0.000000 0.000000 0.647044 5.000001 0.647050
+ END
+
+SUBCONTENTS Atlas N-Scale Track - Standard Remote Switches
+# Remote Std #4 LH Switch 2700 Design by Bob Blackwell
+TURNOUT N "Atlas Remote Std #4 LH Switch 2700"
+ P "Normal" 1
+ P "Reverse" 2
+ E 0.001050 0.708331 270.000000
+ E 4.911050 0.708331 90.000000
+ E 4.918050 1.354745 75.000000
+ S 0 0.000000 0.001050 0.708331 4.911050 0.708331
+ C 0 0.000000 -19.000000 0.000050 19.708331 165.000000 15.000000
+ L3 0 0.020833 4.131258 0.479164 0 0.537508 0.479170 0
+ L3 0 0.020833 4.131258 0.479164 0 4.131258 0.244789 0
+ L3 0 0.020833 0.537508 0.479174 0 0.537508 0.244799 0
+ L3 0 0.020833 3.131258 0.276042 0 1.537508 0.276046 0
+ L3 0 0.020833 1.537507 0.010421 0 3.131257 0.010417 0
+ L3 0 0.020833 4.131258 0.244789 0 3.131257 0.010417 0
+ L3 0 0.020833 1.537507 0.010421 0 0.537508 0.244799 0
+ L3 0 0.020833 3.131257 0.010417 0 3.131258 0.276042 0
+ L3 0 0.020833 1.537507 0.010421 0 1.537508 0.276046 0
+ L3 0 0.020833 3.881258 0.479165 0 3.881258 0.197915 0
+ L3 0 0.020833 0.787508 0.479173 0 0.787508 0.197923 0
+ A3 0 0.010417 0.064424 4.006258 0.354164 0 180.000000 360.000000
+ A3 0 0.010417 0.049411 4.006258 0.354164 0 180.000000 360.000000
+ A3 0 0.010417 0.062500 0.662508 0.354173 0 180.000000 360.000000
+ A3 0 0.010417 0.044194 0.662508 0.354173 0 180.000000 360.000000
+ END
+# Remote Std #4 RH Switch 2701 Design by Bob Blackwell
+TURNOUT N "Atlas Remote Std #4 RH Switch 2701"
+ P "Normal" 1
+ P "Reverse" 2
+ E 0.001000 0.647408 270.000000
+ E 4.911000 0.647408 90.000000
+ E 4.911000 0.000994 105.000000
+ S 0 0.000000 0.001000 0.647408 4.911000 0.647408
+ C 0 0.000000 19.000000 0.000000 -18.352592 0.000000 15.000000
+ L3 0 0.020833 0.527042 0.876575 0 4.120792 0.876579 0
+ L3 0 0.020833 0.527042 0.876575 0 0.527042 1.110950 0
+ L3 0 0.020833 4.120792 0.876575 0 4.120792 1.110950 0
+ L3 0 0.020833 1.527042 1.079700 0 3.120792 1.079700 0
+ L3 0 0.020833 3.120792 1.345325 0 1.527042 1.345325 0
+ L3 0 0.020833 0.527042 1.110950 0 1.527042 1.345325 0
+ L3 0 0.020833 3.120792 1.345325 0 4.120792 1.110950 0
+ L3 0 0.020833 1.527042 1.345325 0 1.527042 1.079700 0
+ L3 0 0.020833 3.120792 1.345325 0 3.120792 1.079700 0
+ L3 0 0.020833 0.777042 0.876575 0 0.777042 1.157825 0
+ L3 0 0.020833 3.870792 0.876575 0 3.870792 1.157825 0
+ A3 0 0.010417 0.064424 0.652042 1.001575 0 0.000000 360.000000
+ A3 0 0.010417 0.049411 0.652042 1.001575 0 0.000000 360.000000
+ A3 0 0.010417 0.062500 3.995792 1.001575 0 0.000000 360.000000
+ A3 0 0.010417 0.044194 3.995792 1.001575 0 0.000000 360.000000
+ END
+# Remote #6 LH Switch 2704 Design by Bob Blackwell
+TURNOUT N "Atlas Remote #6 LH Switch 2704"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.708331 270.000000
+ E 6.109375 0.708331 90.000000
+ E 6.156250 1.364581 80.500000
+ S 0 0.000000 0.000000 0.708331 0.353100 0.708331
+ S 0 0.000000 0.353100 0.708331 6.109375 0.708331
+ C 0 0.000000 -22.644376 0.353130 23.352707 170.499924 9.500152
+ S 0 0.000000 4.090556 1.018894 6.156250 1.364581
+ L3 0 0.020833 4.489583 0.479164 0 0.895833 0.479170 0
+ L3 0 0.020833 4.489583 0.479164 0 4.489582 0.244789 0
+ L3 0 0.020833 0.895833 0.479174 0 0.895832 0.244799 0
+ L3 0 0.020833 3.489582 0.276042 0 1.895832 0.276046 0
+ L3 0 0.020833 1.895832 0.010421 0 3.489582 0.010417 0
+ L3 0 0.020833 4.489582 0.244789 0 3.489582 0.010417 0
+ L3 0 0.020833 1.895832 0.010421 0 0.895832 0.244799 0
+ L3 0 0.020833 3.489582 0.010417 0 3.489582 0.276042 0
+ L3 0 0.020833 1.895832 0.010421 0 1.895832 0.276046 0
+ L3 0 0.020833 4.239583 0.479165 0 4.239582 0.197915 0
+ L3 0 0.020833 1.145833 0.479173 0 1.145832 0.197923 0
+ A3 0 0.010417 0.064424 4.364583 0.354164 0 180.000000 360.000000
+ A3 0 0.010417 0.049411 4.364583 0.354164 0 180.000000 360.000000
+ A3 0 0.010417 0.062500 1.020833 0.354173 0 180.000000 360.000000
+ A3 0 0.010417 0.044194 1.020833 0.354173 0 180.000000 360.000000
+ END
+# Remote #6 RH Switch 2705 Design by Bob Blackwell
+TURNOUT N "Atlas Remote #6 RH Switch 2705"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.656250 270.000000
+ E 6.109375 0.656250 90.000000
+ E 6.156250 0.000000 99.500000
+ S 0 0.000000 0.000000 0.656250 0.353100 0.656250
+ S 0 0.000000 0.353100 0.656250 6.109375 0.656250
+ C 0 0.000000 22.644376 0.353010 -21.988126 0.000076 9.500152
+ S 0 0.000000 4.090556 0.345687 6.156250 0.000000
+ L3 0 0.020833 0.885417 0.885417 0 4.479167 0.885421 0
+ L3 0 0.020833 0.885417 0.885417 0 0.885417 1.119792 0
+ L3 0 0.020833 4.479167 0.885417 0 4.479167 1.119792 0
+ L3 0 0.020833 1.885417 1.088542 0 3.479167 1.088542 0
+ L3 0 0.020833 3.479167 1.354167 0 1.885417 1.354167 0
+ L3 0 0.020833 0.885417 1.119792 0 1.885417 1.354167 0
+ L3 0 0.020833 3.479167 1.354167 0 4.479167 1.119792 0
+ L3 0 0.020833 1.885417 1.354167 0 1.885417 1.088542 0
+ L3 0 0.020833 3.479167 1.354167 0 3.479167 1.088542 0
+ L3 0 0.020833 1.135417 0.885417 0 1.135417 1.166667 0
+ L3 0 0.020833 4.229167 0.885417 0 4.229167 1.166667 0
+ A3 0 0.010417 0.064424 1.010417 1.010417 0 0.000000 360.000000
+ A3 0 0.010417 0.049411 1.010417 1.010417 0 0.000000 360.000000
+ A3 0 0.010417 0.062500 4.354167 1.010417 0 0.000000 360.000000
+ A3 0 0.010417 0.044194 4.354167 1.010417 0 0.000000 360.000000
+ END
+SUBCONTENTS Atlas N-Scale Track - Standard Manual Switches
+# Manual Std #4 LH Switch 2702 Design by Bob Blackwell
+TURNOUT N "Atlas Manual Std #4 LH Switch 2702"
+ P "Normal" 1
+ P "Reverse" 2
+ E 0.001050 0.708331 270.000000
+ E 4.911050 0.708331 90.000000
+ E 4.918050 1.354745 75.000000
+ S 0 0.000000 0.001050 0.708331 4.911050 0.708331
+ C 0 0.000000 -19.000000 0.000050 19.708331 165.000000 15.000000
+ L3 0 0.020833 4.131258 0.479164 0 0.537508 0.479170 0
+ L3 0 0.020833 4.131258 0.479164 0 4.131258 0.244789 0
+ L3 0 0.020833 0.537508 0.479174 0 0.537508 0.244799 0
+ L3 0 0.020833 3.131258 0.276042 0 1.537508 0.276046 0
+ L3 0 0.020833 1.537507 0.010421 0 3.131257 0.010417 0
+ L3 0 0.020833 4.131258 0.244789 0 3.131257 0.010417 0
+ L3 0 0.020833 1.537507 0.010421 0 0.537508 0.244799 0
+ L3 0 0.020833 3.131257 0.010417 0 3.131258 0.276042 0
+ L3 0 0.020833 1.537507 0.010421 0 1.537508 0.276046 0
+ L3 0 0.020833 3.881258 0.479165 0 3.881258 0.197915 0
+ L3 0 0.020833 0.787508 0.479173 0 0.787508 0.197923 0
+ A3 0 0.010417 0.064424 4.006258 0.354164 0 180.000000 360.000000
+ A3 0 0.010417 0.049411 4.006258 0.354164 0 180.000000 360.000000
+ A3 0 0.010417 0.062500 0.662508 0.354173 0 180.000000 360.000000
+ A3 0 0.010417 0.044194 0.662508 0.354173 0 180.000000 360.000000
+ END
+# Manual Std #4 RH Switch 2703 Design by Bob Blackwell
+TURNOUT N "Atlas Manual Std #4 RH Switch 2703"
+ P "Normal" 1
+ P "Reverse" 2
+ E 0.001000 0.647408 270.000000
+ E 4.911000 0.647408 90.000000
+ E 4.911000 0.000994 105.000000
+ S 0 0.000000 0.001000 0.647408 4.911000 0.647408
+ C 0 0.000000 19.000000 0.000000 -18.352592 0.000000 15.000000
+ L3 0 0.020833 0.527042 0.876575 0 4.120792 0.876579 0
+ L3 0 0.020833 0.527042 0.876575 0 0.527042 1.110950 0
+ L3 0 0.020833 4.120792 0.876575 0 4.120792 1.110950 0
+ L3 0 0.020833 1.527042 1.079700 0 3.120792 1.079700 0
+ L3 0 0.020833 3.120792 1.345325 0 1.527042 1.345325 0
+ L3 0 0.020833 0.527042 1.110950 0 1.527042 1.345325 0
+ L3 0 0.020833 3.120792 1.345325 0 4.120792 1.110950 0
+ L3 0 0.020833 1.527042 1.345325 0 1.527042 1.079700 0
+ L3 0 0.020833 3.120792 1.345325 0 3.120792 1.079700 0
+ L3 0 0.020833 0.777042 0.876575 0 0.777042 1.157825 0
+ L3 0 0.020833 3.870792 0.876575 0 3.870792 1.157825 0
+ A3 0 0.010417 0.064424 0.652042 1.001575 0 0.000000 360.000000
+ A3 0 0.010417 0.049411 0.652042 1.001575 0 0.000000 360.000000
+ A3 0 0.010417 0.062500 3.995792 1.001575 0 0.000000 360.000000
+ A3 0 0.010417 0.044194 3.995792 1.001575 0 0.000000 360.000000
+ END
+# Manual #6 LH Switch 2706 Design by Bob Blackwell
+TURNOUT N "Atlas Manual #6 LH Switch 2706"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.708331 270.000000
+ E 6.109375 0.708331 90.000000
+ E 6.156250 1.364581 80.500000
+ S 0 0.000000 0.000000 0.708331 0.353100 0.708331
+ S 0 0.000000 0.353100 0.708331 6.109375 0.708331
+ C 0 0.000000 -22.644376 0.353130 23.352707 170.499924 9.500152
+ S 0 0.000000 4.090556 1.018894 6.156250 1.364581
+ L3 0 0.020833 4.489583 0.479164 0 0.895833 0.479170 0
+ L3 0 0.020833 4.489583 0.479164 0 4.489582 0.244789 0
+ L3 0 0.020833 0.895833 0.479174 0 0.895832 0.244799 0
+ L3 0 0.020833 3.489582 0.276042 0 1.895832 0.276046 0
+ L3 0 0.020833 1.895832 0.010421 0 3.489582 0.010417 0
+ L3 0 0.020833 4.489582 0.244789 0 3.489582 0.010417 0
+ L3 0 0.020833 1.895832 0.010421 0 0.895832 0.244799 0
+ L3 0 0.020833 3.489582 0.010417 0 3.489582 0.276042 0
+ L3 0 0.020833 1.895832 0.010421 0 1.895832 0.276046 0
+ L3 0 0.020833 4.239583 0.479165 0 4.239582 0.197915 0
+ L3 0 0.020833 1.145833 0.479173 0 1.145832 0.197923 0
+ A3 0 0.010417 0.064424 4.364583 0.354164 0 180.000000 360.000000
+ A3 0 0.010417 0.049411 4.364583 0.354164 0 180.000000 360.000000
+ A3 0 0.010417 0.062500 1.020833 0.354173 0 180.000000 360.000000
+ A3 0 0.010417 0.044194 1.020833 0.354173 0 180.000000 360.000000
+ END
+# Manual #6 RH Switch 2707 Design by Bob Blackwell
+TURNOUT N "Atlas Manual #6 RH Switch 2707"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.656250 270.000000
+ E 6.109375 0.656250 90.000000
+ E 6.156250 0.000000 99.500000
+ S 0 0.000000 0.000000 0.656250 0.353100 0.656250
+ S 0 0.000000 0.353100 0.656250 6.109375 0.656250
+ C 0 0.000000 22.644376 0.353010 -21.988126 0.000076 9.500152
+ S 0 0.000000 4.090556 0.345687 6.156250 0.000000
+ L3 0 0.020833 0.885417 0.885417 0 4.479167 0.885421 0
+ L3 0 0.020833 0.885417 0.885417 0 0.885417 1.119792 0
+ L3 0 0.020833 4.479167 0.885417 0 4.479167 1.119792 0
+ L3 0 0.020833 1.885417 1.088542 0 3.479167 1.088542 0
+ L3 0 0.020833 3.479167 1.354167 0 1.885417 1.354167 0
+ L3 0 0.020833 0.885417 1.119792 0 1.885417 1.354167 0
+ L3 0 0.020833 3.479167 1.354167 0 4.479167 1.119792 0
+ L3 0 0.020833 1.885417 1.354167 0 1.885417 1.088542 0
+ L3 0 0.020833 3.479167 1.354167 0 3.479167 1.088542 0
+ L3 0 0.020833 1.135417 0.885417 0 1.135417 1.166667 0
+ L3 0 0.020833 4.229167 0.885417 0 4.229167 1.166667 0
+ A3 0 0.010417 0.064424 1.010417 1.010417 0 0.000000 360.000000
+ A3 0 0.010417 0.049411 1.010417 1.010417 0 0.000000 360.000000
+ A3 0 0.010417 0.062500 4.354167 1.010417 0 0.000000 360.000000
+ A3 0 0.010417 0.044194 4.354167 1.010417 0 0.000000 360.000000
+ END
+TURNOUT N "Atlas Remote Standard Wye 2708"
+ P "Left" 1 2 3
+ P "Right" 1 4 5
+ E 0.000000 0.000000 270.000000
+ E 4.910000 0.646414 75.000000
+ E 4.910000 -0.646414 105.000000
+ S 0 0.000000 0.000000 0.000000 0.354344 0.000000
+ C 0 0.000000 -16.279453 0.354366 16.279453 164.999924 15.000152
+ S 0 0.000000 4.567815 0.554719 4.910000 0.646414
+ C 0 0.000000 16.279453 0.354280 -16.279453 0.000076 15.000152
+ S 0 0.000000 4.567815 -0.554719 4.910000 -0.646414
+ L3 0 0.020833 0.616960 0.202769 0 4.178616 0.681977 0
+ L3 0 0.020833 0.616960 0.202769 0 0.585708 0.435051 0
+ L3 0 0.020833 4.178617 0.681973 0 4.147364 0.914255 0
+ L3 0 0.020833 1.580944 0.537424 0 3.160462 0.749940 0
+ L3 0 0.020833 3.125042 1.013193 0 1.545524 0.800677 0
+ L3 0 0.020833 0.585708 0.435051 0 1.545524 0.800677 0
+ L3 0 0.020833 3.125042 1.013193 0 4.147364 0.914255 0
+ L3 0 0.020833 1.545524 0.800677 0 1.580944 0.537424 0
+ L3 0 0.020833 3.125042 1.013193 0 3.160462 0.749940 0
+ L3 0 0.020833 0.864727 0.236105 0 0.827224 0.514844 0
+ L3 0 0.020833 3.930850 0.648638 0 3.893346 0.927376 0
+ A3 0 0.010417 0.064424 0.724175 0.343321 0 352.337139 360.000000
+ A3 0 0.010417 0.049411 0.724175 0.343321 0 352.337139 360.000000
+ A3 0 0.010417 0.062500 4.038066 0.789189 0 352.337139 360.000000
+ A3 0 0.010417 0.044194 4.038066 0.789189 0 352.337139 360.000000
+ END
+TURNOUT N "Atlas Manual Standard Wye 2709"
+ P "Left" 1 2 3
+ P "Right" 1 4 5
+ E 0.000000 0.000000 270.000000
+ E 4.910000 0.646414 75.000000
+ E 4.910000 -0.646414 105.000000
+ S 0 0.000000 0.000000 0.000000 0.354344 0.000000
+ C 0 0.000000 -16.279453 0.354366 16.279453 164.999924 15.000152
+ S 0 0.000000 4.567815 0.554719 4.910000 0.646414
+ C 0 0.000000 16.279453 0.354280 -16.279453 0.000076 15.000152
+ S 0 0.000000 4.567815 -0.554719 4.910000 -0.646414
+ L3 0 0.020833 0.616960 0.202769 0 4.178616 0.681977 0
+ L3 0 0.020833 0.616960 0.202769 0 0.585708 0.435051 0
+ L3 0 0.020833 4.178617 0.681973 0 4.147364 0.914255 0
+ L3 0 0.020833 1.580944 0.537424 0 3.160462 0.749940 0
+ L3 0 0.020833 3.125042 1.013193 0 1.545524 0.800677 0
+ L3 0 0.020833 0.585708 0.435051 0 1.545524 0.800677 0
+ L3 0 0.020833 3.125042 1.013193 0 4.147364 0.914255 0
+ L3 0 0.020833 1.545524 0.800677 0 1.580944 0.537424 0
+ L3 0 0.020833 3.125042 1.013193 0 3.160462 0.749940 0
+ L3 0 0.020833 0.864727 0.236105 0 0.827224 0.514844 0
+ L3 0 0.020833 3.930850 0.648638 0 3.893346 0.927376 0
+ A3 0 0.010417 0.064424 0.724175 0.343321 0 352.337139 360.000000
+ A3 0 0.010417 0.049411 0.724175 0.343321 0 352.337139 360.000000
+ A3 0 0.010417 0.062500 4.038066 0.789189 0 352.337139 360.000000
+ A3 0 0.010417 0.044194 4.038066 0.789189 0 352.337139 360.000000
+ END
+
+SUBCONTENTS Atlas N-Scale Track - Custom (Motorless) Switches
+# Custom Std #4 LH Switch 2750 Design by Bob Blackwell
+TURNOUT N "Atlas Custom Std #4 LH Switch 2750"
+ P "Normal" 1
+ P "Reverse" 2
+ E 0.000000 0.000000 270.000000
+ E 4.910000 0.000000 90.000000
+ E 4.917000 0.646414 75.000000
+ S 0 0 0.000000 0.000000 4.910000 0.000000
+ C 0 0 -19.000000 -0.001000 19.000000 165.000000 15.000000
+ END
+# Custom Std #4 RH Switch 2751 Design by Bob Blackwell
+TURNOUT N "Atlas Custom Std #4 RH Switch 2751"
+ P "Normal" 1
+ P "Reverse" 2
+ E 0.000000 0.000000 270.000000
+ E 4.910000 0.000000 90.000000
+ E 4.910000 -0.646414 105.000000
+ S 0 0 0.000000 0.000000 4.910000 0.000000
+ C 0 0 19.000000 -0.001000 -19.000000 0.000000 15.000000
+ END
+# Custom LH #6 Switch 2752 Design by Bob Blackwell
+TURNOUT N "Atlas Custom LH #6 Switch 2752"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 6.109375 0.000000 90.000000
+ E 6.156250 0.656250 80.500000
+ S 0 0.000000 0.000000 0.000000 0.353100 0.000000
+ S 0 0.000000 0.353100 0.000000 6.109375 0.000000
+ C 0 0.000000 -22.644376 0.353130 22.644376 170.499924 9.500152
+ S 0 0.000000 4.090556 0.310563 6.156250 0.656250
+ END
+# Custom RH #6 Switch 2753 Design by Bob Blackwell
+TURNOUT N "Atlas Custom RH #6 Switch 2753"
+ P "Normal" 1 2
+ P "Reverse" 1 3 4
+ E 0.000000 0.000000 270.000000
+ E 6.109375 0.000000 90.000000
+ E 6.156250 -0.656250 99.500000
+ S 0 0.000000 0.000000 0.000000 0.353100 0.000000
+ S 0 0.000000 0.353100 0.000000 6.109375 0.000000
+ C 0 0.000000 22.644376 0.353010 -22.644376 0.000076 9.500152
+ S 0 0.000000 4.090556 -0.310563 6.156250 -0.656250
+ END
+TURNOUT N "Atlas Custom Standard Wye 2754"
+ P "Left" 1 2 3
+ P "Right" 1 4 5
+ E 0.000000 0.000000 270.000000
+ E 4.910000 0.646414 75.000000
+ E 4.910000 -0.646414 105.000000
+ S 0 0.000000 0.000000 0.000000 0.354344 0.000000
+ C 0 0.000000 -16.279453 0.354366 16.279453 164.999924 15.000152
+ S 0 0.000000 4.567815 0.554719 4.910000 0.646414
+ C 0 0.000000 16.279453 0.354280 -16.279453 0.000076 15.000152
+ S 0 0.000000 4.567815 -0.554719 4.910000 -0.646414
+ END
+
+SUBCONTENTS Atlas N-Scale Structures - Bridge
+# Bridge Pier (Base) Design by Bob Blackwell
+STRUCTURE N "Atlas Bridge Pier 2541"
+ X pier 0.140625 "1" 0.281250 "2" 0.421875 "3" 0.562500 "4" 0.703125 "5" 0.843750 "6" 0.984375 "7" 1.125000 "8" 1.265625 "9" 1.406250 "10" 1.546875 "11" 1.687500 "12"
+ A3 0 0.020833 0.312500 -0.000000 0.687500 0 270.000000 180.000000
+ A3 0 0.020833 0.312500 -0.000000 -0.687500 0 90.000000 180.000000
+ L3 0 0.020833 0.312500 0.687500 0 0.312500 -0.687500 0
+ L3 0 0.020833 -0.312500 0.687500 0 -0.312500 -0.687500 0
+ A3 0 0.020833 0.250000 -0.000000 -0.375000 0 90.000000 180.000000
+ A3 0 0.020833 0.250000 -0.000000 0.375000 0 270.000000 180.000000
+ L3 0 0.020833 -0.250000 0.375000 0 -0.249999 -0.375000 0
+ L3 0 0.020833 0.250000 0.375000 0 0.250001 -0.375000 0
+ END
+STRUCTURE N "Atlas Bridge Pier (Base) 2543"
+ X pier 1.687500 "B"
+ A3 0 0.020833 0.312500 -0.000000 0.687500 0 270.000000 180.000000
+ A3 0 0.020833 0.312500 -0.000000 -0.687500 0 90.000000 180.000000
+ L3 0 0.020833 0.312500 0.687500 0 0.312500 -0.687500 0
+ L3 0 0.020833 -0.312500 0.687500 0 -0.312500 -0.687500 0
+ A3 0 0.020833 0.250000 -0.000000 -0.375000 0 90.000000 180.000000
+ A3 0 0.020833 0.250000 -0.000000 0.375000 0 270.000000 180.000000
+ L3 0 0.020833 -0.250000 0.375000 0 -0.249999 -0.375000 0
+ L3 0 0.020833 0.250000 0.375000 0 0.250001 -0.375000 0
+ END
+# Viaduct Kit Design by Bob Blackwell
+STRUCTURE N "Atlas Viaduct Kit 2826"
+ L3 0 0.020833 0.010419 0.010417 0 4.385419 0.010422 0
+ L3 0 0.020833 4.385419 0.010417 0 4.385419 1.135417 0
+ L3 0 0.020833 4.385419 1.135422 0 0.010419 1.135417 0
+ L3 0 0.020833 0.010418 1.135417 0 0.010417 0.010417 0
+ L3 0 0.020833 4.385419 0.104172 0 0.010419 0.104167 0
+ L3 0 0.020833 4.385419 1.041676 0 0.010419 1.041670 0
+ L3 0 0.020833 4.385419 1.088547 0 0.010419 1.088542 0
+ L3 0 0.020833 4.385419 0.057297 0 0.010419 0.057292 0
+ END
+SUBCONTENTS Atlas N-Scale Structures - Switch Machines
+# Remote Switch Machine Design by Bob Blackwell
+STRUCTURE N "Atlas Remote Switch Machine 271x"
+ L3 0 0.020833 0.010417 0.010417 0 3.604167 0.010421 0
+ L3 0 0.020833 0.010417 0.010417 0 0.010417 0.244792 0
+ L3 0 0.020833 3.604167 0.010417 0 3.604167 0.244792 0
+ L3 0 0.020833 1.010417 0.213542 0 2.604167 0.213542 0
+ L3 0 0.020833 2.604167 0.479167 0 1.010417 0.479167 0
+ L3 0 0.020833 0.010417 0.244792 0 1.010417 0.479167 0
+ L3 0 0.020833 2.604167 0.479167 0 3.604167 0.244792 0
+ L3 0 0.020833 1.010417 0.479167 0 1.010417 0.213542 0
+ L3 0 0.020833 2.604167 0.479167 0 2.604167 0.213542 0
+ L3 0 0.020833 0.260417 0.010417 0 0.260417 0.291667 0
+ L3 0 0.020833 3.354167 0.010417 0 3.354167 0.291667 0
+ A3 0 0.010417 0.064424 0.135417 0.135417 0 0.000000 360.000000
+ A3 0 0.010417 0.049411 0.135417 0.135417 0 0.000000 360.000000
+ A3 0 0.010417 0.062500 3.479167 0.135417 0 0.000000 360.000000
+ A3 0 0.010417 0.044194 3.479167 0.135417 0 0.000000 360.000000
+ END
+
+
+SUBCONTENTS Atlas N-Scale Structures - Turn Table
+TURNOUT N "Atlas Turn Table 2790"
+# TT was designed with 7.5in bridge, 8.5in outside dia., 15 degree spacing
+ P "1" 1 2 3
+ P "2" 4 5 6
+ P "3" 7 8 9
+ P "4" 10 11 12
+ P "5" 13 14 15
+ P "6" 16 17 18
+ P "7" 19 20 21
+ P "8" 22 23 24
+ P "9" 25 26 27
+ P "10" 28 29 30
+ P "11" 31 32 33
+ P "12" 34 35 36
+
+ E 0.000000 4.250000 0.000000
+ E 1.099981 4.105185 15.000000
+ E 2.125000 3.680608 30.000000
+ E 3.005204 3.005204 45.000000
+ E 3.680608 2.125000 60.000000
+# E 4.105185 1.099981 75.000000
+# E 4.250000 0.000000 90.000000
+# E 4.105185 -1.099981 105.000000
+ E 3.680608 -2.125000 120.000000
+ E 3.005204 -3.005204 135.000000
+ E 2.125000 -3.680608 150.000000
+ E 1.099981 -4.105185 165.000000
+ E 0.000000 -4.250000 180.000000
+ E -1.099981 -4.105185 195.000000
+ E -2.125000 -3.680608 210.000000
+ E -3.005204 -3.005204 225.000000
+ E -3.680608 -2.125000 240.000000
+ E -4.105185 -1.099981 255.000000
+ E -4.250000 0.000000 270.000000
+ E -4.105185 1.099981 285.000000
+ E -3.680608 2.125000 300.000000
+ E -3.005204 3.005204 315.000000
+ E -2.125000 3.680608 330.000000
+ E -1.080111 4.031029 345.000000
+#0/360
+ S 0 0 0.000000 4.250000 0.000000 3.750000
+ S 0 0 0.000000 3.750000 0.000000 -3.750000
+ S 0 0 0.000000 -3.750000 0.000000 -4.250000
+#15/195
+ S 0 0 1.099981 4.105185 0.970571 3.622222
+ S 0 0 0.970571 3.622222 -0.970571 -3.622222
+ S 0 0 -0.970571 -3.622222 -1.099981 -4.105185
+#30/210
+ S 0 0 2.125000 3.680608 1.875000 3.247595
+ S 0 0 1.836614 3.247595 -1.875000 -3.247595
+ S 0 0 -1.875000 -3.247595 -2.125000 -3.680608
+#45/225
+ S 0 0 3.005204 3.005204 2.651650 2.651650
+ S 0 0 2.651650 2.651650 -2.651650 -2.651650
+ S 0 0 -2.651650 -2.651650 -3.005204 -3.005204
+#60/240
+ S 0 0 3.680608 2.125000 3.247595 1.875000
+ S 0 0 3.247595 1.875000 -3.247595 -1.875000
+ S 0 0 -3.247595 -1.875000 -3.680608 -2.125000
+#75/255
+ S 0 0 4.105185 1.099981 3.622222 0.970571
+ S 0 0 3.622222 0.970571 -3.622222 -0.970571
+ S 0 0 -3.622222 -0.970571 -4.105185 -1.099981
+#90/270
+ S 0 0 4.250000 0.000000 3.750000 0.000000
+ S 0 0 3.750000 0.000000 -3.750000 0.000000
+ S 0 0 -3.750000 0.000000 -4.250000 0.000000
+#105/285
+ S 0 0 4.105185 -1.099981 3.622222 -0.970571
+ S 0 0 3.622222 -0.970571 -3.622222 0.970571
+ S 0 0 -3.622222 0.970571 -4.105185 1.099981
+#120/300
+ S 0 0 3.680608 -2.125000 3.247595 -1.875000
+ S 0 0 3.247595 -1.875000 -3.247595 1.875000
+ S 0 0 -3.247595 1.875000 -3.680608 2.125000
+#135/315
+ S 0 0 3.005204 -3.005204 2.651650 -2.651650
+ S 0 0 2.651650 -2.651650 -2.651650 2.651650
+ S 0 0 -2.651650 2.651650 -3.005204 3.005204
+#150/330
+ S 0 0 2.125000 -3.680608 1.875000 -3.247595
+ S 0 0 1.836614 -3.247595 -1.875000 3.247595
+ S 0 0 -1.875000 3.247595 -2.125000 3.680608
+#165/345
+ S 0 0 1.099981 -4.105185 0.970571 -3.622222
+ S 0 0 0.970571 -3.622222 -0.970571 3.622222
+ S 0 0 -0.970571 3.622222 -1.099981 4.105185
+
+ A 11579568 0.053333 4.250000 0.000000 0.000000 0.000000 360.000000
+ A 11579568 0.053333 3.750000 0.000000 0.000000 0.000000 360.000000
+ L 11579568 0.053333 4.000000 1.437500 6.000000 1.437500 0
+ L 11579568 0.053333 6.000000 1.437500 6.000000 -1.437500 0
+ L 11579568 0.053333 4.000000 -1.437500 6.000000 -1.437500 0
+ END \ No newline at end of file
diff --git a/app/bin/utf8convert.c b/app/bin/utf8convert.c
new file mode 100644
index 0000000..0573c93
--- /dev/null
+++ b/app/bin/utf8convert.c
@@ -0,0 +1,96 @@
+/**
+ * \file utf8convert.c
+ *
+ * UTF8 conversion functions
+ */
+
+ /* XTrackCad - Model Railroad CAD
+ * Copyright (C) 2020 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 <string.h>
+
+#include <wlib.h>
+#include "misc.h"
+#include "include/utf8convert.h"
+
+/**
+ * Convert to UTF-8. The string must by a dynamically allocated storage block
+ * allocated with MyMalloc(). The functions returns a pointer to the converted
+ * string. If no conversion was necessary the returned string is identical to
+ * the parameter. Otherwise a new buffer is allocated and returned.
+ *
+ * \param [in] string If non-null, the string.
+ *
+ * \returns a pointer to a MyMalloc'ed string in UTF-8 format.
+ */
+
+char *
+Convert2UTF8( char *string )
+{
+ if (RequiresConvToUTF8(string)) {
+ unsigned cnt = strlen(string) * 2 + 2;
+ unsigned char *out = MyMalloc(cnt);
+ wSystemToUTF8(string, out, cnt);
+ MyFree(string);
+ return(out);
+ } else {
+ return(string);
+ }
+}
+
+/**
+ * Convert a string from UTF-8 to system codepage in place. As the length of
+ * the result most be equal or smaller than the input this is a safe
+ * approach.
+ *
+ * \param [in,out] in the string to be converted
+ */
+
+void
+ConvertUTF8ToSystem(unsigned char *in)
+{
+ if (wIsUTF8(in)) {
+ unsigned cnt = strlen(in) * 2 + 1;
+ unsigned char *out = MyMalloc(cnt);
+ wUTF8ToSystem(in, out, cnt);
+ strcpy(in, out);
+ MyFree(out);
+ }
+}
+
+/**
+ * Requires convert to UTF-8 If at least one character is >127 the string
+ * has to be converted.
+ *
+ * \param [in9 string the string.
+ *
+ * \returns True if conversion is required, false if not.
+ */
+
+bool
+RequiresConvToUTF8(char *string)
+{
+ while (*string) {
+ if (*string++ & 0x7F) {
+ return(true);
+ }
+ }
+ return(false);
+}
+
+
diff --git a/app/bin/utility.c b/app/bin/utility.c
index d1f798c..93f9979 100644
--- a/app/bin/utility.c
+++ b/app/bin/utility.c
@@ -217,6 +217,115 @@ void FindPos( coOrd * res, double * beyond, coOrd pos, coOrd orig, double angle,
}
+/* Find Arc Intersection
+ * Given two circles described by centers and radius (C1, R1) (C2, R2) Find the zero, one or two intersection points
+ *
+ */
+BOOL_T FindArcIntersections ( coOrd *Pc, coOrd *Pc2, coOrd center1, DIST_T radius1, coOrd center2, DIST_T radius2) {
+ double d,a,h;
+
+ d = sqrt((center2.x-center1.x)*(center2.x-center1.x)+(center2.y-center1.y)*(center2.y-center1.y));
+ if (d >(radius1+radius2)) return FALSE; //Too far apart
+ if (d<fabs(radius1-radius2)) return FALSE; //Inside each other
+ if ((d == 0) && (radius1 == radius2)) return FALSE; // Coincident and the same
+ a=((radius1*radius1)-(radius2*radius2)+(d*d))/(2*d);
+ if ((radius1*radius1)<(a*a)) return FALSE;
+ h = sqrt((radius1*radius1)-(a*a));
+
+ coOrd center_c;
+ center_c.x = center1.x+a*(center2.x - center1.x)/d;
+ center_c.y = center1.y+a*(center2.y - center1.y)/d;
+
+ (*Pc).x = center_c.x+h*(center2.y-center1.y)/d;
+ (*Pc).y = center_c.y-h*(center2.x-center1.x)/d;
+ (*Pc2).x = center_c.x-h*(center2.y-center1.y)/d;
+ (*Pc2).y = center_c.y+h*(center2.x-center1.x)/d;
+
+ return TRUE;
+}
+
+/*
+ * Find Intersections between a line and a circle
+ *
+ * |c-x|^2 = r^2
+ *
+ * π‘₯(𝑑)=π‘Ž+𝑑𝑏
+ *
+ * where π‘Ž is a point and 𝑏 is a vector.
+ *
+ * For a point on this line to satisfy the equation, you need to have
+ *
+ * (𝑑𝑏+(π‘Žβˆ’π‘))β‹…(𝑑𝑏+(π‘Žβˆ’π‘))=π‘Ÿ^2
+ *
+ * which is a quadratic in 𝑑:
+ * |b|^2*t^2 + 2(a-c).bt +(|a-c|^2-r^2) = 0
+ *
+ * whose solutions are
+ *
+ * t = (-2(a-c).b +/- SQRT([2(a-c).b]^2 - 4|b|^2(|a-c|^2-r^2)) / 2|b|^2
+ *
+ */
+
+double VectorLength (coOrd v) {
+ return sqrt(v.x*v.x+v.y+v.y);
+}
+double VectorDot (coOrd v1, coOrd v2) {
+ return (v1.x*v2.x+ v1.y*v2.y);
+}
+coOrd VectorSubtract (coOrd v1, coOrd v2) {
+ coOrd result;
+ result.x = v1.x-v2.x;
+ result.y = v1.y-v2.y;
+ return result;
+}
+coOrd VectorAdd (coOrd v1, coOrd v2) {
+ coOrd result;
+ result.x = v1.x+v2.x;
+ result.y = v1.y+v2.y;
+ return result;
+}
+
+BOOL_T FindArcAndLineIntersections(coOrd *intersection1, coOrd *intersection2, coOrd c, DIST_T radius,
+ coOrd point1, coOrd point2 )
+{
+ double dx, dy, cx, cy, A, B, C, det, t;
+
+ dx = point2.x - point1.x;
+ dy = point2.y - point1.y;
+
+ cx = c.x;
+ cy = c.y;
+
+ A = dx * dx + dy * dy;
+ B = 2 * (dx * (point1.x - cx) + dy * (point1.x - cy));
+ C = (point1.x - cx) * (point1.x - cx) + (point1.y - cy) * (point1.y - cy) - radius * radius;
+
+ det = B * B - 4 * A * C;
+ if ((A <= 0.0000001) || (det < 0))
+ {
+ return FALSE;
+ }
+ else if (det == 0)
+ {
+ // One solution.
+ t = -B / (2 * A);
+ (*intersection1).x = point1.x + t * dx;
+ (*intersection1).y = point1.y + t * dy;
+ intersection2 = intersection1;
+ return TRUE;
+ }
+ else
+ {
+ // Two solutions.
+ t = (float)((-B + sqrt(det)) / (2 * A));
+ (*intersection1).x = point1.x + t * dx;
+ (*intersection1).y = point1.y + t * dy;
+ t = (float)((-B - sqrt(det)) / (2 * A));
+ (*intersection2).x = point1.x + t * dx;
+ (*intersection2).y = point1.y + t * dy;
+ return TRUE;
+ }
+}
/* Find intersection:
Given 2 lines each described by a point and angle (P0,A0) (P1,A1)
@@ -489,6 +598,7 @@ static void IntersectBox( coOrd *p1, coOrd p0, coOrd size, int x1, int y1 )
#ifndef WINDOWS
else
fprintf(stderr, "intersectBox bogus\n" );
+ getchar();
#endif
}
@@ -589,6 +699,67 @@ BOOL_T ClipLine( coOrd *fp0, coOrd *fp1, coOrd orig, double angle, coOrd size )
return 1;
}
+coOrd FindCentroid(int vertexCount, pts_t vertices[] )
+{
+ coOrd centroid = {0, 0};
+ double signedArea = 0.0;
+ double x0 = 0.0; // Current vertex X
+ double y0 = 0.0; // Current vertex Y
+ double x1 = 0.0; // Next vertex X
+ double y1 = 0.0; // Next vertex Y
+ double a = 0.0; // Partial signed area
+
+ // For all vertices except last
+ int i=0;
+ for (i=0; i<vertexCount-1; ++i)
+ {
+ x0 = vertices[i].pt.x;
+ y0 = vertices[i].pt.y;
+ x1 = vertices[i+1].pt.x;
+ y1 = vertices[i+1].pt.y;
+ a = x0*y1 - x1*y0;
+ signedArea += a;
+ centroid.x += (x0 + x1)*a;
+ centroid.y += (y0 + y1)*a;
+ }
+
+ // Do last vertex separately to avoid performing an expensive
+ // modulus operation in each iteration.
+ x0 = vertices[i].pt.x;
+ y0 = vertices[i].pt.y;
+ x1 = vertices[0].pt.x;
+ y1 = vertices[0].pt.y;
+ a = x0*y1 - x1*y0;
+ signedArea += a;
+ centroid.x += (x0 + x1)*a;
+ centroid.y += (y0 + y1)*a;
+
+ signedArea *= 0.5;
+ centroid.x /= (6.0*signedArea);
+ centroid.y /= (6.0*signedArea);
+
+ return centroid;
+}
+
+double FindArcCenter(
+ coOrd * pos,
+ coOrd p0,
+ coOrd p1,
+ double radius )
+{
+ double d;
+ double a0, a1;
+ d = FindDistance( p0, p1 )/2.0;
+ a0 = FindAngle( p0, p1 );
+ a1 = NormalizeAngle(R2D(asin( d/radius )));
+ if (a1 > 180)
+ a1 -= 360;
+ a0 = NormalizeAngle( a0 + (90.0-a1) );
+ Translate( pos, p0, a0, radius );
+ return a1*2.0;
+}
+
+
#ifdef LATER
BOOL_T ClipArc( double a0, double a1, coOrd pos, double radius, coOrd orig, double angle, double size )
{
diff --git a/app/bin/utility.h b/app/bin/utility.h
index 8666e6b..fad74be 100644
--- a/app/bin/utility.h
+++ b/app/bin/utility.h
@@ -57,11 +57,15 @@ int PointOnCircle( coOrd * resP, coOrd center, double radius, double angle );
double ConstrainR( double r );
void FindPos( coOrd * res, double * beyond, coOrd pos, coOrd orig, double angle, double length );
int FindIntersection( coOrd *Pc, coOrd P00, double A0, coOrd P10, double A1 );
+BOOL_T FindArcAndLineIntersections (coOrd *Pc1, coOrd *Pc2, coOrd c, DIST_T r, coOrd p0, coOrd p1);
+BOOL_T FindArcIntersections ( coOrd *Pc, coOrd *Pc2, coOrd center1, DIST_T radius1, coOrd center2, DIST_T radius2);
double LineDistance( coOrd *p, coOrd p0, coOrd p1 );
double CircleDistance( coOrd *p, coOrd c, double r, double a0, double a1 );
int PickArcEndPt( coOrd, coOrd, coOrd );
int PickLineEndPt( coOrd, double, coOrd );
coOrd AddCoOrd( coOrd, coOrd, double );
int ClipLine( coOrd *, coOrd *, coOrd, double, coOrd );
+coOrd FindCentroid(int vertexCount, pts_t vertices[] );
+double FindArcCenter(coOrd * c,coOrd p0,coOrd p1, double r );
#endif
diff --git a/app/bin/validator.c b/app/bin/validator.c
new file mode 100644
index 0000000..c415471
--- /dev/null
+++ b/app/bin/validator.c
@@ -0,0 +1,87 @@
+/** \file validator.c
+* Validators for misc textformats
+*/
+
+/* XTrackCAD - Model Railroad CAD
+* Copyright (C) 2019 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 <stdbool.h>
+#include "validator.h"
+
+/**
+* Simplistic checking of URL syntax validity. Checks:
+* if scheme is present, it has to be terminated by double /
+* hostname has at least 5 characters
+*
+* \param testString
+* \return TRUE if valid, FALSE otherwise
+*/
+
+enum URLSCANSTATE { STATE_SCHEME, STATE_ENDOFSCHEME, STATE_HIER, STATE_PATH, STATE_ERROR };
+
+#define MINURLLENGTH 5 /* 2 chars domain name, dot, 2 chars TLD */
+
+bool
+IsValidURL(char *testString)
+{
+ char *result = testString;
+ char *hostname = testString;
+ enum URLSCANSTATE state = STATE_SCHEME;
+
+ if (!*result) {
+ return(false);
+ }
+
+ while (*result && state != STATE_ERROR) {
+ switch (*result) {
+ case ':':
+ if (state == STATE_SCHEME) {
+ if (result == testString) {
+ state = STATE_ERROR;
+ } else {
+ state = STATE_ENDOFSCHEME;
+ }
+ }
+ break;
+ case '/':
+ if (state == STATE_ENDOFSCHEME) {
+ if (*(result + 1) == '/') {
+ state = STATE_HIER;
+ hostname = result + 2;
+ result++;
+ } else {
+ state = STATE_ERROR;
+ }
+ } else {
+ if (state == STATE_HIER || state == STATE_SCHEME) {
+ state = STATE_PATH;
+ if (result - hostname < MINURLLENGTH) {
+ state = STATE_ERROR;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+
+ }
+ result++;
+ }
+
+ return (state != STATE_ERROR);
+}
diff --git a/app/bin/validator.h b/app/bin/validator.h
new file mode 100644
index 0000000..3706f0f
--- /dev/null
+++ b/app/bin/validator.h
@@ -0,0 +1,29 @@
+/** \file validator.h
+ * Validators for misc textformats
+*/
+
+/* XTrackCAD - Model Railroad CAD
+* Copyright (C) 2019 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
+*/
+
+#ifndef HAVE_VALIDATOR_H
+#define HAVE_VALIDATOR_H
+
+#include <stdbool.h>
+bool IsValidURL(char *testString);
+
+#endif // !HAVE_VALIDATOR_H
+