OSDN Git Service

MacGui: Add some activity log messages pertaining to source scan selection
[handbrake-jp/handbrake-jp-git.git] / macosx / PictureController.mm
1 /* $Id: PictureController.mm,v 1.11 2005/08/01 15:10:44 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.m0k.org/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "PictureController.h"
8
9 @interface PictureController (Private)
10
11 - (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize;
12 - (void)resizeSheetForViewSize: (NSSize)viewSize;
13 - (void)setViewSize: (NSSize)viewSize;
14 - (BOOL)viewNeedsToResizeToSize: (NSSize)newSize;
15
16 @end
17
18 static int GetAlignedSize( int size )
19 {
20     int result = 1;
21     while( result < size )
22     {
23         result *= 2;
24     }
25     return result;
26 }
27
28 @implementation PictureController
29
30 - (id)initWithDelegate:(id)del
31 {
32         if (self = [super init])
33         {
34                 delegate = del;
35         [self loadMyNibFile];
36         }
37         return self;
38 }
39
40 - (void) SetHandle: (hb_handle_t *) handle
41 {
42     fHandle = handle;
43
44     fHasQE = CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay );
45
46     fBuffer     = NULL;
47     fBufferSize = 0;
48     fTexBuf[0]  = NULL;
49     fTexBuf[1]  = NULL;
50     fTexBufSize = 0;
51
52     [fWidthStepper  setValueWraps: NO];
53     [fWidthStepper  setIncrement: 16];
54     [fWidthStepper  setMinValue: 64];
55     [fHeightStepper setValueWraps: NO];
56     [fHeightStepper setIncrement: 16];
57     [fHeightStepper setMinValue: 64];
58
59     [fCropTopStepper    setIncrement: 2];
60     [fCropTopStepper    setMinValue:  0];
61     [fCropBottomStepper setIncrement: 2];
62     [fCropBottomStepper setMinValue:  0];
63     [fCropLeftStepper   setIncrement: 2];
64     [fCropLeftStepper   setMinValue:  0];
65     [fCropRightStepper  setIncrement: 2];
66     [fCropRightStepper  setMinValue:  0];
67 }
68
69 - (void) SetTitle: (hb_title_t *) title
70 {
71     hb_job_t * job = title->job;
72
73     fTitle = title;
74
75     /* Make sure we have big enough buffers */
76     int newSize;
77     newSize = ( title->width + 2 ) * (title->height + 2 ) * 4;
78     if( fBufferSize < newSize )
79     {
80         fBufferSize = newSize;
81         fBuffer     = (uint8_t *) realloc( fBuffer, fBufferSize );
82     }
83     if( !fHasQE )
84     {
85         newSize = ( GetAlignedSize( title->width + 2 ) *
86             GetAlignedSize( title->height + 2 ) * 4 );
87     }
88     if( fTexBufSize < newSize )
89     {
90         fTexBufSize = newSize;
91         fTexBuf[0]  = (uint8_t *) realloc( fTexBuf[0], fTexBufSize );
92         fTexBuf[1]  = (uint8_t *) realloc( fTexBuf[1], fTexBufSize );
93     }
94
95
96     [fWidthStepper      setMaxValue: title->width];
97     [fWidthStepper      setIntValue: job->width];
98     [fWidthField        setIntValue: job->width];
99     [fHeightStepper     setMaxValue: title->height];
100     [fHeightStepper     setIntValue: job->height];
101     [fHeightField       setIntValue: job->height];
102     [fRatioCheck        setState:    job->keep_ratio ? NSOnState : NSOffState];
103     [fCropTopStepper    setMaxValue: title->height/2-2];
104     [fCropBottomStepper setMaxValue: title->height/2-2];
105     [fCropLeftStepper   setMaxValue: title->width/2-2];
106     [fCropRightStepper  setMaxValue: title->width/2-2];
107
108     /* Populate the Anamorphic NSPopUp button here */
109     [fAnamorphicPopUp removeAllItems];
110     [fAnamorphicPopUp addItemWithTitle: @"None"];
111     [fAnamorphicPopUp addItemWithTitle: @"Strict"];
112     if (allowLooseAnamorphic)
113     {
114     [fAnamorphicPopUp addItemWithTitle: @"Loose"];
115     }
116     [fAnamorphicPopUp selectItemAtIndex: job->pixel_ratio];
117     
118         /* Set deinterlaces level according to the integer in the main window */
119         [fDeinterlacePopUp selectItemAtIndex: fPictureFilterSettings.deinterlace];
120     
121     /* We initially set the previous state of keep ar to on */
122     keepAspectRatioPreviousState = 1;
123         if (!autoCrop)
124         {
125         [fCropMatrix  selectCellAtRow: 1 column:0];
126         /* If auto, lets set the crop steppers according to current job->crop values */
127         [fCropTopStepper    setIntValue: job->crop[0]];
128         [fCropTopField      setIntValue: job->crop[0]];
129         [fCropBottomStepper setIntValue: job->crop[1]];
130         [fCropBottomField   setIntValue: job->crop[1]];
131         [fCropLeftStepper   setIntValue: job->crop[2]];
132         [fCropLeftField     setIntValue: job->crop[2]];
133         [fCropRightStepper  setIntValue: job->crop[3]];
134         [fCropRightField    setIntValue: job->crop[3]];
135         }
136         else
137         {
138         [fCropMatrix  selectCellAtRow: 0 column:0];
139         }
140         
141     fPicture = 0;
142     MaxOutputWidth = title->width - job->crop[2] - job->crop[3];
143     MaxOutputHeight = title->height - job->crop[0] - job->crop[1];
144     [self SettingsChanged: nil];
145 }
146
147 /* we use this to setup the initial picture filters upon first launch, after that their states
148 are maintained across different sources */
149 - (void) setInitialPictureFilters
150 {
151         /* we use a popup to show the deinterlace settings */
152         [fDeinterlacePopUp removeAllItems];
153     [fDeinterlacePopUp addItemWithTitle: @"None"];
154     [fDeinterlacePopUp addItemWithTitle: @"Fast"];
155     [fDeinterlacePopUp addItemWithTitle: @"Slow"];
156         [fDeinterlacePopUp addItemWithTitle: @"Slower"];
157         [fDeinterlacePopUp addItemWithTitle: @"Slowest"];
158     
159         /* Set deinterlaces level according to the integer in the main window */
160         [fDeinterlacePopUp selectItemAtIndex: fPictureFilterSettings.deinterlace];
161
162         /* we use a popup to show the denoise settings */
163         [fDenoisePopUp removeAllItems];
164     [fDenoisePopUp addItemWithTitle: @"None"];
165     [fDenoisePopUp addItemWithTitle: @"Weak"];
166         [fDenoisePopUp addItemWithTitle: @"Medium"];
167     [fDenoisePopUp addItemWithTitle: @"Strong"];
168         /* Set denoises level according to the integer in the main window */
169         [fDenoisePopUp selectItemAtIndex: fPictureFilterSettings.denoise];
170
171 }
172 - (void) Display: (int) anim
173 {
174     hb_get_preview( fHandle, fTitle, fPicture, fBuffer );
175     
176     /* Backup previous picture (for effects) */
177     memcpy( fTexBuf[1], fTexBuf[0], fTexBufSize );
178     
179     if( fHasQE )
180     {
181         /* Simply copy */
182         memcpy( fTexBuf[0], fBuffer, fTexBufSize );
183     }
184     else
185     {
186         /* Copy line by line */
187         uint8_t * in  = fBuffer;
188         uint8_t * out = fTexBuf[0];
189                 
190         for( int i = fTitle->height + 2; i--; )
191         {
192             memcpy( out, in, 4 * ( fTitle->width + 2 ) );
193             in  += 4 * ( fTitle->width + 2 );
194             out += 4 * GetAlignedSize( fTitle->width + 2 );
195         }
196         
197     }
198     
199     if( [fEffectsCheck state] == NSOffState )
200     {
201         anim = HB_ANIMATE_NONE;
202     }
203     else if( [[NSApp currentEvent] modifierFlags] & NSShiftKeyMask )
204     {
205         anim |= HB_ANIMATE_SLOW;
206     }
207     
208     [fPictureGLView Display: anim buffer1: fTexBuf[0]
209                     buffer2: fTexBuf[1] width: ( fTitle->width + 2 )
210                      height: ( fTitle->height + 2 )];
211         
212         NSSize displaySize = NSMakeSize( (float)fTitle->width, (float)fTitle->height );
213     /* Set the picture size display fields below the Preview Picture*/
214     if( fTitle->job->pixel_ratio == 1 ) // Original PAR Implementation
215     {
216         output_width = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3];
217         output_height = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1];
218         display_width = output_width * fTitle->job->pixel_aspect_width / fTitle->job->pixel_aspect_height;
219         [fInfoField setStringValue:[NSString stringWithFormat:
220                                     @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d",
221                                     fTitle->width, fTitle->height, output_width, output_height, display_width, output_height]];
222         displaySize.width *= ((float)fTitle->job->pixel_aspect_width) / ((float)fTitle->job->pixel_aspect_height);   
223     }
224     else if (fTitle->job->pixel_ratio == 2) // Loose Anamorphic
225     {
226         display_width = output_width * output_par_width / output_par_height;
227         [fInfoField setStringValue:[NSString stringWithFormat:
228                                     @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d",
229                                     fTitle->width, fTitle->height, output_width, output_height, display_width, output_height]];
230         
231         /* FIXME: needs to be fixed so that the picture window does not resize itself on the first
232          anamorphic width drop
233          */
234         if (fTitle->width - 8 < output_width)
235         {
236             displaySize.width *= ((float)output_par_width) / ((float)output_par_height);
237         }
238     }
239     else // No Anamorphic
240     {
241         [fInfoField setStringValue: [NSString stringWithFormat:
242                                      @"Source: %dx%d, Output: %dx%d", fTitle->width, fTitle->height,
243                                      fTitle->job->width, fTitle->job->height]];
244     }
245     
246     NSSize viewSize = [self optimalViewSizeForImageSize:displaySize];
247     if( [self viewNeedsToResizeToSize:viewSize] )
248     {
249         [self resizeSheetForViewSize:viewSize];
250         [self setViewSize:viewSize];
251     }
252     
253     // Show the scaled text (use the height to check since the width can vary
254     // with anamorphic video).
255     if( ((int)viewSize.height) != fTitle->height )
256     {
257         float scale = viewSize.width / ((float)fTitle->width);
258         NSString *scaleString = [NSString stringWithFormat:
259                                  NSLocalizedString( @" (Preview scaled to %.0f%% actual size)",
260                                                    @"String shown when a preview is scaled" ),
261                                  scale * 100.0];
262         [fInfoField setStringValue:
263          [[fInfoField stringValue] stringByAppendingString:scaleString]];
264     }
265     
266     [fPrevButton setEnabled: ( fPicture > 0 )];
267     [fNextButton setEnabled: ( fPicture < 9 )];
268 }
269
270 - (IBAction) SettingsChanged: (id) sender
271 {
272     hb_job_t * job = fTitle->job;
273     
274         if( [fAnamorphicPopUp indexOfSelectedItem] > 0 )
275         {
276         if ([fAnamorphicPopUp indexOfSelectedItem] == 2) // Loose anamorphic
277         {
278             job->pixel_ratio = 2;
279             [fWidthStepper setEnabled: YES];
280             [fWidthField setEnabled: YES];
281             /* We set job->width and call hb_set_anamorphic_size in libhb to do a "dry run" to get
282              * the values to be used by libhb for loose anamorphic
283              */
284             job->width       = [fWidthStepper  intValue];
285             hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height);
286             [fHeightStepper      setIntValue: output_height];
287             [fHeightField        setIntValue: output_height];
288             job->height      = [fHeightStepper intValue];
289             
290         }
291         else // must be "1" or strict anamorphic
292         {
293             [fWidthStepper      setIntValue: fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]];
294             [fWidthField        setIntValue: fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]];
295             
296             /* This will show correct anamorphic height values, but
297              show distorted preview picture ratio */
298             [fHeightStepper      setIntValue: fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1]];
299             [fHeightField        setIntValue: fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1]];
300             job->width       = [fWidthStepper  intValue];
301             job->height      = [fHeightStepper intValue];
302             
303             job->pixel_ratio = 1;
304             [fWidthStepper setEnabled: NO];
305             [fWidthField setEnabled: NO];
306         }
307         
308         /* if the sender is the Anamorphic checkbox, record the state
309          of KeepAspect Ratio so it can be reset if Anamorphic is unchecked again */
310         if (sender == fAnamorphicPopUp)
311         {
312             keepAspectRatioPreviousState = [fRatioCheck state];
313         }
314         [fRatioCheck setState:NSOffState];
315         [fRatioCheck setEnabled: NO];
316         
317         
318         [fHeightStepper setEnabled: NO];
319         [fHeightField setEnabled: NO];
320         
321     }
322     else
323         {
324         job->width       = [fWidthStepper  intValue];
325         job->height      = [fHeightStepper intValue];
326         job->pixel_ratio = 0;
327         [fWidthStepper setEnabled: YES];
328         [fWidthField setEnabled: YES];
329         [fHeightStepper setEnabled: YES];
330         [fHeightField setEnabled: YES];
331         [fRatioCheck setEnabled: YES];
332         /* if the sender is the Anamorphic checkbox, we return the
333          keep AR checkbox to its previous state */
334         if (sender == fAnamorphicPopUp)
335         {
336             [fRatioCheck setState:keepAspectRatioPreviousState];
337         }
338         
339         }
340         
341     
342     job->keep_ratio  = ( [fRatioCheck state] == NSOnState );
343     
344         fPictureFilterSettings.deinterlace = [fDeinterlacePopUp indexOfSelectedItem];
345     /* if the gui deinterlace settings are fast through slowest, the job->deinterlace
346      value needs to be set to one, for the job as well as the previews showing deinterlacing
347      otherwise set job->deinterlace to 0 or "off" */
348     if (fPictureFilterSettings.deinterlace > 0)
349     {
350         job->deinterlace  = 1;
351     }
352     else
353     {
354         job->deinterlace  = 0;
355     }
356     fPictureFilterSettings.denoise     = [fDenoisePopUp indexOfSelectedItem];
357     fPictureFilterSettings.vfr  = [fVFRCheck state];
358     if (fPictureFilterSettings.vfr > 0)
359     {
360         [fDetelecineCheck setState:NSOnState];
361         [fDetelecineCheck setEnabled: NO];
362     }
363     else
364     {
365         [fDetelecineCheck setEnabled: YES];
366     }
367     fPictureFilterSettings.detelecine  = [fDetelecineCheck state];
368     fPictureFilterSettings.deblock  = [fDeblockCheck state];
369         //job->pixel_ratio = ( [fPARCheck state] == NSOnState );
370     
371     autoCrop = ( [fCropMatrix selectedRow] == 0 );
372     [fCropTopStepper    setEnabled: !autoCrop];
373     [fCropBottomStepper setEnabled: !autoCrop];
374     [fCropLeftStepper   setEnabled: !autoCrop];
375     [fCropRightStepper  setEnabled: !autoCrop];
376     
377     if( autoCrop )
378     {
379         memcpy( job->crop, fTitle->crop, 4 * sizeof( int ) );
380     }
381     else
382     {
383         job->crop[0] = [fCropTopStepper    intValue];
384         job->crop[1] = [fCropBottomStepper intValue];
385         job->crop[2] = [fCropLeftStepper   intValue];
386         job->crop[3] = [fCropRightStepper  intValue];
387     }
388     
389     if( job->keep_ratio )
390     {
391         if( sender == fWidthStepper || sender == fRatioCheck ||
392            sender == fCropTopStepper || sender == fCropBottomStepper )
393         {
394             hb_fix_aspect( job, HB_KEEP_WIDTH );
395             if( job->height > fTitle->height )
396             {
397                 job->height = fTitle->height;
398                 hb_fix_aspect( job, HB_KEEP_HEIGHT );
399             }
400         }
401         else
402         {
403             hb_fix_aspect( job, HB_KEEP_HEIGHT );
404             if( job->width > fTitle->width )
405             {
406                 job->width = fTitle->width;
407                 hb_fix_aspect( job, HB_KEEP_WIDTH );
408             }
409         }
410     }
411     
412     [fWidthStepper      setIntValue: job->width];
413     [fWidthField        setIntValue: job->width];
414     if( [fAnamorphicPopUp indexOfSelectedItem] < 2 )
415         {
416         [fHeightStepper     setIntValue: job->height];
417         [fHeightField       setIntValue: job->height];
418     }
419     [fCropTopStepper    setIntValue: job->crop[0]];
420     [fCropTopField      setIntValue: job->crop[0]];
421     [fCropBottomStepper setIntValue: job->crop[1]];
422     [fCropBottomField   setIntValue: job->crop[1]];
423     [fCropLeftStepper   setIntValue: job->crop[2]];
424     [fCropLeftField     setIntValue: job->crop[2]];
425     [fCropRightStepper  setIntValue: job->crop[3]];
426     [fCropRightField    setIntValue: job->crop[3]];
427     /* Sanity Check Here for < 16 px preview to avoid
428      crashing hb_get_preview. In fact, just for kicks
429      lets getting previews at a min limit of 32, since
430      no human can see any meaningful detail below that */
431     if (job->width >= 64 && job->height >= 64)
432     {
433         [self Display: HB_ANIMATE_NONE];
434     }
435 }
436
437 - (IBAction) PreviousPicture: (id) sender
438 {   
439     if( fPicture <= 0 )
440     {
441         return;
442     }
443     fPicture--;
444     [self Display: HB_ANIMATE_BACKWARD];
445 }
446
447 - (IBAction) NextPicture: (id) sender
448 {
449     if( fPicture >= 9 )
450     {
451         return;
452     }
453     fPicture++;
454     [self Display: HB_ANIMATE_FORWARD];
455 }
456
457 - (IBAction) ClosePanel: (id) sender
458 {
459     if ([delegate respondsToSelector:@selector(pictureSettingsDidChange)])
460         [delegate pictureSettingsDidChange];
461         
462     [NSApp endSheet: fPicturePanel];
463     [fPicturePanel orderOut: self];
464 }
465
466 - (BOOL) autoCrop
467 {
468     return autoCrop;
469 }
470 - (void) setAutoCrop: (BOOL) setting
471 {
472     autoCrop = setting;
473 }
474
475 - (BOOL) allowLooseAnamorphic
476 {
477     return allowLooseAnamorphic;
478 }
479
480 - (void) setAllowLooseAnamorphic: (BOOL) setting
481 {
482     allowLooseAnamorphic = setting;
483 }
484
485 - (int) detelecine
486 {
487     return fPictureFilterSettings.detelecine;
488 }
489
490 - (void) setDetelecine: (int) setting
491 {
492     fPictureFilterSettings.detelecine = setting;
493 }
494
495 - (int) vfr
496 {
497     return fPictureFilterSettings.vfr;
498 }
499
500 - (void) setVFR: (int) setting
501 {
502     fPictureFilterSettings.vfr = setting;
503 }
504
505 - (int) deinterlace
506 {
507     return fPictureFilterSettings.deinterlace;
508 }
509
510 - (void) setDeinterlace: (int) setting {
511     fPictureFilterSettings.deinterlace = setting;
512 }
513
514 - (int) denoise
515 {
516     return fPictureFilterSettings.denoise;
517 }
518
519 - (void) setDenoise: (int) setting
520 {
521     fPictureFilterSettings.denoise = setting;
522 }
523
524 - (int) deblock
525 {
526     return fPictureFilterSettings.deblock;
527 }
528
529 - (void) setDeblock: (int) setting
530 {
531     fPictureFilterSettings.deblock = setting;
532 }
533
534 - (void)showPanelInWindow: (NSWindow *)fWindow forTitle: (hb_title_t *)title
535 {
536     [self SetTitle:title];
537     
538     [NSApp beginSheet:fPicturePanel
539        modalForWindow:fWindow
540         modalDelegate:nil
541        didEndSelector:nil
542           contextInfo:NULL];
543 }
544
545 - (BOOL) loadMyNibFile
546 {
547     if(![NSBundle loadNibNamed:@"PictureSettings" owner:self])
548     {
549         NSLog(@"Warning! Could not load myNib file.\n");
550         return NO;
551     }
552     
553     return YES;
554 }
555
556 @end
557
558 @implementation PictureController (Private)
559
560 //
561 // -[PictureController(Private) optimalViewSizeForImageSize:]
562 //
563 // Given the size of the preview image to be shown, returns the best possible
564 // size for the OpenGL view.
565 //
566 - (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize
567 {
568     // The min size is 320x240
569     float minWidth = 320.0;
570     float minHeight = 240.0;
571     
572     // The max size of the view is when the sheet is taking up 85% of the screen.
573     NSSize screenSize = [[NSScreen mainScreen] frame].size;
574     NSSize sheetSize = [fPicturePanel frame].size;
575     NSSize viewAreaSize = [fPictureGLViewArea frame].size;
576     float paddingX = sheetSize.width - viewAreaSize.width;
577     float paddingY = sheetSize.height - viewAreaSize.height;
578     float maxWidth = (0.85 * screenSize.width) - paddingX;
579     float maxHeight = (0.85 * screenSize.height) - paddingY;
580     
581     NSSize resultSize = imageSize;
582     
583     // Its better to have a view that's too small than a view that's too big, so
584     // apply the maximum constraints last.
585     if( resultSize.width < minWidth )
586     {
587         resultSize.height *= (minWidth / resultSize.width);
588         resultSize.width = minWidth;
589     }
590     if( resultSize.height < minHeight )
591     {
592         resultSize.width *= (minHeight / resultSize.height);
593         resultSize.height = minHeight;
594     }
595     if( resultSize.width > maxWidth )
596     {
597         resultSize.height *= (maxWidth / resultSize.width);
598         resultSize.width = maxWidth;
599     }
600     if( resultSize.height > maxHeight )
601     {
602         resultSize.width *= (maxHeight / resultSize.height);
603         resultSize.height = maxHeight;
604     }
605     
606     return resultSize;
607 }
608
609 //
610 // -[PictureController(Private) resizePanelForViewSize:animate:]
611 //
612 // Resizes the entire sheet to accomodate an OpenGL view of a particular size.
613 //
614 - (void)resizeSheetForViewSize: (NSSize)viewSize
615 {
616     // Figure out the deltas for the new frame area
617     NSSize currentSize = [fPictureGLViewArea frame].size;
618     float deltaX = viewSize.width - currentSize.width;
619     float deltaY = viewSize.height - currentSize.height;
620     
621     // Now resize the whole panel by those same deltas, but don't exceed the min
622     NSRect frame = [fPicturePanel frame];
623     NSSize maxSize = [fPicturePanel maxSize];
624     NSSize minSize = [fPicturePanel minSize];
625     frame.size.width += deltaX;
626     frame.size.height += deltaY;
627     if( frame.size.width < minSize.width )
628     {
629         frame.size.width = minSize.width;
630     }
631     if( frame.size.height < minSize.height )
632     {
633         frame.size.height = minSize.height;
634     }
635
636     // But now the sheet is off-center, so also shift the origin to center it and
637     // keep the top aligned.
638     frame.origin.x -= (deltaX / 2.0);
639     frame.origin.y -= deltaY;
640
641     [fPicturePanel setFrame:frame display:YES animate:YES];
642 }
643
644 //
645 // -[PictureController(Private) setViewSize:]
646 //
647 // Changes the OpenGL view's size and centers it vertially inside of its area.
648 // Assumes resizeSheetForViewSize: has already been called.
649 //
650 - (void)setViewSize: (NSSize)viewSize
651 {
652     [fPictureGLView setFrameSize:viewSize];
653     
654     // center it vertically
655     NSPoint origin = [fPictureGLViewArea frame].origin;
656     origin.y += ([fPictureGLViewArea frame].size.height -
657                  [fPictureGLView frame].size.height) / 2.0;
658     [fPictureGLView setFrameOrigin:origin];
659 }
660
661 //
662 // -[PictureController(Private) viewNeedsToResizeToSize:]
663 //
664 // Returns YES if the view will need to resize to match the given size.
665 //
666 - (BOOL)viewNeedsToResizeToSize: (NSSize)newSize
667 {
668     NSSize viewSize = [fPictureGLView frame].size;
669     return (newSize.width != viewSize.width || newSize.height != viewSize.height);
670 }
671
672
673 @end