OpenRCT2/src/openrct2-ui/UiContext.macOS.mm

230 lines
7.5 KiB
Plaintext
Raw Normal View History

/*****************************************************************************
2020-07-21 15:04:34 +02:00
* Copyright (c) 2014-2020 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#if defined(__APPLE__) && defined(__MACH__)
2018-07-21 16:17:06 +02:00
# include "UiContext.h"
2018-07-21 16:17:06 +02:00
# include <openrct2/common.h>
# include <openrct2/core/String.hpp>
# include <openrct2/ui/UiContext.h>
2018-06-21 12:48:12 +02:00
// undefine `interface` and `abstract`, because it's causing conflicts with Objective-C's keywords
2018-07-21 16:17:06 +02:00
# undef interface
# undef abstract
2018-06-21 12:48:12 +02:00
2020-08-01 13:44:06 +02:00
# include <ApplicationServices/ApplicationServices.h>
2018-07-21 16:17:06 +02:00
# import <Cocoa/Cocoa.h>
2020-08-01 13:44:06 +02:00
# include <CoreFoundation/CFBundle.h>
2018-07-21 16:17:06 +02:00
# include <SDL.h>
# include <mach-o/dyld.h>
2020-08-01 13:44:06 +02:00
# include <string>
2018-02-16 00:43:16 +01:00
namespace OpenRCT2::Ui
{
class macOSContext final : public IPlatformUiContext
{
private:
public:
macOSContext()
{
2020-07-27 17:20:28 +02:00
@autoreleasepool
{
2018-06-22 23:22:29 +02:00
if ([NSWindow respondsToSelector:@selector(setAllowsAutomaticWindowTabbing:)])
{
2017-05-17 19:22:25 +02:00
[NSWindow setAllowsAutomaticWindowTabbing:NO];
}
}
}
2018-06-22 23:22:29 +02:00
void SetWindowIcon(SDL_Window* window) override
{
}
bool IsSteamOverlayAttached() override
{
2017-05-17 19:22:25 +02:00
STUB();
return false;
}
2018-06-22 23:22:29 +02:00
void ShowMessageBox(SDL_Window* window, const std::string& message) override
{
2020-07-27 17:20:28 +02:00
@autoreleasepool
{
2018-06-22 23:22:29 +02:00
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
2017-05-17 19:22:25 +02:00
[alert addButtonWithTitle:@"OK"];
alert.messageText = [NSString stringWithUTF8String:message.c_str()];
[alert runModal];
}
}
2020-10-21 19:53:22 +02:00
bool HasMenuSupport() override
{
return false;
}
int32_t ShowMenuDialog(
const std::vector<std::string>& options, const std::string& title, const std::string& text) override
{
return -1;
}
2018-09-04 15:38:19 +02:00
void OpenFolder(const std::string& path) override
{
2020-07-27 17:20:28 +02:00
@autoreleasepool
{
2018-09-04 15:38:19 +02:00
NSString* nsPath = [NSString stringWithUTF8String:path.c_str()];
2020-07-27 17:20:28 +02:00
NSURL* folderURL = [NSURL fileURLWithPath:nsPath];
[[NSWorkspace sharedWorkspace] openURL:folderURL];
2018-09-04 15:38:19 +02:00
}
}
void OpenURL(const std::string& url) override
{
2020-08-01 13:44:06 +02:00
CFURLRef urlRef = CFURLCreateWithBytes(
nullptr, reinterpret_cast<const UInt8*>(url.c_str()), url.length(), kCFStringEncodingUTF8, nullptr);
LSOpenCFURLRef(urlRef, 0);
CFRelease(urlRef);
}
2018-06-22 23:22:29 +02:00
std::string ShowFileDialog(SDL_Window* window, const FileDialogDesc& desc) override
{
2020-07-27 17:20:28 +02:00
@autoreleasepool
{
2018-06-22 23:22:29 +02:00
NSMutableArray* extensions = [NSMutableArray new];
for (const OpenRCT2::Ui::FileDialogDesc::Filter& filter : desc.Filters)
{
if (filter.Pattern != "")
{
NSString* fp = [NSString stringWithUTF8String:filter.Pattern.c_str()];
2017-05-17 19:22:25 +02:00
fp = [fp stringByReplacingOccurrencesOfString:@"*." withString:@""];
[extensions addObjectsFromArray:[fp componentsSeparatedByString:@";"]];
}
}
2018-06-22 23:22:29 +02:00
NSString* directory;
NSSavePanel* panel;
2022-01-28 23:50:24 +01:00
if (desc.Type == FileDialogType::Save)
2017-05-17 19:22:25 +02:00
{
2018-06-22 23:22:29 +02:00
NSString* filePath = [NSString stringWithUTF8String:desc.DefaultFilename.c_str()];
2017-05-17 19:22:25 +02:00
directory = filePath.stringByDeletingLastPathComponent;
2018-06-22 23:22:29 +02:00
NSString* basename = filePath.lastPathComponent;
2017-05-17 19:22:25 +02:00
panel = [NSSavePanel savePanel];
panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.%@", basename, extensions.firstObject];
}
2022-01-28 23:50:24 +01:00
else if (desc.Type == FileDialogType::Open)
2017-05-17 19:22:25 +02:00
{
directory = [NSString stringWithUTF8String:desc.InitialDirectory.c_str()];
2018-06-22 23:22:29 +02:00
NSOpenPanel* open = [NSOpenPanel openPanel];
2017-05-17 19:22:25 +02:00
open.canChooseDirectories = false;
open.canChooseFiles = true;
open.allowsMultipleSelection = false;
panel = open;
2018-06-22 23:22:29 +02:00
}
else
{
2017-05-17 19:22:25 +02:00
return std::string();
}
panel.title = [NSString stringWithUTF8String:desc.Title.c_str()];
panel.allowedFileTypes = extensions;
panel.directoryURL = [NSURL fileURLWithPath:directory];
if ([panel runModal] == NSModalResponseCancel)
{
2017-05-17 19:22:25 +02:00
return std::string();
2018-06-22 23:22:29 +02:00
}
else
{
2017-05-17 19:22:25 +02:00
return panel.URL.path.UTF8String;
}
}
}
2018-06-22 23:22:29 +02:00
std::string ShowDirectoryDialog(SDL_Window* window, const std::string& title) override
{
2020-07-27 17:20:28 +02:00
@autoreleasepool
{
2018-06-22 23:22:29 +02:00
NSOpenPanel* panel = [NSOpenPanel openPanel];
2017-05-17 19:22:25 +02:00
panel.canChooseFiles = false;
panel.canChooseDirectories = true;
panel.allowsMultipleSelection = false;
if ([panel runModal] == NSModalResponseOK)
2017-05-17 19:22:25 +02:00
{
2018-06-22 23:22:29 +02:00
NSString* selectedPath = panel.URL.path;
const char* path = selectedPath.UTF8String;
return path;
2018-06-22 23:22:29 +02:00
}
else
{
return "";
2017-05-17 19:22:25 +02:00
}
}
}
2020-11-08 13:29:44 +01:00
bool HasFilePicker() const override
{
return true;
}
private:
2018-06-22 23:22:29 +02:00
static int32_t Execute(const std::string& command, std::string* output = nullptr)
{
log_verbose("executing \"%s\"...", command.c_str());
2018-06-22 23:22:29 +02:00
FILE* fpipe = popen(command.c_str(), "r");
if (fpipe == nullptr)
{
return -1;
}
if (output != nullptr)
{
// Read output into buffer
std::vector<char> outputBuffer;
char buffer[1024];
size_t readBytes;
while ((readBytes = fread(buffer, 1, sizeof(buffer), fpipe)) > 0)
{
outputBuffer.insert(outputBuffer.begin(), buffer, buffer + readBytes);
}
// Trim line breaks
size_t outputLength = outputBuffer.size();
for (size_t i = outputLength - 1; i != SIZE_MAX; i--)
{
if (outputBuffer[i] == '\n')
{
outputLength = i;
}
else
{
break;
}
}
// Convert to string
*output = std::string(outputBuffer.data(), outputLength);
}
else
{
fflush(fpipe);
}
// Return exit code
return pclose(fpipe);
}
};
std::unique_ptr<IPlatformUiContext> CreatePlatformUiContext()
{
return std::make_unique<macOSContext>();
}
2018-05-04 22:40:09 +02:00
} // namespace OpenRCT2::Ui
#endif // __APPLE__ && __MACH__