OSDN Git Service

Cygwin: Patches for xvid and mpeg4ip Updated to work with new nasm 2.x.x
[handbrake-jp/handbrake-jp-git.git] / macosx / InstantHandBrake / ExpressController.m
1 #import "ExpressController.h"
2
3 #define INSERT_STRING       @"Insert a DVD"
4 #define TOOLBAR_START       @"TOOLBAR_START"
5 #define TOOLBAR_PAUSE       @"TOOLBAR_PAUSE"
6 #define TOOLBAR_OPEN        @"TOOLBAR_OPEN"
7 #define TOOLBAR_ADVANCED    @"TOOLBAR_ADVANCED"
8
9 #define p fState->param
10
11 @interface ExpressController (Private)
12
13 - (void) openUpdateDrives: (NSDictionary *) drives;
14 - (void) openBrowseDidEnd: (NSOpenPanel *) sheet returnCode: (int)
15     returnCode contextInfo: (void *) contextInfo;
16 - (void) openEnable: (BOOL) b;
17
18 - (id) updatePopUpIcon: (id) value;
19 - (void) convertShow;
20 - (void) convertEnable: (BOOL) b;
21
22 @end
23
24 @implementation ExpressController
25
26 /***********************************************************************
27  * Application delegate methods
28  **********************************************************************/
29 - (void) awakeFromNib
30 {
31     NSEnumerator * enumerator;
32     
33     /* NSToolbar initializations */
34     fToolbar = [[NSToolbar alloc] initWithIdentifier: @"InstantHandBrake Toolbar"];
35     [fToolbar setDelegate: self];
36     [fToolbar setAllowsUserCustomization: YES];
37     [fToolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
38     [fToolbar setVisible:NO];
39     [fWindow setShowsToolbarButton:NO];
40     [fWindow setToolbar: fToolbar];
41         
42     /* Show the "Open DVD" interface */
43     fDriveDetector = [[DriveDetector alloc] initWithCallback: self
44         selector: @selector( openUpdateDrives: )];
45     [fDriveDetector run];
46     [self openEnable: YES];
47     [fWindow setContentSize: [fOpenView frame].size];
48     [fWindow setContentView: fOpenView];
49     [fWindow center];
50     [fWindow makeKeyAndOrderFront: nil];
51
52     /* NSTableView initializations */
53      NSButtonCell * buttonCell;
54      NSTableColumn * tableColumn;
55      enumerator = [[fConvertTableView tableColumns] objectEnumerator];
56      while( ( tableColumn = [enumerator nextObject] ) )
57      {
58          [tableColumn setEditable: NO];
59      }
60      tableColumn = [fConvertTableView tableColumnWithIdentifier: @"Check"];
61      buttonCell = [[[NSButtonCell alloc] initTextCell: @""] autorelease];
62     [buttonCell setEditable: YES];
63     [buttonCell setButtonType: NSSwitchButton];
64     [tableColumn setDataCell: buttonCell];
65
66     /* Preferences */
67     fConvertFolderString = [NSString stringWithFormat:@"%@/Desktop", NSHomeDirectory()];
68     [fConvertFolderString retain];
69 }
70
71 - (void) applicationWillFinishLaunching: (NSNotification *) n
72 {
73     fCore = [[HBCore alloc] init];
74     [fCore openInDebugMode:NO checkForUpdates:NO];
75     fHandle = [fCore hb_handle];
76     fState = [fCore hb_state];
77     fList   = hb_get_titles( fHandle );
78     
79     [[NSNotificationCenter defaultCenter] addObserver:self
80     selector:@selector(scanningSource:)
81     name:@"HBCoreScanningNotification" object:nil];
82     
83     [[NSNotificationCenter defaultCenter] addObserver:self
84     selector:@selector(scanDone:)
85     name:@"HBCoreScanDoneNotification" object:nil];
86     
87     [[NSNotificationCenter defaultCenter] addObserver:self
88     selector:@selector(muxing:)
89     name:@"HBCoreMuxingNotification" object:nil];
90     
91     [[NSNotificationCenter defaultCenter] addObserver:self
92     selector:@selector(working:)
93     name:@"HBCoreWorkingNotification" object:nil];
94     
95     [[NSNotificationCenter defaultCenter] addObserver:self
96     selector:@selector(workDone:)
97     name:@"HBCoreWorkDoneNotification" object:nil];
98 }
99
100 - (void) applicationWillTerminate: (NSNotification *) n
101 {
102     [fCore close];
103 }
104
105 - (NSToolbarItem *) toolbar: (NSToolbar *) toolbar itemForItemIdentifier: (NSString *) ident
106                     willBeInsertedIntoToolbar: (BOOL) flag
107 {
108     NSToolbarItem * item;
109     item = [[NSToolbarItem alloc] initWithItemIdentifier: ident];
110
111     if ([ident isEqualToString: TOOLBAR_START])
112     {
113         [item setLabel: NSLocalizedString(@"Convert", "Convert")];
114         [item setPaletteLabel: NSLocalizedString(@"Convert/Cancel", @"Convert/Cancel")];
115         [item setImage: [NSImage imageNamed: @"Play"]];
116         [item setTarget: self];
117         [item setAction: @selector(convertGo:)];
118     }
119     else if ([ident isEqualToString: TOOLBAR_PAUSE])
120     {
121         [item setLabel: NSLocalizedString(@"Pause", "Pause")];
122         [item setPaletteLabel: NSLocalizedString(@"Pause/Resume", @"Pause/Resume")];
123         [item setImage: [NSImage imageNamed: @"Pause"]];
124         [item setTarget: self];
125         [item setAction: @selector(pauseGo:)];
126     }
127     else if ([ident isEqualToString: TOOLBAR_OPEN])
128     {
129         [item setLabel: NSLocalizedString(@"Open...", "Open...")];
130         [item setPaletteLabel: NSLocalizedString(@"Open Another Source", "Open Another Source")];
131         [item setImage: [NSImage imageNamed: @"Open"]];
132         [item setTarget: self];
133         [item setAction: @selector(openShow:)];
134     }
135     else
136     {
137         [item release];
138         return nil;
139     }
140
141     return item;
142 }
143
144 - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
145 {
146     return [NSArray arrayWithObjects: TOOLBAR_START, TOOLBAR_PAUSE,
147                                     NSToolbarFlexibleSpaceItemIdentifier, TOOLBAR_OPEN, nil];
148 }
149
150 - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
151 {
152     return [NSArray arrayWithObjects: TOOLBAR_START, TOOLBAR_PAUSE,
153                                         TOOLBAR_OPEN, NSToolbarFlexibleSpaceItemIdentifier, nil];
154 }
155
156 /***********************************************************************
157  * Tableview datasource methods
158  **********************************************************************/
159 - (int) numberOfRowsInTableView: (NSTableView *) t
160 {
161     if( !fHandle )
162         return 0;
163
164     return hb_list_count( fList );
165 }
166
167 - (id) tableView:(NSTableView *) t objectValueForTableColumn:
168     (NSTableColumn *) col row: (int) row
169 {
170     if( [[col identifier] isEqualToString: @"Check"] )
171     {
172         return [fConvertCheckArray objectAtIndex: row];
173     }
174     else
175     {
176         hb_title_t * title = hb_list_item( fList, row );
177         if( [[col identifier] isEqualToString: @"Title"] )
178         {
179             return [@"Title " stringByAppendingFormat: @"%d",
180                     title->index];
181         }
182         else if( [[col identifier] isEqualToString: @"Duration"] )
183         {
184             if( title->hours > 0 )
185             {
186                 return [NSString stringWithFormat:
187                     @"%d hour%s %d min%s", title->hours,
188                     title->hours > 1 ? "s" : "", title->minutes,
189                     title->minutes > 1 ? "s": ""];
190             }
191             else if( title->minutes > 0 )
192             {
193                 return [NSString stringWithFormat:
194                     @"%d min%s %d sec%s", title->minutes,
195                     title->minutes > 1 ? "s" : "", title->seconds,
196                     title->seconds > 1 ? "s": ""];
197             }
198             else
199             {
200                 return [NSString stringWithFormat: @"%d seconds",
201                         title->seconds];
202             }
203         }
204     }
205     return nil;
206 }
207
208 - (void) tableView: (NSTableView *) t setObjectValue: (id) object
209     forTableColumn: (NSTableColumn *) col row: (int) row
210 {
211     if( [[col identifier] isEqualToString: @"Check"] )
212     {
213         [fConvertCheckArray replaceObjectAtIndex: row withObject: object];
214     }
215 }
216
217 /***********************************************************************
218  * User events methods
219  **********************************************************************/
220 - (void) openShow: (id) sender
221 {
222     NSRect frame  = [fWindow frame];
223     float  offset = [fConvertView frame].size.height -
224                     [fOpenView frame].size.height;
225
226     frame.origin.y    += offset;
227     frame.size.height -= offset;
228     [fWindow setContentView: fEmptyView];
229     [fWindow setFrame: frame display: YES animate: YES];
230     [fToolbar setVisible:NO];
231     [fOpenProgressField setStringValue: @""];
232     [fWindow setContentView: fOpenView];
233
234     [fDriveDetector run];
235 }
236
237 - (void) openMatrixChanged: (id) sender
238 {
239     [self openEnable: YES];
240     if( [fOpenMatrix selectedRow] )
241     {
242         [self openBrowse: self];
243     }
244 }
245
246 - (void) openBrowse: (id) sender
247 {
248     NSOpenPanel * panel = [NSOpenPanel openPanel];
249     [panel setAllowsMultipleSelection: NO];
250     [panel setCanChooseFiles: YES];
251     [panel setCanChooseDirectories: YES ];
252     [panel beginSheetForDirectory: nil file: nil types: nil
253         modalForWindow: fWindow modalDelegate: self
254         didEndSelector: @selector( openBrowseDidEnd:returnCode:contextInfo: )
255         contextInfo: nil];                                                      
256 }
257
258 - (void) openGo: (id) sender
259 {
260     [self openEnable: NO];
261     [fOpenIndicator setIndeterminate: YES];
262     [fOpenIndicator startAnimation: nil];
263     [fOpenProgressField setStringValue: @"Opening..."];
264     [fDriveDetector stop];
265
266     if( [fOpenMatrix selectedRow] )
267     {
268         hb_scan( fHandle, [fOpenFolderString UTF8String], 0 );
269     }
270     else
271     {
272         hb_scan( fHandle, [[fDrives objectForKey: [fOpenPopUp
273                  titleOfSelectedItem]] UTF8String], 0 );
274     }
275 }
276
277 - (void) selectFolderSheetShow: (id) sender
278 {
279     NSOpenPanel * panel = [NSOpenPanel openPanel];
280
281     [panel setPrompt: NSLocalizedString(@"Select", "Convert -> Save panel prompt")];
282     [panel setAllowsMultipleSelection: NO];
283     [panel setCanChooseFiles: NO];
284     [panel setCanChooseDirectories: YES];
285     [panel setCanCreateDirectories: YES];
286
287     [panel beginSheetForDirectory: nil file: nil types: nil
288         modalForWindow: fWindow modalDelegate: self didEndSelector:
289         @selector(selectFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
290 }
291
292 - (void) selectFolderSheetClosed: (NSOpenPanel *) sheet returnCode: (int)
293     returnCode contextInfo: (void *) contextInfo
294 {
295     if( returnCode != NSOKButton )
296         return;
297
298     if( fConvertFolderString )
299         [fConvertFolderString release];
300     fConvertFolderString = [[[sheet filenames] objectAtIndex: 0] retain];
301     [[fConvertFolderPopUp itemAtIndex: 0] setTitle: [fConvertFolderString lastPathComponent]];
302     [fConvertFolderPopUp selectItemAtIndex:0];
303     
304     NSMenuItem * item = [fConvertFolderPopUp itemAtIndex: 0];
305     [item setImage: [self updatePopUpIcon:fConvertFolderString]];
306     
307 }
308
309 - (void) convertGo: (id) sender
310 {
311     int i, j;
312
313     for( i = 0; i < hb_list_count( fList ); i++ )
314     {
315         if( ![[fConvertCheckArray objectAtIndex: i] boolValue] )
316             continue;
317
318         hb_title_t * title = hb_list_item( fList, i );
319         hb_job_t   * job   = title->job;
320
321         int pixels = 307200;
322                 int aspect = title->aspect;
323                 if( [fConvertAspectPopUp indexOfSelectedItem] == 1)
324                 {
325             aspect = 4 * HB_ASPECT_BASE / 3;
326                 }
327
328                 int maxwidth = 640;
329                 job->vbitrate = 1000;
330                 if( [fConvertMaxWidthPopUp indexOfSelectedItem] == 1)
331                 {
332             maxwidth = 320;
333                         job->vbitrate = 500;
334                 }
335                 job->deinterlace = 1;
336                 
337                 do
338                 {
339                         hb_set_size( job, aspect, pixels );
340                         pixels -= 10;
341                 } while(job->width > maxwidth);
342                 
343         if( [fConvertFormatPopUp indexOfSelectedItem] == 0 )
344         {
345             /* iPod / H.264 */
346             job->mux        = HB_MUX_IPOD;
347             job->vcodec     = HB_VCODEC_X264;
348                         job->h264_level = 30;
349             job->x264opts   = "bframes=0:cabac=0:ref=1:vbv-maxrate=1500:vbv-bufsize=2000:analyse=all:me=umh:subq=6:no-fast-pskip=1";
350         }
351         else if( [fConvertFormatPopUp indexOfSelectedItem] == 1 )
352         {
353             /* PSP / MPEG-4 */
354             job->mux        = HB_MUX_PSP;
355             job->vrate      = 27000000;
356             job->vrate_base = 900900;   /* 29.97 fps */
357             job->vcodec     = HB_VCODEC_FFMPEG;
358             job->vbitrate   = 600;
359             pixels          = 76800;
360             job->arate      = 24000;
361             job->abitrate   = 96;
362             aspect          = 16 * HB_ASPECT_BASE / 9;
363
364                         if( [fConvertAspectPopUp indexOfSelectedItem] )
365                         {
366                                 aspect = -1;
367                         }
368
369                         hb_set_size( job, aspect, pixels );
370         }
371         else
372         {
373             job->mux      = HB_MUX_MP4;
374             job->vcodec   = HB_VCODEC_X264;
375             job->x264opts = "bframes=3:ref=1:subq=5:me=umh:no-fast-pskip=1:trellis=1:cabac=0";
376             job->abitrate = 128;
377             job->vbitrate = 1500;
378         }
379
380         job->vquality = -1.0;
381
382         const char * lang;
383
384         /* Audio selection */
385         hb_audio_t * audio;
386         lang = [[fConvertAudioPopUp titleOfSelectedItem] UTF8String];
387         job->audios[0] = -1;
388         for( j = 0; j < hb_list_count( title->list_audio ); j++ )
389         {
390             /* Choose the first track that matches the language */
391             audio = hb_list_item( title->list_audio, j );
392             if( !strcmp( lang, audio->lang_simple ) )
393             {
394                 job->audios[0] = j;
395                 break;
396             }
397         }
398         if( job->audios[0] == -1 )
399         {
400             /* If the language isn't available in this title, choose
401                the first track */
402             job->audios[0] = 0;
403         }
404         job->audios[1] = -1;
405
406         job->audio_mixdowns[0] = HB_AMIXDOWN_DOLBYPLII;
407         
408         /* Subtitle selection */
409         hb_subtitle_t * subtitle;
410         lang = [[fConvertSubtitlePopUp titleOfSelectedItem] UTF8String];
411         job->subtitle = -1;
412         for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
413         {
414             /* Choose the first track that matches the language */
415             subtitle = hb_list_item( title->list_subtitle, j );
416             if( !strcmp( lang, subtitle->lang ) )
417             {
418                 job->subtitle = j;
419                 break;
420             }
421         }
422         
423         job->file = strdup( [[NSString stringWithFormat:                 
424                 @"%@/%s - Title %d.m4v", fConvertFolderString,      
425                 title->name, title->index] UTF8String] );
426         hb_add( fHandle, job );
427     }
428
429     hb_start( fHandle );
430
431     [self convertEnable: NO];
432 }
433
434 - (void) convertCancel: (id) sender
435 {
436     hb_stop( fHandle );
437     [self convertEnable: YES];
438 }
439
440 @end
441
442 /***********************************************************************
443  * Private methods
444  **********************************************************************/
445
446 @implementation ExpressController (Private)
447
448 - (void) openUpdateDrives: (NSDictionary *) drives
449 {
450     if( fDrives )
451     {
452         [fDrives release];
453     }
454     fDrives = [[NSDictionary alloc] initWithDictionary: drives];
455
456     NSString * device;
457     NSEnumerator * enumerator = [fDrives keyEnumerator];
458     [fOpenPopUp removeAllItems];
459     while( ( device = [enumerator nextObject] ) )
460     {
461         [fOpenPopUp addItemWithTitle: device];
462     }
463
464     if( ![fOpenPopUp numberOfItems] )
465     {
466         [fOpenPopUp addItemWithTitle: INSERT_STRING];
467     }
468     [fOpenPopUp selectItemAtIndex: 0];
469     if( [fOpenMatrix isEnabled] )
470     {
471         [self openEnable: YES];
472     }
473 }
474
475 - (void) openBrowseDidEnd: (NSOpenPanel *) sheet returnCode: (int)
476     returnCode contextInfo: (void *) contextInfo
477 {
478     if( returnCode != NSOKButton )
479         return;
480
481     if( fOpenFolderString )
482         [fOpenFolderString release];
483     fOpenFolderString = [[[sheet filenames] objectAtIndex: 0] retain];
484     [fOpenFolderField setStringValue: [fOpenFolderString lastPathComponent]];
485     [self openGo: self];
486 }
487
488 - (BOOL)validateToolbarItem: (NSToolbarItem *) toolbarItem
489 {
490     NSString * ident = [toolbarItem itemIdentifier];
491     
492     if ([ident isEqualToString: TOOLBAR_START] && [HBStateWorking isEqualToString:[fCore state]])
493     {
494         [toolbarItem setAction: @selector(convertCancel:)];
495         [toolbarItem setLabel:NSLocalizedString(@"Cancel", @"Cancel")];
496         return YES;
497     }
498     else if ([ident isEqualToString: TOOLBAR_START] && [HBStateWorkDone isEqualToString:[fCore state]])
499     {
500         [toolbarItem setAction: @selector(convertGo:)];
501         [toolbarItem setLabel:NSLocalizedString(@"Convert", @"Convert")];
502         return YES;
503     }
504     else if ([ident isEqualToString: TOOLBAR_OPEN] && [HBStateWorking isEqualToString:[fCore state]])
505     {
506         return NO;
507     }
508     
509     return YES;
510 }
511
512 - (void) openEnable: (BOOL) b
513 {
514     [fOpenMatrix       setEnabled: b];
515     [fOpenPopUp        setEnabled: b];
516     [fOpenFolderField  setEnabled: b];
517     [fOpenBrowseButton setEnabled: b];
518     [fOpenGoButton     setEnabled: b]; 
519
520     if( b )
521     {
522         if( [fOpenMatrix selectedRow] )
523         {
524             [fOpenPopUp setEnabled: NO];
525         }
526         else
527         {
528             [fOpenFolderField  setEnabled: NO];
529             [fOpenBrowseButton setEnabled: NO];
530             if( [[fOpenPopUp titleOfSelectedItem]
531                     isEqualToString: INSERT_STRING] )
532             {
533                 [fOpenGoButton setEnabled: NO];
534             }
535         }
536     }
537 }
538
539 - (void) scanningSource: (NSNotification *) n
540 {
541     [fOpenIndicator setIndeterminate: NO];
542     [fOpenIndicator setDoubleValue: 100.0 *
543             ( (float) p.scanning.title_cur - 0.5 ) / p.scanning.title_count];
544     [fOpenProgressField setStringValue: [NSString
545             stringWithFormat: @"Scanning title %d of %d...",
546             p.scanning.title_cur, p.scanning.title_count]];
547 }
548
549 - (void) scanDone: (NSNotification *) n
550 {    
551     [fOpenIndicator setIndeterminate: NO];
552     [fOpenIndicator setDoubleValue: 0.0];
553    
554      [self openEnable: YES];
555
556     if( hb_list_count( fList ) )
557     {
558         [self convertShow];
559     }
560     else
561     {
562         [fDriveDetector run];
563         [fOpenProgressField setStringValue: NSLocalizedString(@"No Title Found...",@"No Title Found...")];
564     }
565 }
566
567 - (void) convertShow
568 {
569     int i, j;
570
571     fConvertCheckArray = [[NSMutableArray alloc] initWithCapacity:
572         hb_list_count( fList )];
573     [fConvertAudioPopUp removeAllItems];
574     [fConvertSubtitlePopUp removeAllItems];
575     [fConvertSubtitlePopUp addItemWithTitle: @"None"];
576     for( i = 0; i < hb_list_count( fList ); i++ )
577     {
578         /* Default is to convert titles longer than 30 minutes. */
579         hb_title_t * title = hb_list_item( fList, i );
580         [fConvertCheckArray addObject: [NSNumber numberWithBool:
581             ( 60 * title->hours + title->minutes > 30 )]];
582
583         /* Update audio popup */
584         hb_audio_t * audio;
585         for( j = 0; j < hb_list_count( title->list_audio ); j++ )
586         {
587             audio = hb_list_item( title->list_audio, j );
588             [fConvertAudioPopUp addItemWithTitle:
589                 [NSString stringWithUTF8String: audio->lang_simple]];
590         }
591                 [fConvertAudioPopUp selectItemWithTitle: @"English"];
592         
593         if ( [fConvertAudioPopUp selectedItem] == nil )
594             [fConvertAudioPopUp selectItemWithTitle: @"Unknown"];
595
596         /* Update subtitle popup */
597         hb_subtitle_t * subtitle;
598         for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
599         {
600             subtitle = hb_list_item( title->list_subtitle, j );
601             [fConvertSubtitlePopUp addItemWithTitle:
602                 [NSString stringWithUTF8String: subtitle->lang]];
603         }
604     }
605     [fConvertTableView reloadData];
606
607     NSRect frame  = [fWindow frame];
608     float  offset = [fConvertView frame].size.height -
609                     [fOpenView frame].size.height;
610     float hoffset = [fConvertView frame].size.width -
611                     [fOpenView frame].size.width;
612     frame.origin.y    -= offset;
613     frame.size.height += offset;
614     frame.size.width += hoffset;
615     [fWindow setContentView: fEmptyView];
616     [fWindow setFrame: frame display: YES animate: YES];
617     [fToolbar setVisible:YES];
618     [fWindow setContentView: fConvertView];
619
620     NSMenuItem * item = [fConvertFolderPopUp itemAtIndex: 0];
621     [item setTitle: [fConvertFolderString lastPathComponent]];
622     [item setImage: [self updatePopUpIcon:fConvertFolderString]];
623     
624     [self convertEnable: YES];
625 }
626
627 - (void) convertEnable: (BOOL) b
628 {
629     [fConvertTableView setEnabled: b];
630     [fConvertFolderPopUp setEnabled: b];
631     [fConvertFormatPopUp setEnabled: b];
632     [fConvertAspectPopUp setEnabled: b];
633     [fConvertMaxWidthPopUp setEnabled: b];
634     [fConvertAudioPopUp setEnabled: b];
635     [fConvertSubtitlePopUp setEnabled: b];
636 }
637
638 /***********************************************************************
639 * UpdateDockIcon
640 ***********************************************************************
641 * Shows a progression bar on the dock icon, filled according to
642 * 'progress' (0.0 <= progress <= 1.0).
643 * Called with progress < 0.0 or progress > 1.0, restores the original
644 * icon.
645 **********************************************************************/
646 - (void) UpdateDockIcon: (float) progress
647 {
648     NSImage * icon;
649     NSData * tiff;
650     NSBitmapImageRep * bmp;
651     uint32_t * pen;
652     uint32_t black = htonl( 0x000000FF );
653     uint32_t red   = htonl( 0xFF0000FF );
654     uint32_t white = htonl( 0xFFFFFFFF );
655     int row_start, row_end;
656     int i, j;
657         
658     /* Get application original icon */
659     icon = [NSImage imageNamed: @"NSApplicationIcon"];
660         
661     if( progress < 0.0 || progress > 1.0 )
662     {
663         [NSApp setApplicationIconImage: icon];
664         return;
665     }
666         
667     /* Get it in a raw bitmap form */
668     tiff = [icon TIFFRepresentationUsingCompression:
669                                            NSTIFFCompressionNone factor: 1.0];
670     bmp = [NSBitmapImageRep imageRepWithData: tiff];
671     
672     /* Draw the progression bar */
673     /* It's pretty simple (ugly?) now, but I'm no designer */
674         
675     row_start = 3 * (int) [bmp size].height / 4;
676     row_end   = 7 * (int) [bmp size].height / 8;
677         
678     for( i = row_start; i < row_start + 2; i++ )
679     {
680         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
681         for( j = 0; j < (int) [bmp size].width; j++ )
682         {
683             pen[j] = black;
684         }
685     }
686     for( i = row_start + 2; i < row_end - 2; i++ )
687     {
688         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
689         pen[0] = black;
690         pen[1] = black;
691         for( j = 2; j < (int) [bmp size].width - 2; j++ )
692         {
693             if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
694             {
695                 pen[j] = red;
696             }
697             else
698             {
699                 pen[j] = white;
700             }
701         }
702         pen[j]   = black;
703         pen[j+1] = black;
704     }
705     for( i = row_end - 2; i < row_end; i++ )
706     {
707         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
708         for( j = 0; j < (int) [bmp size].width; j++ )
709         {
710             pen[j] = black;
711         }
712     }
713         
714     /* Now update the dock icon */
715     tiff = [bmp TIFFRepresentationUsingCompression:
716                                           NSTIFFCompressionNone factor: 1.0];
717     icon = [[NSImage alloc] initWithData: tiff];
718     [NSApp setApplicationIconImage: icon];
719     [icon release];
720 }
721
722 - (id) updatePopUpIcon: (id) value
723 {
724     if (!value)
725         return nil;
726     
727     NSImage * icon;
728     
729     icon = [[NSWorkspace sharedWorkspace] iconForFile: value];
730     
731     [icon setScalesWhenResized: YES];
732     [icon setSize: NSMakeSize(16.0, 16.0)];
733     
734     return icon;
735 }
736
737 - (void) working: (NSNotification *) n
738 {
739    float progress_total = ( p.working.progress + p.working.job_cur - 1 ) / p.working.job_count;
740     NSMutableString * string = [NSMutableString stringWithFormat: @"Converting: %.1f %%", 100.0 * progress_total];
741     
742     if( p.working.seconds > -1 )
743     {
744         [string appendFormat: @" (%.1f fps, ", p.working.rate_avg];
745         if( p.working.hours > 0 )
746         {
747         [string appendFormat: @"%d hour%s %d min%s",
748             p.working.hours, p.working.hours == 1 ? "" : "s",
749             p.working.minutes, p.working.minutes == 1 ? "" : "s"];
750         }
751         else if( p.working.minutes > 0 )
752         {
753             [string appendFormat: @"%d min%s %d sec%s",
754                 p.working.minutes, p.working.minutes == 1 ? "" : "s",
755                 p.working.seconds, p.working.seconds == 1 ? "" : "s"];
756         }
757         else
758         {
759             [string appendFormat: @"%d second%s",
760                 p.working.seconds, p.working.seconds == 1 ? "" : "s"];
761         }
762             [string appendString: @" left)"];
763     }
764     
765     [fConvertInfoString setStringValue: string];
766     [fConvertIndicator setIndeterminate: NO];
767     [fConvertIndicator setDoubleValue: 100.0 * progress_total];
768     [self UpdateDockIcon: progress_total];
769 }
770
771 - (void) muxing: (NSNotification *) n
772 {
773     [fConvertInfoString setStringValue: NSLocalizedString(@"Muxing...",@"Muxing...")];
774     [fConvertIndicator setIndeterminate: YES];
775     [fConvertIndicator startAnimation: nil];
776     [self UpdateDockIcon: 1.0];
777 }
778
779 - (void) workDone: (NSNotification *) n
780 {    
781     [fConvertIndicator setIndeterminate: NO];
782     [fConvertIndicator setDoubleValue: 0.0];
783     [self UpdateDockIcon: -1.0];
784     [self convertEnable: YES];
785         
786     [fConvertInfoString setStringValue: NSLocalizedString(@"Done.",@"Done.")];
787
788     [fCore removeAllJobs];
789 }
790
791 @end