Sliding Modal Dialogs in Cocoa Applications & Bundles

×

This post was originally published in 2011
It may contain stale & outdated information. Or it may have grown more awesome with age, like the author.

Example project available on GitHub – CIModalSheetDialog

One thing I wanted to be able to use during the development of Slider 2 was modal dialogs that slide out from the top of Rapid Weaver. This was troublesome for me as Slider 2 is a bundle that runs within Rapid Weaver – not as a standalone application.

Googling and experimentation allowed me to find a solution for problem that I find acceptable. Below is my implementation of a modal sheet dialog, further down one may find some usage examples.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//
//  SModalSheetDialogs.h
//
//  Created by Michael Robinson on 7/08/11.
//  Copyright 2011 Code of Interest. All rights reserved.
//
#import <Foundation/Foundation.h>
 
@interface SModalSheetDialogs : NSObject
 
+ (void) showModalMessage:(NSString *)message withInformativeText:(NSString *)informativeText 
                withStyle:(NSAlertStyle)style fromSender:(id)sender;
 
+ (void) showModalRequest:(NSString *)message withInformativeText:(NSString *)informativeText 
                withStyle:(NSAlertStyle)style andButtons:(NSArray *)buttons 
           andContextInfo:(void *)contextInfo fromSender:(id)sender;
 
@end

And the implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//
//  SModalSheetDialogs.m
//{filelink=1}
//  Created by Michael Robinson on 7/08/11.
//  Copyright 2011 Code of Interest. All rights reserved.
//
 
#import "SModalSheetDialogs.h"
 
@implementation SModalSheetDialogs
 
+ (void) showModalMessage:(NSString *)message withInformativeText:(NSString *)informativeText 
                withStyle:(NSAlertStyle)style fromSender:(id)sender {
 
    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
 
    [alert addButtonWithTitle:@"OK"];
 
    [alert setInformativeText:informativeText];
    [alert setMessageText:message];
 
    [alert setAlertStyle:style];
 
    [alert beginSheetModalForWindow:[NSApp mainWindow] 
                      modalDelegate:sender 
                     didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) 
                        contextInfo:nil];
}
 
+ (void) showModalRequest:(NSString *)message withInformativeText:(NSString *)informativeText 
                withStyle:(NSAlertStyle)style andButtons:(NSArray *)buttons 
           andContextInfo:(void *)contextInfo fromSender:(id)sender {
 
    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
 
    NSEnumerator *e = [buttons objectEnumerator];
    id object;
    while (object = [e nextObject]) {
        [alert addButtonWithTitle:(NSString*)object];
    }
 
    [alert setInformativeText:informativeText];
    [alert setMessageText:message];
 
    [alert setAlertStyle:style];
 
    [alert beginSheetModalForWindow:[NSApp mainWindow] 
                      modalDelegate:sender 
                     didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) 
                        contextInfo:contextInfo];
 
}
 
@end

Showing a dialog is simple, example below.

1
2
3
4
[CIModalSheetDialog showModalMessage:@"Dialog title" 
                     withInformativeText:@"Dialog content" 
                               withStyle:NSInformationalAlertStyle 
                              fromSender:self];

This is fine for cases where we’re just informing the user that something happened – in these cases we don’t care what the user does, as the only option they have is to acknowledge the message. In more complex cases, where the user is presented with a choice, we need to have a way to catch that choice.

As the object handling the user’s choice may differ across use cases, we set the sender (as above). It is expected that this sender implements the following delegate method:

- (void) alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo

An example, first of showing a more complex dialog, with two buttons:

1
2
3
4
5
6
[CIModalSheetDialog showModalRequest:@"Dialog title" 
                     withInformativeText:@"Dialog content" 
                               withStyle:NSInformationalAlertStyle
                              andButtons:[NSArray arrayWithObjects:@"OK", @"Cancel", nil]
                          andContextInfo:@"Some identifying information"
                              fromSender:self];

And our implentation of alertDidEnd:

1
2
3
4
5
6
7
8
9
- (void) alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
    if (contextInfo == @"Some identifying information") {
        if (returnCode == NSAlertSecondButtonReturn) { // OK button was clicked
            // Handle OK
        } else {
            // Handle Cancel
        }
    }
}
No comments | Trackback