Merge branch 'master' into jgrpp

# Conflicts:
#	src/gfx.cpp
#	src/lang/traditional_chinese.txt
#	src/station_cmd.cpp
This commit is contained in:
Jonathan G Rennison
2022-01-04 17:42:36 +00:00
21 changed files with 444 additions and 185 deletions

View File

@@ -232,11 +232,15 @@ void VideoDriver_CocoaOpenGL::Stop()
void VideoDriver_CocoaOpenGL::PopulateSystemSprites()
{
VideoDriver_Cocoa::PopulateSystemSprites();
OpenGLBackend::Get()->PopulateCursorCache();
}
void VideoDriver_CocoaOpenGL::ClearSystemSprites()
{
VideoDriver_Cocoa::ClearSystemSprites();
CGLSetCurrentContext(this->gl_context);
OpenGLBackend::Get()->ClearCursorCache();
}

View File

@@ -22,7 +22,8 @@ extern bool _cocoa_video_started;
class VideoDriver_Cocoa : public VideoDriver {
private:
Dimension orig_res; ///< Saved window size for non-fullscreen mode.
Dimension orig_res; ///< Saved window size for non-fullscreen mode.
bool refresh_sys_sprites; ///< System sprites need refreshing.
public:
bool setup; ///< Window is currently being created.
@@ -45,6 +46,9 @@ public:
bool ChangeResolution(int w, int h) override;
bool ToggleFullscreen(bool fullscreen) override;
void ClearSystemSprites() override;
void PopulateSystemSprites() override;
void EditBoxLostFocus() override;
std::vector<int> GetListOfMonitorRefreshRates() override;

View File

@@ -98,6 +98,8 @@ VideoDriver_Cocoa::VideoDriver_Cocoa()
this->setup = false;
this->buffer_locked = false;
this->refresh_sys_sprites = true;
this->window = nil;
this->cocoaview = nil;
this->delegate = nil;
@@ -220,6 +222,19 @@ bool VideoDriver_Cocoa::ToggleFullscreen(bool full_screen)
return false;
}
void VideoDriver_Cocoa::ClearSystemSprites()
{
this->refresh_sys_sprites = true;
}
void VideoDriver_Cocoa::PopulateSystemSprites()
{
if (this->refresh_sys_sprites && this->window != nil) {
[ this->window refreshSystemSprites ];
this->refresh_sys_sprites = false;
}
}
/**
* Callback invoked after the blitter was changed.
* @return True if no error.

View File

@@ -11,8 +11,10 @@
#define COCOA_WND_H
#import <Cocoa/Cocoa.h>
#include "toolbar_gui.h"
#include "table/sprites.h"
#ifdef MAC_OS_X_VERSION_10_12_2
# define HAVE_TOUCHBAR_SUPPORT
#endif
class VideoDriver_Cocoa;
@@ -30,70 +32,17 @@ extern NSString *OTTDMainLaunchGameEngine;
+ (NSCursor *) clearCocoaCursor;
@end
#ifdef HAVE_OSX_1015_SDK
/* 9 items can be displayed on the touch bar when using default buttons. */
static NSArray *touchBarButtonIdentifiers = @[
@"openttd.pause",
@"openttd.fastforward",
@"openttd.zoom_in",
@"openttd.zoom_out",
@"openttd.build_rail",
@"openttd.build_road",
@"openttd.build_tram",
@"openttd.build_docks",
@"openttd.build_airport",
NSTouchBarItemIdentifierOtherItemsProxy
];
static NSDictionary *touchBarButtonSprites = @{
@"openttd.pause": [NSNumber numberWithInt:SPR_IMG_PAUSE],
@"openttd.fastforward": [NSNumber numberWithInt:SPR_IMG_FASTFORWARD],
@"openttd.zoom_in": [NSNumber numberWithInt:SPR_IMG_ZOOMIN],
@"openttd.zoom_out": [NSNumber numberWithInt:SPR_IMG_ZOOMOUT],
@"openttd.build_rail": [NSNumber numberWithInt:SPR_IMG_BUILDRAIL],
@"openttd.build_road": [NSNumber numberWithInt:SPR_IMG_BUILDROAD],
@"openttd.build_tram": [NSNumber numberWithInt:SPR_IMG_BUILDTRAMS],
@"openttd.build_docks": [NSNumber numberWithInt:SPR_IMG_BUILDWATER],
@"openttd.build_airport": [NSNumber numberWithInt:SPR_IMG_BUILDAIR],
};
static NSDictionary *touchBarButtonActions = @{
@"openttd.pause": [NSNumber numberWithInt:MTHK_PAUSE],
@"openttd.fastforward": [NSNumber numberWithInt:MTHK_FASTFORWARD],
@"openttd.zoom_in": [NSNumber numberWithInt:MTHK_ZOOM_IN],
@"openttd.zoom_out": [NSNumber numberWithInt:MTHK_ZOOM_OUT],
@"openttd.build_rail": [NSNumber numberWithInt:MTHK_BUILD_RAIL],
@"openttd.build_road": [NSNumber numberWithInt:MTHK_BUILD_ROAD],
@"openttd.build_tram": [NSNumber numberWithInt:MTHK_BUILD_TRAM],
@"openttd.build_docks": [NSNumber numberWithInt:MTHK_BUILD_DOCKS],
@"openttd.build_airport": [NSNumber numberWithInt:MTHK_BUILD_AIRPORT],
};
static NSDictionary *touchBarFallbackText = @{
@"openttd.pause": @"Pause",
@"openttd.fastforward": @"Fast Forward",
@"openttd.zoom_in": @"Zoom In",
@"openttd.zoom_out": @"Zoom Out",
@"openttd.build_rail": @"Rail",
@"openttd.build_road": @"Road",
@"openttd.build_tram": @"Tram",
@"openttd.build_docks": @"Docks",
@"openttd.build_airport": @"Airport",
};
#endif
/** Subclass of NSWindow to cater our special needs */
#ifdef HAVE_OSX_1015_SDK
@interface OTTD_CocoaWindow : NSWindow <NSTouchBarDelegate>
@property (strong) NSSet *touchbarItems;
- (NSImage*)generateImage:(int)spriteId;
#else
@interface OTTD_CocoaWindow : NSWindow
#ifdef HAVE_TOUCHBAR_SUPPORT
<NSTouchBarDelegate>
#endif
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag driver:(VideoDriver_Cocoa *)drv;
- (void)setFrame:(NSRect)frameRect display:(BOOL)flag;
- (void)refreshSystemSprites;
@end
/** Subclass of NSView to support mouse awareness and text input. */

