2017-05-12 01:37:00 +02:00
|
|
|
/*****************************************************************************
|
2018-06-15 14:07:34 +02:00
|
|
|
* Copyright (c) 2014-2018 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.
|
|
|
|
*****************************************************************************/
|
2017-05-12 01:37:00 +02:00
|
|
|
|
|
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
|
|
|
2018-07-21 16:17:06 +02:00
|
|
|
# include "UiContext.h"
|
2017-05-12 01:37:00 +02:00
|
|
|
|
2018-07-21 16:17:06 +02:00
|
|
|
# include <openrct2/common.h>
|
|
|
|
# include <openrct2/core/String.hpp>
|
|
|
|
# include <openrct2/ui/UiContext.h>
|
2017-05-12 01:37:00 +02:00
|
|
|
|
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
|
|
|
|
2018-07-21 16:17:06 +02:00
|
|
|
# import <Cocoa/Cocoa.h>
|
|
|
|
# include <SDL.h>
|
|
|
|
# include <mach-o/dyld.h>
|
2017-05-12 01:37:00 +02:00
|
|
|
|
2018-02-16 00:43:16 +01:00
|
|
|
namespace OpenRCT2::Ui
|
2017-05-12 01:37:00 +02:00
|
|
|
{
|
|
|
|
class macOSContext final : public IPlatformUiContext
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
public:
|
|
|
|
macOSContext()
|
|
|
|
{
|
2017-05-17 19:22:25 +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];
|
|
|
|
}
|
|
|
|
}
|
2017-05-12 01:37:00 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
void SetWindowIcon(SDL_Window* window) override
|
2017-05-12 01:37:00 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsSteamOverlayAttached() override
|
|
|
|
{
|
2017-05-17 19:22:25 +02:00
|
|
|
STUB();
|
|
|
|
return false;
|
2017-05-12 01:37:00 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
void ShowMessageBox(SDL_Window* window, const std::string& message) override
|
2017-05-12 01:37:00 +02:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
@autoreleasepool {
|
|
|
|
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];
|
|
|
|
}
|
2017-05-12 01:37:00 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 15:38:19 +02:00
|
|
|
void OpenFolder(const std::string& path) override
|
|
|
|
{
|
|
|
|
@autoreleasepool {
|
|
|
|
NSString* nsPath = [NSString stringWithUTF8String:path.c_str()];
|
|
|
|
NSURL *folderURL = [NSURL fileURLWithPath: nsPath];
|
|
|
|
[[NSWorkspace sharedWorkspace] openURL: folderURL];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
std::string ShowFileDialog(SDL_Window* window, const FileDialogDesc& desc) override
|
2017-05-12 01:37:00 +02:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
@autoreleasepool {
|
|
|
|
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;
|
2017-05-17 19:22:25 +02:00
|
|
|
if (desc.Type == FILE_DIALOG_TYPE::SAVE)
|
|
|
|
{
|
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];
|
|
|
|
}
|
|
|
|
else if (desc.Type == FILE_DIALOG_TYPE::OPEN)
|
|
|
|
{
|
|
|
|
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];
|
2017-10-06 01:46:23 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2017-05-12 01:37:00 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
std::string ShowDirectoryDialog(SDL_Window* window, const std::string& title) override
|
2017-05-12 01:37:00 +02:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
@autoreleasepool {
|
|
|
|
NSOpenPanel* panel = [NSOpenPanel openPanel];
|
2017-05-17 19:22:25 +02:00
|
|
|
panel.canChooseFiles = false;
|
|
|
|
panel.canChooseDirectories = true;
|
|
|
|
panel.allowsMultipleSelection = false;
|
2017-10-06 01:46:23 +02:00
|
|
|
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;
|
2017-07-14 01:12:03 +02:00
|
|
|
return path;
|
2018-06-22 23:22:29 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-07-14 01:12:03 +02:00
|
|
|
return "";
|
2017-05-17 19:22:25 +02:00
|
|
|
}
|
|
|
|
}
|
2017-05-12 01:37:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-06-22 23:22:29 +02:00
|
|
|
static int32_t Execute(const std::string& command, std::string* output = nullptr)
|
2017-05-12 01:37:00 +02:00
|
|
|
{
|
|
|
|
log_verbose("executing \"%s\"...\n", command.c_str());
|
2018-06-22 23:22:29 +02:00
|
|
|
FILE* fpipe = popen(command.c_str(), "r");
|
2017-05-12 01:37:00 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2017-05-12 01:37:00 +02:00
|
|
|
// Convert to string
|
|
|
|
*output = std::string(outputBuffer.data(), outputLength);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fflush(fpipe);
|
|
|
|
}
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2017-05-12 01:37:00 +02:00
|
|
|
// Return exit code
|
|
|
|
return pclose(fpipe);
|
|
|
|
}
|
|
|
|
};
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
IPlatformUiContext* CreatePlatformUiContext()
|
2017-05-12 01:37:00 +02:00
|
|
|
{
|
|
|
|
return new macOSContext();
|
|
|
|
}
|
2018-05-04 22:40:09 +02:00
|
|
|
} // namespace OpenRCT2::Ui
|
2017-05-12 01:37:00 +02:00
|
|
|
|
|
|
|
#endif // __APPLE__ && __MACH__
|