1/*
2 Project: Graphos
3 GRText.m
4
5 Copyright (C) 2000-2018 GNUstep Application Project
6
7 Author: Enrico Sersale (original GDraw implementation)
8 Author: Ing. Riccardo Mottola
9
10 This application is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
14
15 This application is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 Library General Public License for more details.
19
20 You should have received a copy of the GNU General Public
21 License along with this library; if not, write to the Free
22 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23 */
24
25
26#import "GRText.h"
27#import "GRDocView.h"
28#import "GRFunctions.h"
29#import "Graphos.h"
30#import "GRTextEditor.h"
31
32@implementation GRText
33
34- (GRObjectEditor *)allocEditor
35{
36  return [[GRTextEditor alloc] initEditor:self];
37}
38
39- (id)initInView:(GRDocView *)aView
40         atPoint:(NSPoint)p
41      zoomFactor:(CGFloat)zf
42  withProperties:(NSDictionary *) properties
43      openEditor:(BOOL)openedit
44{
45  self = [super initInView:aView zoomFactor:zf withProperties:properties];
46  if(self)
47    {
48      int result;
49      NSString *s;
50      NSFont *f;
51      NSParagraphStyle *parStyle;
52      NSDictionary *parAttr;
53
54      pos = p;
55      selRect = NSMakeRect(pos.x - 3, pos.y - 3, 6, 6);
56      rotation = 0;
57      scalex = 1;
58      scaley = 1;
59
60      s = [properties objectForKey:@"string"];
61      if (nil == s)
62        s = @"";
63      f = [properties objectForKey:@"font"];
64      if (nil == f)
65        f = [NSFont systemFontOfSize:12];
66      parStyle = [properties objectForKey:@"paragraphstyle"];
67      if (nil == parStyle)
68        parStyle = [NSParagraphStyle defaultParagraphStyle];
69      parAttr = [NSDictionary dictionaryWithObjectsAndKeys:
70                                f, NSFontAttributeName,
71                              parStyle, NSParagraphStyleAttributeName, nil];
72      [self setString:s attributes:parAttr];
73
74      if(openedit)
75	{
76	  [(GRTextEditor *)editor setPoint: pos
77				withString: nil
78				attributes: nil];
79	  result = [(GRTextEditor *)editor runModal];
80	  if(result == NSAlertDefaultReturn)
81	    {
82	      [self setString: [[(GRTextEditor *)editor editorView] textString]
83		   attributes: [[(GRTextEditor *)editor editorView] textAttributes]];
84	    }
85	  else
86	    {
87	      [self release];
88	      return nil;
89	    }
90        }
91    }
92  return self;
93}
94
95- (id)initFromData:(NSDictionary *)description
96            inView:(GRDocView *)aView
97        zoomFactor:(CGFloat)zf
98{
99  self = [super initFromData:description inView:aView zoomFactor:zf];
100  if(self)
101    {
102      NSString *s;
103      NSString *fontname;
104      CGFloat fsize;
105      NSFont *fontObj;
106      float parspace;
107      NSTextAlignment align;
108      NSMutableParagraphStyle *style;
109      NSDictionary *parAttr;
110      id obj;
111
112      s = [description objectForKey: @"string"];
113
114      pos = NSMakePoint([[description objectForKey: @"posx"]  floatValue],
115			[[description objectForKey: @"posy"]  floatValue]);
116
117      fontname = [description objectForKey: @"fontname"];
118      fsize = [[description objectForKey: @"fontsize"] floatValue];
119      if (fsize == 0)
120	{
121	  NSLog(@"font size invalid");
122	  fsize = 12.0;
123	}
124      fontObj = [NSFont fontWithName: fontname size: fsize];
125      if (nil == fontObj)
126	{
127	  NSLog(@"font %@ of size %f not found using system", fontname, fsize);
128	  fontObj = [NSFont systemFontOfSize:fsize];
129	}
130
131      align = [[description objectForKey: @"txtalign"] intValue];
132      parspace = [[description objectForKey: @"parspace"] floatValue];
133      style = [[NSMutableParagraphStyle alloc] init];
134      [style setParagraphStyle:[NSParagraphStyle defaultParagraphStyle]];
135      [style setAlignment: align];
136      [style setParagraphSpacing: parspace];
137      parAttr = [NSDictionary dictionaryWithObjectsAndKeys:
138                                fontObj, NSFontAttributeName,
139                              style, NSParagraphStyleAttributeName, nil];
140      [self setString:s attributes:parAttr];
141      [style release];
142
143
144      obj = [description objectForKey: @"rotation"];
145      if (obj)
146	rotation = [obj floatValue];
147
148      scalex = [[description objectForKey: @"scalex"] floatValue];
149      scaley = [[description objectForKey: @"scaley"] floatValue];
150    }
151  return self;
152}
153
154- (id)copyWithZone:(NSZone *)zone
155{
156  GRText *objCopy;
157
158  objCopy = [super copyWithZone:zone];
159
160  objCopy->str = [str copy];
161  objCopy->parAttributes = [parAttributes copy];
162
163  objCopy->pos = NSMakePoint(pos.x, pos.y);
164  objCopy->size = NSMakeSize(size.width, size.height);
165  objCopy->bounds = NSMakeRect(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
166  objCopy->rotation = rotation;
167  objCopy->scalex = scalex;
168  objCopy->scaley = scaley;
169  objCopy->selRect = NSMakeRect(selRect.origin.x, selRect.origin.y, selRect.size.width, selRect.size.height);
170
171  return objCopy;
172}
173
174
175
176- (NSDictionary *)objectDescription
177{
178    NSMutableDictionary *dict;
179    NSString *s;
180    float strokeCol[3];
181    float fillCol[3];
182    float strokeAlpha;
183    float fillAlpha;
184    float parspace;
185    NSTextAlignment align;
186    NSFont *font;
187    float fsize;
188    NSParagraphStyle *pstyle;
189
190    font = [parAttributes objectForKey: NSFontAttributeName];
191    fsize = [font pointSize];
192    pstyle = [parAttributes objectForKey: NSParagraphStyleAttributeName];
193    parspace = [pstyle paragraphSpacing];
194    align = [pstyle alignment];
195
196
197    strokeCol[0] = [strokeColor redComponent];
198    strokeCol[1] = [strokeColor greenComponent];
199    strokeCol[2] = [strokeColor blueComponent];
200    strokeAlpha = [strokeColor alphaComponent];
201
202    fillCol[0] = [fillColor redComponent];
203    fillCol[1] = [fillColor greenComponent];
204    fillCol[2] = [fillColor blueComponent];
205    fillAlpha = [fillColor alphaComponent];
206
207    dict = [NSMutableDictionary dictionaryWithCapacity: 1];
208    [dict setObject: @"text" forKey: @"type"];
209
210    [dict setObject: str forKey: @"string"];
211    s = [NSString stringWithFormat: @"%.3f", pos.x];
212    [dict setObject: s forKey: @"posx"];
213    s = [NSString stringWithFormat: @"%.3f", pos.y];
214    [dict setObject: s forKey: @"posy"];
215    s = [font fontName];
216    [dict setObject: s forKey: @"fontname"];
217    s = [NSString stringWithFormat: @"%.3f", fsize];
218    [dict setObject: s forKey: @"fontsize"];
219    s = [NSString stringWithFormat: @"%.3f", parspace];
220    [dict setObject: s forKey: @"parspace"];
221    s = [NSString stringWithFormat: @"%i", (int)align];
222    [dict setObject: s forKey: @"txtalign"];
223    s = [NSString stringWithFormat: @"%.3f", scalex];
224    [dict setObject: s forKey: @"scalex"];
225    s = [NSString stringWithFormat: @"%.3f", scaley];
226    [dict setObject: s forKey: @"scaley"];
227    s = [NSString stringWithFormat: @"%.3f", rotation];
228    [dict setObject: s forKey: @"rotation"];
229    [dict setObject: [NSNumber numberWithBool:stroked] forKey: @"stroked"];
230    s = [NSString stringWithFormat: @"%.3f %.3f %.3f",
231        strokeCol[0], strokeCol[1], strokeCol[2]];
232    [dict setObject: s forKey: @"strokecolor"];
233    s = [NSString stringWithFormat: @"%.3f", strokeAlpha];
234    [dict setObject: s forKey: @"strokealpha"];
235    [dict setObject: [NSNumber numberWithBool: filled] forKey: @"filled"];
236    s = [NSString stringWithFormat: @"%.3f %.3f %.3f",
237        fillCol[0], fillCol[1], fillCol[2]];
238    [dict setObject: s forKey: @"fillcolor"];
239    s = [NSString stringWithFormat: @"%.3f", fillAlpha];
240    [dict setObject: s forKey: @"fillalpha"];
241    [dict setObject: [NSNumber numberWithBool: visible] forKey: @"visible"];
242    [dict setObject: [NSNumber numberWithBool: locked] forKey: @"locked"];
243
244    return dict;
245}
246
247
248- (void)dealloc
249{
250  [str release];
251  [parAttributes release];
252  [super dealloc];
253}
254
255- (void)setString:(NSString *)aString attributes:(NSDictionary *)attrs
256{
257  ASSIGN(str, aString);
258  ASSIGN(parAttributes, attrs);
259
260  size = NSMakeSize(0, 0);
261  if (str)
262    size = [str sizeWithAttributes: attrs];
263  bounds = NSMakeRect(pos.x, pos.y, size.width, size.height);
264}
265
266// maybe should be moved into the editor
267- (void)edit
268{
269    int result;
270
271    [(GRTextEditor *)editor setPoint: pos
272          withString: str
273          attributes: parAttributes];
274    result = [(GRTextEditor *)editor runModal];
275    if(result == NSAlertDefaultReturn)
276        [self setString: [[(GRTextEditor *)editor editorView] textString]
277             attributes: [[(GRTextEditor *)editor editorView] textAttributes]];
278}
279
280- (BOOL)objectHitForSelection:(NSPoint)p
281{
282    if(pointInRect(bounds, p) || pointInRect(selRect, p))
283        return YES;
284    return NO;
285}
286
287- (void)moveAddingCoordsOfPoint:(NSPoint)p
288{
289    pos.x += p.x;
290    pos.y += p.y;
291    bounds = NSMakeRect(pos.x, pos.y, size.width, size.height);
292    selRect = NSMakeRect(pos.x - 3, pos.y - 3, 6, 6);
293}
294
295- (void)setZoomFactor:(CGFloat)f
296{
297    zmFactor = f;
298}
299
300- (void)setScalex:(float)x scaley:(float)y
301{
302    scalex = x;
303    scaley = y;
304}
305
306- (void)setRotation:(float)r
307{
308    rotation = r;
309}
310
311- (void)setLocked:(BOOL)value
312{
313    [super setLocked:value];
314    if(!locked)
315        [editor unselect];
316    else
317        [editor selectAsGroup];
318}
319
320
321
322- (NSBezierPath *) makePathFromString: (NSString *) aString
323                              forFont: (NSFont *) aFont
324                              atPoint: (NSPoint) aPoint
325{
326    NSTextView *textview;
327    NSGlyph *glyphs;
328    NSBezierPath *path;
329    NSRange range;
330    NSLayoutManager *layoutManager;
331
332
333    textview = [[NSTextView alloc] init];
334
335    [textview setString: aString];
336    [textview setFont: aFont];
337
338    layoutManager = [textview layoutManager];
339
340    range = [layoutManager glyphRangeForCharacterRange:
341        NSMakeRange (0, [aString length])
342                                  actualCharacterRange: NULL];
343
344    glyphs = (NSGlyph *) malloc (sizeof(NSGlyph) * (range.length * 2));
345    [layoutManager getGlyphs: glyphs  range: range];
346
347
348    path = [NSBezierPath bezierPath];
349
350    [path moveToPoint: aPoint];
351    [path appendBezierPathWithGlyphs: glyphs
352                               count: range.length  inFont: aFont];
353
354    free (glyphs);
355    [textview release];
356
357    return (path);
358}
359
360- (void)draw
361{
362  NSArray *lines;
363  float baselny;
364  NSInteger i;
365  NSBezierPath *bezp;
366  NSMutableParagraphStyle *style;
367  CGFloat parSpacing;
368  NSDictionary *strAttr;
369  NSFont *font;
370  NSFont *tempFont;
371  CGFloat fontSize;
372  NSPoint posZ;
373  NSRect boundsZ;
374  NSSize sizeZ;
375
376  if(!visible)
377    return;
378
379  posZ = pos;
380  font = [parAttributes objectForKey: NSFontAttributeName];
381  fontSize = [font pointSize];
382  if ([[NSGraphicsContext currentContext] isDrawingToScreen])
383    {
384      posZ = GRpointZoom(pos, zmFactor);
385      fontSize = fontSize * zmFactor;
386    }
387
388  NSAssert (font != nil, @"Font object nil during drawing");
389  style = [parAttributes objectForKey: NSParagraphStyleAttributeName];
390  parSpacing = [style paragraphSpacing];
391
392  tempFont = [NSFont fontWithName:[font fontName] size:fontSize];
393  if (tempFont == nil)
394    {
395      NSLog(@"temp font obtained from %@ zoomFactor: %f is nil", font, zmFactor);
396      tempFont = font;
397    }
398  if (filled)
399    {
400      strAttr = [[NSDictionary dictionaryWithObjectsAndKeys:
401				 tempFont, NSFontAttributeName,
402			       strokeColor, NSForegroundColorAttributeName,
403			       fillColor, NSBackgroundColorAttributeName,
404			       style, NSParagraphStyleAttributeName, nil] retain];
405    }
406  else
407    {
408      strAttr = [[NSDictionary dictionaryWithObjectsAndKeys:
409				 tempFont, NSFontAttributeName,
410			       strokeColor, NSForegroundColorAttributeName,
411			       style, NSParagraphStyleAttributeName, nil] retain];
412    }
413  baselny = posZ.y;
414
415  sizeZ  = [str sizeWithAttributes: strAttr];
416  boundsZ = NSMakeRect(posZ.x, posZ.y, sizeZ.width, sizeZ.height);
417
418  [str drawInRect:boundsZ withAttributes:strAttr];
419
420  if ([[NSGraphicsContext currentContext] isDrawingToScreen] && [editor isSelected])
421    {
422      NSRect selRectZ;
423
424      selRectZ = NSMakeRect(selRect.origin.x * zmFactor, selRect.origin.y * zmFactor, selRect.size.width, selRect.size.height);
425
426      bezp = [NSBezierPath bezierPath];
427      [bezp setLineWidth:0];
428      if([str length] > 0)
429	{
430	  lines = [str componentsSeparatedByString: @"\n"];
431	  for(i = 0; i < [lines count]; i++)
432	    {
433	      NSString *line;
434	      NSSize lineSize;
435
436	      line = [lines objectAtIndex: i];
437	      lineSize = [line sizeWithAttributes:strAttr];
438
439	      [[NSColor blackColor] set];
440	      [bezp moveToPoint:NSMakePoint(posZ.x, baselny)];
441	      [bezp lineToPoint:NSMakePoint(posZ.x + bounds.size.width*zmFactor, baselny)];
442
443	      baselny += lineSize.height + parSpacing;
444	    }
445
446	  [bezp stroke];
447	  [[NSColor blackColor] set];
448	  NSRectFill(selRectZ);
449	}
450    }
451  [strAttr release];
452}
453
454@end
455