1// pgviewobj.m is the custom view object for the pgview program.  PGView
2// receives 132 byte character arrays filled with PostScript code.  PGView
3// saves these buffers in a Storage object.  When the PGPLOT program
4// executes a flushpg operation, this stored data is then sent to the
5// display.
6//
7// 1999-Feb-20 - Update for OpenStep - [AFT]
8// 1992-Mar-09 - [AFT]
9//---
10#import "pgviewobj.h"
11
12@implementation pgviewobj
13
14- initWithFrame:(NSRect)frameRect
15{
16      [super initWithFrame:frameRect];
17
18// Create an enclosing window and bring it upfront
19      myWindow = [[NSWindow alloc] initWithContentRect:frameRect
20         styleMask:NSResizableWindowMask|
21               (NSMiniaturizableWindowMask | NSClosableWindowMask)
22         backing:NSBackingStoreBuffered
23         defer:NO];
24      [myWindow setContentView:self];
25      [myWindow setBackgroundColor:[NSColor whiteColor]];
26      [myWindow setReleasedWhenClosed:YES];
27      [myWindow setTitle:@"PGPLOT Viewer"];
28      [myWindow display];
29      [myWindow orderFront:self];
30
31// Save portrait/landscape flag
32      if( frameRect.size.width > frameRect.size.height) {
33         lwtype=0;
34      } else {
35         lwtype=1;
36      }
37
38// Needed to do PostScript scaling
39      [self scaleUnitSquareToSize:NSMakeSize(0.1, 0.1)];
40      prevw = [self bounds].size.width;
41      prevh = [self bounds].size.height;
42
43// PostScript data sent from PGPLOT will be stored in psdata.
44      psdata = [Storage newCount:0
45                elementSize:132
46                description:"[132c]"];
47      nplot=0;
48
49// Allocate private graphics state, so things like the current color
50// setting will be preserved between different calls to drawSelf.
51      [self allocateGState];
52
53      return self;
54}
55
56- (void)drawRect:(NSRect)rect
57{
58      DPSContext ctxt;
59      NSRect bounds;
60      int    i;
61
62      if ( nplot > 0) {
63         bounds=[self bounds];
64         if( prevw != bounds.size.width || prevh != bounds.size.height) {
65            [self scaleUnitSquareToSize:NSMakeSize(bounds.size.width/prevw,
66                                                   bounds.size.height/prevh)];
67            prevw = bounds.size.width;
68            prevh = bounds.size.height;
69         }
70
71         ctxt= DPSGetCurrentContext();
72         for(i=0; i<nplot; i++) {
73            DPSPrintf(ctxt, "%s\n", (char *) [psdata elementAt:i]);
74         }
75      }
76      return;
77}
78
79- (void)dealloc
80{
81printf("in dealloc\n");
82      [psdata free];
83      [super dealloc];
84      return;
85}
86
87- (void)endPrologue
88// This routine sends the PGPLOT defines to the print job.
89{
90      DPSContext ctxt;
91
92      ctxt= DPSGetCurrentContext();
93      [self pgplotDefs:ctxt];
94      [super endPrologue];
95      return;
96}
97
98- (void) pgplotDefs: (DPSContext) ctxt
99{
100      DPSPrintf(ctxt,
101      "/l {moveto rlineto currentpoint stroke moveto} bind def\n");
102      DPSPrintf(ctxt,
103      "/c {rlineto currentpoint stroke moveto} bind def\n");
104      DPSPrintf(ctxt,
105      "/d {moveto 0 0 rlineto currentpoint stroke moveto} bind def\n");
106      DPSPrintf(ctxt,"/SLW {5 mul setlinewidth} bind def\n");
107      DPSPrintf(ctxt,"/BP {newpath moveto} bind def\n");
108      DPSPrintf(ctxt,"/LP /rlineto load def\n");
109      DPSPrintf(ctxt,"/EP {rlineto closepath eofill} bind def\n");
110      return;
111}
112
113- (void) beginp
114{
115      DPSContext ctxt;
116
117      if([NSApp isHidden]) {
118         [NSApp unhideWithoutActivation];
119      }
120      [myWindow setDocumentEdited:YES];
121      [self lockFocus];
122      ctxt= DPSGetCurrentContext();
123      DPSPrintf(ctxt,"cleardictstack\n");
124      [self pgplotDefs:ctxt];
125      [self unlockFocus];
126      [myWindow orderFrontRegardless];
127      [psdata empty];
128      nplot=0;
129
130      return;
131}
132
133- (void) endp
134{
135      [myWindow setDocumentEdited:NO];
136      return;
137}
138
139- (void) flushpg
140{
141      DPSContext ctxt;
142      int   i, ibeg;
143
144      if ([psdata count] > nplot) {
145         [self lockFocus];
146         ibeg=nplot;
147         nplot = [psdata count];
148         ctxt= DPSGetCurrentContext();
149         for(i=ibeg; i<nplot; i++) {
150            DPSPrintf(ctxt, "%s\n", (char *) [psdata elementAt:i]);
151         }
152         PScurrentgstate([self gState]);
153         PSpop();
154         [myWindow flushWindow];
155         [self unlockFocus];
156      }
157      return;
158}
159
160- (void) gettype: (int *) iwtype;
161{
162      *iwtype=lwtype;
163      return;
164}
165
166- (void) getwind: (int *) ixdim  by: (int *) iydim
167      color: (int *) icol  scale: (int *) imag
168{
169      *ixdim= (int) ([self bounds].size.width+0.5);
170      *iydim= (int) ([self bounds].size.height+0.5);
171      *icol = [self shouldDrawColor];
172      *imag=10;
173      return;
174}
175
176- (void) pscode: (char *) cbuf
177{
178      [psdata addElement:(void *) cbuf];
179      return;
180}
181
182- (void) readcursor: (NSPoint *) aPoint char: (int *) ichar
183         cursor: (NSCursor *) crossCursor
184{
185      char     cbuf[8];
186      NSEvent  *nextEvent;
187      NSModalSession session;
188      NSPoint  curPoint;
189      NSRect   hitRect;
190      NSView   *mysuper;
191      BOOL     qinside, qloop;
192
193// Since pgview is not the active application, it cannot read the
194// the keyboard.  The following code forces pgview to become the
195// active application.
196      [NSApp activateIgnoringOtherApps:YES];
197
198// Calculate the coordinates of the view in the window coordinate system.
199      mysuper = [self superview];
200      hitRect = [self convertRect:[self frame] fromView:mysuper];
201
202      [myWindow makeKeyAndOrderFront:self];
203      curPoint = [myWindow mouseLocationOutsideOfEventStream];
204      qinside=[self mouse:curPoint inRect:hitRect];
205      [self addTrackingRect:hitRect
206         owner:self
207         userData:nil
208         assumeInside:qinside];
209
210      [self lockFocus];
211      if(qinside) [crossCursor set];
212
213// If I don't use a Modal loop, then sometimes a busy cursor occurs.
214// The modal loop is the only way I know how to prevent this, sorry.
215      session = [NSApp beginModalSessionForWindow:myWindow];
216      [NSApp runModalSession:session];
217
218      qloop=YES;
219      do {
220         nextEvent=[myWindow nextEventMatchingMask:
221            NSLeftMouseDownMask| NSLeftMouseUpMask |
222            NSKeyDownMask      | NSKeyUpMask   |
223            NSMouseEnteredMask | NSMouseExitedMask];
224
225         switch ([nextEvent type]) {
226         case NSLeftMouseDown:
227         case NSKeyDown:
228// Ignore down events.
229            break;
230         case NSLeftMouseUp:
231         case NSKeyUp:
232// Only process events if mouse is inside the current view.
233            if(qinside) {
234               if([nextEvent type]==NSKeyUp) {
235                  [[nextEvent characters] getCString:cbuf maxLength:8];
236                  *ichar= (int) cbuf[0];
237                  curPoint = [myWindow mouseLocationOutsideOfEventStream];
238               } else {
239                  *ichar= 65;
240                  curPoint=[nextEvent locationInWindow];
241               }
242// First convert from pixel coordinate in the window system to view
243               curPoint = [mysuper convertPoint:curPoint fromView:[mysuper superview]];
244// Now convert from pixel to scaled coordinate
245               curPoint = [self convertPoint:curPoint fromView:mysuper];
246               *aPoint = curPoint;
247               qloop=NO;
248            }
249            break;
250         case NSMouseEntered:
251            qinside = YES;
252            [crossCursor set];
253            break;
254         case NSMouseExited:
255            qinside = NO;
256            [[NSCursor arrowCursor] set];
257            break;
258         default:
259printf("PGView--mystery event type=%d  flags=%d  window=%u\n",
260         [nextEvent type], [nextEvent modifierFlags], [nextEvent windowNumber]);
261            break;
262         }
263
264      } while (qloop);
265
266      [NSApp endModalSession:session];
267      [[NSCursor arrowCursor] set];
268      [self unlockFocus];
269
270// I have not found a nice way to return control the last active application.
271// This kludge does the job, but flashes the window on and off the screen.
272//      [NSApp hide:self];
273//      [NSApp unhideWithoutActivation];
274      [NSApp deactivate];
275      return;
276}
277
278@end
279