View File

@@ -32,7 +32,11 @@
#include "../../gfx_func.h"
#include "../../window_func.h"
#include "../../window_gui.h"
#include "spritecache.h"
#include "../../spritecache.h"
#include "../../toolbar_gui.h"
#include <array>
#include "table/sprites.h"
/* Table data for key mapping. */
#include "cocoa_keys.h"
@@ -56,6 +60,31 @@
* Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information.
*/
#ifdef HAVE_TOUCHBAR_SUPPORT
struct TouchBarButton {
NSTouchBarItemIdentifier key;
SpriteID sprite;
MainToolbarHotkeys hotkey;
NSString *fallback_text;
bool operator ==(const NSTouchBarItemIdentifier other) const { return this->key == other; }
};
/* 9 items can be displayed on the touch bar when using default buttons. */
static const std::array<TouchBarButton, 9> _touchbar_buttons{{
{ @"openttd.pause", SPR_IMG_PAUSE, MTHK_PAUSE, @"Pause" },
{ @"openttd.fastforward", SPR_IMG_FASTFORWARD, MTHK_FASTFORWARD, @"Fast Forward" },
{ @"openttd.zoom_in", SPR_IMG_ZOOMIN, MTHK_ZOOM_IN, @"Zoom In" },
{ @"openttd.zoom_out", SPR_IMG_ZOOMOUT, MTHK_ZOOM_OUT, @"Zoom Out" },
{ @"openttd.build_rail", SPR_IMG_BUILDRAIL, MTHK_BUILD_RAIL, @"Rail" },
{ @"openttd.build_road", SPR_IMG_BUILDROAD, MTHK_BUILD_ROAD, @"Road" },
{ @"openttd.build_tram", SPR_IMG_BUILDTRAMS, MTHK_BUILD_TRAM, @"Tram" },
{ @"openttd.build_docks", SPR_IMG_BUILDWATER, MTHK_BUILD_DOCKS, @"Docks" },
{ @"openttd.build_airport", SPR_IMG_BUILDAIR, MTHK_BUILD_AIRPORT, @"Airport" }
}};
#endif
bool _allow_hidpi_window = true; // Referenced from table/misc_settings.ini
@interface OTTDMain : NSObject <NSApplicationDelegate>
@@ -132,6 +161,37 @@ static std::vector<WChar> NSStringToUTF32(NSString *s)
return unicode_str;
}
static void CGDataFreeCallback(void *, const void *data, size_t)
{
delete[] (const uint32 *)data;
}
/**
* Render an OTTD sprite to a Cocoa image.
* @param sprite_id Sprite to make a NSImage from.
* @param zoom Zoom level to render the sprite in.
* @return Autorelease'd image or nullptr on any error.
*/
static NSImage *NSImageFromSprite(SpriteID sprite_id, ZoomLevel zoom)
{
if (!SpriteExists(sprite_id)) return nullptr;
/* Fetch the sprite and create a new bitmap */
Dimension dim = GetSpriteSize(sprite_id, nullptr, zoom);
std::unique_ptr<uint32[]> buffer = DrawSpriteToRgbaBuffer(sprite_id, zoom);
if (!buffer) return nullptr; // Failed to blit sprite for some reason.
CFAutoRelease<CGDataProvider> data(CGDataProviderCreateWithData(nullptr, buffer.release(), dim.width * dim.height * 4, &CGDataFreeCallback));
if (!data) return nullptr;
CGBitmapInfo info = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
CFAutoRelease<CGColorSpaceRef> color_space(CGColorSpaceCreateWithName(kCGColorSpaceSRGB));
CFAutoRelease<CGImage> bitmap(CGImageCreate(dim.width, dim.height, 8, 32, dim.width * 4, color_space.get(), info, data.get(), nullptr, false, kCGRenderingIntentDefault));
if (!bitmap) return nullptr;
return [ [ [ NSImage alloc ] initWithCGImage:bitmap.get() size:NSZeroSize ] autorelease ];
}
/**
* The main class of the application, the application's delegate.
@@ -383,6 +443,7 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
@implementation OTTD_CocoaWindow {
VideoDriver_Cocoa *driver;
bool touchbar_created;
}
/**
@@ -392,6 +453,7 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
{
if (self = [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ]) {
self->driver = drv;
self->touchbar_created = false;
[ self setContentMinSize:NSMakeSize(64.0f, 64.0f) ];
@@ -405,87 +467,6 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
return self;
}
#ifdef HAVE_OSX_1015_SDK
- (void)touchBarButtonAction:(id)sender
{
if (@available(macOS 10.15, *)) {
NSButtonTouchBarItem *btn = (NSButtonTouchBarItem *)sender;
NSNumber *hotkeyIndex = [ touchBarButtonActions objectForKey:btn.identifier ];
HandleToolbarHotkey(hotkeyIndex.intValue);
}
}
#pragma mark NSTouchBarProvider
- (nullable NSTouchBar *)makeTouchBar
{
NSTouchBar *bar = [ [ NSTouchBar alloc ] init ];
bar.delegate = self;
bar.defaultItemIdentifiers = touchBarButtonIdentifiers;
return bar;
}
-(NSImage *)generateImage:(int)spriteId
{
if (!SpriteExists(spriteId)) {
return nullptr;
}
/* Fetch the sprite and create a new bitmap */
const Sprite *fullspr = GetSprite(spriteId, ST_NORMAL);
const std::unique_ptr<uint32[]> buffer = DrawSpriteToRgbaBuffer(spriteId);
if (!buffer) {
return nullptr; // failed to blit sprite or we're using an 8bpp blitter.
}
NSBitmapImageRep *bitmap = [ [ NSBitmapImageRep alloc ] initWithBitmapDataPlanes:nil pixelsWide:fullspr->width pixelsHigh:fullspr->height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bytesPerRow:0 bitsPerPixel:0 ];
/* Copy the sprite to the NSBitmapImageRep image buffer */
const Colour *src = (const Colour *)buffer.get();
for (int y = 0; y < fullspr->height; y++) {
for (int x = 0; x < fullspr->width; x++) {
NSUInteger pixel[4];
pixel[0] = src->r;
pixel[1] = src->g;
pixel[2] = src->b;
pixel[3] = src->a;
[ bitmap setPixel:pixel atX:x y:y ];
src += 1;
}
}
/* Finally, convert the NSBitmapImageRep we created to a NSimage we can put on the button and clean up. */
NSImage *outImage = [ [ NSImage alloc ] initWithSize:NSMakeSize(fullspr->width, fullspr->height) ];
[ outImage addRepresentation:bitmap ];
[ bitmap release ];
return outImage;
}
#pragma mark NSTouchBarDelegate
- (nullable NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
{
if (@available(macOS 10.15, *)) {
NSButtonTouchBarItem *button = [ [ NSButtonTouchBarItem alloc ] initWithIdentifier:identifier ];
button.target = self;
button.action = @selector(touchBarButtonAction:);
NSNumber *num = touchBarButtonSprites[identifier];
NSImage *generatedImage = [ self generateImage:num.unsignedIntValue ];
if (generatedImage != nullptr) {
button.image = generatedImage;
} else {
button.title = NSLocalizedString(touchBarFallbackText[identifier], @"");
}
return button;
} else {
return nullptr;
}
}
#endif
/**
* Define the rectangle we draw our window in
*/
@@ -496,6 +477,83 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
driver->AllocateBackingStore();
}
#ifdef HAVE_TOUCHBAR_SUPPORT
- (void)touchBarButtonAction:(id)sender
{
NSButton *btn = (NSButton *)sender;
if (auto item = std::find(_touchbar_buttons.cbegin(), _touchbar_buttons.cend(), (NSTouchBarItemIdentifier)btn.identifier); item != _touchbar_buttons.cend()) {
HandleToolbarHotkey(item->hotkey);
}
}
- (nullable NSTouchBar *)makeTouchBar
{
/* Make button identifier array. */
NSMutableArray<NSTouchBarItemIdentifier> *button_ids = [ [ NSMutableArray alloc ] init ];
for (const auto &button : _touchbar_buttons) {
[ button_ids addObject:button.key ];
}
[ button_ids addObject:NSTouchBarItemIdentifierOtherItemsProxy ];
NSTouchBar *bar = [ [ NSTouchBar alloc ] init ];
bar.delegate = self;
bar.defaultItemIdentifiers = button_ids;
[ button_ids release ];
self->touchbar_created = true;
return bar;
}
- (nullable NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
{
auto item = std::find(_touchbar_buttons.cbegin(), _touchbar_buttons.cend(), identifier);
assert(item != _touchbar_buttons.cend());
NSButton *button = [ NSButton buttonWithTitle:item->fallback_text target:self action:@selector(touchBarButtonAction:) ];
button.identifier = identifier;
button.imageScaling = NSImageScaleProportionallyDown;
NSCustomTouchBarItem *tb_item = [ [ NSCustomTouchBarItem alloc] initWithIdentifier:identifier ];
tb_item.view = button;
return tb_item;
}
#endif /* HAVE_TOUCHBAR_SUPPORT */
- (void)refreshSystemSprites
{
#ifdef HAVE_TOUCHBAR_SUPPORT
if (!self->touchbar_created || ![ self respondsToSelector:@selector(touchBar) ] || self.touchBar == nil) return;
/* Re-create button images from OTTD sprites. */
for (NSTouchBarItemIdentifier ident in self.touchBar.itemIdentifiers) {
auto item = std::find(_touchbar_buttons.cbegin(), _touchbar_buttons.cend(), ident);
if (item == _touchbar_buttons.cend()) continue;
NSCustomTouchBarItem *tb_item = [ self.touchBar itemForIdentifier:ident ];
NSButton *button = tb_item.view;
NSImage *image = NSImageFromSprite(item->sprite, _settings_client.gui.zoom_min);
if (image != nil) {
/* Human Interface Guidelines: Maximum touch bar glyph size 22 pt. */
CGFloat max_dim = std::max(image.size.width, image.size.height);
if (max_dim > 0.0) {
CGFloat scale = 22.0 / max_dim;
image.size = NSMakeSize(image.size.width * scale, image.size.height * scale);
}
button.image = image;
button.imagePosition = NSImageOnly;
} else {
button.image = nil;
button.imagePosition = NSNoImage;
}
}
#endif /* HAVE_TOUCHBAR_SUPPORT */
}
@end
@implementation OTTD_CocoaView {