20#if defined(WITH_COCOA) || defined(DOXYGEN_API)
47 NSTouchBarItemIdentifier
key;
58 {
@"openttd.pause", SPR_IMG_PAUSE, MTHK_PAUSE,
@"Pause" },
59 {
@"openttd.fastforward", SPR_IMG_FASTFORWARD, MTHK_FASTFORWARD,
@"Fast Forward" },
60 {
@"openttd.zoom_in", SPR_IMG_ZOOMIN, MTHK_ZOOM_IN,
@"Zoom In" },
61 {
@"openttd.zoom_out", SPR_IMG_ZOOMOUT, MTHK_ZOOM_OUT,
@"Zoom Out" },
62 {
@"openttd.build_rail", SPR_IMG_BUILDRAIL, MTHK_BUILD_RAIL,
@"Rail" },
63 {
@"openttd.build_road", SPR_IMG_BUILDROAD, MTHK_BUILD_ROAD,
@"Road" },
64 {
@"openttd.build_tram", SPR_IMG_BUILDTRAMS, MTHK_BUILD_TRAM,
@"Tram" },
65 {
@"openttd.build_docks", SPR_IMG_BUILDWATER, MTHK_BUILD_DOCKS,
@"Docks" },
66 {
@"openttd.build_airport", SPR_IMG_BUILDAIR, MTHK_BUILD_AIRPORT,
@"Airport" }
71@interface OTTDMain : NSObject <NSApplicationDelegate>
92 i += c < 0x10000 ? 1 : 2;
106 auto it = view.begin();
107 const auto end = view.end();
108 for (NSUInteger i = 0; it != end && i < count; ++it) {
109 i += *it < 0x10000 ? 1 : 2;
111 return it.GetByteOffset();
121 std::vector<char32_t> unicode_str;
124 for (NSUInteger i = 0; i < s.length; i++) {
125 unichar c = [ s characterAtIndex:i ];
132 unicode_str.push_back(c);
145 delete[] (
const uint32_t *)data;
156 if (!SpriteExists(sprite_id))
return nullptr;
161 if (!buffer)
return nullptr;
164 if (!data)
return nullptr;
166 CGBitmapInfo info = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
168 CFAutoRelease<CGImage> bitmap(CGImageCreate(dim.width, dim.height, 8, 32, dim.width * 4, colour_space.get(), info, data.get(),
nullptr,
false, kCGRenderingIntentDefault));
169 if (!bitmap)
return nullptr;
171 return [ [ [ NSImage alloc ] initWithCGImage:bitmap.get() size:NSZeroSize ] autorelease ];
178@implementation OTTDMain
187 NSEventType type = NSEventTypeApplicationDefined;
188 NSEvent *
event = [
NSEvent otherEventWithType:type location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0 ];
189 [
NSApp postEvent:event atStart:YES ];
196- (void)launchGameEngine: (NSNotification*) note
201 NSEvent *e = [ [
NSEvent alloc ] init ];
202 [
drv->cocoaview cursorUpdate:e ];
209 [
self performSelectorOnMainThread:@selector(stopEngine) withObject:nil waitUntilDone:FALSE ];
216- (void) applicationDidFinishLaunching: (NSNotification*) note
219 [ [
NSNotificationCenter defaultCenter ] addObserver:
self selector:@selector(launchGameEngine:) name:OTTDMainLaunchGameEngine object:nil ];
222 [ [
NSNotificationCenter defaultCenter ] postNotificationName:OTTDMainLaunchGameEngine object:nil ];
230- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*) sender
232 HandleExitGameRequest();
234 return NSTerminateCancel;
254- (BOOL)applicationSupportsSecureRestorableState:(NSApplication*) sender
265 NSString *appName =
@"OpenTTD";
266 NSMenu *appleMenu = [ [ NSMenu alloc ] initWithTitle:appName ];
269 NSString *title = [ @"About " stringByAppendingString:appName ];
270 [ appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@"" ];
272 [ appleMenu addItem:[ NSMenuItem separatorItem ] ];
274 title = [ @"Hide " stringByAppendingString:appName ];
275 [ appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h" ];
277 NSMenuItem *menuItem = [ appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h" ];
278 [ menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand) ];
280 [ appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@"" ];
282 [ appleMenu addItem:[ NSMenuItem separatorItem ] ];
284 title = [ @"Quit " stringByAppendingString:appName ];
285 [ appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q" ];
288 menuItem = [ [ NSMenuItem alloc ] initWithTitle:@"" action:nil keyEquivalent:@"" ];
289 [ menuItem setSubmenu:appleMenu ];
290 [ [ NSApp mainMenu ] addItem:menuItem ];
295 if ([ NSApp respondsToSelector:
@selector(setAppleMenu:) ]) {
296 [ NSApp performSelector:@selector(setAppleMenu:) withObject:appleMenu ];
300 [ appleMenu release ];
301 [ menuItem release ];
309 NSMenu *windowMenu = [ [ NSMenu alloc ] initWithTitle:@"Window" ];
312 [ windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m" ];
315 NSMenuItem *menuItem = [ [ NSMenuItem alloc ] initWithTitle:@"Window" action:nil keyEquivalent:@"" ];
316 [ menuItem setSubmenu:windowMenu ];
317 [ [ NSApp mainMenu ] addItem:menuItem ];
320 [ windowMenu addItemWithTitle:@"Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"^f" ];
323 [ NSApp setWindowsMenu:windowMenu ];
326 [ windowMenu release ];
327 [ menuItem release ];
336 ProcessSerialNumber psn = { 0, kCurrentProcess };
339 [ NSApplication sharedApplication ];
342 OSStatus returnCode = TransformProcessType(&psn, kProcessTransformToForegroundApplication);
343 if (returnCode != 0)
Debug(driver, 0,
"Could not change to foreground application. Error {}", (
int)returnCode);
346 if ([ NSWindow respondsToSelector:
@selector(setAllowsAutomaticWindowTabbing:) ]) {
348 [
NSWindow performSelector:@selector(setAllowsAutomaticWindowTabbing:) withObject:nil];
352 [ [ NSApplication sharedApplication ] setActivationPolicy:NSApplicationActivationPolicyRegular ];
353 [ [ NSApplication sharedApplication ] activateIgnoringOtherApps:YES ];
356 [ NSApp setMainMenu:[ [ NSMenu alloc ] init ] ];
362 [ NSApp setDelegate:_ottd_main ];
385void CocoaDialog(std::string_view title, std::string_view message, std::string_view buttonLabel)
393 fmt::print(stderr,
"{}: {}\n", title, message);
398 NSAlert *alert = [ [ NSAlert alloc ] init ];
399 [ alert setAlertStyle: NSAlertStyleCritical ];
400 [ alert setMessageText:[ [ NSString alloc ] initWithBytes:title.data() length:title.size() encoding:NSUTF8StringEncoding ] ];
401 [ alert setInformativeText:[ [ NSString alloc ] initWithBytes:message.data() length:message.size() encoding:NSUTF8StringEncoding ] ];
402 [ alert addButtonWithTitle: [ [ NSString alloc ] initWithBytes:buttonLabel.data() length:buttonLabel.size() encoding:NSUTF8StringEncoding ] ];
416@implementation NSCursor (OTTD_CocoaCursor)
424 unsigned char clearGIFBytes[] = {
425 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80, 0x00,
426 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x01, 0x00,
427 0x00, 0x01, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,
428 0x00, 0x02, 0x0E, 0x8C, 0x8F, 0xA9, 0xCB, 0xED, 0x0F, 0xA3, 0x9C, 0xB4,
429 0xDA, 0x8B, 0xB3, 0x3E, 0x05, 0x00, 0x3B};
430 NSData *clearGIFData = [
NSData dataWithBytesNoCopy:&clearGIFBytes[0] length:55 freeWhenDone:NO ];
431 NSImage *clearImg = [ [
NSImage alloc ] initWithData:clearGIFData ];
432 return [ [
NSCursor alloc ] initWithImage:clearImg hotSpot:NSMakePoint(0.0,0.0) ];
450- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag driver:(
VideoDriver_Cocoa *)drv
452 if (self = [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ]) {
454 self->touchbar_created =
false;
456 [
self setContentMinSize:NSMakeSize(64.0f, 64.0f) ];
459 NSString *nsscaption = [ [
NSString alloc ] initWithBytes:caption.data() length:caption.size() encoding:NSUTF8StringEncoding ];
460 [
self setTitle:nsscaption ];
461 [
self setMiniwindowTitle:nsscaption ];
473- (void)setFrame:(NSRect)frameRect display:(BOOL)flag
475 [
super setFrame:frameRect display:flag ];
480- (void)touchBarButtonAction:(
id)sender
482 NSButton *btn = (NSButton *)sender;
488- (nullable NSTouchBar *)makeTouchBar
491 NSMutableArray<NSTouchBarItemIdentifier> *button_ids = [ [ NSMutableArray alloc ] init ];
493 [ button_ids addObject:button.key ];
495 [ button_ids addObject:NSTouchBarItemIdentifierOtherItemsProxy ];
497 NSTouchBar *bar = [ [ NSTouchBar alloc ] init ];
499 bar.defaultItemIdentifiers = button_ids;
500 [ button_ids release ];
502 self->touchbar_created =
true;
507- (nullable NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
512 NSButton *button = [ NSButton buttonWithTitle:item->fallback_text target:
self action:@selector(touchBarButtonAction:) ];
513 button.identifier = identifier;
514 button.imageScaling = NSImageScaleProportionallyDown;
516 NSCustomTouchBarItem *tb_item = [ [ NSCustomTouchBarItem alloc] initWithIdentifier:identifier ];
517 tb_item.view = button;
521- (void)refreshSystemSprites
523 if (!self->touchbar_created || ![ self respondsToSelector:
@selector(touchBar) ] || self.touchBar == nil)
return;
526 for (NSTouchBarItemIdentifier ident in self.touchBar.itemIdentifiers) {
530 NSCustomTouchBarItem *tb_item = [
self.touchBar itemForIdentifier:ident ];
531 NSButton *button = tb_item.view;
536 CGFloat max_dim = std::max(image.size.width, image.size.height);
538 CGFloat scale = 22.0 / max_dim;
539 image.size = NSMakeSize(image.size.width * scale, image.size.height * scale);
542 button.image = image;
543 button.imagePosition = NSImageOnly;
546 button.imagePosition = NSNoImage;
554 float _current_magnification;
560- (instancetype)initWithFrame:(NSRect)frameRect
562 if (self = [ super initWithFrame:frameRect ]) {
563 self->_use_hidpi =
_allow_hidpi_window && [
self respondsToSelector:@selector(convertRectToBacking:) ] && [
self respondsToSelector:@selector(convertRectFromBacking:) ];
568- (NSRect)getRealRect:(NSRect)rect
570 return _use_hidpi ? [
self convertRectToBacking:rect ] : rect;
573- (NSRect)getVirtualRect:(NSRect)rect
575 return _use_hidpi ? [
self convertRectFromBacking:rect ] : rect;
578- (CGFloat)getContentsScale
580 return _use_hidpi && self.window != nil ? [
self.window backingScaleFactor ] : 1.0f;
592- (void)setNeedsDisplayInRect:(NSRect)invalidRect
595 for ( NSView *v in [ self subviews ]) {
596 [ v setNeedsDisplayInRect:[ v convertRect:invalidRect fromView:
self ] ];
604- (void)cursorUpdate:(NSEvent *)event
606 [ (_game_mode == GM_BOOTSTRAP ? [
NSCursor arrowCursor ] : [
NSCursor clearCocoaCursor ]) set ];
609- (void)viewWillMoveToWindow:(NSWindow *)win
611 for (NSTrackingArea *a in [ self trackingAreas ]) {
612 [
self removeTrackingArea:a ];
616- (void)viewDidMoveToWindow
619 NSTrackingAreaOptions track_opt = NSTrackingInVisibleRect | NSTrackingActiveInActiveApp | NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate;
620 NSTrackingArea *track = [ [ NSTrackingArea alloc ] initWithRect:[
self bounds ] options:track_opt owner:
self userInfo:nil ];
621 [
self addTrackingArea:track ];
628- (void)mouseEntered:(NSEvent *)theEvent
630 _cursor.in_window =
true;
636- (void)mouseExited:(NSEvent *)theEvent
638 if ([ self window ] != nil) UndrawMouseCursor();
639 _cursor.in_window =
false;
647- (NSPoint)mousePositionFromEvent:(NSEvent *)e
649 NSPoint pt = e.locationInWindow;
650 if ([ e window ] == nil) pt = [
self.
window convertRectFromScreen:NSMakeRect(pt.x, pt.y, 0, 0) ].origin;
651 pt = [
self convertPoint:pt fromView:nil ];
653 return [
self getRealRect:NSMakeRect(pt.x,
self.bounds.size.height - pt.y, 0, 0) ].origin;
660- (void)internalMouseMoveEvent:(NSEvent *)event
662 if (_cursor.fix_at) {
663 _cursor.UpdateCursorPositionRelative(event.deltaX * self.getContentsScale, event.deltaY * self.getContentsScale);
666 _cursor.UpdateCursorPosition(pt.x, pt.y);
677 bool cur_fix = _cursor.fix_at;
681 if (cur_fix != _cursor.fix_at) CGAssociateMouseAndMouseCursorPosition(!_cursor.fix_at);
689- (BOOL)emulateRightButton:(NSEvent *)event
691 uint32_t keymask = 0;
692 if (
_settings_client.gui.right_mouse_btn_emulation == RMBE_COMMAND) keymask |= NSEventModifierFlagCommand;
693 if (
_settings_client.gui.right_mouse_btn_emulation == RMBE_CONTROL) keymask |= NSEventModifierFlagControl;
695 return (event.modifierFlags & keymask) != 0;
702- (void)mouseMoved:(NSEvent *)event
711- (void)mouseDragged:(NSEvent *)event
720- (void)mouseDown:(NSEvent *)event
722 if ([ self emulateRightButton:event ]) {
723 self->_emulated_down =
true;
735- (void)mouseUp:(NSEvent *)event
737 if (self->_emulated_down) {
738 self->_emulated_down =
false;
751- (void)rightMouseDragged:(NSEvent *)event
760- (void)rightMouseDown:(NSEvent *)event
771- (void)rightMouseUp:(NSEvent *)event
781- (void)scrollWheel:(NSEvent *)event
783 if ([ event deltaY ] > 0.0) {
785 }
else if ([ event deltaY ] < 0.0) {
794 if ([ event respondsToSelector:
@selector(hasPreciseScrollingDeltas) ]) {
796 if (![ event hasPreciseScrollingDeltas ])
return;
798 deltaX = [
event scrollingDeltaX ] * 0.5f;
799 deltaY = [
event scrollingDeltaY ] * 0.5f;
801 deltaX = [
event deltaX ] * 5;
802 deltaY = [
event deltaY ] * 5;
805 _cursor.h_wheel -=
static_cast<float>(deltaX *
_settings_client.gui.scrollwheel_multiplier);
806 _cursor.v_wheel -=
static_cast<float>(deltaY *
_settings_client.gui.scrollwheel_multiplier);
807 _cursor.wheel_moved =
true;
814- (void)magnifyWithEvent:(NSEvent *)event
817 self->_current_magnification += [
event magnification ] * 5.0f;
819 while (self->_current_magnification >= 1.0f) {
820 self->_current_magnification -= 1.0f;
824 while (self->_current_magnification <= -1.0f) {
825 self->_current_magnification += 1.0f;
835- (void)endGestureWithEvent:(NSEvent *)event
838 self->_current_magnification = 0.0f;
850- (BOOL)internalHandleKeycode:(
unsigned short)keycode unicode:(
char32_t)unicode pressed:(BOOL)down modifiers:(NSUInteger)modifiers
854 case QZ_DOWN:
SB(
_dirkeys, 3, 1, down);
break;
855 case QZ_LEFT:
SB(
_dirkeys, 0, 1, down);
break;
856 case QZ_RIGHT:
SB(
_dirkeys, 2, 1, down);
break;
867 if (down && (modifiers & NSEventModifierFlagCommand)) {
873 if (down &&
EditBoxInGlobalFocus() && (modifiers & (NSEventModifierFlagCommand | NSEventModifierFlagControl))) {
878 if (down &&
EditBoxInGlobalFocus() && (modifiers & (NSEventModifierFlagCommand | NSEventModifierFlagControl))) {
884 BOOL interpret_keys = YES;
887 auto vk = std::ranges::find(_vk_mapping, keycode, &CocoaVkMapping::vk_from);
888 uint32_t pressed_key = vk != std::end(_vk_mapping) ? vk->map_to : 0;
890 if (modifiers & NSEventModifierFlagShift) pressed_key |= WKC_SHIFT;
891 if (modifiers & NSEventModifierFlagControl) pressed_key |= (
_settings_client.gui.right_mouse_btn_emulation != RMBE_CONTROL ? WKC_CTRL : WKC_META);
892 if (modifiers & NSEventModifierFlagOption) pressed_key |= WKC_ALT;
893 if (modifiers & NSEventModifierFlagCommand) pressed_key |= (
_settings_client.gui.right_mouse_btn_emulation != RMBE_CONTROL ? WKC_META : WKC_CTRL);
895 static bool console =
false;
898 if (pressed_key == WKC_BACKQUOTE && (console || unicode == 0)) {
914 Debug(driver, 3,
"cocoa_v: QZ_KeyEvent: {:x} ({:x}), down, mapping: {:x}", keycode, (
int)unicode, pressed_key);
916 Debug(driver, 3,
"cocoa_v: QZ_KeyEvent: {:x} ({:x}), up", keycode, (
int)unicode);
919 return interpret_keys;
926- (void)keyDown:(NSEvent *)event
929 switch (event.keyCode) {
933 if (event.modifierFlags & NSEventModifierFlagCommand) {
934 [
self interpretKeyEvents:[
NSArray arrayWithObject:event ] ];
940 std::vector<char32_t> unicode_str =
NSStringToUTF32([ event characters ]);
941 if (unicode_str.empty()) unicode_str.push_back(0);
944 if ([ self internalHandleKeycode:event.keyCode unicode:unicode_str[0] pressed:YES modifiers:event.modifierFlags ]) {
945 [
self interpretKeyEvents:[
NSArray arrayWithObject:event ] ];
949 for (
size_t i = 1; i < unicode_str.size(); i++) {
959- (void)keyUp:(NSEvent *)event
962 switch (event.keyCode) {
966 if (event.modifierFlags & NSEventModifierFlagCommand) {
967 [
self interpretKeyEvents:[
NSArray arrayWithObject:event ] ];
973 std::vector<char32_t> unicode_str =
NSStringToUTF32([ event characters ]);
974 if (unicode_str.empty()) unicode_str.push_back(0);
983- (void)flagsChanged:(NSEvent *)event
985 const int mapping[] = { QZ_CAPSLOCK, QZ_LSHIFT, QZ_LCTRL, QZ_LALT, QZ_LMETA };
987 NSUInteger newMods =
event.modifierFlags;
988 if (self->_current_mods == newMods)
return;
991 for (
unsigned int i = 0, bit = NSEventModifierFlagCapsLock; bit <= NSEventModifierFlagCommand; bit <<= 1, ++i) {
992 unsigned int currentMask, newMask;
994 currentMask = self->_current_mods & bit;
995 newMask = newMods & bit;
997 if (currentMask && currentMask != newMask) {
999 }
else if (newMask && currentMask != newMask) {
1013- (void)insertText:(
id)aString replacementRange:(NSRange)replacementRange
1019 std::optional<size_t> insert_point;
1020 std::optional<size_t> replace_range;
1021 if (replacementRange.location != NSNotFound) {
1023 std::string_view focused_text{
_focused_window->GetFocusedTextbuf()->GetText()};
1025 replace_range = *insert_point +
Utf8AdvanceByUtf16Units(focused_text.substr(*insert_point), replacementRange.length);
1029 HandleTextInput([ s UTF8String ],
false, std::nullopt, insert_point, replace_range);
1036- (void)insertText:(
id)aString
1047- (void)setMarkedText:(
id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange
1053 const char *utf8 = [
s UTF8String ];
1054 if (utf8 !=
nullptr) {
1055 std::optional<size_t> insert_point;
1056 std::optional<size_t> replace_range;
1057 if (replacementRange.location != NSNotFound) {
1060 std::string_view focused_text{
_focused_window->GetFocusedTextbuf()->GetText()};
1061 insert_point =
Utf8AdvanceByUtf16Units(focused_text, replacementRange.location + (marked.location != NSNotFound ? marked.location : 0u));
1062 replace_range = *insert_point +
Utf8AdvanceByUtf16Units(focused_text.substr(*insert_point), replacementRange.length);
1077- (void)setMarkedText:(
id)aString selectedRange:(NSRange)selRange
1097 std::string_view text = text_buf->
GetText();
1099 return NSMakeRange(start, 0);
1112 std::string_view text = text_buf->
GetText();
1116 return NSMakeRange(start, len);
1119 return NSMakeRange(NSNotFound, 0);
1139- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
1144 NSString *s = [ [
NSString alloc] initWithBytes:text.data() length:text.size() encoding:NSUTF8StringEncoding ];
1145 NSRange valid_range = NSIntersectionRange(NSMakeRange(0, [ s length ]), theRange);
1147 if (actualRange !=
nullptr) *actualRange = valid_range;
1148 if (valid_range.length == 0)
return nil;
1150 return [ [ [
NSAttributedString alloc ] initWithString:[
s substringWithRange:valid_range ] ] autorelease ];
1158- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
1172 return [ [ [
NSAttributedString alloc ] initWithString:[ [
NSString alloc ] initWithBytes:text.data() length:text.size() encoding:NSUTF8StringEncoding ] ] autorelease ];
1180- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1184 NSPoint view_pt = [
self convertRect:[ [
self window ] convertRectFromScreen:NSMakeRect(thePoint.x, thePoint.y, 0, 0) ] fromView:nil ].origin;
1186 Point pt = { (int)view_pt.x, (
int)[
self frame ].size.height - (int)view_pt.y };
1189 if (index == -1)
return NSNotFound;
1200- (NSRect)firstRectForCharacterRange:(NSRange)aRange
1204 std::string_view focused_text =
_focused_window->GetFocusedTextbuf()->GetText();
1211 NSRect view_rect = NSMakeRect(
_focused_window->left + r.left, [ self frame ].size.height -
_focused_window->top - r.bottom, r.right - r.left, r.bottom - r.top);
1213 return [ [
self window ] convertRectToScreen:[
self convertRect:view_rect toView:nil ] ];
1222- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
1240- (void)deleteBackward:(
id)sender
1249- (void)deleteWordBackward:(
id)sender
1258- (void)deleteForward:(
id)sender
1267- (void)deleteWordForward:(
id)sender
1276- (void)moveLeft:(
id)sender
1285- (void)moveWordLeft:(
id)sender
1294- (void)moveRight:(
id)sender
1303- (void)moveWordRight:(
id)sender
1312- (void)moveUp:(
id)sender
1321- (void)moveDown:(
id)sender
1330- (void)moveUpAndModifySelection:(
id)sender
1339- (void)moveDownAndModifySelection:(
id)sender
1348- (void)moveToBeginningOfLine:(
id)sender
1357- (void)moveToEndOfLine:(
id)sender
1366- (void)scrollPageUp:(
id)sender
1375- (void)scrollPageDown:(
id)sender
1384- (void)pageUpAndModifySelection:(
id)sender
1393- (void)pageDownAndModifySelection:(
id)sender
1402- (void)scrollToBeginningOfDocument:(
id)sender
1412- (void)scrollToEndOfDocument:(
id)sender
1422- (void)insertNewline:(
id)sender
1431- (void)cancelOperation:(
id)sender
1440- (void)doCommandBySelector:(
SEL)aSelector
1442 if ([ self respondsToSelector:aSelector ]) [
self performSelector:aSelector ];
1459 if (self = [ super init ]) {
1469- (BOOL)windowShouldClose:(
id)sender
1471 HandleExitGameRequest();
1479- (void)windowDidEnterFullScreen:(NSNotification *)aNotification
1481 NSPoint loc = [
driver->cocoaview convertPoint:[ [
aNotification object ] mouseLocationOutsideOfEventStream ] fromView:nil ];
1482 BOOL inside = ([
driver->cocoaview hitTest:loc ] == driver->cocoaview);
1486 NSEvent *e = [ [
NSEvent alloc ] init ];
1487 [
driver->cocoaview mouseEntered:e ];
1495- (void)windowDidChangeBackingProperties:(NSNotification *)notification
1500 driver->AllocateBackingStore();
1511- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
1513 return NSApplicationPresentationFullScreen | NSApplicationPresentationHideMenuBar | NSApplicationPresentationHideDock;
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
Re-implement the system cursor in order to allow hiding and showing it nicely.
NSCursor * clearCocoaCursor()
Create clear cursor for cocoa driver.
virtual void Stop()=0
Stop this driver.
Constant span of UTF-8 encoded data.
virtual void AllocateBackingStore(bool force=false)=0
Resize the window.
void MainLoopReal()
Main game loop.
virtual bool ToggleFullscreen(bool fullscreen)=0
Change the full screen setting.
static std::string GetCaption()
Get the caption to use for the game's title bar.
static VideoDriver * GetInstance()
Get the currently active instance of the video driver.
bool _cocoa_video_started
Is the Cocoa video driver running.
bool _tab_is_down
Is tab button pressed.
OS interface for the cocoa video driver.
bool _allow_hidpi_window
Storage for allow_hidpi setting. If true renders OTTD in native resolution.
NSString * OTTDMainLaunchGameEngine
Name of notification observer used to restart the game loop if necessary.
static bool _cocoa_video_dialog
True iff inside the scope of CocoaDialog method.
static NSImage * NSImageFromSprite(SpriteID sprite_id, ZoomLevel zoom)
Render an OTTD sprite to a Cocoa image.
bool _emulated_down
Whether the mouse button is emulated or real.
bool touchbar_created
Whether the touchbar exists.
static void setupWindowMenu()
Create a window menu.
void CocoaDialog(std::string_view title, std::string_view message, std::string_view buttonLabel)
Catch asserts prior to initialization of the videodriver.
bool _use_hidpi
Render content in native resolution?
static const std::array< TouchBarButton, 9 > _touchbar_buttons
Storage of defined touch bar buttons.
static NSUInteger CountUtf16Units(std::string_view str)
Count the number of UTF-16 code points in a range of an UTF-8 string.
static size_t Utf8AdvanceByUtf16Units(std::string_view str, NSUInteger count)
Advance an UTF-8 string by a number of equivalent UTF-16 code points.
static void CGDataFreeCallback(void *, const void *data, size_t)
Free memory where data was stored.
static void setApplicationMenu()
Initialize the application menu shown in top bar.
static std::vector< char32_t > NSStringToUTF32(NSString *s)
Convert a NSString to an UTF-32 encoded string.
NSUInteger _current_mods
Currently applied modifier flags.
static OTTDMain * _ottd_main
App delegate instance of OTTDMain.
bool CocoaSetupApplication()
Startup the application.
void CocoaExitApplication()
Deregister app delegate.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
bool _left_button_down
Is left mouse button pressed?
uint8_t _dirkeys
1 = left, 2 = up, 4 = right, 8 = down
bool _left_button_clicked
Is left mouse button clicked?
bool _right_button_clicked
Is right mouse button clicked?
std::unique_ptr< uint32_t[]> DrawSpriteToRgbaBuffer(SpriteID spriteId, ZoomLevel zoom)
Draws a sprite to a new RGBA buffer (see Colour union) instead of drawing to the screen.
bool _right_button_down
Is right mouse button pressed?
bool AdjustGUIZoom(bool automatic)
Resolve GUI zoom level and adjust GUI to new zoom, if auto-suggestion is requested.
Functions related to the gfx engine.
void HandleToolbarHotkey(int hotkey)
Handle Toolbar hotkey events - can come from a source like the MacBook Touch Bar.
void HandleMouseEvents()
Handle a mouse event from the video driver.
void HandleKeypress(uint keycode, char32_t key)
Handle keyboard input.
void HandleTextInput(std::string_view str, bool marked=false, std::optional< size_t > caret=std::nullopt, std::optional< size_t > insert_location=std::nullopt, std::optional< size_t > replacement_end=std::nullopt)
Handle text input.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
The main class of the application, the application's delegate.
void unregisterObserver()
Remove ourself as a notification observer.
void stopEngine()
Stop the game engine.
Subclass of NSView to support mouse awareness and text input.
void unmarkText()
Unmark the current marked text.
NSRange selectedRange()
Get the caret position.
NSPoint mousePositionFromEvent:(NSEvent *e)
Return the mouse location.
void rightMouseDown:(NSEvent *event)
Handler of right mouse button pressing.
void setMarkedText:selectedRange:replacementRange:(id aString, [selectedRange] NSRange selRange, [replacementRange] NSRange replacementRange)
Set a new marked text and reposition the caret.
void internalMouseButtonEvent()
Internal handler of mouse buttons.
void moveToEndOfLine:(id sender)
Move cursor to the end of the line.
NSAttributedString * attributedString()
Get the current edit box string.
BOOL hasMarkedText()
Is any text marked?
void internalMouseMoveEvent:(NSEvent *event)
Internal handler of mouse movement.
BOOL internalHandleKeycode:unicode:pressed:modifiers:(unsigned short keycode, [unicode] char32_t unicode, [pressed] BOOL down, [modifiers] NSUInteger modifiers)
Internal handler of keyboard keys.
void moveToBeginningOfLine:(id sender)
Move cursor to the start of the line.
void rightMouseUp:(NSEvent *event)
Handler of right mouse button releasing.
BOOL acceptsFirstResponder()
Allow to handle events.
NSRect firstRectForCharacterRange:(NSRange aRange)
Get the bounding rect for the given range.
NSArray * validAttributesForMarkedText()
Get all string attributes that we can process for marked text.
NSRange markedRange()
Get the currently marked range.
void insertText:replacementRange:(id aString, [replacementRange] NSRange replacementRange)
Insert the given text at the given range.
NSAttributedString * attributedSubstringForProposedRange:actualRange:(NSRange theRange, [actualRange] NSRangePointer actualRange)
Get a string corresponding to the given range.
Delegate for our NSWindow to send ask for quit on close.
Subclass of NSWindow to cater our special needs.
Functions related to MacOS support.
std::unique_ptr< typename std::remove_pointer< T >::type, CFDeleter< typename std::remove_pointer< T >::type > > CFAutoRelease
Specialisation of std::unique_ptr for CoreFoundation objects.
Includes of mac os specific headers wich contain objective c.
#define Point
Macro that prevents name conflicts between included headers.
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
ClientSettings _settings_client
The current settings for this game.
Types related to global configuration settings.
Functions to cache sprites in memory.
This file contains all sprite-related enums and defines.
Definition of base types and functions in a cross-platform compatible way.
Functions related to low-level strings.
char32_t Utf16DecodeSurrogate(uint lead, uint trail)
Convert an UTF-16 surrogate pair to the corresponding Unicode character.
bool Utf16IsLeadSurrogate(uint c)
Is the given character a lead surrogate code point?
bool Utf16IsTrailSurrogate(uint c)
Is the given character a lead surrogate code point?
Dimensions (a width and height) of a rectangle in 2D.
Specification of a rectangle with absolute coordinates of all edges.
Helper/buffer for input fields.
uint16_t caretpos
the current position of the caret in the buffer, in bytes
std::string_view GetText() const
Get the current text.
uint16_t markend
the end position of the marked area in the buffer, in bytes
uint16_t markpos
the start position of the marked area in the buffer, in bytes
Stuff related to text buffers.
Handling of UTF-8 encoded data.
Window * _focused_window
Window that currently has focus.
void ReInitAllWindows(bool zoom_changed)
Re-initialize all windows.
bool EditBoxInGlobalFocus()
Check if an edit box is in global focus.
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
ZoomLevel
All zoom levels we know.