1//
2//  ZoomUpperWindow.m
3//  ZoomCocoa
4//
5//  Created by Andrew Hunter on Thu Oct 09 2003.
6//  Copyright (c) 2003 Andrew Hunter. All rights reserved.
7//
8
9#import "ZoomUpperWindow.h"
10
11
12@implementation ZoomUpperWindow
13
14- (id) initWithZoomView: (ZoomView*) view {
15    self = [super init];
16    if (self) {
17        theView = view;
18        lines = [[NSMutableArray allocWithZone: [self zone]] init];
19
20        backgroundColour = [[NSColor blueColor] retain];
21
22        endLine = startLine = 0;
23    }
24    return self;
25}
26
27- (void) dealloc {
28    //[theView release];
29    [lines release];
30	[inputStyle release];
31    [backgroundColour release];
32    [super dealloc];
33}
34
35// Clears the window
36- (void) clearWithStyle: (ZStyle*) style {
37    [lines release];
38    lines = [[NSMutableArray allocWithZone: [self zone]] init];
39    xpos = ypos = 0;
40
41    [backgroundColour release];
42    backgroundColour = [[style reversed]?[theView foregroundColourForStyle: style]:[theView backgroundColourForStyle: style]
43		retain];
44}
45
46// Sets the input focus to this window
47- (void) setFocus {
48	[theView setFocusedView: self];
49}
50
51// Sending data to a window
52- (void) writeString: (NSString*) string
53           withStyle: (ZStyle*) style {
54    [style setFixed: YES];
55
56    int x;
57    int len = [string length];
58    for (x=0; x<len; x++) {
59        if ([string characterAtIndex: x] == '\n') {
60            [self writeString: [string substringToIndex: x]
61                    withStyle: style];
62            ypos++; xpos = 0;
63            [self writeString: [string substringFromIndex: x+1]
64                    withStyle: style];
65            return;
66        }
67    }
68
69    if (ypos >= [lines count]) {
70        int x;
71        for (x=[lines count]; x<=ypos; x++) {
72            [lines addObject: [[[NSMutableAttributedString alloc] init] autorelease]];
73        }
74    }
75
76    NSMutableAttributedString* thisLine;
77    thisLine = [lines objectAtIndex: ypos];
78
79    int strlen = [string length];
80
81    // Make sure there is enough space on this line for the text
82    if ([thisLine length] <= xpos+strlen) {
83        NSFont* fixedFont = [theView fontWithStyle: ZFixedStyle];
84        NSDictionary* clearStyle = [NSDictionary dictionaryWithObjectsAndKeys:
85            fixedFont, NSFontAttributeName,
86            nil];
87        char* spaces = malloc((xpos+strlen)-[thisLine length]);
88
89        int x;
90        for (x=0; x<(xpos+strlen)-[thisLine length]; x++) {
91            spaces[x] = ' ';
92        }
93
94        NSAttributedString* spaceString = [[NSAttributedString alloc]
95            initWithString: [NSString stringWithCString: spaces
96                                                 length: (xpos+strlen)-[thisLine length]]
97                attributes: clearStyle];
98
99        [thisLine appendAttributedString: spaceString];
100
101        [spaceString release];
102        free(spaces);
103    }
104
105    // Replace the appropriate section of the line
106    NSAttributedString* thisString = [theView formatZString: string
107                                                  withStyle: style];
108    [thisLine replaceCharactersInRange: NSMakeRange(xpos, strlen)
109                  withAttributedString: thisString];
110    xpos += strlen;
111
112    [theView upperWindowNeedsRedrawing];
113}
114
115// Size (-1 to indicate an unsplit window)
116- (void) startAtLine: (int) line {
117    startLine = line;
118}
119
120- (void) endAtLine:   (int) line {
121    endLine = line;
122
123    [theView rearrangeUpperWindows];
124}
125
126// Cursor positioning
127- (void) setCursorPositionX: (int) xp
128                          Y: (int) yp {
129    xpos = xp; ypos = yp-startLine;
130
131	if (xpos < 0) xpos = 0;
132	if (ypos < 0) ypos = 0;
133}
134
135- (NSPoint) cursorPosition {
136    return NSMakePoint(xpos, ypos+startLine);
137}
138
139
140// Line erasure
141static NSString* blankLine(int length) {
142	char* cString = malloc(length);
143	int x;
144
145	for (x=0; x<length; x++) cString[x] = ' ';
146
147	NSString* res = [NSString stringWithCString: cString
148										 length: length];
149
150	return res;
151}
152
153- (void) eraseLineWithStyle: (ZStyle*) style {
154    if (ypos >= [lines count]) {
155        int x;
156        for (x=[lines count]; x<=ypos; x++) {
157            [lines addObject: [[[NSMutableAttributedString alloc] init] autorelease]];
158        }
159    }
160
161		int xs, ys;
162		NSAttributedString* newString;
163
164		[theView dimensionX: &xs Y: &ys];
165
166		newString = [theView formatZString: blankLine(xs+1)
167								 withStyle: style];
168
169        [[lines objectAtIndex: ypos] setAttributedString: newString];
170}
171
172// Maintainance
173- (int) length {
174    return (endLine - startLine);
175}
176
177- (NSArray*) lines {
178    return lines;
179}
180
181- (NSColor*) backgroundColour {
182    return backgroundColour;
183}
184
185- (void) cutLines {
186	int length = [self length];
187	if ([lines count] < length) return;
188
189    [lines removeObjectsInRange: NSMakeRange(length,
190                                             [lines count] - length)];
191}
192
193- (void) reformatLines {
194	NSEnumerator* lineEnum = [lines objectEnumerator];
195	NSMutableAttributedString* string;
196
197	while (string = [lineEnum nextObject]) {
198		NSRange attributedRange;
199		NSDictionary* attr;
200		int len = [string length];
201
202		attributedRange.location = 0;
203
204		 while (attributedRange.location < len) {
205			attr = [string attributesAtIndex: attributedRange.location
206							  effectiveRange: &attributedRange];
207
208			if (attributedRange.location == NSNotFound) break;
209			if (attributedRange.length == 0) break;
210
211			// Re-apply the style associated with this block of text
212			ZStyle* sty = [attr objectForKey: ZoomStyleAttributeName];
213
214			if (sty) {
215				NSDictionary* newAttr = [theView attributesForStyle: sty];
216
217				[string setAttributes: newAttr
218								range: attributedRange];
219			}
220
221			attributedRange.location += attributedRange.length;
222		}
223	}
224}
225
226// = NSCoding =
227- (void) encodeWithCoder: (NSCoder*) encoder {
228	[encoder encodeValueOfObjCType: @encode(int)
229								at: &startLine];
230	[encoder encodeValueOfObjCType: @encode(int)
231								at: &endLine];
232	[encoder encodeValueOfObjCType: @encode(int)
233								at: &xpos];
234	[encoder encodeValueOfObjCType: @encode(int)
235								at: &ypos];
236	[encoder encodeObject: lines];
237	[encoder encodeObject: backgroundColour];
238}
239
240- (id)initWithCoder:(NSCoder *)decoder {
241	self = [super init];
242
243    if (self) {
244		[decoder decodeValueOfObjCType: @encode(int)
245									at: &startLine];
246		[decoder decodeValueOfObjCType: @encode(int)
247									at: &endLine];
248		[decoder decodeValueOfObjCType: @encode(int)
249									at: &xpos];
250		[decoder decodeValueOfObjCType: @encode(int)
251									at: &ypos];
252		lines = [[decoder decodeObject] retain];
253		backgroundColour = [[decoder decodeObject] retain];
254    }
255
256    return self;
257}
258
259- (void) setZoomView: (ZoomView*) view {
260	theView = view;
261}
262
263// = Input styles =
264
265- (void) setInputStyle: (ZStyle*) newInputStyle {
266	if (inputStyle) [inputStyle release];
267	inputStyle = [newInputStyle copy];
268}
269
270- (ZStyle*) inputStyle {
271	return inputStyle;
272}
273
274@end
275