TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
6.4 KiB
197 lines
6.4 KiB
#include <AppKit/AppKit.h>
|
|
#include <phpx.h>
|
|
|
|
static NSString *to_ns_string(const php::Str &value)
|
|
{
|
|
NSString *result = [[NSString alloc] initWithBytes:value.data()
|
|
length:value.length()
|
|
encoding:NSUTF8StringEncoding];
|
|
return result == nil ? @"" : result;
|
|
}
|
|
|
|
@interface TypePHPAppKitBridge : NSObject <NSWindowDelegate>
|
|
|
|
@property(nonatomic, strong) NSWindow *window;
|
|
@property(nonatomic, strong) NSMutableDictionary<NSNumber *, NSControl *> *controls;
|
|
@property(nonatomic) NSInteger nextControlId;
|
|
@property(nonatomic) NSInteger pendingControlId;
|
|
@property(nonatomic) BOOL running;
|
|
|
|
- (void)controlActivated:(NSControl *)sender;
|
|
|
|
@end
|
|
|
|
@implementation TypePHPAppKitBridge
|
|
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
if (self != nil) {
|
|
self.controls = [[NSMutableDictionary alloc] init];
|
|
self.nextControlId = 1;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)controlActivated:(NSControl *)sender
|
|
{
|
|
self.pendingControlId = sender.tag;
|
|
}
|
|
|
|
- (void)windowWillClose:(NSNotification *)notification
|
|
{
|
|
(void) notification;
|
|
self.running = NO;
|
|
}
|
|
|
|
@end
|
|
|
|
static __strong TypePHPAppKitBridge *bridge = nil;
|
|
|
|
static void install_application_menu(NSString *applicationName)
|
|
{
|
|
NSMenu *menuBar = [[NSMenu alloc] init];
|
|
NSMenuItem *applicationMenuItem = [[NSMenuItem alloc] init];
|
|
[menuBar addItem:applicationMenuItem];
|
|
NSApp.mainMenu = menuBar;
|
|
|
|
NSMenu *applicationMenu = [[NSMenu alloc] init];
|
|
NSString *quitTitle = [@"Quit " stringByAppendingString:applicationName];
|
|
NSMenuItem *quitItem = [[NSMenuItem alloc] initWithTitle:quitTitle
|
|
action:@selector(terminate:)
|
|
keyEquivalent:@"q"];
|
|
[applicationMenu addItem:quitItem];
|
|
applicationMenuItem.submenu = applicationMenu;
|
|
}
|
|
|
|
static NSInteger store_control(NSControl *control)
|
|
{
|
|
const NSInteger controlId = bridge.nextControlId++;
|
|
control.tag = controlId;
|
|
bridge.controls[@(controlId)] = control;
|
|
return controlId;
|
|
}
|
|
|
|
void php_ui_app_init(php::Str applicationName)
|
|
{
|
|
@autoreleasepool {
|
|
NSApplication *application = NSApplication.sharedApplication;
|
|
application.activationPolicy = NSApplicationActivationPolicyRegular;
|
|
bridge = [[TypePHPAppKitBridge alloc] init];
|
|
install_application_menu(to_ns_string(applicationName));
|
|
[application finishLaunching];
|
|
}
|
|
}
|
|
|
|
void php_ui_create_window(php::Str title, php::Int width, php::Int height)
|
|
{
|
|
@autoreleasepool {
|
|
const NSRect frame = NSMakeRect(0, 0, static_cast<CGFloat>(width), static_cast<CGFloat>(height));
|
|
const NSWindowStyleMask style = NSWindowStyleMaskTitled |
|
|
NSWindowStyleMaskClosable |
|
|
NSWindowStyleMaskMiniaturizable |
|
|
NSWindowStyleMaskResizable;
|
|
bridge.window = [[NSWindow alloc] initWithContentRect:frame
|
|
styleMask:style
|
|
backing:NSBackingStoreBuffered
|
|
defer:NO];
|
|
bridge.window.releasedWhenClosed = NO;
|
|
bridge.window.delegate = bridge;
|
|
bridge.window.title = to_ns_string(title);
|
|
bridge.window.minSize = NSMakeSize(480, 300);
|
|
[bridge.window center];
|
|
}
|
|
}
|
|
|
|
php::Int php_ui_add_label(
|
|
php::Str text,
|
|
php::Int x,
|
|
php::Int y,
|
|
php::Int width,
|
|
php::Int height,
|
|
php::Int fontSize,
|
|
php::Bool bold)
|
|
{
|
|
@autoreleasepool {
|
|
NSTextField *label = [NSTextField wrappingLabelWithString:to_ns_string(text)];
|
|
label.frame = NSMakeRect(
|
|
static_cast<CGFloat>(x),
|
|
static_cast<CGFloat>(y),
|
|
static_cast<CGFloat>(width),
|
|
static_cast<CGFloat>(height));
|
|
label.font = bold
|
|
? [NSFont systemFontOfSize:static_cast<CGFloat>(fontSize)
|
|
weight:NSFontWeightSemibold]
|
|
: [NSFont systemFontOfSize:static_cast<CGFloat>(fontSize)];
|
|
label.alignment = NSTextAlignmentCenter;
|
|
label.autoresizingMask = NSViewWidthSizable | NSViewMinYMargin;
|
|
[bridge.window.contentView addSubview:label];
|
|
return static_cast<php::Int>(store_control(label));
|
|
}
|
|
}
|
|
|
|
php::Int php_ui_add_button(
|
|
php::Str title,
|
|
php::Int x,
|
|
php::Int y,
|
|
php::Int width,
|
|
php::Int height)
|
|
{
|
|
@autoreleasepool {
|
|
NSButton *button = [NSButton buttonWithTitle:to_ns_string(title)
|
|
target:bridge
|
|
action:@selector(controlActivated:)];
|
|
button.frame = NSMakeRect(
|
|
static_cast<CGFloat>(x),
|
|
static_cast<CGFloat>(y),
|
|
static_cast<CGFloat>(width),
|
|
static_cast<CGFloat>(height));
|
|
button.bezelStyle = NSBezelStyleRounded;
|
|
button.keyEquivalent = @"\r";
|
|
button.autoresizingMask = NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin;
|
|
[bridge.window.contentView addSubview:button];
|
|
return static_cast<php::Int>(store_control(button));
|
|
}
|
|
}
|
|
|
|
void php_ui_set_control_text(php::Int controlId, php::Str text)
|
|
{
|
|
@autoreleasepool {
|
|
NSControl *control = bridge.controls[@(static_cast<NSInteger>(controlId))];
|
|
if (control != nil) {
|
|
control.stringValue = to_ns_string(text);
|
|
}
|
|
}
|
|
}
|
|
|
|
void php_ui_show_window()
|
|
{
|
|
@autoreleasepool {
|
|
[bridge.window makeKeyAndOrderFront:nil];
|
|
bridge.running = YES;
|
|
[NSApp activateIgnoringOtherApps:YES];
|
|
}
|
|
}
|
|
|
|
php::Int php_ui_next_event()
|
|
{
|
|
while (bridge.running) {
|
|
@autoreleasepool {
|
|
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny
|
|
untilDate:NSDate.distantFuture
|
|
inMode:NSDefaultRunLoopMode
|
|
dequeue:YES];
|
|
if (event != nil) {
|
|
[NSApp sendEvent:event];
|
|
[NSApp updateWindows];
|
|
}
|
|
|
|
if (bridge.pendingControlId != 0) {
|
|
const NSInteger controlId = bridge.pendingControlId;
|
|
bridge.pendingControlId = 0;
|
|
return static_cast<php::Int>(controlId);
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|