bsnes/phoenix/cocoa/window.cpp

416 lines
11 KiB
C++

@implementation CocoaWindow : NSWindow
-(id) initWith:(phoenix::Window&)windowReference {
window = &windowReference;
NSUInteger style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask;
if(window->state.resizable) style |= NSResizableWindowMask;
if(self = [super initWithContentRect:NSMakeRect(0, 0, 640, 480) styleMask:style backing:NSBackingStoreBuffered defer:YES]) {
[self setDelegate:self];
[self setReleasedWhenClosed:NO];
[self setAcceptsMouseMovedEvents:YES];
[self setTitle:@""];
NSBundle* bundle = [NSBundle mainBundle];
NSDictionary* dictionary = [bundle infoDictionary];
NSString* applicationName = [dictionary objectForKey:@"CFBundleDisplayName"];
if(applicationName == nil) applicationName = [NSString stringWithUTF8String:phoenix::applicationState.name];
menuBar = [[NSMenu alloc] init];
NSMenuItem* item;
string text;
rootMenu = [[NSMenu alloc] init];
item = [[[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""] autorelease];
[item setSubmenu:rootMenu];
[menuBar addItem:item];
item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"About %@ ...", applicationName] action:@selector(menuAbout) keyEquivalent:@""] autorelease];
[item setTarget:self];
[rootMenu addItem:item];
[rootMenu addItem:[NSMenuItem separatorItem]];
item = [[[NSMenuItem alloc] initWithTitle:@"Preferences" action:@selector(menuPreferences) keyEquivalent:@""] autorelease];
[item setTarget:self];
[rootMenu addItem:item];
[rootMenu addItem:[NSMenuItem separatorItem]];
NSMenu* servicesMenu = [[[NSMenu alloc] initWithTitle:@"Services"] autorelease];
item = [[[NSMenuItem alloc] initWithTitle:@"Services" action:nil keyEquivalent:@""] autorelease];
[item setTarget:self];
[item setSubmenu:servicesMenu];
[rootMenu addItem:item];
[rootMenu addItem:[NSMenuItem separatorItem]];
[NSApp setServicesMenu:servicesMenu];
item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Hide %@", applicationName] action:@selector(hide:) keyEquivalent:@""] autorelease];
[item setTarget:NSApp];
[rootMenu addItem:item];
item = [[[NSMenuItem alloc] initWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@""] autorelease];
[item setTarget:NSApp];
[rootMenu addItem:item];
item = [[[NSMenuItem alloc] initWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""] autorelease];
[item setTarget:NSApp];
[rootMenu addItem:item];
[rootMenu addItem:[NSMenuItem separatorItem]];
item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Quit %@", applicationName] action:@selector(menuQuit) keyEquivalent:@""] autorelease];
[item setTarget:self];
[rootMenu addItem:item];
statusBar = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)];
[statusBar setAlignment:NSLeftTextAlignment];
[statusBar setBordered:YES];
[statusBar setBezeled:YES];
[statusBar setBezelStyle:NSTextFieldSquareBezel];
[statusBar setEditable:NO];
[statusBar setHidden:YES];
[[self contentView] addSubview:statusBar positioned:NSWindowBelow relativeTo:nil];
}
return self;
}
-(BOOL) canBecomeKeyWindow {
return YES;
}
-(BOOL) canBecomeMainWindow {
return YES;
}
-(void) windowDidBecomeMain:(NSNotification*)notification {
if(window->state.menu.size() > 0) {
[NSApp setMainMenu:menuBar];
}
}
-(void) windowDidMove:(NSNotification*)notification {
window->p.moveEvent();
}
-(void) windowDidResize:(NSNotification*)notification {
window->p.sizeEvent();
}
-(BOOL) windowShouldClose:(id)sender {
if(window->onClose) window->onClose();
else window->setVisible(false);
if(window->state.modal && !window->visible()) window->setModal(false);
return NO;
}
-(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender {
return DropPathsOperation(sender);
}
-(BOOL) performDragOperation:(id<NSDraggingInfo>)sender {
lstring paths = DropPaths(sender);
if(paths.empty()) return NO;
if(window->onDrop) window->onDrop(paths);
return YES;
}
-(NSMenu*) menuBar {
return menuBar;
}
-(void) menuAbout {
using phoenix::Application;
if(Application::Cocoa::onAbout) Application::Cocoa::onAbout();
}
-(void) menuPreferences {
using phoenix::Application;
if(Application::Cocoa::onPreferences) Application::Cocoa::onPreferences();
}
-(void) menuQuit {
using phoenix::Application;
if(Application::Cocoa::onQuit) Application::Cocoa::onQuit();
}
-(NSTextField*) statusBar {
return statusBar;
}
@end
namespace phoenix {
Window& pWindow::none() {
static Window* window = nullptr;
if(window == nullptr) window = new Window;
return *window;
}
void pWindow::append(Layout& layout) {
Geometry geometry = window.state.geometry;
geometry.x = geometry.y = 0;
layout.setGeometry(geometry);
statusBarReposition();
}
void pWindow::append(Menu& menu) {
@autoreleasepool {
[[cocoaWindow menuBar] addItem:menu.p.cocoaAction];
}
}
void pWindow::append(Widget& widget) {
if(widget.font().empty() && !window.state.widgetFont.empty()) {
widget.setFont(window.state.widgetFont);
}
@autoreleasepool {
[widget.p.cocoaView removeFromSuperview];
[[cocoaWindow contentView] addSubview:widget.p.cocoaView positioned:NSWindowAbove relativeTo:nil];
widget.p.setGeometry(widget.geometry());
[[cocoaWindow contentView] setNeedsDisplay:YES];
}
}
bool pWindow::focused() {
@autoreleasepool {
return [cocoaWindow isMainWindow] == YES;
}
}
Geometry pWindow::frameMargin() {
@autoreleasepool {
NSRect frame = [cocoaWindow frameRectForContentRect:NSMakeRect(0, 0, 640, 480)];
return {abs(frame.origin.x), frame.size.height - 480, frame.size.width - 640, abs(frame.origin.y)};
}
}
Geometry pWindow::geometry() {
@autoreleasepool {
NSRect area = [cocoaWindow contentRectForFrameRect:[cocoaWindow frame]];
area.size.height -= statusBarHeight();
return {area.origin.x, Desktop::size().height - area.origin.y - area.size.height, area.size.width, area.size.height};
}
}
void pWindow::remove(Layout& layout) {
@autoreleasepool {
[[cocoaWindow contentView] setNeedsDisplay:YES];
}
}
void pWindow::remove(Menu& menu) {
@autoreleasepool {
[[cocoaWindow menuBar] removeItem:menu.p.cocoaAction];
}
}
void pWindow::remove(Widget& widget) {
@autoreleasepool {
[widget.p.cocoaView removeFromSuperview];
[[cocoaWindow contentView] setNeedsDisplay:YES];
}
}
void pWindow::setBackgroundColor(Color color) {
@autoreleasepool {
[cocoaWindow
setBackgroundColor:[NSColor
colorWithCalibratedRed:color.red / 255.0
green:color.green / 255.0
blue:color.blue / 255.0
alpha:color.alpha / 255.0
]
];
}
}
void pWindow::setDroppable(bool droppable) {
@autoreleasepool {
if(droppable) {
[cocoaWindow registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
} else {
[cocoaWindow unregisterDraggedTypes];
}
}
}
void pWindow::setFocused() {
@autoreleasepool {
[cocoaWindow makeKeyAndOrderFront:nil];
}
}
void pWindow::setFullScreen(bool fullScreen) {
@autoreleasepool {
if(fullScreen == true) {
[NSApp setPresentationOptions:NSApplicationPresentationFullScreen];
[cocoaWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
[cocoaWindow toggleFullScreen:nil];
} else {
[cocoaWindow toggleFullScreen:nil];
[cocoaWindow setCollectionBehavior:NSWindowCollectionBehaviorDefault];
[NSApp setPresentationOptions:NSApplicationPresentationDefault];
}
}
}
void pWindow::setGeometry(Geometry geometry) {
locked = true;
@autoreleasepool {
[cocoaWindow
setFrame:[cocoaWindow
frameRectForContentRect:NSMakeRect(
geometry.x, Desktop::size().height - geometry.y - geometry.height,
geometry.width, geometry.height + statusBarHeight()
)
]
display:YES
];
for(auto& layout : window.state.layout) {
Geometry geometry = this->geometry();
geometry.x = geometry.y = 0;
layout.setGeometry(geometry);
}
statusBarReposition();
}
locked = false;
}
void pWindow::setMenuFont(string font) {
}
void pWindow::setMenuVisible(bool visible) {
}
void pWindow::setModal(bool modal) {
@autoreleasepool {
if(modal == true) {
[NSApp runModalForWindow:cocoaWindow];
} else {
[NSApp stopModal];
NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0];
[NSApp postEvent:event atStart:true];
}
}
}
void pWindow::setResizable(bool resizable) {
@autoreleasepool {
NSUInteger style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask;
if(resizable) style |= NSResizableWindowMask;
[cocoaWindow setStyleMask:style];
}
}
void pWindow::setStatusFont(string font) {
@autoreleasepool {
[[cocoaWindow statusBar] setFont:pFont::cocoaFont(font)];
}
statusBarReposition();
}
void pWindow::setStatusText(string text) {
@autoreleasepool {
[[cocoaWindow statusBar] setStringValue:[NSString stringWithUTF8String:text]];
}
}
void pWindow::setStatusVisible(bool visible) {
@autoreleasepool {
[[cocoaWindow statusBar] setHidden:!visible];
setGeometry(geometry());
}
}
void pWindow::setTitle(string text) {
@autoreleasepool {
[cocoaWindow setTitle:[NSString stringWithUTF8String:text]];
}
}
void pWindow::setVisible(bool visible) {
@autoreleasepool {
if(visible) [cocoaWindow makeKeyAndOrderFront:nil];
else [cocoaWindow orderOut:nil];
}
}
void pWindow::setWidgetFont(string font) {
}
void pWindow::constructor() {
@autoreleasepool {
cocoaWindow = [[CocoaWindow alloc] initWith:window];
NSColor* color = [[cocoaWindow backgroundColor] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
window.state.backgroundColor = Color(
(uint8_t)(255 * [color redComponent]),
(uint8_t)(255 * [color greenComponent]),
(uint8_t)(255 * [color blueComponent]),
(uint8_t)(255 * [color alphaComponent])
);
}
}
void pWindow::destructor() {
@autoreleasepool {
[cocoaWindow release];
}
}
void pWindow::moveEvent() {
if(locked == false && window.fullScreen() == false && window.visible() == true) {
Geometry geometry = this->geometry();
window.state.geometry.x = geometry.x;
window.state.geometry.y = geometry.y;
}
if(locked == false) {
if(window.onMove) window.onMove();
}
}
void pWindow::sizeEvent() {
if(locked == false && window.fullScreen() == false && window.visible() == true) {
Geometry geometry = this->geometry();
window.state.geometry.width = geometry.width;
window.state.geometry.height = geometry.height;
}
for(auto& layout : window.state.layout) {
Geometry geometry = this->geometry();
geometry.x = geometry.y = 0;
layout.setGeometry(geometry);
}
statusBarReposition();
if(locked == false) {
if(window.onSize) window.onSize();
}
}
unsigned pWindow::statusBarHeight() {
if(!window.state.statusVisible) return 0;
return Font::size(window.state.statusFont, " ").height + 6;
}
void pWindow::statusBarReposition() {
@autoreleasepool {
NSRect area = [cocoaWindow contentRectForFrameRect:[cocoaWindow frame]];
[[cocoaWindow statusBar] setFrame:NSMakeRect(0, 0, area.size.width, statusBarHeight())];
[[cocoaWindow contentView] setNeedsDisplay:YES];
}
}
}