1/* dvGrid.m
2 * Grid additions for Cenon DocView class
3 *
4 * Copyright (C) 1997-2012 by vhf interservice GmbH
5 * Author:   Georg Fleischmann
6 *
7 * created:  1997-11-05
8 * modified: 2012-06-25 (display x10 grid even if x1 grid becomes too small)
9 *           2012-02-13 (thicker line every 10 thin lines)
10 *           2005-05-19 (line width set to 0.51)
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the vhf Public License as
14 * published by vhf interservice GmbH. Among other things, the
15 * License requires that the copyright notices and this notice
16 * be preserved on all copies.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21 * See the vhf Public License for more details.
22 *
23 * You should have received a copy of the vhf Public License along
24 * with this program; see the file LICENSE. If not, write to vhf.
25 *
26 * vhf interservice GmbH, Im Marxle 3, 72119 Altingen, Germany
27 * eMail: info@vhf.de
28 * http://www.vhf.de
29 */
30
31#include <AppKit/AppKit.h>
32#include "App.h"
33#include "DocView.h"
34#include "DocWindow.h"
35#include "locations.h"
36#include "functions.h"
37
38
39@implementation DocView(Grid)
40
41/* Methods to modify the grid of the GraphicView. */
42
43- (void)drawGrid
44{   VFloat  trueGridSpacing = gridSpacing;
45    int     n = 10;
46
47    if ( [self gridIsRelative] )
48        trueGridSpacing = trueGridSpacing * [self resolution] * scale;
49    if ( [self gridIsEnabled] && numGridRectsX && trueGridSpacing >= 1 )
50    {   int     i, offX, offY;
51        double  bigGridSpacing = gridSpacing * [self resolution] * n;   // larger grid (* 10)
52        NSPoint pStart;
53
54        /* fine grid */
55        if ( trueGridSpacing >= 4 )
56        {
57            [[NSColor lightGrayColor] set];
58            //[[NSColor colorWithDeviceRed:0.91 green:0.95 blue:1.0 alpha:1.0] set]; // light blue
59            [NSBezierPath setDefaultLineWidth:(VHFIsDrawingToScreen() ? 1.0/scale : 0.1)];
60            for ( i=0; i<numGridRectsX; i++ )
61                [NSBezierPath strokeRect:gridListX[i]];
62            for ( i=0; i<numGridRectsY; i++ )
63                [NSBezierPath strokeRect:gridListY[i]];
64        }
65
66        /* we draw every n'th line stronger (centered at crosshair origin) */
67        pStart = [self pointAbsolute:NSZeroPoint];   // this is the crosshair position
68        pStart.x = pStart.x - floor(pStart.x / bigGridSpacing) * bigGridSpacing;
69        pStart.y = pStart.y - floor(pStart.y / bigGridSpacing) * bigGridSpacing;
70        for ( offX=0; offX < Min(n, numGridRectsX); offX++ )
71            if ( gridListX[offX].origin.x + TOLERANCE >= pStart.x )
72                break;
73        for ( offY=0; offY < Min(n, numGridRectsY); offY++ )
74            if ( gridListY[offY].origin.y + TOLERANCE >= pStart.y )
75                break;
76        [[NSColor grayColor] set];
77        //[[NSColor colorWithDeviceRed:0.8 green:0.89 blue:1.0 alpha:1.0] set]; // light blue
78        [NSBezierPath setDefaultLineWidth:(VHFIsDrawingToScreen() ? 1.0/scale : 0.1)];
79        for ( i = offX; i < numGridRectsX; i += n ) // X
80            [NSBezierPath strokeRect:gridListX[i]];
81        for ( i = offY; i < numGridRectsY; i += n ) // Y
82            [NSBezierPath strokeRect:gridListY[i]];
83    }
84}
85
86- (void)setGridSpacing:(float)spacing
87{
88    if ( gridSpacing != spacing && spacing > 0 && spacing < 256 )
89    {
90        gridSpacing   = spacing;
91        gridIsEnabled = YES;
92        [self resetGrid];
93        [self drawAndDisplay];
94        [[self window] flushWindow];
95    }
96}
97
98- (float)gridSpacing
99{
100    return gridSpacing;
101}
102
103- (void)toggleGrid:sender
104{
105    if ([sender respondsToSelector:@selector(tag)])
106        [self setGridEnabled:[(NSMenuItem*)sender tag] ? YES : NO];
107}
108
109- (void)setGridEnabled:(BOOL)flag
110{
111    if (gridIsEnabled != flag)
112    {
113        gridIsEnabled = flag;
114        if (flag)
115            [self resetGrid];
116        [self drawAndDisplay];
117        [[self window] flushWindow];
118    }
119}
120
121- (BOOL)gridIsEnabled
122{
123    return gridIsEnabled;
124}
125
126- (void)setGridUnit:(int)value
127{
128    if (gridUnit != value)
129    {
130        gridUnit = value;
131        [self resetGrid];
132        [self drawAndDisplay];
133        [[self window] flushWindow];
134    }
135}
136
137- (int)gridUnit
138{
139    return gridUnit;
140}
141
142/* relative unit (mm, inch, pt)
143 */
144- (BOOL)gridIsRelative;
145{
146    return (gridUnit > 3) ? NO : YES;
147}
148
149//#define GRID (gridIsEnabled ? (gridSpacing ? gridSpacing : 1.0) : 1.0)
150#define GRID (gridIsEnabled ? (([self gridIsRelative]) ? gridSpacing*[self resolution] \
151                                                       : gridSpacing/scale) : 1.0)
152/*#define grid(point) \
153	{ (point).x = floor(((point).x / GRID) + 0.5) * GRID; \
154	  (point).y = floor(((point).y / GRID) + 0.5) * GRID; }*/
155
156/* grid spacing including scale
157 */
158- (float)grid
159{
160    return GRID;
161}
162
163/* return closest point on grid
164 */
165- (NSPoint)grid:(NSPoint)p
166{
167    if ( gridIsEnabled )
168    {   float	grid = GRID;
169
170        p = [self pointRelativeOrigin:p];
171        p.x = floor((p.x / grid) + 0.5) * grid;
172        p.y = floor((p.y / grid) + 0.5) * grid;
173        p = [self pointAbsolute:p];
174    }
175    return p;
176}
177
178/*
179 * converts a value from internal unit to the current unit
180 */
181- (float)resolution
182{
183    switch ( gridUnit )
184    {
185        case UNIT_MM:    return 72.0/25.4;
186        case UNIT_INCH:  return 72.0;
187        case UNIT_POINT: return 1.0;
188    }
189    return 1.0;
190}
191
192/* we maintain a list of rectangles representing the horicontal and vertical lines of the grid.
193 * We use Rectangles because they usually draw faster than lines
194 */
195- (void)resetGrid
196{   int		x, y, i;
197    float	w, h, res = [self resolution], relGrid;
198    NSZone	*zone = [self zone];
199    NSRect	bounds = [self bounds];
200    NSPoint	p, offset;	// start offset for grid
201    BOOL	gridIsRelative = [self gridIsRelative];
202
203    if ( (!gridIsRelative && gridSpacing < 1) || (gridIsRelative && gridSpacing*res*scale < 1) )
204        return;
205
206    relGrid = (gridIsRelative) ? gridSpacing*res : gridSpacing/scale;
207
208    x = (int)bounds.size.width  / relGrid;
209    y = (int)bounds.size.height / relGrid;
210    numGridRectsX = x + 1;
211    numGridRectsY = y + 1;
212    if (gridListX)
213    {   NSZoneFree(zone, gridListX);
214        NSZoneFree(zone, gridListY);
215    }
216    gridListX = NSZoneMalloc(zone, (numGridRectsX+2) * sizeof(NSRect));
217    gridListY = NSZoneMalloc(zone, (numGridRectsY+2) * sizeof(NSRect));
218    w = bounds.size.width;
219    h = bounds.size.height;
220
221    p = [self pointAbsolute:NSZeroPoint];
222    offset.x = p.x - floor(p.x / relGrid) * relGrid;
223    offset.y = p.y - floor(p.y / relGrid) * relGrid;
224
225    for (i = 0; i <= y; i++)
226    {
227        gridListY[i].origin.x = 0.0;
228        gridListY[i].origin.y = offset.y + i * relGrid;
229        gridListY[i].size.width  = w;
230        gridListY[i].size.height = 0.0;
231    }
232    for (i = 0; i <= x; i++)
233    {
234        gridListX[i].origin.x = offset.x + i * relGrid;
235        gridListX[i].origin.y = 0.0;
236        gridListX[i].size.width  = 0.0;
237        gridListX[i].size.height = h;
238    }
239}
240
241@end
242