summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny de Bruijne <dannydb44@gmail.com>2021-08-19 17:39:44 +0100
committerMichael Lutz <michi@icosahedron.de>2021-09-23 21:03:00 +0200
commit753b1d7e155ffe7b3585273998278aceee25fa1a (patch)
treeb8ba3600e21138ee0441970ff57a9b0aeaa3c4b8
parent16aac9c34126d3af183f3782571791dddcbbcf6b (diff)
downloadopenttd-753b1d7e155ffe7b3585273998278aceee25fa1a.tar.xz
Feature: Add selected toolbar buttons to MacBook Pro Touch Bar
-rw-r--r--src/gfx.cpp56
-rw-r--r--src/gfx_func.h2
-rw-r--r--src/os/macosx/osx_stdafx.h4
-rw-r--r--src/toolbar_gui.cpp43
-rw-r--r--src/toolbar_gui.h43
-rw-r--r--src/video/cocoa/cocoa_wnd.h61
-rw-r--r--src/video/cocoa/cocoa_wnd.mm83
-rw-r--r--src/window.cpp16
8 files changed, 257 insertions, 51 deletions
diff --git a/src/gfx.cpp b/src/gfx.cpp
index 9ccb036d2..ad775803b 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -1059,18 +1059,19 @@ void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub,
/**
* The code for setting up the blitter mode and sprite information before finally drawing the sprite.
* @param sprite The sprite to draw.
- * @param x The X location to draw.
- * @param y The Y location to draw.
- * @param mode The settings for the blitter to pass.
- * @param sub Whether to only draw a sub set of the sprite.
- * @param zoom The zoom level at which to draw the sprites.
+ * @param x The X location to draw.
+ * @param y The Y location to draw.
+ * @param mode The settings for the blitter to pass.
+ * @param sub Whether to only draw a sub set of the sprite.
+ * @param zoom The zoom level at which to draw the sprites.
+ * @param dst Optional parameter for a different blitting destination.
* @tparam ZOOM_BASE The factor required to get the sub sprite information into the right size.
* @tparam SCALED_XY Whether the X and Y are scaled or unscaled.
*/
template <int ZOOM_BASE, bool SCALED_XY>
-static void GfxBlitter(const Sprite * const sprite, int x, int y, BlitterMode mode, const SubSprite * const sub, SpriteID sprite_id, ZoomLevel zoom)
+static void GfxBlitter(const Sprite * const sprite, int x, int y, BlitterMode mode, const SubSprite * const sub, SpriteID sprite_id, ZoomLevel zoom, const DrawPixelInfo *dst = nullptr)
{
- const DrawPixelInfo *dpi = _cur_dpi;
+ const DrawPixelInfo *dpi = (dst != nullptr) ? dst : _cur_dpi;
Blitter::BlitterParams bp;
if (SCALED_XY) {
@@ -1185,6 +1186,47 @@ static void GfxBlitter(const Sprite * const sprite, int x, int y, BlitterMode mo
BlitterFactory::GetCurrentBlitter()->Draw(&bp, mode, zoom);
}
+/**
+ * Draws a sprite to a new RGBA buffer (see Colour union) instead of drawing to the screen.
+ *
+ * @param spriteId The sprite to draw.
+ * @return Pixel buffer, or nullptr if an 8bpp blitter is being used.
+ */
+std::unique_ptr<uint32[]> DrawSpriteToRgbaBuffer(SpriteID spriteId)
+{
+ Blitter *blitter = BlitterFactory::GetCurrentBlitter();
+ if (!blitter->Is32BppSupported()) return nullptr;
+
+ /* Gather information about the sprite to write, reserve memory */
+ const SpriteID real_sprite = GB(spriteId, 0, SPRITE_WIDTH);
+ const Sprite *sprite = GetSprite(real_sprite, ST_NORMAL);
+ std::unique_ptr<uint32[]> result(new uint32[sprite->width * sprite->height]);
+
+ /* Prepare new DrawPixelInfo - Normally this would be the screen but we want to draw to another buffer here.
+ * Normally, pitch would be scaled screen width, but in our case our "screen" is only the sprite width wide. */
+ DrawPixelInfo dpi;
+ dpi.dst_ptr = result.get();
+ dpi.pitch = sprite->width;
+ dpi.left = 0;
+ dpi.top = 0;
+ dpi.width = sprite->width;
+ dpi.height = sprite->height;
+ dpi.zoom = ZOOM_LVL_NORMAL;
+
+ /* Zero out the allocated memory, there may be garbage present. */
+ uint32 *writeHead = (uint32*)result.get();
+ for (int i = 0; i < sprite->width * sprite->height; i++) {
+ writeHead[i] = 0;
+ }
+
+ /* Temporarily disable screen animations while blitting - This prevents 40bpp_anim from writing to the animation buffer. */
+ _screen_disable_anim = true;
+ GfxBlitter<1, false>(sprite, 0, 0, BM_NORMAL, nullptr, real_sprite, ZOOM_LVL_NORMAL, &dpi);
+ _screen_disable_anim = false;
+
+ return result;
+}
+
static void GfxMainBlitterViewport(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub, SpriteID sprite_id)
{
GfxBlitter<ZOOM_LVL_BASE, false>(sprite, x, y, mode, sub, sprite_id, _cur_dpi->zoom);
diff --git a/src/gfx_func.h b/src/gfx_func.h
index f23f8bfee..462f693b6 100644
--- a/src/gfx_func.h
+++ b/src/gfx_func.h
@@ -68,6 +68,7 @@ extern std::vector<Dimension> _resolutions;
extern Dimension _cur_resolution;
extern Palette _cur_palette; ///< Current palette
+void HandleToolbarHotkey(int hotkey);
void HandleKeypress(uint keycode, WChar key);
void HandleTextInput(const char *str, bool marked = false, const char *caret = nullptr, const char *insert_location = nullptr, const char *replacement_end = nullptr);
void HandleCtrlChanged();
@@ -90,6 +91,7 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo);
Dimension GetSpriteSize(SpriteID sprid, Point *offset = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI);
void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr);
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI);
+std::unique_ptr<uint32[]> DrawSpriteToRgbaBuffer(SpriteID spriteId);
int DrawString(int left, int right, int top, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);
int DrawString(int left, int right, int top, const std::string &str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL);
diff --git a/src/os/macosx/osx_stdafx.h b/src/os/macosx/osx_stdafx.h
index 9c4276d05..c8de60e22 100644
--- a/src/os/macosx/osx_stdafx.h
+++ b/src/os/macosx/osx_stdafx.h
@@ -30,6 +30,10 @@
#define HAVE_OSX_1012_SDK
#endif
+#ifdef MAC_OS_X_VERSION_10_15
+#define HAVE_OSX_1015_SDK
+#endif
+
/* It would seem that to ensure backward compatibility we have to ensure that we have defined MAC_OS_X_VERSION_10_x everywhere */
#ifndef MAC_OS_X_VERSION_10_3
#define MAC_OS_X_VERSION_10_3 1030
diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp
index ddc07854b..f5b3fa3b7 100644
--- a/src/toolbar_gui.cpp
+++ b/src/toolbar_gui.cpp
@@ -1944,49 +1944,6 @@ static ToolbarButtonProc * const _toolbar_button_procs[] = {
ToolbarSwitchClick,
};
-enum MainToolbarHotkeys {
- MTHK_PAUSE,
- MTHK_FASTFORWARD,
- MTHK_SETTINGS,
- MTHK_SAVEGAME,
- MTHK_LOADGAME,
- MTHK_SMALLMAP,
- MTHK_TOWNDIRECTORY,
- MTHK_SUBSIDIES,
- MTHK_STATIONS,
- MTHK_FINANCES,
- MTHK_COMPANIES,
- MTHK_STORY,
- MTHK_GOAL,
- MTHK_GRAPHS,
- MTHK_LEAGUE,
- MTHK_INDUSTRIES,
- MTHK_TRAIN_LIST,
- MTHK_ROADVEH_LIST,
- MTHK_SHIP_LIST,
- MTHK_AIRCRAFT_LIST,
- MTHK_ZOOM_IN,
- MTHK_ZOOM_OUT,
- MTHK_BUILD_RAIL,
- MTHK_BUILD_ROAD,
- MTHK_BUILD_TRAM,
- MTHK_BUILD_DOCKS,
- MTHK_BUILD_AIRPORT,
- MTHK_BUILD_TREES,
- MTHK_MUSIC,
- MTHK_LANDINFO,
- MTHK_AI_DEBUG,
- MTHK_SMALL_SCREENSHOT,
- MTHK_ZOOMEDIN_SCREENSHOT,
- MTHK_DEFAULTZOOM_SCREENSHOT,
- MTHK_GIANT_SCREENSHOT,
- MTHK_CHEATS,
- MTHK_TERRAFORM,
- MTHK_EXTRA_VIEWPORT,
- MTHK_CLIENT_LIST,
- MTHK_SIGN_LIST,
-};
-
/** Main toolbar. */
struct MainToolbarWindow : Window {
GUITimer timer;
diff --git a/src/toolbar_gui.h b/src/toolbar_gui.h
index 6199e0eb7..5b8000f0c 100644
--- a/src/toolbar_gui.h
+++ b/src/toolbar_gui.h
@@ -10,6 +10,49 @@
#ifndef TOOLBAR_GUI_H
#define TOOLBAR_GUI_H
+enum MainToolbarHotkeys {
+ MTHK_PAUSE,
+ MTHK_FASTFORWARD,
+ MTHK_SETTINGS,
+ MTHK_SAVEGAME,
+ MTHK_LOADGAME,
+ MTHK_SMALLMAP,
+ MTHK_TOWNDIRECTORY,
+ MTHK_SUBSIDIES,
+ MTHK_STATIONS,
+ MTHK_FINANCES,
+ MTHK_COMPANIES,
+ MTHK_STORY,
+ MTHK_GOAL,
+ MTHK_GRAPHS,
+ MTHK_LEAGUE,
+ MTHK_INDUSTRIES,
+ MTHK_TRAIN_LIST,
+ MTHK_ROADVEH_LIST,
+ MTHK_SHIP_LIST,
+ MTHK_AIRCRAFT_LIST,
+ MTHK_ZOOM_IN,
+ MTHK_ZOOM_OUT,
+ MTHK_BUILD_RAIL,
+ MTHK_BUILD_ROAD,
+ MTHK_BUILD_TRAM,
+ MTHK_BUILD_DOCKS,
+ MTHK_BUILD_AIRPORT,
+ MTHK_BUILD_TREES,
+ MTHK_MUSIC,
+ MTHK_LANDINFO,
+ MTHK_AI_DEBUG,
+ MTHK_SMALL_SCREENSHOT,
+ MTHK_ZOOMEDIN_SCREENSHOT,
+ MTHK_DEFAULTZOOM_SCREENSHOT,
+ MTHK_GIANT_SCREENSHOT,
+ MTHK_CHEATS,
+ MTHK_TERRAFORM,
+ MTHK_EXTRA_VIEWPORT,
+ MTHK_CLIENT_LIST,
+ MTHK_SIGN_LIST
+};
+
void AllocateToolbar();
void ToggleBoundingBoxes();
void ToggleDirtyBlocks();
diff --git a/src/video/cocoa/cocoa_wnd.h b/src/video/cocoa/cocoa_wnd.h
index 3ddd5a4f0..0b5c51b99 100644
--- a/src/video/cocoa/cocoa_wnd.h
+++ b/src/video/cocoa/cocoa_wnd.h
@@ -11,6 +11,8 @@
#define COCOA_WND_H
#import <Cocoa/Cocoa.h>
+#include "toolbar_gui.h"
+#include "table/sprites.h"
class VideoDriver_Cocoa;
@@ -28,8 +30,67 @@ 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
+#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;
diff --git a/src/video/cocoa/cocoa_wnd.mm b/src/video/cocoa/cocoa_wnd.mm
index 05b55e2a8..9ded8c80d 100644
--- a/src/video/cocoa/cocoa_wnd.mm
+++ b/src/video/cocoa/cocoa_wnd.mm
@@ -32,7 +32,7 @@
#include "../../gfx_func.h"
#include "../../window_func.h"
#include "../../window_gui.h"
-
+#include "spritecache.h"
/* Table data for key mapping. */
#include "cocoa_keys.h"
@@ -405,6 +405,87 @@ 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
*/
diff --git a/src/window.cpp b/src/window.cpp
index 407288511..d07b597e4 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -2587,6 +2587,22 @@ EventState Window::HandleEditBoxKey(int wid, WChar key, uint16 keycode)
}
/**
+ * Handle Toolbar hotkey events - can come from a source like the MacBook Touch Bar.
+ * @param hotkey Hotkey code
+ */
+void HandleToolbarHotkey(int hotkey)
+{
+ assert(HasModalProgress() || IsLocalCompany());
+
+ Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+ if (w != nullptr) {
+ if (w->window_desc->hotkeys != nullptr) {
+ if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return;
+ }
+ }
+}
+
+/**
* Handle keyboard input.
* @param keycode Virtual keycode of the key.
* @param key Unicode character of the key.