-
Notifications
You must be signed in to change notification settings - Fork 2
/
macos.m
127 lines (105 loc) · 3.91 KB
/
macos.m
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "violet/core.h"
#include "violet/os.h"
#include "violet/array.h"
#include "violet/string.h"
#import <Foundation/Foundation.h>
#import <AppKit/NSOpenPanel.h>
#import <AppKit/NSSavePanel.h>
#import <AppKit/NSPopUpButton.h>
/* Unfortunately, we can't just call setAllowedFileTypes on the creation of the panel
* like we can in other saner OS file panels. MacOS makes us handle it ourselves,
* which results in all this callback stuff. */
@interface FileButtonHandler : NSObject {
id panel;
const file_dialog_filter_t *filters;
}
- (id)initWithPanel:(id)aPanel andFilters:(const file_dialog_filter_t*)filterList;
- (void)trigger:(id)sender;
@end
@implementation FileButtonHandler
- (id)initWithPanel:(id)aPanel andFilters:(const file_dialog_filter_t*)filterList
{
self = [super init];
panel = aPanel;
filters = filterList;
return self;
}
- (void)trigger:(id)sender
{
const int idx = max([sender indexOfSelectedItem], 0);
const file_dialog_filter_t *filter = &filters[idx];
const char *pattern = filter->pattern;
/* For some reason, the title doesn't update unless we call this. */
[sender synchronizeTitleAndSelectedItem];
/* NOTE(rgriege): this probably leaks, but it shouldn't happen often */
NSMutableArray<NSString*> *file_types = [NSMutableArray arrayWithCapacity:1];
/* MacOS also doesn't allow ';' delimeters, so we have to split them manually. */
do {
/* Don't include the "*." from the pattern - keep just the extension. */
const char *extension = &pattern[2];
const char *delim = strstr(extension, ";");
const char *end = delim ? delim : extension + strlen(extension);
const char *next = delim ? delim + 1 : extension + strlen(extension);
const u32 len = (u32)(end - extension);
log_error("adding filter %.*s", len, extension);
[file_types addObject:[[NSString alloc] initWithBytes:extension length:len encoding:NSUTF8StringEncoding]];
pattern = next;
} while (*pattern != '\0');
[panel setAllowedFileTypes:file_types];
}
@end
typedef struct file__ctx
{
NSPopUpButton *button;
FileButtonHandler *handler;
NSView *accessoryView;
} file__ctx_t;
static
file__ctx_t file__setup_panel(id panel, const file_dialog_filter_t filters[], u32 num_filters)
{
file__ctx_t ctx = {0};
NSRect frame = NSMakeRect(0, 10, 300, 22);
ctx.button = [[NSPopUpButton alloc] initWithFrame:frame pullsDown:NO];
ctx.handler = [[FileButtonHandler alloc] initWithPanel:panel andFilters:filters];
ctx.button.target = ctx.handler;
ctx.button.action = @selector(trigger:);
for (u32 i = 0; i < num_filters; ++i)
[ctx.button addItemWithTitle:[NSString stringWithUTF8String:filters[i].name]];
[ctx.handler trigger:ctx.button];
NSRect viewFrame = NSMakeRect(0, 0, 300, 42);
ctx.accessoryView = [[NSView alloc] initWithFrame:viewFrame];
[ctx.accessoryView addSubview:ctx.button];
[panel setAccessoryView:ctx.accessoryView];
[panel setAllowsOtherFileTypes: NO];
[panel setExtensionHidden: YES];
return ctx;
}
static
void file__destroy_panel(file__ctx_t ctx)
{
[ctx.handler release];
[ctx.button release];
[ctx.accessoryView release];
}
b32 file_open_dialog(char *fname, u32 fname_sz, const file_dialog_filter_t filters[], u32 num_filters)
{
NSOpenPanel *panel = [NSOpenPanel openPanel];
file__ctx_t ctx = file__setup_panel(panel, filters, num_filters);
b32 success = [panel runModal] == NSModalResponseOK
&& [[[panel URLs] objectAtIndex:0] getFileSystemRepresentation:fname maxLength:fname_sz] == YES;
file__destroy_panel(ctx);
return success;
}
b32 file_save_dialog(char *fname, u32 fname_sz, const file_dialog_filter_t filters[], u32 num_filters)
{
NSSavePanel *panel = [NSSavePanel savePanel];
file__ctx_t ctx = file__setup_panel(panel, filters, num_filters);
b32 success = [panel runModal] == NSModalResponseOK
&& [[panel URL] getFileSystemRepresentation:fname maxLength:fname_sz] == YES;
file__destroy_panel(ctx);
return success;
}
char *imhomedir(void)
{
return imstrcpy([NSHomeDirectory() UTF8String]);
}