Changeset - r24770:fdcfd3362821
[Not reviewed]
master
0 3 0
Michael Lutz - 3 years ago 2021-01-31 17:58:23
michi@icosahedron.de
Codechange: [OSX] Split drawing into its own subview.

This allows the drawing backend code to be independent
of any event or command handling.
3 files changed with 126 insertions and 105 deletions:
0 comments (0 inline, 0 general)
src/video/cocoa/cocoa_v.mm
Show inline comments
 
@@ -77,7 +77,11 @@ static FVideoDriver_Cocoa iFVideoDriver_
 

	
 

	
 
/* Subclass of OTTD_CocoaView to fix Quartz rendering */
 
@interface OTTD_QuartzView : OTTD_CocoaView
 
@interface OTTD_QuartzView : NSView {
 
	VideoDriver_Cocoa *driver;
 
}
 
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv;
 

	
 
- (void)drawRect:(NSRect)invalidRect;
 
@end
 

	
 
@@ -311,6 +315,28 @@ void VideoDriver_Cocoa::GameSizeChanged(
 

	
 
@implementation OTTD_QuartzView
 

	
 
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv
 
{
 
	if (self = [ super initWithFrame:frameRect ]) {
 
		self->driver = drv;
 
	}
 
	return self;
 
}
 

	
 
- (BOOL)acceptsFirstResponder
 
{
 
	return NO;
 
}
 

	
 
/**
 
 * Define the opaqueness of the window / screen
 
 * @return opaqueness of window / screen
 
 */
 
- (BOOL)isOpaque
 
{
 
	return YES;
 
}
 

	
 
- (void)drawRect:(NSRect)invalidRect
 
{
 
	if (driver->cgcontext == NULL) return;
 
@@ -429,13 +455,12 @@ bool VideoDriver_Cocoa::MakeWindow(int w
 

	
 
	/* Create main window. */
 
	unsigned int style = NSTitledWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask;
 
	this->window = [ [ OTTD_CocoaWindow alloc ] initWithContentRect:contentRect styleMask:style backing:NSBackingStoreBuffered defer:NO ];
 
	this->window = [ [ OTTD_CocoaWindow alloc ] initWithContentRect:contentRect styleMask:style backing:NSBackingStoreBuffered defer:NO driver:this ];
 
	if (this->window == nil) {
 
		DEBUG(driver, 0, "Could not create the Cocoa window.");
 
		this->setup = false;
 
		return false;
 
	}
 
	[ this->window setDriver:this ];
 

	
 
	/* Add built in full-screen support when available (OS X 10.7 and higher)
 
	 * This code actually compiles for 10.5 and later, but only makes sense in conjunction
 
@@ -468,16 +493,28 @@ bool VideoDriver_Cocoa::MakeWindow(int w
 
	[ (OTTD_CocoaWindow *)this->window center ];
 
	[ this->window makeKeyAndOrderFront:nil ];
 

	
 
	/* Create content view. */
 
	this->cocoaview = [ [ OTTD_QuartzView alloc ] initWithFrame:[ this->window contentRectForFrameRect:[ this->window frame ] ] andDriver:this ];
 
	/* Create wrapper view for text input. */
 
	NSRect view_frame = [ this->window contentRectForFrameRect:[ this->window frame ] ];
 
	this->cocoaview = [ [ OTTD_CocoaView alloc ] initWithFrame:view_frame andDriver:this ];
 
	if (this->cocoaview == nil) {
 
		DEBUG(driver, 0, "Could not create the Quartz view.");
 
		DEBUG(driver, 0, "Could not create the text wrapper view.");
 
		this->setup = false;
 
		return false;
 
	}
 
	[ (NSView *)this->cocoaview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ];
 

	
 
	[ (NSView*)this->cocoaview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ];
 
	[ this->window setContentView:cocoaview ];
 
	/* Create content view. */
 
	NSView *draw_view = [ [ OTTD_QuartzView alloc ] initWithFrame:[ this->cocoaview bounds ] andDriver:this ];
 
	if (draw_view == nil) {
 
		DEBUG(driver, 0, "Could not create the drawing view.");
 
		this->setup = false;
 
		return false;
 
	}
 
	[ draw_view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ];
 

	
 
	[ this->window setContentView:this->cocoaview ];
 
	[ this->cocoaview addSubview:draw_view ];
 
	[ draw_view release ];
 

	
 
	[ this->window setColorSpace:[ NSColorSpace sRGBColorSpace ] ];
 
	CGColorSpaceRelease(this->color_space);
src/video/cocoa/cocoa_wnd.h
Show inline comments
 
@@ -22,31 +22,23 @@ extern NSString *OTTDMainLaunchGameEngin
 
@end
 

	
 
/** Subclass of NSWindow to cater our special needs */
 
@interface OTTD_CocoaWindow : NSWindow {
 
	VideoDriver_Cocoa *driver;
 
}
 

	
 
- (void)setDriver:(VideoDriver_Cocoa *)drv;
 
@interface OTTD_CocoaWindow : NSWindow
 
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag driver:(VideoDriver_Cocoa *)drv;
 

	
 
- (void)miniaturize:(id)sender;
 
- (void)display;
 
- (void)setFrame:(NSRect)frameRect display:(BOOL)flag;
 
- (void)appDidHide:(NSNotification*)note;
 
- (void)appDidUnhide:(NSNotification*)note;
 
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag;
 
@end
 

	
 
/** Subclass of NSView to fix Quartz rendering and mouse awareness */
 
@interface OTTD_CocoaView : NSView <NSTextInputClient>
 
{
 
@interface OTTD_CocoaView : NSView <NSTextInputClient> {
 
	VideoDriver_Cocoa *driver;
 
	NSTrackingRectTag trackingtag;
 
}
 
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv;
 
- (void)drawRect:(NSRect)rect;
 
- (BOOL)isOpaque;
 

	
 
- (BOOL)acceptsFirstResponder;
 
- (BOOL)becomeFirstResponder;
 
- (void)setTrackingRect;
 
- (void)clearTrackingRect;
 
- (void)resetCursorRects;
 
@@ -58,9 +50,6 @@ extern NSString *OTTDMainLaunchGameEngin
 

	
 
/** Delegate for our NSWindow to send ask for quit on close */
 
@interface OTTD_CocoaWindowDelegate : NSObject <NSWindowDelegate>
 
{
 
	VideoDriver_Cocoa *driver;
 
}
 
- (instancetype)initWithDriver:(VideoDriver_Cocoa *)drv;
 

	
 
- (BOOL)windowShouldClose:(id)sender;
src/video/cocoa/cocoa_wnd.mm
Show inline comments
 
@@ -48,6 +48,46 @@ NSString *OTTDMainLaunchGameEngine = @"o
 
static bool _cocoa_video_dialog = false;
 
static OTTDMain *_ottd_main;
 

	
 

	
 
/**
 
 * Count the number of UTF-16 code points in a range of an UTF-8 string.
 
 * @param from Start of the range.
 
 * @param to End of the range.
 
 * @return Number of UTF-16 code points in the range.
 
 */
 
static NSUInteger CountUtf16Units(const char *from, const char *to)
 
{
 
	NSUInteger i = 0;
 

	
 
	while (from < to) {
 
		WChar c;
 
		size_t len = Utf8Decode(&c, from);
 
		i += len < 4 ? 1 : 2; // Watch for surrogate pairs.
 
		from += len;
 
	}
 

	
 
	return i;
 
}
 

	
 
/**
 
 * Advance an UTF-8 string by a number of equivalent UTF-16 code points.
 
 * @param str UTF-8 string.
 
 * @param count Number of UTF-16 code points to advance the string by.
 
 * @return Advanced string pointer.
 
 */
 
static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count)
 
{
 
	for (NSUInteger i = 0; i < count && *str != '\0'; ) {
 
		WChar c;
 
		size_t len = Utf8Decode(&c, str);
 
		i += len < 4 ? 1 : 2; // Watch for surrogates.
 
		str += len;
 
	}
 

	
 
	return str;
 
}
 

	
 

	
 
/**
 
 * The main class of the application, the application's delegate.
 
 */
 
@@ -69,11 +109,13 @@ static OTTDMain *_ottd_main;
 
 */
 
- (void)launchGameEngine: (NSNotification*) note
 
{
 
	auto *drv = static_cast<VideoDriver_Cocoa *>(VideoDriver::GetInstance());
 

	
 
	/* Setup cursor for the current _game_mode. */
 
	[ static_cast<VideoDriver_Cocoa *>(VideoDriver::GetInstance())->cocoaview resetCursorRects ];
 
	[ drv->window invalidateCursorRectsForView:[ drv->window contentView ] ];
 

	
 
	/* Hand off to main application code. */
 
	static_cast<VideoDriver_Cocoa *>(VideoDriver::GetInstance())->GameLoop();
 
	drv->GameLoop();
 

	
 
	/* We are done, thank you for playing. */
 
	[ self performSelectorOnMainThread:@selector(stopEngine) withObject:nil waitUntilDone:FALSE ];
 
@@ -283,12 +325,10 @@ void CocoaDialog(const char *title, cons
 
}
 
@end
 

	
 
@implementation OTTD_CocoaWindow
 
@implementation OTTD_CocoaWindow {
 
	VideoDriver_Cocoa *driver;
 
}
 

	
 
- (void)setDriver:(VideoDriver_Cocoa *)drv
 
{
 
	driver = drv;
 
}
 
/**
 
 * Minimize the window
 
 */
 
@@ -346,62 +386,28 @@ void CocoaDialog(const char *title, cons
 
/**
 
 * Initialize event system for the application rectangle
 
 */
 
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag
 
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag driver:(VideoDriver_Cocoa *)drv
 
{
 
	/* Make our window subclass receive these application notifications */
 
	[ [ NSNotificationCenter defaultCenter ] addObserver:self
 
		selector:@selector(appDidHide:) name:NSApplicationDidHideNotification object:NSApp ];
 
	if (self = [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ]) {
 
		/* Make our window subclass receive these application notifications */
 
		[ [ NSNotificationCenter defaultCenter ] addObserver:self
 
			selector:@selector(appDidHide:) name:NSApplicationDidHideNotification object:NSApp ];
 

	
 
	[ [ NSNotificationCenter defaultCenter ] addObserver:self
 
		selector:@selector(appDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp ];
 
		[ [ NSNotificationCenter defaultCenter ] addObserver:self
 
			selector:@selector(appDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp ];
 

	
 
	return [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ];
 
		self->driver = drv;
 
	}
 

	
 
	return self;
 
}
 

	
 
@end
 

	
 

	
 

	
 
/**
 
 * Count the number of UTF-16 code points in a range of an UTF-8 string.
 
 * @param from Start of the range.
 
 * @param to End of the range.
 
 * @return Number of UTF-16 code points in the range.
 
 */
 
static NSUInteger CountUtf16Units(const char *from, const char *to)
 
{
 
	NSUInteger i = 0;
 

	
 
	while (from < to) {
 
		WChar c;
 
		size_t len = Utf8Decode(&c, from);
 
		i += len < 4 ? 1 : 2; // Watch for surrogate pairs.
 
		from += len;
 
	}
 

	
 
	return i;
 
@implementation OTTD_CocoaView {
 
	NSTrackingRectTag trackingtag;
 
}
 

	
 
/**
 
 * Advance an UTF-8 string by a number of equivalent UTF-16 code points.
 
 * @param str UTF-8 string.
 
 * @param count Number of UTF-16 code points to advance the string by.
 
 * @return Advanced string pointer.
 
 */
 
static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count)
 
{
 
	for (NSUInteger i = 0; i < count && *str != '\0'; ) {
 
		WChar c;
 
		size_t len = Utf8Decode(&c, str);
 
		i += len < 4 ? 1 : 2; // Watch for surrogates.
 
		str += len;
 
	}
 

	
 
	return str;
 
}
 

	
 
@implementation OTTD_CocoaView
 

	
 
- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv
 
{
 
	if (self = [ super initWithFrame:frameRect ]) {
 
@@ -409,22 +415,7 @@ static const char *Utf8AdvanceByUtf16Uni
 
	}
 
	return self;
 
}
 
/**
 
 * Define the opaqueness of the window / screen
 
 * @return opaqueness of window / screen
 
 */
 
- (BOOL)isOpaque
 
{
 
	return YES;
 
}
 
/**
 
 * Draws a rectangle on the screen.
 
 * It's overwritten by the individual drivers but must be defined
 
 */
 
- (void)drawRect:(NSRect)invalidRect
 
{
 
	return;
 
}
 

	
 
/**
 
 * Allow to handle events
 
 */
 
@@ -432,13 +423,15 @@ static const char *Utf8AdvanceByUtf16Uni
 
{
 
	return YES;
 
}
 
/**
 
 * Actually handle events
 
 */
 
- (BOOL)becomeFirstResponder
 

	
 
- (void)setNeedsDisplayInRect:(NSRect)invalidRect
 
{
 
	return YES;
 
	/* Drawing is handled by our sub-views. Just pass it along. */
 
	for ( NSView *v in [ self subviews ]) {
 
		[ v setNeedsDisplayInRect:[ v convertRect:invalidRect fromView:self ] ];
 
	}
 
}
 

	
 
/**
 
 * Define the rectangle where we draw our application window
 
 */
 
@@ -556,7 +549,7 @@ static const char *Utf8AdvanceByUtf16Uni
 
/** Unmark the current marked text. */
 
- (void)unmarkText
 
{
 
	HandleTextInput(NULL, true);
 
	HandleTextInput(nullptr, true);
 
}
 

	
 
/** Get the caret position. */
 
@@ -575,7 +568,7 @@ static const char *Utf8AdvanceByUtf16Uni
 

	
 
	size_t mark_len;
 
	const char *mark = _focused_window->GetMarkedText(&mark_len);
 
	if (mark != NULL) {
 
	if (mark != nullptr) {
 
		NSUInteger start = CountUtf16Units(_focused_window->GetFocusedText(), mark);
 
		NSUInteger len = CountUtf16Units(mark, mark + mark_len);
 

	
 
@@ -591,7 +584,7 @@ static const char *Utf8AdvanceByUtf16Uni
 
	if (!EditBoxInGlobalFocus()) return NO;
 

	
 
	size_t len;
 
	return _focused_window->GetMarkedText(&len) != NULL;
 
	return _focused_window->GetMarkedText(&len) != nullptr;
 
}
 

	
 
/** Get a string corresponding to the given range. */
 
@@ -602,7 +595,7 @@ static const char *Utf8AdvanceByUtf16Uni
 
	NSString *s = [ NSString stringWithUTF8String:_focused_window->GetFocusedText() ];
 
	NSRange valid_range = NSIntersectionRange(NSMakeRange(0, [ s length ]), theRange);
 

	
 
	if (actualRange != NULL) *actualRange = valid_range;
 
	if (actualRange != nullptr) *actualRange = valid_range;
 
	if (valid_range.length == 0) return nil;
 

	
 
	return [ [ [ NSAttributedString alloc ] initWithString:[ s substringWithRange:valid_range ] ] autorelease ];
 
@@ -611,7 +604,7 @@ static const char *Utf8AdvanceByUtf16Uni
 
/** Get a string corresponding to the given range. */
 
- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
 
{
 
	return [ self attributedSubstringForProposedRange:theRange actualRange:NULL ];
 
	return [ self attributedSubstringForProposedRange:theRange actualRange:nil ];
 
}
 

	
 
/** Get the current edit box string. */
 
@@ -632,7 +625,7 @@ static const char *Utf8AdvanceByUtf16Uni
 
	Point pt = { (int)view_pt.x, (int)[ self frame ].size.height - (int)view_pt.y };
 

	
 
	const char *ch = _focused_window->GetTextCharacterAtPosition(pt);
 
	if (ch == NULL) return NSNotFound;
 
	if (ch == nullptr) return NSNotFound;
 

	
 
	return CountUtf16Units(_focused_window->GetFocusedText(), ch);
 
}
 
@@ -808,8 +801,10 @@ static const char *Utf8AdvanceByUtf16Uni
 
@end
 

	
 

	
 
@implementation OTTD_CocoaWindowDelegate {
 
	VideoDriver_Cocoa *driver;
 
}
 

	
 
@implementation OTTD_CocoaWindowDelegate
 
/** Initialize the video driver */
 
- (instancetype)initWithDriver:(VideoDriver_Cocoa *)drv
 
{
0 comments (0 inline, 0 general)