Created
July 28, 2018 17:01
-
-
Save classilla/9ca19fdc28d588bf54f3d730d16e2836 to your computer and use it in GitHub Desktop.
A simple modal date panel using undocumented methods in Mac OS X Tiger.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Cocoa/Cocoa.h> | |
// (C)2018 Cameron Kaiser. BSD license. | |
// gcc -o datepanel datepanel.m -framework Cocoa | |
// 10.4 does not have an accessory view method for NSAlert, but we can | |
// simulate it with these undocumented methods. | |
@interface NSAlert(WithCustomStyle) | |
- (void)prepare; | |
- (id)buildAlertStyle:(int)fp8 title:(id)fp12 formattedMsg:(id)fp16 first:(id)fp20 second:(id)fp24 third:(id)fp28 oldStyle:(BOOL)fp32; | |
- (id)buildAlertStyle:(int)fp8 title:(id)fp12 message:(id)fp16 first:(id)fp20 second:(id)fp24 third:(id)fp28 oldStyle:(BOOL)fp32 args:(char *)fp36; | |
@end | |
////// NSPopUpDatePicker | |
////// based on NSAlertCheckbox, http://cocoadev.github.io/NSAlertCheckbox/ | |
@interface NSPopUpDatePicker : NSAlert { | |
NSDatePicker *_picker; | |
} | |
- (void)dealloc; | |
- (NSPopUpDatePicker *)datePicker:(NSString *)message | |
defaultButton:(NSString *)defaultButton | |
alternateButton:(NSString *)alternateButton | |
otherButton:(NSString *)otherButton | |
informativeTextWithFormat:(NSString *)format; | |
- (NSDate *)date; | |
- (void)setDate:(NSDate *)date; | |
@end | |
@interface NSPopUpDatePicker(Private) | |
- (void)_ensureDatePicker; | |
- (void)_addDatePickerToAlert; | |
@end | |
@implementation NSPopUpDatePicker | |
- (void)dealloc | |
{ | |
// NSLog(@"dealloc"); | |
[_picker release]; | |
[super dealloc]; | |
} | |
- (NSPopUpDatePicker *)datePicker:(NSString *)message | |
defaultButton:(NSString *)defaultButton | |
alternateButton:(NSString *)alternateButton | |
otherButton:(NSString *)otherButton | |
informativeTextWithFormat:(NSString *)format | |
{ | |
NSAlert *alert = [super alertWithMessageText:message | |
defaultButton:defaultButton | |
alternateButton:alternateButton | |
otherButton:otherButton | |
informativeTextWithFormat:format]; | |
return (NSPopUpDatePicker *)alert; | |
} | |
- (id)buildAlertStyle:(int)fp8 | |
title:(id)fp12 | |
formattedMsg:(id)fp16 | |
first:(id)fp20 | |
second:(id)fp24 | |
third:(id)fp28 | |
oldStyle:(BOOL)fp32 | |
{ | |
// NSLog(@"buildAlertStyle 1"); | |
id rv = [super buildAlertStyle:fp8 | |
title:fp12 | |
formattedMsg:fp16 | |
first:fp20 | |
second:fp24 | |
third:fp28 | |
oldStyle:fp32]; | |
[self _addDatePickerToAlert]; | |
return rv; | |
} | |
- (id)buildAlertStyle:(int)fp8 | |
title:(id)fp12 | |
message:(id)fp16 | |
first:(id)fp20 | |
second:(id)fp24 | |
third:(id)fp28 | |
oldStyle:(BOOL)fp32 | |
args:(char *)fp36 | |
{ | |
// NSLog(@"buildAlertStyle 2"); | |
id rv = [super buildAlertStyle:fp8 | |
title:fp12 | |
message:fp16 | |
first:fp20 | |
second:fp24 | |
third:fp28 | |
oldStyle:fp32 | |
args:fp36]; | |
[self _addDatePickerToAlert]; | |
return rv; | |
} | |
- (NSDate *)date | |
{ | |
[self _ensureDatePicker]; | |
return [_picker dateValue]; | |
} | |
- (void)setDate:(NSDate *)date | |
{ | |
[self _ensureDatePicker]; | |
[_picker setDateValue:date]; | |
} | |
@end | |
@implementation NSPopUpDatePicker(Private) | |
- (void)_ensureDatePicker | |
{ | |
if (!_picker) { | |
// NSLog(@"picker init"); | |
_picker = [[NSDatePicker alloc] initWithFrame:NSMakeRect(10,10,295,154)]; | |
[_picker setDatePickerStyle:NSClockAndCalendarDatePickerStyle]; | |
[_picker setDatePickerElements:NSYearMonthDayDatePickerElementFlag]; | |
} | |
} | |
- (void)_addDatePickerToAlert | |
{ | |
NSWindow *window = [self window]; | |
NSView *content = [window contentView]; | |
float padding = 14.0f; | |
NSArray *subviews = [content subviews]; | |
NSEnumerator *en = [subviews objectEnumerator]; | |
NSView *subview = nil; | |
NSTextField *messageText = nil; | |
int count = 0; | |
[self _ensureDatePicker]; | |
// Find the main text field. | |
while (subview = [en nextObject]) { | |
if ([subview isKindOfClass:[NSTextField class]]) { | |
if (++count == 2) | |
messageText = (NSTextField *)subview; | |
} | |
} | |
if (messageText) { | |
[content addSubview:_picker]; | |
[_picker sizeToFit]; | |
// Expand the alert window. | |
NSRect windowFrame = [window frame]; | |
NSRect pickerFrame = [_picker frame]; | |
windowFrame.size.height += pickerFrame.size.height + padding; | |
[window setFrame:windowFrame display:YES]; | |
// Insert the picker below the main text field. | |
pickerFrame.origin.y = [messageText frame].origin.y - | |
pickerFrame.size.height - padding; | |
pickerFrame.origin.x = [messageText frame].origin.x; | |
[_picker setFrame:pickerFrame]; | |
//NSLog(@"Picker installed"); | |
} else | |
NSLog(@"Couldn't find message text, did not add picker"); | |
} | |
@end | |
////// App delegate runner | |
@interface AppDelegate : NSObject | |
- (id) init; | |
- (void) applicationWillFinishLaunching: (NSNotification*) aNotification; | |
- (void) applicationDidFinishLaunching: (NSNotification*) aNotification; | |
@end | |
@implementation AppDelegate | |
- (id) init | |
{ | |
return [super init]; | |
} | |
- (void) applicationWillFinishLaunching: (NSNotification*) aNotification | |
{ | |
// NSLog(@"WillFinish"); | |
} | |
- (void) applicationDidFinishLaunching: (NSNotification*) aNotification; | |
{ | |
NSPopUpDatePicker *alert = [NSPopUpDatePicker | |
alertWithMessageText:@"One" | |
defaultButton:@"OK" | |
alternateButton:@"Cancel" | |
otherButton:nil | |
informativeTextWithFormat:@"Blah blah"]; | |
[alert setDate:[NSDate date]]; | |
int32_t result = [alert runModal]; | |
NSDate *date = [alert date]; | |
NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; | |
[formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; | |
[formatter setDateFormat:@"yyyy-MM-dd"]; | |
NSString *stringFromDate = [formatter stringFromDate:date]; | |
printf("%d %s\n", result, [stringFromDate UTF8String]); | |
[[NSApplication sharedApplication] terminate:nil]; | |
} | |
@end | |
int main(int argc, char **argv) { | |
NSAutoreleasePool *shutup = [[NSAutoreleasePool alloc] init]; | |
NSApplication *application = [NSApplication sharedApplication]; | |
AppDelegate *applicationDelegate = [[AppDelegate alloc] init]; | |
[application setDelegate:applicationDelegate]; | |
[application run]; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment