diff options
author | dynaflash <[email protected]> | 2009-01-12 00:07:38 +0000 |
---|---|---|
committer | dynaflash <[email protected]> | 2009-01-12 00:07:38 +0000 |
commit | 7e73b3884143ae1fb8c8cd9a384c1ef959fa0a86 (patch) | |
tree | 3921b193dd1dbf5aafbe206d525ad4d40bf702fb /macosx/PictureController.mm | |
parent | f2bd5d8c9da510bfc2969d0cf23a68196d61faa5 (diff) |
MacGui: Separate Picture Settings and Preview Window Initial Implementation
- Picture Settings is now a hud style inspector panel:
-- Allows more room to be displayed along with Main Window.
-- Has button (though ugly ... for now) to open the preview window.
- Separate Preview Window:
-- Preview Window can now show the entire preview content via a hud style overlay controller (ala iTunes, DvdPlayer controls) activated by mouse movement.
-- Has button to allow opening the Picture Settings inspector.
-- Full Screen Mode (ala iTunes, DvdPlayer) which should help for max preview size for HD sources.
- Note: all hud style controls in this implementation are created only using core animation filters, I decided against a third party hud control framework, though one can certainly be implemented at any time.
- Known Issues:
-- WARNING: Quitting HB while in full screen mode will crash the macgui.
-- The hud overlay controls in the Preview Window will align kind of wonky when the resolution is scaled way below the source.
-- Ideally, after moving the mouse within the preview area then stopping, after a certain amount of time the hud overlay control box should disappear.
-- Hud style controls still need alot of development to fit within the HIG.
-- Need a keboard shortcut for the Preview Window.
-- As usual with initial implementations there are likely many more Bugs/Issues.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2076 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'macosx/PictureController.mm')
-rw-r--r-- | macosx/PictureController.mm | 804 |
1 files changed, 44 insertions, 760 deletions
diff --git a/macosx/PictureController.mm b/macosx/PictureController.mm index 8d61f562e..df70de657 100644 --- a/macosx/PictureController.mm +++ b/macosx/PictureController.mm @@ -6,15 +6,9 @@ #import "PictureController.h" #import "Controller.h" +#import "HBPreviewController.h" -@interface PictureController (Private) -- (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize; -- (void)resizeSheetForViewSize: (NSSize)viewSize; -- (void)setViewSize: (NSSize)viewSize; -- (BOOL)viewNeedsToResizeToSize: (NSSize)newSize; - -@end @implementation PictureController @@ -32,11 +26,8 @@ // go away. [self window]; - fPicturePreviews = [[NSMutableDictionary dictionaryWithCapacity: HB_NUM_HBLIB_PICTURES] retain]; - /* Init libhb with check for updates libhb style set to "0" so its ignored and lets sparkle take care of it */ - int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue]; - fPreviewLibhb = hb_init(loggingLevel, 0); - } + fPreviewController = [[PreviewController alloc] init]; + } return self; } @@ -48,9 +39,35 @@ [self showWindow:sender]; } +- (IBAction) showPreviewWindow: (id)sender +{ + [fPreviewController showWindow:sender]; +} + +- (void) setToFullScreenMode +{ + [self showWindow:nil]; + int32_t shieldLevel = CGShieldingWindowLevel(); + + [fPictureWindow setLevel:shieldLevel]; + // Show the window. + [fPictureWindow makeKeyAndOrderFront:self]; +} + +- (void) setToWindowedMode +{ + /* Set the window back to regular level */ + + [self showWindow:nil]; + + [[self window] setLevel:NSNormalWindowLevel]; +} + - (void)setHBController: (HBController *)controller { fHBController = controller; + [fPreviewController setHBController: controller]; + } - (void)awakeFromNib @@ -61,12 +78,7 @@ - (void)windowWillClose:(NSNotification *)aNotification { - /* Upon Closing the picture window, we make sure we clean up any - * preview movie that might be playing - */ - play_movie = NO; - hb_stop( fPreviewLibhb ); - [self pictureSliderChanged:nil]; + } - (BOOL)windowShouldClose:(id)fPictureWindow @@ -76,17 +88,7 @@ - (void) dealloc { - hb_stop(fPreviewLibhb); - if (fPreviewMoviePath) - { - [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath handler:nil]; - [fPreviewMoviePath release]; - } - - [fLibhbTimer invalidate]; - [fLibhbTimer release]; - - [fPicturePreviews release]; + [fPreviewController release]; [super dealloc]; } @@ -110,36 +112,9 @@ [fCropRightStepper setIncrement: 2]; [fCropRightStepper setMinValue: 0]; - /* we set the preview length popup in seconds */ - [fPreviewMovieLengthPopUp removeAllItems]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"5"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"10"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"15"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"20"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"25"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"30"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"35"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"40"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"45"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"50"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"55"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"60"]; - - /* adjust the preview slider length */ - /* We use our advance pref to determine how many previews we scanned */ - int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; - [fPictureSlider setMaxValue: hb_num_previews - 1.0]; - [fPictureSlider setNumberOfTickMarks: hb_num_previews]; + [fPreviewController SetHandle: fHandle]; - if ([[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"]) - { - [fPreviewMovieLengthPopUp selectItemWithTitle:[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"]]; - } - else - { - /* currently hard set default to 10 seconds */ - [fPreviewMovieLengthPopUp selectItemAtIndex: 1]; - } + } - (void) SetTitle: (hb_title_t *) title @@ -147,7 +122,9 @@ hb_job_t * job = title->job; fTitle = title; - + + + [fWidthStepper setMaxValue: title->width]; [fWidthStepper setIntValue: job->width]; [fWidthField setIntValue: job->width]; @@ -200,6 +177,9 @@ fPicture = 0; MaxOutputWidth = title->width - job->crop[2] - job->crop[3]; MaxOutputHeight = title->height - job->crop[0] - job->crop[1]; + + //[fPreviewController SetTitle:fTitle]; + [self SettingsChanged: nil]; } @@ -229,82 +209,6 @@ are maintained across different sources */ } -// Adjusts the window to draw the current picture (fPicture) adjusting its size as -// necessary to display as much of the picture as possible. -- (void) displayPreview -{ - - /* lets make sure that the still picture view is not hidden and that - * the movie preview is - */ - [fMovieView pause:nil]; - [fMovieView setHidden:YES]; - [fMovieCreationProgressIndicator stopAnimation: nil]; - [fMovieCreationProgressIndicator setHidden: YES]; - - [fPictureView setHidden:NO]; - - [fPictureView setImage: [self imageForPicture: fPicture]]; - - NSSize displaySize = NSMakeSize( ( CGFloat )fTitle->width, ( CGFloat )fTitle->height ); - /* Set the picture size display fields below the Preview Picture*/ - if( fTitle->job->pixel_ratio == 1 ) // Original PAR Implementation - { - output_width = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]; - output_height = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1]; - display_width = output_width * fTitle->job->pixel_aspect_width / fTitle->job->pixel_aspect_height; - [fInfoField setStringValue:[NSString stringWithFormat: - @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d", - fTitle->width, fTitle->height, output_width, output_height, display_width, output_height]]; - displaySize.width *= ( ( CGFloat )fTitle->job->pixel_aspect_width ) / ( ( CGFloat )fTitle->job->pixel_aspect_height ); - } - else if (fTitle->job->pixel_ratio == 2) // Loose Anamorphic - { - display_width = output_width * output_par_width / output_par_height; - [fInfoField setStringValue:[NSString stringWithFormat: - @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d", - fTitle->width, fTitle->height, output_width, output_height, display_width, output_height]]; - - displaySize.width = display_width; - } - else // No Anamorphic - { - [fInfoField setStringValue: [NSString stringWithFormat: - @"Source: %dx%d, Output: %dx%d", fTitle->width, fTitle->height, - fTitle->job->width, fTitle->job->height]]; - } - - NSSize viewSize = [self optimalViewSizeForImageSize:displaySize]; - if( [self viewNeedsToResizeToSize:viewSize] ) - { - /* In the case of loose anamorphic, do not resize the window when scaling down */ - if (fTitle->job->pixel_ratio != 2 || [fWidthField intValue] == fTitle->width) - { - [self resizeSheetForViewSize:viewSize]; - [self setViewSize:viewSize]; - } - } - - // Show the scaled text (use the height to check since the width can vary - // with anamorphic video). - if( ( ( int )viewSize.height ) != fTitle->height ) - { - CGFloat scale = viewSize.width / ( ( CGFloat ) fTitle->width ); - NSString *scaleString = [NSString stringWithFormat: - NSLocalizedString( @" (Preview scaled to %.0f%% actual size)", - @"String shown when a preview is scaled" ), - scale * 100.0]; - [fInfoField setStringValue: [[fInfoField stringValue] stringByAppendingString:scaleString]]; - } - -} - -- (IBAction) previewDurationPopUpChanged: (id) sender -{ - -[[NSUserDefaults standardUserDefaults] setObject:[fPreviewMovieLengthPopUp titleOfSelectedItem] forKey:@"PreviewLength"]; - -} @@ -492,6 +396,8 @@ are maintained across different sources */ [fCropLeftField setIntValue: job->crop[2]]; [fCropRightStepper setIntValue: job->crop[3]]; [fCropRightField setIntValue: job->crop[3]]; + + [fPreviewController SetTitle:fTitle]; /* Sanity Check Here for < 16 px preview to avoid crashing hb_get_preview. In fact, just for kicks lets getting previews at a min limit of 32, since @@ -501,12 +407,12 @@ are maintained across different sources */ // Purge the existing picture previews so they get recreated the next time // they are needed. - [self purgeImageCache]; + [fPreviewController purgeImageCache]; /* We actually call displayPreview now from pictureSliderChanged which keeps * our picture preview slider in sync with the previews being shown */ - //[self displayPreview]; - [self pictureSliderChanged:nil]; + + [fPreviewController pictureSliderChanged:nil]; } @@ -517,334 +423,7 @@ are maintained across different sources */ } -- (IBAction) pictureSliderChanged: (id) sender -{ - // Show the picture view - [fCreatePreviewMovieButton setTitle: @"Live Preview"]; - [fPictureView setHidden:NO]; - [fMovieView pause:nil]; - [fMovieView setHidden:YES]; - [fPreviewMovieStatusField setHidden: YES]; - - int newPicture = [fPictureSlider intValue]; - if (newPicture != fPicture) - { - fPicture = newPicture; - } - [self displayPreview]; - -} - -#pragma mark Movie Preview -- (IBAction) createMoviePreview: (id) sender -{ - - - /* Lets make sure the still picture previews are showing in case - * there is currently a movie showing */ - [self pictureSliderChanged:nil]; - - /* Rip or Cancel ? */ - hb_state_t s; - hb_get_state2( fPreviewLibhb, &s ); - - if(s.state == HB_STATE_WORKING || s.state == HB_STATE_PAUSED) - { - - play_movie = NO; - hb_stop( fPreviewLibhb ); - [fPictureView setHidden:NO]; - [fMovieView pause:nil]; - [fMovieView setHidden:YES]; - [fPictureSlider setHidden:NO]; - [fCreatePreviewMovieButton setTitle: @"Live Preview"]; - return; - } - - - /* we use controller.mm's prepareJobForPreview to go ahead and set all of our settings - * however, we want to use a temporary destination field of course - * so that we do not put our temp preview in the users chosen - * directory */ - - hb_job_t * job = fTitle->job; - - /* We run our current setting through prepeareJob in Controller.mm - * just as if it were a regular encode */ - - [fHBController prepareJobForPreview]; - - /* Destination file. We set this to our preview directory - * changing the extension appropriately.*/ - if (fTitle->job->mux == HB_MUX_MP4) // MP4 file - { - /* we use .m4v for our mp4 files so that ac3 and chapters in mp4 will play properly */ - fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.m4v"; - } - else if (fTitle->job->mux == HB_MUX_MKV) // MKV file - { - fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.mkv"; - } - else if (fTitle->job->mux == HB_MUX_AVI) // AVI file - { - fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.avi"; - } - else if (fTitle->job->mux == HB_MUX_OGM) // OGM file - { - fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.ogm"; - } - - fPreviewMoviePath = [[fPreviewMoviePath stringByExpandingTildeInPath]retain]; - - /* See if there is an existing preview file, if so, delete it */ - if( ![[NSFileManager defaultManager] fileExistsAtPath:fPreviewMoviePath] ) - { - [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath - handler:nil]; - } - - /* We now direct our preview encode to fPreviewMoviePath */ - fTitle->job->file = [fPreviewMoviePath UTF8String]; - - /* We use our advance pref to determine how many previews to scan */ - int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; - job->start_at_preview = fPicture + 1; - job->seek_points = hb_num_previews; - - /* we use the preview duration popup to get the specified - * number of seconds for the preview encode. - */ - - job->pts_to_stop = [[fPreviewMovieLengthPopUp titleOfSelectedItem] intValue] * 90000LL; - - /* lets go ahead and send it off to libhb - * Note: unlike a full encode, we only send 1 pass regardless if the final encode calls for 2 passes. - * this should suffice for a fairly accurate short preview and cuts our preview generation time in half. - */ - hb_add( fPreviewLibhb, job ); - - [fPictureSlider setHidden:YES]; - [fMovieCreationProgressIndicator setHidden: NO]; - [fPreviewMovieStatusField setHidden: NO]; - [self startReceivingLibhbNotifications]; - - - [fCreatePreviewMovieButton setTitle: @"Cancel Preview"]; - - play_movie = YES; - - /* Let fPreviewLibhb do the job */ - hb_start( fPreviewLibhb ); - -} -- (void) startReceivingLibhbNotifications -{ - if (!fLibhbTimer) - { - fLibhbTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(libhbTimerFired:) userInfo:nil repeats:YES]; - [fLibhbTimer retain]; - } -} - -- (void) stopReceivingLibhbNotifications -{ - if (fLibhbTimer) - { - [fLibhbTimer invalidate]; - [fLibhbTimer release]; - fLibhbTimer = nil; - } -} -- (void) libhbTimerFired: (NSTimer*)theTimer -{ - hb_state_t s; - hb_get_state( fPreviewLibhb, &s ); - [self libhbStateChanged: s]; -} -- (void) libhbStateChanged: (hb_state_t &)state -{ - switch( state.state ) - { - case HB_STATE_IDLE: - case HB_STATE_SCANNING: - case HB_STATE_SCANDONE: - break; - - case HB_STATE_WORKING: - { -#define p state.param.working - - NSMutableString * string; - /* Update text field */ - string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding %d seconds of preview %d: %.2f %%", @"" ), [[fPreviewMovieLengthPopUp titleOfSelectedItem] intValue], fPicture + 1, 100.0 * p.progress]; - - if( p.seconds > -1 ) - { - [string appendFormat: - NSLocalizedString( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @"" ), - p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds]; - } - [fPreviewMovieStatusField setStringValue: string]; - - [fMovieCreationProgressIndicator setIndeterminate: NO]; - /* Update slider */ - [fMovieCreationProgressIndicator setDoubleValue: 100.0 * p.progress]; - - [fCreatePreviewMovieButton setTitle: @"Cancel Preview"]; - - break; - - } -#undef p - -#define p state.param.muxing - case HB_STATE_MUXING: - { - // Update fMovieCreationProgressIndicator - [fMovieCreationProgressIndicator setIndeterminate: YES]; - [fMovieCreationProgressIndicator startAnimation: nil]; - [fPreviewMovieStatusField setStringValue: [NSString stringWithFormat: - NSLocalizedString( @"Muxing Preview ...", @"" )]]; - break; - } -#undef p - case HB_STATE_PAUSED: - [fMovieCreationProgressIndicator stopAnimation: nil]; - break; - - case HB_STATE_WORKDONE: - { - // Delete all remaining jobs since libhb doesn't do this on its own. - hb_job_t * job; - while( ( job = hb_job(fPreviewLibhb, 0) ) ) - hb_rem( fHandle, job ); - - [self stopReceivingLibhbNotifications]; - [fPreviewMovieStatusField setStringValue: @""]; - [fPreviewMovieStatusField setHidden: YES]; - - [fMovieCreationProgressIndicator stopAnimation: nil]; - [fMovieCreationProgressIndicator setHidden: YES]; - /* we make sure the picture slider and preview match */ - [self pictureSliderChanged:nil]; - [fPictureSlider setHidden:NO]; - - // Show the movie view - if (play_movie) - { - [self showMoviePreview:fPreviewMoviePath]; - } - - [fCreatePreviewMovieButton setTitle: @"Live Preview"]; - - - break; - } - } - -} - -- (IBAction) showMoviePreview: (NSString *) path -{ - /* Since the gray background for the still images is part of - * fPictureView, lets leave the picture view visible and postion - * the fMovieView over the image portion of fPictureView so - * we retain the gray cropping border we have already established - * with the still previews - */ - [fMovieView setHidden:NO]; - - /* Load the new movie into fMovieView */ - QTMovie * aMovie; - NSRect movieBounds; - if (path) - { - [fMovieView setControllerVisible: YES]; - /* let's make sure there is no movie currently set */ - [fMovieView setMovie:nil]; - - aMovie = [QTMovie movieWithFile:path error:nil]; - - /* we get some size information from the preview movie */ - Rect movieBox; - GetMovieBox ([aMovie quickTimeMovie], &movieBox); - movieBounds = [fMovieView movieBounds]; - movieBounds.size.height = movieBox.bottom - movieBox.top; - - if ([fMovieView isControllerVisible]) - movieBounds.size.height += [fMovieView controllerBarHeight]; - /* since for whatever the reason I cannot seem to get the [fMovieView controllerBarHeight] - * For now just use 15 for additional height as it seems to line up well - */ - movieBounds.size.height += 15; - - movieBounds.size.width = movieBox.right - movieBox.left; - - /* We need to find out if the preview movie needs to be scaled down so - * that it doesn't overflow our available viewing container (just like for image - * in -displayPreview) for HD sources, etc. [fPictureViewArea frame].size.height*/ - if( ((int)movieBounds.size.height) > [fPictureView frame].size.height ) - { - /* The preview movie would be larger than the available viewing area - * in the preview movie, so we go ahead and scale it down to the same size - * as the still preview or we readjust our window to allow for the added height if need be - */ - NSSize displaySize = NSMakeSize( (float)movieBounds.size.width, (float)movieBounds.size.height ); - //NSSize displaySize = NSMakeSize( (float)fTitle->width, (float)fTitle->height ); - NSSize viewSize = [self optimalViewSizeForImageSize:displaySize]; - if( [self viewNeedsToResizeToSize:viewSize] ) - { - - [self resizeSheetForViewSize:viewSize]; - [self setViewSize:viewSize]; - - } - - [fMovieView setFrameSize:viewSize]; - } - else - { - /* Since the preview movie is smaller than the available viewing area - * we can go ahead and use the preview movies native size */ - [fMovieView setFrameSize:movieBounds.size]; - } - - // lets reposition the movie if need be - - NSPoint origin = [fPictureViewArea frame].origin; - origin.x += trunc(([fPictureViewArea frame].size.width - - [fMovieView frame].size.width) / 2.0); - /* We need to detect whether or not we are currently less than the available height.*/ - if (movieBounds.size.height < [fPictureView frame].size.height) - { - /* If we are, we are adding 15 to the height to allow for the controller bar so - * we need to subtract half of that for the origin.y to get the controller bar - * below the movie to it lines up vertically with where our still preview was - */ - origin.y += trunc((([fPictureViewArea frame].size.height - - [fMovieView frame].size.height) / 2.0) - 7.5); - } - else - { - /* if we are >= to the height of the picture view area, the controller bar - * gets taken care of with picture resizing, so we do not want to offset the height - */ - origin.y += trunc(([fPictureViewArea frame].size.height - - [fMovieView frame].size.height) / 2.0); - } - [fMovieView setFrameOrigin:origin]; - - [fMovieView setMovie:aMovie]; - /// to actually play the movie - [fMovieView play:aMovie]; - } - else - { - aMovie = nil; - } - -} #pragma mark - @@ -920,300 +499,5 @@ are maintained across different sources */ } - -// This function converts an image created by libhb (specified via pictureIndex) into -// an NSImage suitable for the GUI code to use. If removeBorders is YES, -// makeImageForPicture crops the image generated by libhb stripping off the gray -// border around the content. This is the low-level method that generates the image. -// -imageForPicture calls this function whenever it can't find an image in its cache. -+ (NSImage *) makeImageForPicture: (int)pictureIndex - libhb:(hb_handle_t*)handle - title:(hb_title_t*)title - removeBorders:(BOOL)removeBorders -{ - if (removeBorders) - { - // |<---------- title->width ----------->| - // | |<---- title->job->width ---->| | - // | | | | - // ....................................... - // ....+-----------------------------+.... - // ....| |....<-- gray border - // ....| |.... - // ....| |.... - // ....| |<------- image - // ....| |.... - // ....| |.... - // ....| |.... - // ....| |.... - // ....| |.... - // ....+-----------------------------+.... - // ....................................... - - static uint8_t * buffer; - static int bufferSize; - - // Make sure we have a big enough buffer to receive the image from libhb. libhb - // creates images with a one-pixel border around the original content. Hence we - // add 2 pixels horizontally and vertically to the buffer size. - int srcWidth = title->width + 2; - int srcHeight= title->height + 2; - int newSize; - newSize = srcWidth * srcHeight * 4; - if( bufferSize < newSize ) - { - bufferSize = newSize; - buffer = (uint8_t *) realloc( buffer, bufferSize ); - } - - hb_get_preview( handle, title, pictureIndex, buffer ); - - // Create an NSBitmapImageRep and copy the libhb image into it, converting it from - // libhb's format to one suitable for NSImage. Along the way, we'll strip off the - // border around libhb's image. - - // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format. - // Alpha is ignored. - - int dstWidth = title->job->width; - int dstHeight = title->job->height; - NSBitmapFormat bitmapFormat = (NSBitmapFormat)NSAlphaFirstBitmapFormat; - NSBitmapImageRep * imgrep = [[[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:nil - pixelsWide:dstWidth - pixelsHigh:dstHeight - bitsPerSample:8 - samplesPerPixel:3 // ignore alpha - hasAlpha:NO - isPlanar:NO - colorSpaceName:NSCalibratedRGBColorSpace - bitmapFormat:bitmapFormat - bytesPerRow:dstWidth * 4 - bitsPerPixel:32] autorelease]; - - int borderTop = (srcHeight - dstHeight) / 2; - int borderLeft = (srcWidth - dstWidth) / 2; - - UInt32 * src = (UInt32 *)buffer; - UInt32 * dst = (UInt32 *)[imgrep bitmapData]; - src += borderTop * srcWidth; // skip top rows in src to get to first row of dst - src += borderLeft; // skip left pixels in src to get to first pixel of dst - for (int r = 0; r < dstHeight; r++) - { - for (int c = 0; c < dstWidth; c++) -#if TARGET_RT_LITTLE_ENDIAN - *dst++ = Endian32_Swap(*src++); -#else - *dst++ = *src++; -#endif - src += (srcWidth - dstWidth); // skip to next row in src - } - - NSImage * img = [[[NSImage alloc] initWithSize: NSMakeSize(dstWidth, dstHeight)] autorelease]; - [img addRepresentation:imgrep]; - - return img; - } - else - { - // Make sure we have big enough buffer - static uint8_t * buffer; - static int bufferSize; - - int newSize; - newSize = ( title->width + 2 ) * (title->height + 2 ) * 4; - if( bufferSize < newSize ) - { - bufferSize = newSize; - buffer = (uint8_t *) realloc( buffer, bufferSize ); - } - - hb_get_preview( handle, title, pictureIndex, buffer ); - - // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format. - // We'll copy that into an NSImage swapping it to ARGB in the process. Alpha is - // ignored. - int width = title->width + 2; // hblib adds a one-pixel border to the image - int height = title->height + 2; - int numPixels = width * height; - NSBitmapFormat bitmapFormat = (NSBitmapFormat)NSAlphaFirstBitmapFormat; - NSBitmapImageRep * imgrep = [[[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:nil - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 - samplesPerPixel:3 // ignore alpha - hasAlpha:NO - isPlanar:NO - colorSpaceName:NSCalibratedRGBColorSpace - bitmapFormat:bitmapFormat - bytesPerRow:width * 4 - bitsPerPixel:32] autorelease]; - - UInt32 * src = (UInt32 *)buffer; - UInt32 * dst = (UInt32 *)[imgrep bitmapData]; - for (int i = 0; i < numPixels; i++) -#if TARGET_RT_LITTLE_ENDIAN - *dst++ = Endian32_Swap(*src++); -#else - *dst++ = *src++; -#endif - - NSImage * img = [[[NSImage alloc] initWithSize: NSMakeSize(width, height)] autorelease]; - [img addRepresentation:imgrep]; - - return img; - } -} - -// Returns the preview image for the specified index, retrieving it from its internal -// cache or by calling makeImageForPicture if it is not cached. Generally, you should -// use imageForPicture so that images are cached. Calling makeImageForPicture will -// always generate a new copy of the image. -- (NSImage *) imageForPicture: (int) pictureIndex -{ - // The preview for the specified index may not currently exist, so this method - // generates it if necessary. - NSString * key = [NSString stringWithFormat:@"%d", pictureIndex]; - NSImage * theImage = [fPicturePreviews objectForKey:key]; - if (!theImage) - { - theImage = [PictureController makeImageForPicture:pictureIndex libhb:fHandle title:fTitle removeBorders: NO]; - [fPicturePreviews setObject:theImage forKey:key]; - } - return theImage; -} - -// Purges all images from the cache. The next call to imageForPicture will cause a new -// image to be generated. -- (void) purgeImageCache -{ - [fPicturePreviews removeAllObjects]; -} - @end -@implementation PictureController (Private) - -// -// -[PictureController(Private) optimalViewSizeForImageSize:] -// -// Given the size of the preview image to be shown, returns the best possible -// size for the view. -// -- (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize -{ - // The min size is 320x240 - CGFloat minWidth = 320.0; - CGFloat minHeight = 240.0; - - NSSize screenSize = [[NSScreen mainScreen] frame].size; - NSSize sheetSize = [[self window] frame].size; - NSSize viewAreaSize = [fPictureViewArea frame].size; - CGFloat paddingX = sheetSize.width - viewAreaSize.width; - CGFloat paddingY = sheetSize.height - viewAreaSize.height; - /* Since we are now non-modal, lets go ahead and allow the mac size to - * go up to the full screen height or width below. Am leaving the original - * code here that blindjimmy setup for 85% in case we don't like it. - */ - // The max size of the view is when the sheet is taking up 85% of the screen. - //CGFloat maxWidth = (0.85 * screenSize.width) - paddingX; - //CGFloat maxHeight = (0.85 * screenSize.height) - paddingY; - CGFloat maxWidth = screenSize.width - paddingX; - CGFloat maxHeight = screenSize.height - paddingY; - - NSSize resultSize = imageSize; - - // Its better to have a view that's too small than a view that's too big, so - // apply the maximum constraints last. - if( resultSize.width < minWidth ) - { - resultSize.height *= (minWidth / resultSize.width); - resultSize.width = minWidth; - } - if( resultSize.height < minHeight ) - { - resultSize.width *= (minHeight / resultSize.height); - resultSize.height = minHeight; - } - if( resultSize.width > maxWidth ) - { - resultSize.height *= (maxWidth / resultSize.width); - resultSize.width = maxWidth; - } - if( resultSize.height > maxHeight ) - { - resultSize.width *= (maxHeight / resultSize.height); - resultSize.height = maxHeight; - } - - return resultSize; -} - -// -// -[PictureController(Private) resizePanelForViewSize:animate:] -// -// Resizes the entire sheet to accomodate a view of a particular size. -// -- (void)resizeSheetForViewSize: (NSSize)viewSize -{ - // Figure out the deltas for the new frame area - NSSize currentSize = [fPictureViewArea frame].size; - CGFloat deltaX = viewSize.width - currentSize.width; - CGFloat deltaY = viewSize.height - currentSize.height; - - // Now resize the whole panel by those same deltas, but don't exceed the min - NSRect frame = [[self window] frame]; - NSSize maxSize = [[self window] maxSize]; - NSSize minSize = [[self window] minSize]; - frame.size.width += deltaX; - frame.size.height += deltaY; - if( frame.size.width < minSize.width ) - { - frame.size.width = minSize.width; - } - if( frame.size.height < minSize.height ) - { - frame.size.height = minSize.height; - } - - // But now the sheet is off-center, so also shift the origin to center it and - // keep the top aligned. - if( frame.size.width != [[self window] frame].size.width ) - frame.origin.x -= (deltaX / 2.0); - - if( frame.size.height != [[self window] frame].size.height ) - frame.origin.y -= deltaY; - - [[self window] setFrame:frame display:YES animate:YES]; -} - -// -// -[PictureController(Private) setViewSize:] -// -// Changes the view's size and centers it vertically inside of its area. -// Assumes resizeSheetForViewSize: has already been called. -// -- (void)setViewSize: (NSSize)viewSize -{ - [fPictureView setFrameSize:viewSize]; - - // center it vertically - NSPoint origin = [fPictureViewArea frame].origin; - origin.y += ([fPictureViewArea frame].size.height - - [fPictureView frame].size.height) / 2.0; - [fPictureView setFrameOrigin:origin]; -} - -// -// -[PictureController(Private) viewNeedsToResizeToSize:] -// -// Returns YES if the view will need to resize to match the given size. -// -- (BOOL)viewNeedsToResizeToSize: (NSSize)newSize -{ - NSSize viewSize = [fPictureView frame].size; - return (newSize.width != viewSize.width || newSize.height != viewSize.height); -} - -@end |