summaryrefslogtreecommitdiff
path: root/app/bin/csnap.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/csnap.c')
-rw-r--r--app/bin/csnap.c820
1 files changed, 820 insertions, 0 deletions
diff --git a/app/bin/csnap.c b/app/bin/csnap.c
new file mode 100644
index 0000000..1d16136
--- /dev/null
+++ b/app/bin/csnap.c
@@ -0,0 +1,820 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/csnap.c,v 1.7 2008-06-03 15:43:58 m_fischer Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * 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 "track.h"
+#include "i18n.h"
+
+
+/*****************************************************************************
+ *
+ * Draw Snap Grid
+ *
+ */
+
+EXPORT long minGridSpacing = 3;
+
+#define CROSSTICK
+#ifdef CROSSTICK
+#include "bitmaps/cross0.xbm"
+static wDrawBitMap_p cross0_bm;
+#endif
+
+#include "bitmaps/bigdot.xbm"
+static wDrawBitMap_p bigdot_bm;
+
+#define DEFAULTGRIDSPACING (1.0)
+
+EXPORT void MapGrid(
+ coOrd orig,
+ coOrd size,
+ ANGLE_T angle,
+ coOrd gridOrig,
+ ANGLE_T gridAngle,
+ POS_T Xspacing,
+ POS_T Yspacing,
+ int * x0,
+ int * x1,
+ int * y0,
+ int * y1 )
+{
+ coOrd p[4], hi, lo;
+ int i;
+
+ p[0] = p[1] = p[2] = p[3] = orig;
+ p[1].x += size.x;
+ p[2].x += size.x;
+ p[2].y += size.y;
+ p[3].y += size.y;
+ for (i=1; i<4; i++) {
+ Rotate( &p[i], orig, angle );
+ }
+ for (i=0; i<4; i++) {
+ p[i].x -= gridOrig.x;
+ p[i].y -= gridOrig.y;
+ Rotate( &p[i], zero, -gridAngle );
+ }
+ hi = lo = p[0];
+ for (i=1; i<4; i++) {
+ if (hi.x < p[i].x)
+ hi.x = p[i].x;
+ if (hi.y < p[i].y)
+ hi.y = p[i].y;
+ if (lo.x > p[i].x)
+ lo.x = p[i].x;
+ if (lo.y > p[i].y)
+ lo.y = p[i].y;
+ }
+ *x0 = (int)floor( lo.x / Xspacing );
+ *y0 = (int)floor( lo.y / Yspacing );
+ *x1 = (int)ceil( hi.x / Xspacing );
+ *y1 = (int)ceil( hi.y / Yspacing );
+}
+
+
+static DIST_T Gdx, Gdy, Ddx, Ddy;
+static coOrd GDorig;
+static wPos_t lborder, bborder;
+
+void static DrawGridPoint(
+ drawCmd_p D,
+ wDrawColor Color,
+ coOrd orig,
+ coOrd * size,
+ DIST_T dpi,
+ coOrd p0,
+ BOOL_T bigdot )
+{
+ wPos_t x0, y0;
+ POS_T x;
+ x = (p0.x*Gdx + p0.y*Gdy) + orig.x;
+ p0.y = (p0.y*Gdx - p0.x*Gdy) + orig.y;
+ p0.x = x;
+ if (size &&
+ ( p0.x < 0.0 || p0.x > size->x ||
+ p0.y < 0.0 || p0.y > size->y ) )
+ return;
+ p0.x -= D->orig.x;
+ p0.y -= D->orig.y;
+ x = (p0.x*Ddx + p0.y*Ddy);
+ p0.y = (p0.y*Ddx - p0.x*Ddy);
+ p0.x = x;
+ if ( p0.x < 0.0 || p0.x > D->size.x ||
+ p0.y < 0.0 || p0.y > D->size.y )
+ return;
+ x0 = (wPos_t)(p0.x*dpi+0.5) + lborder;
+ y0 = (wPos_t)(p0.y*dpi+0.5) + bborder;
+ if ( bigdot )
+ wDrawBitMap( D->d, bigdot_bm, x0, y0, Color, (wDrawOpts)D->funcs->options );
+ else
+ wDrawPoint( D->d, x0, y0, Color, (wDrawOpts)D->funcs->options );
+}
+
+
+static void DrawGridLine(
+ drawCmd_p D,
+ wDrawColor Color,
+ coOrd orig,
+ coOrd * size,
+ DIST_T dpi,
+ BOOL_T clip,
+ coOrd p0,
+ coOrd p1 )
+{
+ wPos_t x0, y0, x1, y1;
+ POS_T x;
+ x = (p0.x*Gdx + p0.y*Gdy) + orig.x;
+ p0.y = (p0.y*Gdx - p0.x*Gdy) + orig.y;
+ p0.x = x;
+ x = (p1.x*Gdx + p1.y*Gdy) + orig.x;
+ p1.y = (p1.y*Gdx - p1.x*Gdy) + orig.y;
+ p1.x = x;
+ if (size && clip && !ClipLine( &p0, &p1, zero, 0.0, *size ))
+ return;
+ p0.x -= D->orig.x;
+ p0.y -= D->orig.y;
+ p1.x -= D->orig.x;
+ p1.y -= D->orig.y;
+ x = (p0.x*Ddx + p0.y*Ddy);
+ p0.y = (p0.y*Ddx - p0.x*Ddy);
+ p0.x = x;
+ x = (p1.x*Ddx + p1.y*Ddy);
+ p1.y = (p1.y*Ddx - p1.x*Ddy);
+ p1.x = x;
+ if (clip && !ClipLine( &p0, &p1, zero, 0.0, D->size ))
+ return;
+ x0 = (wPos_t)(p0.x*dpi+0.5) + lborder;
+ y0 = (wPos_t)(p0.y*dpi+0.5) + bborder;
+ x1 = (wPos_t)(p1.x*dpi+0.5) + lborder;
+ y1 = (wPos_t)(p1.y*dpi+0.5) + bborder;
+ wDrawLine( D->d, x0, y0, x1, y1, 0, wDrawLineSolid, Color, (wDrawOpts)D->funcs->options );
+}
+
+
+#ifdef WINDOWS
+#define WONE (1)
+#else
+#define WONE (0)
+#endif
+
+EXPORT void DrawGrid(
+ drawCmd_p D,
+ coOrd * size,
+ POS_T hMajSpacing,
+ POS_T vMajSpacing,
+ long Hdivision,
+ long Vdivision,
+ coOrd Gorig,
+ ANGLE_T Gangle,
+ wDrawColor Color,
+ BOOL_T clip )
+{
+ int hMaj, hMajCnt0, hMajCnt1, vMaj, vMajCnt0, vMajCnt1;
+ coOrd p0, p1;
+ DIST_T dpi;
+ int hMin, hMinCnt1, vMin, vMinCnt1;
+ DIST_T hMinSpacing=0, vMinSpacing=0;
+ long f;
+ POS_T hMajSpacing_dpi, vMajSpacing_dpi;
+ BOOL_T bigdot;
+
+ if (hMajSpacing <= 0 && vMajSpacing <= 0)
+ return;
+
+#ifdef CROSSTICK
+ if (!cross0_bm)
+ cross0_bm = wDrawBitMapCreate( mainD.d, cross0_width, cross0_height, 2, 2, cross0_bits );
+#endif
+ if (!bigdot_bm)
+ bigdot_bm = wDrawBitMapCreate( mainD.d, bigdot_width, bigdot_height, 1, 1, bigdot_bits );
+
+ wSetCursor( wCursorWait );
+ dpi = D->dpi/D->scale;
+ Gdx = cos(D2R(Gangle));
+ Gdy = sin(D2R(Gangle));
+ Ddx = cos(D2R(-D->angle));
+ Ddy = sin(D2R(-D->angle));
+ if (D->options&DC_TICKS) {
+ lborder = LBORDER;
+ bborder = BBORDER;
+ } else {
+ lborder = bborder = 0;
+ }
+ GDorig.x = Gorig.x-D->orig.x;
+ GDorig.y = Gorig.y-D->orig.y;
+ hMajSpacing_dpi = hMajSpacing*dpi;
+ vMajSpacing_dpi = vMajSpacing*dpi;
+
+ MapGrid( D->orig, D->size, D->angle, Gorig, Gangle,
+ (hMajSpacing>0?hMajSpacing:vMajSpacing),
+ (vMajSpacing>0?vMajSpacing:hMajSpacing),
+ &hMajCnt0, &hMajCnt1, &vMajCnt0, &vMajCnt1 );
+
+ hMinCnt1 = vMinCnt1 = 0;
+
+ if (hMajSpacing_dpi >= minGridSpacing) {
+ p0.y = vMajCnt0*(vMajSpacing>0?vMajSpacing:hMajSpacing);
+ p1.y = vMajCnt1*(vMajSpacing>0?vMajSpacing:hMajSpacing);
+ p0.x = p1.x = hMajCnt0*hMajSpacing;
+ for ( hMaj=hMajCnt0; hMaj<hMajCnt1; hMaj++ ) {
+ p0.x += hMajSpacing;
+ p1.x += hMajSpacing;
+ DrawGridLine( D, Color, Gorig, size, dpi, clip, p0, p1 );
+ }
+ if ( Hdivision > 0 ) {
+ hMinSpacing = hMajSpacing/Hdivision;
+ if (hMinSpacing*dpi > minGridSpacing)
+ hMinCnt1 = (int)Hdivision;
+ }
+ }
+
+ if (vMajSpacing_dpi >= minGridSpacing) {
+ p0.x = hMajCnt0*(hMajSpacing>0?hMajSpacing:vMajSpacing);
+ p1.x = hMajCnt1*(hMajSpacing>0?hMajSpacing:vMajSpacing);
+ p0.y = p1.y = vMajCnt0*vMajSpacing;
+ for ( vMaj=vMajCnt0; vMaj<vMajCnt1; vMaj++ ) {
+ p0.y += vMajSpacing;
+ p1.y += vMajSpacing;
+ DrawGridLine( D, Color, Gorig, size, dpi, clip, p0, p1 );
+ }
+ if ( Vdivision > 0 ) {
+ vMinSpacing = vMajSpacing/Vdivision;
+ if (vMinSpacing*dpi > minGridSpacing)
+ vMinCnt1 = (int)Vdivision;
+ }
+ }
+
+ if (hMinCnt1 <= 0 && vMinCnt1 <= 0)
+ goto done;
+
+ if (hMajSpacing <= 0) {
+ hMinCnt1 = vMinCnt1+1;
+ hMinSpacing = vMinSpacing;
+ hMajSpacing = vMajSpacing;
+ } else if (hMajSpacing_dpi < minGridSpacing) {
+ hMinCnt1 = 1;
+ hMinSpacing = 0;
+ f = (long)ceil(minGridSpacing/hMajSpacing);
+ hMajSpacing *= f;
+ hMajCnt0 = (int)(hMajCnt0>=0?ceil(hMajCnt0/f):floor(hMajCnt0/f));
+ hMajCnt1 = (int)(hMajCnt1>=0?ceil(hMajCnt1/f):floor(hMajCnt1/f));
+ } else if (Hdivision <= 0) {
+ hMinCnt1 = (int)(hMajSpacing/vMinSpacing);
+ if (hMinCnt1 <= 0) {
+ goto done;
+ }
+ hMinSpacing = hMajSpacing/hMinCnt1;
+ } else if (hMinSpacing*dpi < minGridSpacing) {
+ f = (long)ceil(minGridSpacing/hMinSpacing);
+ hMinCnt1 = (int)(Hdivision/f);
+ hMinSpacing *= f;
+ }
+
+ if (vMajSpacing <= 0) {
+ vMinCnt1 = hMinCnt1+1;
+ vMinSpacing = hMinSpacing;
+ vMajSpacing = hMajSpacing;
+ } else if (vMajSpacing_dpi < minGridSpacing) {
+ vMinCnt1 = 1;
+ vMinSpacing = 0;
+ f = (long)ceil(minGridSpacing/vMajSpacing);
+ vMajSpacing *= f;
+ vMajCnt0 = (int)(vMajCnt0>=0?ceil(vMajCnt0/f):floor(vMajCnt0/f));
+ vMajCnt1 = (int)(vMajCnt1>=0?ceil(vMajCnt1/f):floor(vMajCnt1/f));
+ } else if (Vdivision <= 0) {
+ vMinCnt1 = (int)(vMajSpacing/hMinSpacing);
+ if (vMinCnt1 <= 0) {
+ goto done;
+ }
+ vMinSpacing = vMajSpacing/vMinCnt1;
+ } else if (vMinSpacing*dpi < minGridSpacing) {
+ f = (long)ceil(minGridSpacing/vMinSpacing);
+ vMinCnt1 = (int)(Vdivision/f);
+ vMinSpacing *= f;
+ }
+
+ bigdot = ( hMinSpacing*dpi > 10 && vMinSpacing*dpi > 10 );
+ for ( hMaj=hMajCnt0; hMaj<hMajCnt1; hMaj++ ) {
+ for ( vMaj=vMajCnt0; vMaj<vMajCnt1; vMaj++ ) {
+ for ( hMin=1; hMin<hMinCnt1; hMin++ ) {
+ for ( vMin=1; vMin<vMinCnt1; vMin++ ) {
+ p0.x = hMaj*hMajSpacing + hMin*hMinSpacing;
+ p0.y = vMaj*vMajSpacing + vMin*vMinSpacing;
+ DrawGridPoint( D, Color, Gorig, size, dpi, p0, bigdot );
+ }
+ }
+ }
+ }
+
+
+done:
+ wSetCursor( wCursorNormal );
+}
+
+
+
+static void DrawBigCross( coOrd pos, ANGLE_T angle )
+{
+ coOrd p0, p1;
+ DIST_T d;
+ if (angleSystem!=ANGLE_POLAR)
+ angle += 90.0;
+ d = max( mainD.size.x, mainD.size.y );
+ Translate( &p0, pos, angle, d );
+ Translate( &p1, pos, angle+180, d );
+ if (ClipLine( &p0, &p1, mainD.orig, 0.0, mainD.size )) {
+ DrawLine( &tempD, pos, p0, 0, crossMajorColor );
+ DrawLine( &tempD, pos, p1, 0, crossMinorColor );
+ }
+ Translate( &p0, pos, angle+90, d );
+ Translate( &p1, pos, angle+270, d );
+ if (ClipLine( &p0, &p1, mainD.orig, 0.0, mainD.size )) {
+ DrawLine( &tempD, p0, p1, 0, crossMinorColor );
+ }
+}
+
+
+EXPORT STATUS_T GridAction(
+ wAction_t action,
+ coOrd pos,
+ coOrd *orig,
+ DIST_T *angle )
+{
+
+ static coOrd pos0, pos1;
+ static ANGLE_T newAngle, oldAngle;
+
+ 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;
+ }
+ return C_CONTINUE;
+}
+
+/*****************************************************************************
+ *
+ * Snap Grid Command
+ *
+ */
+
+EXPORT wDrawColor snapGridColor;
+
+typedef struct {
+ DIST_T Spacing;
+ long Division;
+ long Enable;
+ } gridData;
+typedef struct {
+ gridData Horz;
+ gridData Vert;
+ coOrd Orig;
+ ANGLE_T Angle;
+ long Show;
+ } gridHVData;
+
+static gridHVData grid = { { 1.0, 0, 1 },
+ { 1.0, 0, 1 } };
+
+EXPORT void SnapPos( coOrd * pos )
+{
+ coOrd p;
+ DIST_T spacing;
+ if ( grid.Vert.Enable == FALSE && grid.Horz.Enable == FALSE )
+ return;
+ p = *pos;
+ p.x -= grid.Orig.x;
+ p.y -= grid.Orig.y;
+ Rotate( &p, zero, -grid.Angle );
+ if ( grid.Horz.Enable ) {
+ if ( grid.Horz.Division > 0 )
+ spacing = grid.Horz.Spacing / grid.Horz.Division;
+ else
+ spacing = grid.Horz.Spacing;
+ if (spacing > 0.001)
+ p.x = floor(p.x/spacing+0.5) * spacing;
+ }
+ if ( grid.Vert.Enable ) {
+ if ( grid.Vert.Division > 0 )
+ spacing = grid.Vert.Spacing / grid.Vert.Division;
+ else
+ spacing = grid.Vert.Spacing;
+ if (spacing > 0.001)
+ p.y = floor(p.y/spacing+0.5) * spacing;
+ }
+ REORIGIN1( p, grid.Angle, grid.Orig );
+ *pos = p;
+ InfoPos( p );
+}
+
+
+static void DrawASnapGrid( gridHVData * gridP, drawCmd_p d, coOrd size, BOOL_T drawDivisions )
+{
+ if (gridP->Horz.Spacing <= 0.0 && gridP->Vert.Spacing <= 0.0)
+ return;
+ if (gridP->Show == FALSE)
+ return;
+ DrawGrid( d, &size,
+ gridP->Horz.Spacing, gridP->Vert.Spacing,
+ drawDivisions?gridP->Horz.Division:0,
+ drawDivisions?gridP->Vert.Division:0,
+ gridP->Orig, gridP->Angle, snapGridColor, TRUE );
+}
+
+
+EXPORT void DrawSnapGrid( drawCmd_p d, coOrd size, BOOL_T drawDivisions )
+{
+ DrawASnapGrid( &grid, d, size, drawDivisions );
+}
+
+
+EXPORT BOOL_T GridIsVisible( void )
+{
+ return (BOOL_T)grid.Show;
+}
+
+/*****************************************************************************
+ *
+ * Snap Grid Dialog
+ *
+ */
+
+static wWin_p gridW;
+static wMenu_p snapGridPopupM;
+static wButton_p snapGridEnable_b;
+static wButton_p snapGridShow_b;
+EXPORT wMenuToggle_p snapGridEnableMI;
+EXPORT wMenuToggle_p snapGridShowMI;
+
+static gridHVData oldGrid;
+
+#define CHK_HENABLE (1<<0)
+#define CHK_VENABLE (1<<1)
+#define CHK_SHOW (1<<2)
+
+static paramFloatRange_t r0_999999 = { 0.0, 999999.0, 60 };
+static paramIntegerRange_t i0_1000 = { 0, 1000, 30 };
+static paramFloatRange_t r_1000_1000 = { -1000.0, 1000.0, 80 };
+static paramFloatRange_t r0_360 = { 0.0, 360.0, 80 };
+static char *gridLabels[] = { "", NULL };
+static paramData_t gridPLs[] = {
+ { PD_MESSAGE, N_("Horz"), NULL, 0, (void*)60 },
+#define I_HORZSPACING (1)
+ { PD_FLOAT, &grid.Horz.Spacing, "horzspacing", PDO_DIM, &r0_999999, N_("Spacing") },
+#define I_HORZDIVISION (2)
+ { PD_LONG, &grid.Horz.Division, "horzdivision", 0, &i0_1000, N_("Divisions") },
+#define I_HORZENABLE (3)
+#define gridHorzEnableT ((wChoice_p)gridPLs[I_HORZENABLE].control)
+ { PD_TOGGLE, &grid.Horz.Enable, "horzenable", 0, gridLabels, N_("Enable"), BC_HORZ|BC_NOBORDER },
+ { PD_MESSAGE, N_("Vert"), NULL, PDO_DLGNEWCOLUMN|PDO_DLGWIDE, (void*)60},
+#define I_VERTSPACING (5)
+ { PD_FLOAT, &grid.Vert.Spacing, "vertspacing", PDO_DIM, &r0_999999, NULL },
+#define I_VERTDIVISION (6)
+ { PD_LONG, &grid.Vert.Division, "vertdivision", 0, &i0_1000, NULL },
+#define I_VERTENABLE (7)
+#define gridVertEnableT ((wChoice_p)gridPLs[I_VERTENABLE].control)
+ { PD_TOGGLE, &grid.Vert.Enable, "vertenable", 0, gridLabels, NULL, BC_HORZ|BC_NOBORDER },
+#define I_VALUEX (8)
+ { PD_FLOAT, &grid.Orig.x, "origx", PDO_DIM|PDO_DLGNEWCOLUMN|PDO_DLGWIDE, &r_1000_1000, N_("X") },
+#define I_VALUEY (9)
+ { PD_FLOAT, &grid.Orig.y, "origy", PDO_DIM, &r_1000_1000, N_("Y") },
+#define I_VALUEA (10)
+ { PD_FLOAT, &grid.Angle, "origa", PDO_ANGLE, &r0_360, N_("A") },
+#define I_SHOW (11)
+#define gridShowT ((wChoice_p)gridPLs[I_SHOW].control)
+ { PD_TOGGLE, &grid.Show, "show", PDO_DLGIGNORELABELWIDTH, gridLabels, N_("Show"), BC_HORZ|BC_NOBORDER } };
+
+static paramGroup_t gridPG = { "grid", PGO_RECORD, gridPLs, sizeof gridPLs/sizeof gridPLs[0] };
+
+
+static BOOL_T GridChanged( void )
+{
+ return
+ grid.Horz.Spacing != oldGrid.Horz.Spacing ||
+ grid.Horz.Division != oldGrid.Horz.Division ||
+ grid.Vert.Spacing != oldGrid.Vert.Spacing ||
+ grid.Vert.Division != oldGrid.Vert.Division ||
+ grid.Orig.x != oldGrid.Orig.x ||
+ grid.Orig.y != oldGrid.Orig.y ||
+ grid.Angle != oldGrid.Angle ||
+ grid.Horz.Division != oldGrid.Horz.Division;
+}
+
+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 );
+ wDrawDelayUpdate( tempD.d, FALSE );
+ }
+}
+
+
+static void GridOk( void * junk )
+{
+ long changes;
+
+ ParamLoadData( &gridPG );
+ if ( ( grid.Horz.Enable && grid.Horz.Spacing <= 0.0) ||
+ ( grid.Vert.Enable && grid.Vert.Spacing <= 0.0) ) {
+ NoticeMessage( MSG_GRID_ENABLE_SPACE_GTR_0, _("Ok"), NULL );
+ return;
+ }
+ if ( grid.Horz.Spacing <= 0.0 &&
+ grid.Vert.Spacing <= 0.0 )
+ grid.Show = FALSE;
+
+ changes = 0;
+ if ( GridChanged() )
+ changes |= CHANGE_GRID;
+ if (grid.Show != oldGrid.Show || changes != 0)
+ changes |= CHANGE_MAIN;
+ DoChangeNotification( changes );
+ oldGrid = grid;
+ Reset();
+}
+
+
+static void GridButtonUpdate( long mode0 )
+{
+ long mode1;
+ mode1 = 0;
+ if ( grid.Show &&
+ grid.Horz.Spacing <= 0.0 &&
+ grid.Vert.Spacing <= 0.0 ) {
+ grid.Show = FALSE;
+ if ( mode0&CHK_SHOW )
+ ErrorMessage( MSG_GRID_SHOW_SPACE_GTR_0 );
+ }
+ if ( grid.Horz.Enable &&
+ grid.Horz.Spacing <= 0.0 ) {
+ grid.Horz.Enable = FALSE;
+ if ( mode0&CHK_HENABLE )
+ mode1 |= CHK_HENABLE;
+ }
+ if ( grid.Vert.Enable &&
+ grid.Vert.Spacing <= 0.0 ) {
+ grid.Vert.Enable = FALSE;
+ if ( mode0&CHK_VENABLE )
+ mode1 |= CHK_VENABLE;
+ }
+ if ( mode1 &&
+ (mode0&(CHK_HENABLE|CHK_VENABLE)) == mode1 )
+ ErrorMessage( MSG_GRID_ENABLE_SPACE_GTR_0 );
+ if ( gridShowT &&
+ grid.Show != (wToggleGetValue( gridShowT ) != 0) )
+ ParamLoadControl( &gridPG, I_SHOW );
+ if ( gridHorzEnableT &&
+ grid.Horz.Enable != (wToggleGetValue( gridHorzEnableT ) != 0) )
+ ParamLoadControl( &gridPG, I_HORZENABLE );
+ if ( gridVertEnableT &&
+ grid.Vert.Enable != (wToggleGetValue( gridVertEnableT ) != 0) )
+ ParamLoadControl( &gridPG, I_VERTENABLE );
+ if (snapGridEnable_b)
+ wButtonSetBusy( snapGridEnable_b, grid.Horz.Enable||grid.Vert.Enable );
+ if (snapGridShow_b)
+ wButtonSetBusy( snapGridShow_b, (wBool_t)grid.Show );
+ if (snapGridEnableMI)
+ wMenuToggleSet( snapGridEnableMI, grid.Horz.Enable||grid.Vert.Enable );
+ if (snapGridShowMI)
+ wMenuToggleSet( snapGridShowMI, (wBool_t)grid.Show );
+
+ if ( mode0&CHK_SHOW ) {
+ RedrawGrid();
+ }
+ oldGrid = grid;
+}
+
+
+static void GridChange( long changes )
+{
+ if ( (changes&(CHANGE_GRID|CHANGE_UNITS))==0 )
+ return;
+ GridButtonUpdate( 0 );
+ if (gridW==NULL || !wWinIsVisible(gridW))
+ return;
+ ParamLoadControls( &gridPG );
+}
+
+
+static void GridDlgUpdate(
+ paramGroup_p pg,
+ int inx,
+ void * valueP )
+{
+ switch ( inx ) {
+ case I_HORZENABLE:
+ GridButtonUpdate( CHK_HENABLE );
+ break;
+ case I_VERTENABLE:
+ GridButtonUpdate( CHK_VENABLE );
+ break;
+ case I_SHOW:
+ 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 );
+ }
+}
+
+
+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;
+ oldGrid = grid;
+ DrawASnapGrid( &grid, &tempD, mapD.size, TRUE );
+ wDrawDelayUpdate( tempD.d, FALSE );
+ ParamLoadControls( &gridPG );
+}
+
+
+EXPORT STATUS_T CmdGrid(
+ wAction_t action,
+ coOrd pos )
+{
+ STATUS_T rc;
+#ifdef TIMEDRAWGRID
+ unsigned long time0, time1, time2;
+#endif
+
+ switch (action) {
+
+ case C_START:
+ if (gridW == NULL) {
+ gridW = ParamCreateDialog( &gridPG, MakeWindowTitle(_("Snap Grid")), _("Ok"), GridOk, (paramActionCancelProc)Reset, TRUE, NULL, 0, GridDlgUpdate );
+ }
+ oldGrid = grid;
+ ParamLoadControls( &gridPG );
+ wShow( gridW );
+ return C_CONTINUE;
+
+ case C_REDRAW:
+ return C_TERMINATE;
+
+ case C_CANCEL:
+ grid = oldGrid;
+ wHide( gridW );
+ MainRedraw();
+ return C_TERMINATE;
+
+ case C_OK:
+ GridOk( NULL );
+ return C_TERMINATE;
+
+ case C_CONFIRM:
+ if (GridChanged() ||
+ grid.Show != oldGrid.Show )
+ return C_ERROR;
+ else
+ return C_CONTINUE;
+
+ case C_DOWN:
+ case C_RDOWN:
+ oldGrid = grid;
+ rc = GridAction( action, pos, &grid.Orig, &grid.Angle );
+ return rc;
+ case C_MOVE:
+ case C_RMOVE:
+ rc = GridAction( action, pos, &grid.Orig, &grid.Angle );
+ ParamLoadControls( &gridPG );
+ return rc;
+ case C_UP:
+ case C_RUP:
+#ifdef TIMEDRAWGRID
+ time0 = wGetTimer();
+#endif
+#ifdef TIMEDRAWGRID
+ time1 = wGetTimer();
+#endif
+ rc = GridAction( action, pos, &grid.Orig, &grid.Angle );
+ ParamLoadControls( &gridPG );
+ RedrawGrid();
+ oldGrid = grid;
+#ifdef TIMEDRAWGRID
+ time2 = wGetTimer();
+ InfoMessage( "undraw %ld, draw %ld", (long)(time1-time0), (long)(time2-time1) );
+#endif
+ return rc;
+
+ case C_CMDMENU:
+ wMenuPopupShow( snapGridPopupM );
+ break;
+ }
+
+ return C_CONTINUE;
+}
+
+
+/**
+ * Initialize the user interface for the grid functions.
+ *
+ * \param menu IN pulldown to which the grid function will be added
+ * \return created command button
+*/
+
+EXPORT wIndex_t InitGrid( wMenu_p menu )
+{
+ ParamRegister( &gridPG );
+ RegisterChangeNotification( GridChange );
+ if ( grid.Horz.Enable && grid.Horz.Spacing <= 0.0 )
+ grid.Horz.Enable = FALSE;
+ if ( grid.Vert.Enable && grid.Vert.Spacing <= 0.0 )
+ grid.Vert.Enable = FALSE;
+ if ( grid.Horz.Spacing <= 0.0 &&
+ grid.Vert.Spacing <= 0.0 )
+ grid.Show = FALSE;
+ snapGridPopupM = MenuRegister( "Snap Grid Rotate" );
+ AddRotateMenu( snapGridPopupM, SnapGridRotate );
+ GridButtonUpdate( 0 );
+ return InitCommand( menu, CmdGrid, N_("Change Grid..."), NULL, LEVEL0, IC_CMDMENU, ACCL_GRIDW );
+}
+
+
+EXPORT void SnapGridEnable( void )
+{
+ grid.Vert.Enable = grid.Horz.Enable = !( grid.Vert.Enable || grid.Horz.Enable );
+ GridButtonUpdate( (CHK_HENABLE|CHK_VENABLE) );
+}
+
+
+EXPORT void SnapGridShow( void )
+{
+ grid.Show = !grid.Show;
+ GridButtonUpdate( CHK_SHOW );
+}
+
+#include "bitmaps/snapcurs.xbm"
+#include "bitmaps/snapvis.xbm"
+
+EXPORT void InitSnapGridButtons( void )
+{
+ snapGridEnable_b = AddToolbarButton( "cmdGridEnable", wIconCreateBitMap(snapcurs_width, snapcurs_height, snapcurs_bits, wDrawColorBlack), 0, (addButtonCallBack_t)SnapGridEnable, NULL );
+ snapGridShow_b = AddToolbarButton( "cmdGridShow", wIconCreateBitMap(snapvis_width, snapvis_height, snapvis_bits, wDrawColorBlack), IC_MODETRAIN_TOO, (addButtonCallBack_t)SnapGridShow, NULL );
+}