1/*
2 Project: Graphos
3 GRCircle.m
4
5 Copyright (C) 2009-2018 GNUstep Application Project
6
7 Author: Ing. Riccardo Mottola
8
9 Created: 2009-12-27
10
11 This application is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public
13 License as published by the Free Software Foundation; either
14 version 2 of the License, or (at your option) any later version.
15
16 This application is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 Library General Public License for more details.
20
21 You should have received a copy of the GNU General Public
22 License along with this library; if not, write to the Free
23 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24 */
25
26#import <AppKit/NSColor.h>
27#import <AppKit/NSGraphics.h>
28#import <AppKit/NSGraphicsContext.h>
29#import "GRCircle.h"
30#import "GRCircleEditor.h"
31#import "GRFunctions.h"
32
33@implementation GRCircle
34
35- (GRObjectEditor *)allocEditor
36{
37  return [[GRCircleEditor alloc] initEditor:self];
38}
39
40/** initializes by using the properties array as defaults */
41- (id)initInView:(GRDocView *)aView
42      zoomFactor:(CGFloat)zf
43  withProperties:(NSDictionary *)properties
44{
45  self = [super initInView:aView zoomFactor:zf withProperties:properties];
46  if(self)
47    {
48      id obj;
49
50      pos = NSMakePoint([[properties objectForKey: @"posx"]  floatValue],
51			[[properties objectForKey: @"posy"]  floatValue]);
52      size = NSMakeSize([[properties objectForKey: @"width"]  floatValue],
53			[[properties objectForKey: @"height"]  floatValue]);
54      bounds = GRMakeBounds(pos.x, pos.y, size.width, size.height);
55
56      isCircle = NO;
57      obj = [properties objectForKey: @"circle"];
58      if (obj)
59	isCircle = [obj boolValue];
60
61      rotation = 0;
62      obj = [properties objectForKey: @"rotation"];
63      if (obj)
64	rotation = [obj floatValue];
65
66      startControlPoint = [[GRObjectControlPoint alloc] initAtPoint: pos zoomFactor:zf];
67      endControlPoint = [[GRObjectControlPoint alloc] initAtPoint: NSMakePoint(pos.x + size.width, pos.y + size.height) zoomFactor:zf];
68      [self setZoomFactor: zf];
69    }
70
71  return self;
72}
73
74/** initializes all parameters from a description dictionary */
75- (id)initFromData:(NSDictionary *)description
76            inView:(GRDocView *)aView
77        zoomFactor:(CGFloat)zf
78{
79  self = [super initFromData:description inView:aView zoomFactor:zf];
80  if(self)
81    {
82      id obj;
83
84      pos = NSMakePoint([[description objectForKey: @"posx"]  floatValue],
85			[[description objectForKey: @"posy"]  floatValue]);
86      size = NSMakeSize([[description objectForKey: @"width"]  floatValue],
87			[[description objectForKey: @"height"]  floatValue]);
88      bounds = GRMakeBounds(pos.x, pos.y, size.width, size.height);
89
90      isCircle = NO;
91      obj = [description objectForKey: @"circle"];
92      if (obj)
93	isCircle = [obj boolValue];
94
95      rotation = 0;
96      obj = [description objectForKey: @"rotation"];
97      if (obj)
98	rotation = [obj floatValue];
99
100      startControlPoint = [[GRObjectControlPoint alloc] initAtPoint: pos zoomFactor:zf];
101      endControlPoint = [[GRObjectControlPoint alloc] initAtPoint: NSMakePoint(pos.x + size.width, pos.y + size.height) zoomFactor:zf];
102      [self setZoomFactor: zf];
103    }
104  return self;
105}
106
107- (id)copyWithZone:(NSZone *)zone
108{
109    GRCircle *objCopy;
110
111    objCopy = [super copyWithZone:zone];
112
113    objCopy->startControlPoint = [[GRObjectControlPoint alloc] initAtPoint: pos zoomFactor:zmFactor];
114    objCopy->endControlPoint = [[GRObjectControlPoint alloc] initAtPoint: NSMakePoint(pos.x + size.width, pos.y + size.height) zoomFactor:zmFactor];
115
116
117    objCopy->pos = NSMakePoint(pos.x, pos.y);
118    objCopy->size = NSMakeSize(size.width, size.height);
119    objCopy->bounds = NSMakeRect(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
120    objCopy->boundsZ = NSMakeRect(boundsZ.origin.x, boundsZ.origin.y, boundsZ.size.width, boundsZ.size.height);
121    objCopy->rotation = rotation;
122    objCopy->isCircle = isCircle;
123
124    return objCopy;
125}
126
127- (void)dealloc
128{
129    [startControlPoint release];
130    [endControlPoint release];
131    [super dealloc];
132}
133
134- (NSDictionary *)objectDescription
135{
136    NSMutableDictionary *dict;
137    NSString *str;
138    float strokeCol[3];
139    float fillCol[3];
140    float strokeAlpha;
141    float fillAlpha;
142
143    strokeCol[0] = [strokeColor redComponent];
144    strokeCol[1] = [strokeColor greenComponent];
145    strokeCol[2] = [strokeColor blueComponent];
146    strokeAlpha = [strokeColor alphaComponent];
147
148    fillCol[0] = [fillColor redComponent];
149    fillCol[1] = [fillColor greenComponent];
150    fillCol[2] = [fillColor blueComponent];
151    fillAlpha = [fillColor alphaComponent];
152
153    dict = [NSMutableDictionary dictionaryWithCapacity: 1];
154    [dict setObject: @"circle" forKey: @"type"];
155
156    str = [NSString stringWithFormat: @"%i", isCircle];
157    [dict setObject: str forKey: @"circle"];
158
159    str = [NSString stringWithFormat: @"%.3f", pos.x];
160    [dict setObject: str forKey: @"posx"];
161    str = [NSString stringWithFormat: @"%.3f", pos.y];
162    [dict setObject: str forKey: @"posy"];
163
164    str = [NSString stringWithFormat: @"%.3f", size.width];
165    [dict setObject: str forKey: @"width"];
166    str = [NSString stringWithFormat: @"%.3f", size.height];
167    [dict setObject: str forKey: @"height"];
168
169    str = [NSString stringWithFormat: @"%.3f", flatness];
170    [dict setObject: str forKey: @"flatness"];
171    str = [NSString stringWithFormat: @"%i", linejoin];
172    [dict setObject: str forKey: @"linejoin"];
173    str = [NSString stringWithFormat: @"%i", linecap];
174    [dict setObject: str forKey: @"linecap"];
175    str = [NSString stringWithFormat: @"%.3f", miterlimit];
176    [dict setObject: str forKey: @"miterlimit"];
177    str = [NSString stringWithFormat: @"%.3f", linewidth];
178    [dict setObject: str forKey: @"linewidth"];
179    str = [NSString stringWithFormat: @"%i", stroked];
180    [dict setObject: str forKey: @"stroked"];
181    str = [NSString stringWithFormat: @"%.3f %.3f %.3f",
182        strokeCol[0], strokeCol[1], strokeCol[2]];
183    [dict setObject: str forKey: @"strokecolor"];
184    str = [NSString stringWithFormat: @"%.3f", strokeAlpha];
185    [dict setObject: str forKey: @"strokealpha"];
186    str = [NSString stringWithFormat: @"%i", filled];
187    [dict setObject: str forKey: @"filled"];
188    str = [NSString stringWithFormat: @"%.3f %.3f %.3f",
189        fillCol[0], fillCol[1], fillCol[2]];
190    [dict setObject: str forKey: @"fillcolor"];
191    str = [NSString stringWithFormat: @"%.3f", fillAlpha];
192    [dict setObject: str forKey: @"fillalpha"];
193    str = [NSString stringWithFormat: @"%i", visible];
194    [dict setObject: str forKey: @"visible"];
195    str = [NSString stringWithFormat: @"%i", locked];
196    [dict setObject: str forKey: @"locked"];
197
198    return dict;
199}
200
201- (BOOL)circle
202{
203  return isCircle;
204}
205
206- (void)setCircle:(BOOL)flag
207{
208  isCircle = flag;
209}
210
211- (void)setStartAtPoint:(NSPoint)aPoint
212{
213    pos = aPoint;
214    [startControlPoint moveToPoint: aPoint];
215    [startControlPoint select];
216}
217
218- (void)setEndAtPoint:(NSPoint)aPoint
219{
220  size.width = aPoint.x - pos.x;
221  size.height = aPoint.y- pos.y;
222  bounds = GRMakeBounds(pos.x, pos.y, size.width, size.height);
223  [endControlPoint moveToPoint: aPoint];
224  [endControlPoint select];
225
226  boundsZ = GRMakeBounds(pos.x * zmFactor, pos.y * zmFactor, size.width * zmFactor, size.height * zmFactor);
227}
228
229- (void)remakePath
230{
231    [self setStartAtPoint:[startControlPoint center]];
232    [self setEndAtPoint:[endControlPoint center]];
233    [(GRCircleEditor *)editor setIsDone:YES];
234}
235
236
237- (void)setLocked:(BOOL)value
238{
239    [super setLocked:value];
240    if(!locked)
241        [(GRCircleEditor *)editor unselect];
242    else
243        [(GRCircleEditor *)editor selectAsGroup];
244}
245
246- (BOOL)objectHitForSelection:(NSPoint)p
247{
248  return (pointInRect(bounds, p));
249}
250
251- (BOOL)onControlPoint:(NSPoint)p
252{
253    if (pointInRect([startControlPoint centerRect], p))
254        return YES;
255    if (pointInRect([endControlPoint centerRect], p))
256        return YES;
257    return NO;
258}
259
260- (GRObjectControlPoint *) startControlPoint
261{
262    return startControlPoint;
263}
264
265- (GRObjectControlPoint *) endControlPoint
266{
267    return endControlPoint;
268}
269
270
271- (void)moveAddingCoordsOfPoint:(NSPoint)p
272{
273  pos.x += p.x;
274  pos.y += p.y;
275  bounds = GRMakeBounds(pos.x, pos.y, size.width, size.height);
276  [startControlPoint moveToPoint: pos];
277  [endControlPoint moveToPoint: NSMakePoint(pos.x + size.width, pos.y + size.height)];
278
279  boundsZ = GRMakeBounds(pos.x * zmFactor, pos.y * zmFactor, size.width * zmFactor, size.height * zmFactor);
280}
281
282- (void)setZoomFactor:(CGFloat)f
283{
284    [super setZoomFactor:f];
285
286    [startControlPoint setZoomFactor:f];
287    [endControlPoint setZoomFactor:f];
288    [self remakePath];
289}
290
291/** bounds accessor */
292- (NSRect)bounds
293{
294    return bounds;
295}
296
297/** position accessor */
298- (NSPoint) position
299{
300  return pos;
301}
302
303/** draws the object and calls the editor to draw itself afterwards */
304- (void)draw
305{
306  NSBezierPath *bzp;
307  NSPoint center;
308  CGFloat radius;
309  CGFloat w,h;
310  CGFloat minLength;
311  CGFloat linew;
312  NSRect drawBounds;
313
314  drawBounds = bounds;
315  linew = linewidth;
316  if ([[NSGraphicsContext currentContext] isDrawingToScreen])
317    {
318      drawBounds = boundsZ;
319      linew = linewidth * zmFactor;
320    }
321
322  center = NSMakePoint(NSMidX(drawBounds), NSMidY(drawBounds));
323  w = NSWidth(drawBounds);
324  h = NSHeight(drawBounds);
325  if (w > h)
326    minLength = h;
327  else
328    minLength = w;
329  radius = minLength / 2;
330
331  bzp = [NSBezierPath bezierPath];
332  if (isCircle)
333    [bzp appendBezierPathWithArcWithCenter:center radius:radius startAngle:0 endAngle:360];
334  else
335    [bzp appendBezierPathWithOvalInRect: drawBounds];
336
337  if(filled)
338    {
339      [NSGraphicsContext saveGraphicsState];
340      [fillColor set];
341      [bzp fill];
342      [NSGraphicsContext restoreGraphicsState];
343    }
344  if(stroked)
345    {
346      [NSGraphicsContext saveGraphicsState];
347      [bzp setLineJoinStyle:linejoin];
348      [bzp setLineCapStyle:linecap];
349      [bzp setLineWidth:linew];
350      [strokeColor set];
351      [bzp stroke];
352      [NSGraphicsContext restoreGraphicsState];
353    }
354
355  if ([[NSGraphicsContext currentContext] isDrawingToScreen])
356    [editor draw];
357}
358
359
360@end
361