rocket/ogl_editor/src/macosx/RocketView.m
2013-10-18 19:45:40 +02:00

516 lines
14 KiB
Objective-C

#import "RocketView.h"
#include "../Editor.h"
#include "../rlog.h"
#include "../Menu.h"
#include <emgui/emgui.h>
#include <emgui/gfxbackend.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h>
NSOpenGLContext* g_context = 0;
NSWindow* g_window = 0;
void Window_setTitle(const char* title);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Scan codes on Mac taken from http://boredzo.org/blog/archives/2007-05-22/virtual-key-codes
#define KEY_RETURN 36
#define KEY_TAB 48
#define KEY_DELETE 51
#define KEY_ESCAPE 53
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface MyMenuItem : NSMenuItem
{
}
- (BOOL)isHighlighted;
@end
@implementation MyMenuItem
- (BOOL)isHighlighted
{
return NO;
}
@end
@implementation RocketView
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-(void) updateEditor
{
Editor_timedUpdate();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self == nil)
return nil;
NSOpenGLPixelFormatAttribute attributes[4];
attributes[0] = NSOpenGLPFADoubleBuffer;
attributes[1] = 0;
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
oglContext = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];
[oglContext makeCurrentContext];
g_context = oglContext;
g_window = [self window];
EMGFXBackend_create();
Editor_create();
Editor_update();
const float framerate = 60;
const float frequency = 1.0f/framerate;
[NSTimer scheduledTimerWithTimeInterval:frequency
target:self selector:@selector(updateEditor)
userInfo:nil repeats:YES];
return self;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)lockFocus
{
NSOpenGLContext* context = oglContext;
[super lockFocus];
if ([context view] != self)
[context setView:self];
[context makeCurrentContext];
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)drawRect:(NSRect)frameRect
{
[oglContext update];
g_window = [self window];
EMGFXBackend_updateViewPort((int)frameRect.size.width, (int)frameRect.size.height);
Editor_setWindowSize((int)frameRect.size.width, (int)frameRect.size.height);
Editor_update();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int getModifierFlags(int flags)
{
int specialKeys = 0;
if (flags & NSShiftKeyMask)
specialKeys |= EMGUI_KEY_SHIFT;
if (flags & NSAlternateKeyMask)
specialKeys |= EMGUI_KEY_ALT;
if (flags & NSControlKeyMask)
specialKeys |= EMGUI_KEY_CTRL;
if (flags & NSCommandKeyMask)
specialKeys |= EMGUI_KEY_COMMAND;
return specialKeys;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)keyDown:(NSEvent *)theEvent
{
NSString* key = [theEvent charactersIgnoringModifiers];
unichar keyChar = 0;
if ([key length] == 0)
return;
keyChar = [key characterAtIndex:0];
int keyCode = keyChar;
int specialKeys = getModifierFlags([theEvent modifierFlags]);
if ([theEvent modifierFlags] & NSNumericPadKeyMask)
{
switch (keyChar)
{
case NSLeftArrowFunctionKey: keyCode = EMGUI_KEY_ARROW_LEFT; break;
case NSRightArrowFunctionKey: keyCode = EMGUI_KEY_ARROW_RIGHT; break;
case NSUpArrowFunctionKey: keyCode = EMGUI_KEY_ARROW_UP; break;
case NSDownArrowFunctionKey: keyCode = EMGUI_KEY_ARROW_DOWN; break;
}
}
else
{
switch ([theEvent keyCode])
{
case KEY_TAB : keyCode = EMGUI_KEY_TAB; break;
case KEY_DELETE : keyCode = EMGUI_KEY_BACKSPACE; break;
case KEY_RETURN : keyCode = EMGUI_KEY_ENTER; break;
case KEY_ESCAPE : keyCode = EMGUI_KEY_ESC; break;
case NSPageDownFunctionKey: keyCode = EMGUI_KEY_PAGE_DOWN; break;
case NSPageUpFunctionKey: keyCode = EMGUI_KEY_PAGE_UP; break;
}
}
Emgui_sendKeyinput(keyCode, specialKeys);
if (!Editor_keyDown(keyCode, [theEvent keyCode], specialKeys))
[super keyDown:theEvent];
Editor_update();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)acceptsFirstResponder
{
return YES;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-(void) viewWillMoveToWindow:(NSWindow *)newWindow
{
NSTrackingArea* trackingArea = [[NSTrackingArea alloc] initWithRect:[self frame]
options: (NSTrackingMouseMoved | NSTrackingActiveAlways) owner:self userInfo:nil];
[self addTrackingArea:trackingArea];
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)mouseMoved:(NSEvent *)event
{
NSWindow* window = [self window];
NSRect originalFrame = [window frame];
NSPoint location = [window mouseLocationOutsideOfEventStream];
NSRect adjustFrame = [NSWindow contentRectForFrameRect: originalFrame styleMask: NSTitledWindowMask];
Emgui_setMousePos((int)location.x, (int)adjustFrame.size.height - (int)location.y);
Editor_update();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)mouseDragged:(NSEvent *)event
{
NSWindow* window = [self window];
NSRect originalFrame = [window frame];
NSPoint location = [window mouseLocationOutsideOfEventStream];
NSRect adjustFrame = [NSWindow contentRectForFrameRect: originalFrame styleMask: NSTitledWindowMask];
Emgui_setMousePos((int)location.x, (int)adjustFrame.size.height - (int)location.y);
Editor_update();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)scrollWheel:(NSEvent *)theEvent
{
float x = (float)[theEvent deltaX];
float y = (float)[theEvent deltaY];
int flags = getModifierFlags([theEvent modifierFlags]);
//printf("%f %f %d\n", x, y, flags);
Editor_scroll(-x, -y, flags);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)mouseUp:(NSEvent *)event
{
Emgui_setMouseLmb(0);
Editor_update();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)mouseDown:(NSEvent *)event
{
NSWindow *window = [self window];
NSRect originalFrame = [window frame];
NSPoint location = [window mouseLocationOutsideOfEventStream];
NSRect adjustFrame = [NSWindow contentRectForFrameRect: originalFrame styleMask: NSTitledWindowMask];
Emgui_setMousePos((int)location.x, (int)adjustFrame.size.height - (int)location.y);
Emgui_setMouseLmb(1);
Editor_update();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-(BOOL) isOpaque
{
return YES;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CFStringRef createStringForKey(CGKeyCode keyCode)
{
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef layoutData =
TISGetInputSourceProperty(currentKeyboard,
kTISPropertyUnicodeKeyLayoutData);
if (!layoutData)
return 0;
const UCKeyboardLayout *keyboardLayout =
(const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
UInt32 keysDown = 0;
UniChar chars[4];
UniCharCount realLength;
UCKeyTranslate(keyboardLayout,
keyCode,
kUCKeyActionDisplay,
0,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
&keysDown,
sizeof(chars) / sizeof(chars[0]),
&realLength,
chars);
CFRelease(currentKeyboard);
return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)onMenuPress:(id)sender
{
int id = (int)((NSButton*)sender).tag;
Editor_menuEvent(id);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int s_characterToKeyCode[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x27, // '''
0, 0, 0, 0,
0x2b, // ','
0x1b, // '-'
0x2f, // '.'
0x2c, // '/'
0x1d, // '0'
0x12, // '1'
0x13, // '2'
0x14, // '3'
0x15, // '4'
0x17, // '5'
0x16, // '6'
0x1a, // '7'
0x1c, // '8'
0x19, // '9'
0,
0x29, // ';'
0,
0x18, // '='
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x21, // '['
0x2a, // '\'
0x1e, // ']'
0,
0,
0x32, // '`'
0,
0x0b, // 'b'
0x08, // 'c'
0x02, // 'd'
0x0e, // 'e'
0x03, // 'f'
0x05, // 'g'
0x04, // 'h'
0x22, // 'i'
0x26, // 'j'
0x28, // 'k'
0x25, // 'l'
0x2e, // 'm'
0x2d, // 'n'
0x1f, // 'o'
0x23, // 'p'
0x0c, // 'q'
0x0f, // 'r'
0x01, // 's'
0x11, // 't'
0x20, // 'u'
0x09, // 'v'
0x0d, // 'w'
0x07, // 'x'
0x10, // 'y'
0x06, // 'z'
0, 0, 0, 0, 0,
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
NSString* convertKeyCodeToString(int key)
{
if (key < 128)
{
// first try to translate it and if that doesn't work use it as is
NSString* charName = (NSString*)createStringForKey(s_characterToKeyCode[key]);
if (charName)
return charName;
return [NSString stringWithFormat:@"%c", (char)key];
}
else
{
switch (key)
{
case EMGUI_KEY_ARROW_UP: return [NSString stringWithFormat:@"%C", (uint16_t)0x2191];
case EMGUI_KEY_ARROW_DOWN: return [NSString stringWithFormat:@"%C", (uint16_t)0x2193];
case EMGUI_KEY_ARROW_LEFT: return [NSString stringWithFormat:@"%C", (uint16_t)0x2190];
case EMGUI_KEY_ARROW_RIGHT: return [NSString stringWithFormat:@"%C", (uint16_t)0x2192];
case EMGUI_KEY_ESC : return [NSString stringWithFormat:@"%C", (uint16_t)0x238b];
case EMGUI_KEY_ENTER : return [NSString stringWithFormat:@"%C", (uint16_t)NSCarriageReturnCharacter];
case EMGUI_KEY_SPACE : return @" ";
case EMGUI_KEY_BACKSPACE : return [NSString stringWithFormat:@"%C",(uint16_t)0x232b];
case EMGUI_KEY_TAB : return [NSString stringWithFormat:@"%C",(uint16_t)0x21e4];
case EMGUI_KEY_PAGE_UP : return [NSString stringWithFormat:@"%C",(uint16_t)0x21de];
case EMGUI_KEY_PAGE_DOWN : return [NSString stringWithFormat:@"%C",(uint16_t)0x21df];
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void buildSubMenu(NSMenu* menu, MenuDescriptor menuDesc[])
{
MenuDescriptor* desc = &menuDesc[0];
[menu removeAllItems];
while (desc->name)
{
NSString* name = [NSString stringWithUTF8String: desc->name];
if (desc->id == EDITOR_MENU_SEPARATOR)
{
[menu addItem:[NSMenuItem separatorItem]];
}
else if (desc->id == EDITOR_MENU_SUB_MENU)
{
MyMenuItem* newItem = [[MyMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:name action:NULL keyEquivalent:@""];
NSMenu* newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:name];
[newItem setSubmenu:newMenu];
[newMenu release];
[menu addItem:newItem];
[newItem release];
}
else
{
int mask = 0;
MyMenuItem* newItem = [[MyMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""];
[newItem setTag:desc->id];
if (desc->macMod & EMGUI_KEY_COMMAND)
mask |= NSCommandKeyMask;
if (desc->macMod & EMGUI_KEY_SHIFT)
mask |= NSShiftKeyMask;
if (desc->macMod & EMGUI_KEY_CTRL)
mask |= NSControlKeyMask;
if (desc->macMod & EMGUI_KEY_ALT)
mask |= NSAlternateKeyMask;
NSString* key = convertKeyCodeToString(desc->key);
if (key)
{
[newItem setKeyEquivalentModifierMask: mask];
[newItem setKeyEquivalent:key];
}
else
{
fprintf(stderr, "Unable to map keyboard shortcut for %s\n", desc->name);
}
[newItem setOnStateImage: newItem.offStateImage];
[menu addItem:newItem];
[newItem release];
}
desc++;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Window_buildMenu()
{
NSMenu* fileMenu = [[[NSApp mainMenu] itemWithTitle:@"File"] submenu];
NSMenu* editMenu = [[[NSApp mainMenu] itemWithTitle:@"Edit"] submenu];
NSMenu* viewMenu = [[[NSApp mainMenu] itemWithTitle:@"View"] submenu];
buildSubMenu(fileMenu, g_fileMenu);
buildSubMenu(editMenu, g_editMenu);
buildSubMenu(viewMenu, g_viewMenu);
Window_setTitle("RocketEditor" EDITOR_VERSION);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Window_populateRecentList(const char** files)
{
NSMenu* fileMenu = [[[NSApp mainMenu] itemWithTitle:@"File"] submenu];
NSMenu* recentItems = [[fileMenu itemWithTitle:@"Recent Files"] submenu];
[recentItems removeAllItems];
for (int i = 0; i < 4; ++i)
{
const char* filename = files[i];
if (!strcmp(filename, ""))
continue;
NSString* name = [NSString stringWithUTF8String: filename];
NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""];
[newItem setTag:EDITOR_MENU_RECENT_FILE_0 + i];
[newItem setRepresentedObject:[NSString stringWithFormat:@"%d",i]];
[newItem setKeyEquivalentModifierMask: NSCommandKeyMask];
[newItem setKeyEquivalent:[NSString stringWithFormat:@"%d",i + 1]];
[recentItems addItem:newItem];
[newItem release];
}
}
@end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void swapBuffers()
{
[g_context flushBuffer];
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Window_setTitle(const char* title)
{
[g_window setTitle:[NSString stringWithUTF8String:title]];
}