Update to v092r04 release.

byuu says:

This is the first release with full support for OS X, although it's
certainly still very buggy.

Known issues:
- window status bars are still unsupported (they just don't show up)
- you get the bad keypress chime when you use the keyboard
- window geometry and font metrics aren't perfect (bit of clipping here
  and there)
- list view headers that aren't auto-sized are sometimes too short (file
  browser)
- input assignment is really rough (assigning a key also moves around in
  the list or beeps at you)

Custom OS X integration support so far:
- 512x512 ICNS application icon: will look razor-sharp even on a retina
  display
- basic Info.plist added to application bundle
- program menu about, preferences, quit all connected
- Settings->Configuration removed (use higan->Preferences instead)
- global menubar

To compile and use this, you'll need:
- Xz Utils (to extract .tar.xz)
- Xcode 4.6
- Lion 10.7.4 or newer

    mkdir higan_v092r04
    tar -xJf higan_v092r04.tar.xz -C higan_v092r04
    cd higan_v092r04
    make -j 2

ananke is missing, and I haven't updated purify yet, so you'll have to
move game folders from Windows or Linux over, or make them by hand (a
not so enjoyable experience, to say the least.)
This commit is contained in:
Tim Allen 2013-03-19 19:48:50 +11:00
parent b7c212de7e
commit fdd3ea490e
65 changed files with 1020 additions and 607 deletions

View File

@ -14,8 +14,8 @@ target := ethos
# console := true # console := true
# compiler # compiler
flags := -I. -O3 -fomit-frame-pointer flags += -I. -O3 -fomit-frame-pointer
link := -s link +=
objects := libco objects := libco
# profile-guided optimization mode # profile-guided optimization mode
@ -32,7 +32,9 @@ endif
# platform # platform
ifeq ($(platform),x) ifeq ($(platform),x)
flags += -march=native flags += -march=native
link += -Wl,-export-dynamic -ldl -lX11 -lXext link += -s -Wl,-export-dynamic -ldl -lX11 -lXext
else ifeq ($(platform),osx)
flags += -march=native
else ifeq ($(platform),win) else ifeq ($(platform),win)
ifeq ($(arch),win32) ifeq ($(arch),win32)
flags += -m32 flags += -m32
@ -43,7 +45,7 @@ else ifeq ($(platform),win)
else else
link += -mwindows link += -mwindows
endif endif
link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 -lws2_32 link += -s -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 -lws2_32
link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
else else
$(error unsupported platform.) $(error unsupported platform.)
@ -55,9 +57,9 @@ ui := target-$(target)
compile = \ compile = \
$(strip \ $(strip \
$(if $(filter %.c,$<), \ $(if $(filter %.c,$<), \
$(c) $(flags) $1 -c $< -o $@, \ $(compiler) $(cflags) $(flags) $1 -c $< -o $@, \
$(if $(filter %.cpp,$<), \ $(if $(filter %.cpp,$<), \
$(cpp) $(flags) $1 -c $< -o $@ \ $(compiler) $(cppflags) $(flags) $1 -c $< -o $@ \
) \ ) \
) \ ) \
) )

10
higan/data/Info.plist Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>higan</string>
<key>CFBundleIconFile</key>
<string>higan.icns</string>
</dict>
</plist>

BIN
higan/data/higan512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -3,9 +3,10 @@
namespace Emulator { namespace Emulator {
static const char Name[] = "higan"; static const char Name[] = "higan";
static const char Version[] = "092.03"; static const char Version[] = "092.04";
static const char Author[] = "byuu"; static const char Author[] = "byuu";
static const char License[] = "GPLv3"; static const char License[] = "GPLv3";
static const char Website[] = "http://byuu.org/";
} }
#include <nall/platform.hpp> #include <nall/platform.hpp>

View File

@ -1,4 +1,5 @@
#include <fc/fc.hpp> #include <fc/fc.hpp>
#include <cmath>
#define VIDEO_CPP #define VIDEO_CPP
namespace Famicom { namespace Famicom {

View File

@ -37,19 +37,27 @@ endif
ifeq ($(compiler),) ifeq ($(compiler),)
ifeq ($(platform),win) ifeq ($(platform),win)
compiler := g++ compiler := g++
flags :=
link :=
else ifeq ($(platform),osx) else ifeq ($(platform),osx)
compiler := clang compiler := clang
flags := -w -stdlib=libc++
link := -lc++ -lobjc
else else
compiler := g++-4.7 compiler := g++-4.7
flags :=
link :=
endif endif
cflags := -x c -std=gnu99
objcflags := -x objective-c -std=gnu99
cppflags := -x c++ -std=gnu++11
objcppflags := -x objective-c++ -std=gnu++11
endif endif
c := $(compiler) -x c -std=gnu99
cpp := $(compiler) -std=gnu++11
ifeq ($(arch),x86) ifeq ($(arch),x86)
c := $(c) -m32 flags := -m32 $(flags)
cpp := $(cpp) -m32 link := -m32 $(link)
endif endif
ifeq ($(prefix),) ifeq ($(prefix),)

View File

@ -1,6 +1,7 @@
#ifdef NALL_DSP_INTERNAL_HPP #ifdef NALL_DSP_INTERNAL_HPP
#include <math.h> #include <math.h>
#include <vector>
#include <nall/stdint.hpp> #include <nall/stdint.hpp>
namespace nall { namespace nall {

View File

@ -4,18 +4,21 @@ ifeq ($(platform),x)
endif endif
ifeq ($(phoenix),gtk) ifeq ($(phoenix),gtk)
phoenixflags := -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0` phoenixflags = $(cppflags) $(flags) -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`
phoenixlink := `pkg-config --libs gtk+-2.0` phoenixlink = `pkg-config --libs gtk+-2.0`
endif endif
ifeq ($(phoenix),qt) ifeq ($(phoenix),qt)
phoenixflags := -DPHOENIX_QT `pkg-config --cflags QtCore QtGui` phoenixflags = $(cppflags) $(flags) -DPHOENIX_QT `pkg-config --cflags QtCore QtGui`
phoenixlink := `pkg-config --libs QtCore QtGui` phoenixlink = `pkg-config --libs QtCore QtGui`
endif endif
else ifeq ($(platform),osx)
phoenixflags = $(objcppflags) $(flags) -DPHOENIX_COCOA
phoenixlink = -framework Cocoa -framework Carbon
else ifeq ($(platform),win) else ifeq ($(platform),win)
phoenixflags := -DPHOENIX_WINDOWS phoenixflags = $(cppflags) $(flags) -DPHOENIX_WINDOWS
phoenixlink := -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi phoenixlink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi
else else
phoenixflags := -DPHOENIX_REFERENCE phoenixflags = $(cppflags) $(flags) -DPHOENIX_REFERENCE
phoenixlink := phoenixlink =
endif endif

View File

@ -1,19 +1,8 @@
@implementation CocoaSeparator : NSMenuItem
-(id) initWith :(phoenix::Separator&)separatorReference {
if(self = [super separatorItem]) {
separator = &separatorReference;
}
return self;
}
@end
namespace phoenix { namespace phoenix {
void pSeparator::constructor() { void pSeparator::constructor() {
@autoreleasepool { @autoreleasepool {
cocoaAction = cocoaSeparator = [[CocoaSeparator alloc] initWith:separator]; cocoaAction = cocoaSeparator = [[NSMenuItem separatorItem] retain];
} }
} }

View File

@ -1,15 +1,8 @@
@interface CocoaSeparator : NSMenuItem {
@public
phoenix::Separator *separator;
}
-(id) initWith :(phoenix::Separator&)separator;
@end
namespace phoenix { namespace phoenix {
struct pSeparator : public pAction { struct pSeparator : public pAction {
Separator &separator; Separator &separator;
CocoaSeparator *cocoaSeparator; NSMenuItem *cocoaSeparator;
pSeparator(Separator &separator) : pAction(separator), separator(separator) {} pSeparator(Separator &separator) : pAction(separator), separator(separator) {}
void constructor(); void constructor();

View File

@ -1,22 +1,41 @@
namespace phoenix { namespace phoenix {
string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) { string pBrowserWindow::directory(BrowserWindow::State &state) {
string result;
@autoreleasepool {
NSOpenPanel *panel = [NSOpenPanel openPanel];
if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]];
[panel setCanChooseDirectories:YES];
[panel setCanChooseFiles:NO];
if([panel runModalForDirectory:[NSString stringWithUTF8String:state.path] file:nil] == NSOKButton) {
NSArray *names = [panel filenames];
const char *name = [[names objectAtIndex:0] UTF8String];
if(name) result = name;
}
}
return result;
}
string pBrowserWindow::open(BrowserWindow::State &state) {
string result; string result;
@autoreleasepool { @autoreleasepool {
NSMutableArray *filters = [[NSMutableArray alloc] init]; NSMutableArray *filters = [[NSMutableArray alloc] init];
for(auto &rule : filter) { for(auto &rule : state.filters) {
string pattern = rule.split<1>("(")(1).rtrim<1>(")"); string pattern = rule.split<1>("(")(1).rtrim<1>(")");
if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]]; if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]];
} }
NSOpenPanel *panel = [NSOpenPanel openPanel]; NSOpenPanel *panel = [NSOpenPanel openPanel];
if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]];
[panel setCanChooseDirectories:NO]; [panel setCanChooseDirectories:NO];
[panel setCanChooseFiles:YES]; [panel setCanChooseFiles:YES];
[panel setAllowedFileTypes:filters]; [panel setAllowedFileTypes:filters];
if([panel runModalForDirectory:[NSString stringWithUTF8String:path] file:nil] == NSOKButton) { if([panel runModalForDirectory:[NSString stringWithUTF8String:state.path] file:nil] == NSOKButton) {
NSArray *filenames = [panel filenames]; NSArray *names = [panel filenames];
const char *filename = [[filenames objectAtIndex:0] UTF8String]; const char *name = [[names objectAtIndex:0] UTF8String];
if(filename) result = filename; if(name) result = name;
} }
[filters release]; [filters release];
} }
@ -24,21 +43,22 @@ string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring
return result; return result;
} }
string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) { string pBrowserWindow::save(BrowserWindow::State &state) {
string result; string result;
@autoreleasepool { @autoreleasepool {
NSMutableArray *filters = [[NSMutableArray alloc] init]; NSMutableArray *filters = [[NSMutableArray alloc] init];
for(auto &rule : filter) { for(auto &rule : state.filters) {
string pattern = rule.split<1>("(")(1).rtrim<1>(")"); string pattern = rule.split<1>("(")(1).rtrim<1>(")");
if(!pattern.empty()) [filters addObjects:[NSString stringWithUTF8String:pattern]]; if(!pattern.empty()) [filters addObjects:[NSString stringWithUTF8String:pattern]];
} }
NSSavePanel *panel = [NSSavePanel savePanel]; NSSavePanel *panel = [NSSavePanel savePanel];
if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]];
[panel setAllowedFileTypes:filters]; [panel setAllowedFileTypes:filters];
if([panel runModalForDirectory:[NSString stringWithUTF8String:path] file:nil] == NSOKButton) { if([panel runModalForDirectory:[NSString stringWithUTF8String:state.path] file:nil] == NSOKButton) {
NSArray *filenames = [panel filenames]; NSArray *names = [panel filenames];
const char *filename = [[filenames objectAtIndex:0] UTF8String]; const char *name = [[names objectAtIndex:0] UTF8String];
if(filename) result = filename; if(name) result = name;
} }
[filters release]; [filters release];
} }
@ -46,21 +66,4 @@ string pDialogWindow::fileSave(Window &parent, const string &path, const lstring
return result; return result;
} }
string pDialogWindow::folderSelect(Window &parent, const string &path) {
string result;
@autoreleasepool {
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setCanChooseDirectories:YES];
[panel setCanChooseFiles:NO];
if([panel runModalForDirectory:[NSString stringWithUTF8String:path] file:nil] == NSOKButton) {
NSArray *filenames = [panel filenames];
const char *filename = [[filenames objectAtIndex:0] UTF8String];
if(filename) result = filename;
}
}
return result;
}
} }

View File

@ -0,0 +1,9 @@
namespace phoenix {
struct pBrowserWindow {
static string directory(BrowserWindow::State &state);
static string open(BrowserWindow::State &state);
static string save(BrowserWindow::State &state);
};
}

View File

@ -1,9 +0,0 @@
namespace phoenix {
struct pDialogWindow {
static string fileOpen(Window &parent, const string &path, const lstring &filter);
static string fileSave(Window &parent, const string &path, const lstring &filter);
static string folderSelect(Window &parent, const string &path);
};
}

View File

@ -1,27 +1,14 @@
namespace phoenix { namespace phoenix {
MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { enum class MessageWindowType : unsigned { Error, Information, Question, Warning };
return message(parent, text, buttons, Type::Information);
}
MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response MessageWindow_dialog(MessageWindow::State &state, MessageWindowType type) {
return message(parent, text, buttons, Type::Question);
}
MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return message(parent, text, buttons, Type::Warning);
}
MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return message(parent, text, buttons, Type::Critical);
}
MessageWindow::Response pMessageWindow::message(Window &parent, const string &text, MessageWindow::Buttons buttons, Type type) {
@autoreleasepool { @autoreleasepool {
NSAlert *alert = [[[NSAlert alloc] init] autorelease]; NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert setMessageText:[NSString stringWithUTF8String:text]]; if(state.title) [alert setMessageText:[NSString stringWithUTF8String:state.title]];
[alert setInformativeText:[NSString stringWithUTF8String:state.text]];
switch(buttons) { switch(state.buttons) {
case MessageWindow::Buttons::Ok: case MessageWindow::Buttons::Ok:
[alert addButtonWithTitle:@"Ok"]; [alert addButtonWithTitle:@"Ok"];
break; break;
@ -41,16 +28,16 @@ MessageWindow::Response pMessageWindow::message(Window &parent, const string &te
} }
switch(type) { switch(type) {
case Type::Information: [alert setAlertStyle:NSInformationalAlertStyle]; break; case MessageWindowType::Error: [alert setAlertStyle:NSCriticalAlertStyle]; break;
case Type::Question: [alert setAlertStyle:NSInformationalAlertStyle]; break; case MessageWindowType::Information: [alert setAlertStyle:NSInformationalAlertStyle]; break;
case Type::Warning: [alert setAlertStyle:NSWarningAlertStyle]; break; case MessageWindowType::Question: [alert setAlertStyle:NSInformationalAlertStyle]; break;
case Type::Critical: [alert setAlertStyle:NSCriticalAlertStyle]; break; case MessageWindowType::Warning: [alert setAlertStyle:NSWarningAlertStyle]; break;
} }
NSInteger response = [alert runModal]; NSInteger response = [alert runModal];
//[alert beginSheetModalForWindow:parent.p.cocoaWindow modalDelegate:self didEndSelector:@selector(...) contextInfo:nil]; //[alert beginSheetModalForWindow:parent.p.cocoaWindow modalDelegate:self didEndSelector:@selector(...) contextInfo:nil];
switch(buttons) { switch(state.buttons) {
case MessageWindow::Buttons::Ok: case MessageWindow::Buttons::Ok:
if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Ok; if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Ok;
break; break;
@ -70,7 +57,23 @@ MessageWindow::Response pMessageWindow::message(Window &parent, const string &te
} }
} }
return MessageWindow::Response::Ok; throw;
}
MessageWindow::Response pMessageWindow::error(MessageWindow::State &state) {
return MessageWindow_dialog(state, MessageWindowType::Error);
}
MessageWindow::Response pMessageWindow::information(MessageWindow::State &state) {
return MessageWindow_dialog(state, MessageWindowType::Information);
}
MessageWindow::Response pMessageWindow::question(MessageWindow::State &state) {
return MessageWindow_dialog(state, MessageWindowType::Question);
}
MessageWindow::Response pMessageWindow::warning(MessageWindow::State &state) {
return MessageWindow_dialog(state, MessageWindowType::Warning);
} }
} }

View File

@ -1,13 +1,10 @@
namespace phoenix { namespace phoenix {
struct pMessageWindow { struct pMessageWindow {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response error(MessageWindow::State &state);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response information(MessageWindow::State &state);
static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response question(MessageWindow::State &state);
static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response warning(MessageWindow::State &state);
enum class Type : unsigned { Information, Question, Warning, Critical };
static MessageWindow::Response message(Window &parent, const string &text, MessageWindow::Buttons buttons, Type type);
}; };
} }

View File

@ -4,7 +4,7 @@
#include "desktop.cpp" #include "desktop.cpp"
#include "keyboard.cpp" #include "keyboard.cpp"
#include "mouse.cpp" #include "mouse.cpp"
#include "dialog-window.cpp" #include "browser-window.cpp"
#include "message-window.cpp" #include "message-window.cpp"
#include "font.cpp" #include "font.cpp"
#include "timer.cpp" #include "timer.cpp"

View File

@ -10,7 +10,7 @@ namespace phoenix {
#include "desktop.hpp" #include "desktop.hpp"
#include "keyboard.hpp" #include "keyboard.hpp"
#include "mouse.hpp" #include "mouse.hpp"
#include "dialog-window.hpp" #include "browser-window.hpp"
#include "message-window.hpp" #include "message-window.hpp"
#include "object.hpp" #include "object.hpp"
#include "timer.hpp" #include "timer.hpp"

View File

@ -1,3 +1,14 @@
@implementation CocoaHexEdit : NSScrollView
-(id) initWith :(phoenix::HexEdit&)hexEditReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
hexEdit = &hexEditReference;
}
return self;
}
@end
namespace phoenix { namespace phoenix {
void pHexEdit::setColumns(unsigned columns) { void pHexEdit::setColumns(unsigned columns) {
@ -16,6 +27,15 @@ void pHexEdit::update() {
} }
void pHexEdit::constructor() { void pHexEdit::constructor() {
@autoreleasepool {
cocoaView = cocoaHexEdit = [[CocoaHexEdit alloc] initWith:hexEdit];
}
}
void pHexEdit::destructor() {
@autoreleasepool {
[cocoaView release];
}
} }
} }

View File

@ -1,7 +1,15 @@
@interface CocoaHexEdit : NSScrollView {
@public
phoenix::HexEdit *hexEdit;
}
-(id) initWith :(phoenix::HexEdit&)hexEdit;
@end
namespace phoenix { namespace phoenix {
struct pHexEdit : public pWidget { struct pHexEdit : public pWidget {
HexEdit &hexEdit; HexEdit &hexEdit;
CocoaHexEdit *cocoaHexEdit;
void setColumns(unsigned columns); void setColumns(unsigned columns);
void setLength(unsigned length); void setLength(unsigned length);
@ -11,6 +19,7 @@ struct pHexEdit : public pWidget {
pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {}
void constructor(); void constructor();
void destructor();
}; };
} }

View File

@ -1,10 +1,36 @@
@implementation CocoaViewport : NSView
-(id) initWith :(phoenix::Viewport&)viewportReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
viewport = &viewportReference;
}
return self;
}
-(void) drawRect :(NSRect)rect {
NSColor *background = [NSColor blackColor];
[background set];
NSRectFill([self bounds]);
}
@end
namespace phoenix { namespace phoenix {
uintptr_t pViewport::handle() { uintptr_t pViewport::handle() {
return 0; return (uintptr_t)cocoaViewport;
} }
void pViewport::constructor() { void pViewport::constructor() {
@autoreleasepool {
cocoaView = cocoaViewport = [[CocoaViewport alloc] initWith:viewport];
}
}
void pViewport::destructor() {
@autoreleasepool {
[cocoaView release];
}
} }
} }

View File

@ -1,12 +1,22 @@
@interface CocoaViewport : NSView {
@public
phoenix::Viewport *viewport;
}
-(id) initWith :(phoenix::Viewport&)viewport;
-(void) drawRect :(NSRect)rect;
@end
namespace phoenix { namespace phoenix {
struct pViewport : public pWidget { struct pViewport : public pWidget {
Viewport &viewport; Viewport &viewport;
CocoaViewport *cocoaViewport;
uintptr_t handle(); uintptr_t handle();
pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {}
void constructor(); void constructor();
void destructor();
}; };
} }

View File

@ -13,8 +13,7 @@
[self setLevel:NSFloatingWindowLevel]; //when launched from a terminal, this places the window above it [self setLevel:NSFloatingWindowLevel]; //when launched from a terminal, this places the window above it
[self setTitle:@""]; [self setTitle:@""];
menu = [[NSMenu alloc] init]; menuBar = [[NSMenu alloc] init];
[menu retain];
NSMenuItem *item; NSMenuItem *item;
string text; string text;
@ -22,9 +21,9 @@
rootMenu = [[NSMenu alloc] init]; rootMenu = [[NSMenu alloc] init];
item = [[[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""] autorelease]; item = [[[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""] autorelease];
[item setSubmenu:rootMenu]; [item setSubmenu:rootMenu];
[menu addItem:item]; [menuBar addItem:item];
text = {"About ", phoenix::applicationState.name, "..."}; text = {"About ", phoenix::applicationState.name, " ..."};
item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithUTF8String:text] action:@selector(menuAbout) keyEquivalent:@""] autorelease]; item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithUTF8String:text] action:@selector(menuAbout) keyEquivalent:@""] autorelease];
[rootMenu addItem:item]; [rootMenu addItem:item];
[rootMenu addItem:[NSMenuItem separatorItem]]; [rootMenu addItem:[NSMenuItem separatorItem]];
@ -51,7 +50,7 @@
-(void) windowDidBecomeMain :(NSNotification*)notification { -(void) windowDidBecomeMain :(NSNotification*)notification {
if(window->state.menu.size() > 0) { if(window->state.menu.size() > 0) {
[NSApp setMainMenu:menu]; [NSApp setMainMenu:menuBar];
} }
} }
@ -70,8 +69,8 @@
return NO; return NO;
} }
-(NSMenu*) menu { -(NSMenu*) menuBar {
return menu; return menuBar;
} }
-(void) menuAbout { -(void) menuAbout {
@ -107,7 +106,7 @@ void pWindow::append(Layout &layout) {
void pWindow::append(Menu &menu) { void pWindow::append(Menu &menu) {
@autoreleasepool { @autoreleasepool {
[[cocoaWindow menu] addItem:menu.p.cocoaAction]; [[cocoaWindow menuBar] addItem:menu.p.cocoaAction];
} }
} }
@ -164,7 +163,7 @@ void pWindow::remove(Layout &layout) {
void pWindow::remove(Menu &menu) { void pWindow::remove(Menu &menu) {
@autoreleasepool { @autoreleasepool {
[[cocoaWindow menu] removeItem:menu.p.cocoaAction]; [[cocoaWindow menuBar] removeItem:menu.p.cocoaAction];
} }
} }
@ -196,7 +195,6 @@ void pWindow::setFocused() {
void pWindow::setFullScreen(bool fullScreen) { void pWindow::setFullScreen(bool fullScreen) {
@autoreleasepool { @autoreleasepool {
[cocoaWindow setLevel:NSNormalWindowLevel];
if(fullScreen == true) { if(fullScreen == true) {
[NSApp setPresentationOptions:NSApplicationPresentationFullScreen]; [NSApp setPresentationOptions:NSApplicationPresentationFullScreen];
[cocoaWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; [cocoaWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
@ -273,8 +271,12 @@ void pWindow::setTitle(const string &text) {
void pWindow::setVisible(bool visible) { void pWindow::setVisible(bool visible) {
@autoreleasepool { @autoreleasepool {
if(visible) [cocoaWindow makeKeyAndOrderFront:nil]; if(visible) {
else [cocoaWindow orderOut:nil]; [cocoaWindow makeKeyAndOrderFront:nil];
[cocoaWindow setLevel:NSNormalWindowLevel];
} else {
[cocoaWindow orderOut:nil];
}
} }
} }

View File

@ -1,7 +1,7 @@
@interface CocoaWindow : NSWindow <NSWindowDelegate> { @interface CocoaWindow : NSWindow <NSWindowDelegate> {
@public @public
phoenix::Window *window; phoenix::Window *window;
NSMenu *menu; NSMenu *menuBar;
NSMenu *rootMenu; NSMenu *rootMenu;
} }
-(id) initWith :(phoenix::Window&)window; -(id) initWith :(phoenix::Window&)window;
@ -11,7 +11,7 @@
-(void) windowDidMove :(NSNotification*)notification; -(void) windowDidMove :(NSNotification*)notification;
-(void) windowDidResize :(NSNotification*)notification; -(void) windowDidResize :(NSNotification*)notification;
-(BOOL) windowShouldClose :(id)sender; -(BOOL) windowShouldClose :(id)sender;
-(NSMenu*) menu; -(NSMenu*) menuBar;
-(void) menuAbout; -(void) menuAbout;
-(void) menuPreferences; -(void) menuPreferences;
-(void) menuQuit; -(void) menuQuit;

View File

@ -166,42 +166,94 @@ bool Mouse::released(Mouse::Button button) {
return !pressed(button); return !pressed(button);
} }
//DialogWindow //BrowserWindow
//============ //=============
string DialogWindow::fileOpen_(Window &parent, const string &path, const lstring &filter_) { string BrowserWindow::directory() {
auto filter = filter_; return pBrowserWindow::directory(state);
if(filter.size() == 0) filter.append("All files (*)");
return pDialogWindow::fileOpen(parent, path, filter);
} }
string DialogWindow::fileSave_(Window &parent, const string &path, const lstring &filter_) { string BrowserWindow::open() {
auto filter = filter_; return pBrowserWindow::open(state);
if(filter.size() == 0) filter.append("All files (*)");
return pDialogWindow::fileSave(parent, path, filter);
} }
string DialogWindow::folderSelect(Window &parent, const string &path) { string BrowserWindow::save() {
return pDialogWindow::folderSelect(parent, path); return pBrowserWindow::save(state);
}
BrowserWindow& BrowserWindow::setFilters_(const lstring &filters) {
state.filters = filters;
return *this;
}
BrowserWindow& BrowserWindow::setParent(Window &parent) {
state.parent = &parent;
return *this;
}
BrowserWindow& BrowserWindow::setPath(const string &path) {
state.path = path;
return *this;
}
BrowserWindow& BrowserWindow::setTitle(const string &title) {
state.title = title;
return *this;
}
BrowserWindow::BrowserWindow():
state(*new State) {
}
BrowserWindow::~BrowserWindow() {
delete &state;
} }
//MessageWindow //MessageWindow
//============= //=============
MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response MessageWindow::error(MessageWindow::Buttons buttons) {
return pMessageWindow::information(parent, text, buttons); state.buttons = buttons;
return pMessageWindow::error(state);
} }
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response MessageWindow::information(MessageWindow::Buttons buttons) {
return pMessageWindow::question(parent, text, buttons); state.buttons = buttons;
return pMessageWindow::information(state);
} }
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response MessageWindow::question(MessageWindow::Buttons buttons) {
return pMessageWindow::warning(parent, text, buttons); state.buttons = buttons;
return pMessageWindow::question(state);
} }
MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow& MessageWindow::setParent(Window &parent) {
return pMessageWindow::critical(parent, text, buttons); state.parent = &parent;
return *this;
}
MessageWindow& MessageWindow::setText(const string &text) {
state.text = text;
return *this;
}
MessageWindow& MessageWindow::setTitle(const string &title) {
state.title = title;
return *this;
}
MessageWindow::Response MessageWindow::warning(MessageWindow::Buttons buttons) {
state.buttons = buttons;
return pMessageWindow::warning(state);
}
MessageWindow::MessageWindow(const string &text):
state(*new State) {
state.text = text;
}
MessageWindow::~MessageWindow() {
delete &state;
} }
//Object //Object

View File

@ -141,15 +141,21 @@ struct Mouse {
Mouse() = delete; Mouse() = delete;
}; };
struct DialogWindow { struct BrowserWindow {
template<typename... Args> static nall::string fileOpen(Window &parent, const nall::string &path, const Args&... args) { return fileOpen_(parent, path, { args... }); } template<typename... Args> BrowserWindow& setFilters(const Args&... args) { return setFilters_({args...}); }
template<typename... Args> static nall::string fileSave(Window &parent, const nall::string &path, const Args&... args) { return fileSave_(parent, path, { args... }); }
static nall::string folderSelect(Window &parent, const nall::string &path);
DialogWindow() = delete;
private: nall::string directory();
static nall::string fileOpen_(Window &parent, const nall::string &path, const nall::lstring& filter); nall::string open();
static nall::string fileSave_(Window &parent, const nall::string &path, const nall::lstring& filter); nall::string save();
BrowserWindow& setFilters_(const nall::lstring& filters);
BrowserWindow& setParent(Window &parent);
BrowserWindow& setPath(const nall::string &path);
BrowserWindow& setTitle(const nall::string &title);
BrowserWindow();
~BrowserWindow();
struct State;
State &state;
}; };
struct MessageWindow { struct MessageWindow {
@ -167,11 +173,18 @@ struct MessageWindow {
No, No,
}; };
static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok); Response error(Buttons = Buttons::Ok);
static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo); Response information(Buttons = Buttons::Ok);
static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok); Response question(Buttons = Buttons::YesNo);
static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok); MessageWindow& setParent(Window &parent);
MessageWindow() = delete; MessageWindow& setText(const nall::string &text);
MessageWindow& setTitle(const nall::string &title);
Response warning(Buttons = Buttons::Ok);
MessageWindow(const nall::string &text = "");
~MessageWindow();
struct State;
State &state;
}; };
struct Object { struct Object {

View File

@ -8,6 +8,20 @@ struct Timer::State {
unsigned milliseconds = 0; unsigned milliseconds = 0;
}; };
struct BrowserWindow::State {
lstring filters;
Window *parent = nullptr;
string path;
string title;
};
struct MessageWindow::State {
MessageWindow::Buttons buttons = MessageWindow::Buttons::Ok;
Window *parent = nullptr;
string text;
string title;
};
struct Window::State { struct Window::State {
bool backgroundColorOverride = false; bool backgroundColorOverride = false;
Color backgroundColor = {0, 0, 0, 255}; Color backgroundColor = {0, 0, 0, 255};

View File

@ -0,0 +1,88 @@
namespace phoenix {
static void BrowserWindow_addFilters(GtkWidget *dialog, lstring filters) {
for(auto &filter : filters) {
GtkFileFilter *gtkFilter = gtk_file_filter_new();
gtk_file_filter_set_name(gtkFilter, filter);
lstring patterns = filter.split<1>("(")(1).rtrim<1>(")").split(",");
for(auto &pattern : patterns) gtk_file_filter_add_pattern(gtkFilter, pattern.strip());
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter);
}
}
string pBrowserWindow::directory(BrowserWindow::State &state) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
state.title ? state.title : "Select Directory",
state.parent ? GTK_WINDOW(state.parent->p.widget) : (GtkWindow*)nullptr,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
(const gchar*)nullptr
);
if(state.path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), state.path);
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
name = temp;
g_free(temp);
}
gtk_widget_destroy(dialog);
if(name && !name.endswith("/")) name.append("/");
return name;
}
string pBrowserWindow::open(BrowserWindow::State &state) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
state.title ? state.title : "Open File",
state.parent ? GTK_WINDOW(state.parent->p.widget) : (GtkWindow*)nullptr,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
(const gchar*)nullptr
);
if(state.path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), state.path);
BrowserWindow_addFilters(dialog, state.filters);
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
name = temp;
g_free(temp);
}
gtk_widget_destroy(dialog);
return name;
}
string pBrowserWindow::save(BrowserWindow::State &state) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
state.title ? state.title : "Save File",
state.parent ? GTK_WINDOW(state.parent->p.widget) : (GtkWindow*)nullptr,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
(const gchar*)nullptr
);
if(state.path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), state.path);
BrowserWindow_addFilters(dialog, state.filters);
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
name = temp;
g_free(temp);
}
gtk_widget_destroy(dialog);
return name;
}
}

View File

@ -1,73 +0,0 @@
namespace phoenix {
static string FileDialog(bool save, Window &parent, const string &path, const lstring &filter) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
save == 0 ? "Load File" : "Save File",
&parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr,
save == 0 ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
(const gchar*)nullptr
);
if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
for(auto &filterItem : filter) {
GtkFileFilter *gtkFilter = gtk_file_filter_new();
gtk_file_filter_set_name(gtkFilter, filterItem);
lstring part;
part.split("(", filterItem);
part[1].rtrim<1>(")");
lstring list;
list.split(",", part[1]);
for(auto &pattern : list) gtk_file_filter_add_pattern(gtkFilter, pattern);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter);
}
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
name = temp;
g_free(temp);
}
gtk_widget_destroy(dialog);
return name;
}
string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) {
return FileDialog(0, parent, path, filter);
}
string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) {
return FileDialog(1, parent, path, filter);
}
string pDialogWindow::folderSelect(Window &parent, const string &path) {
string name;
GtkWidget *dialog = gtk_file_chooser_dialog_new(
"Select Folder",
&parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
(const gchar*)nullptr
);
if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
name = temp;
g_free(temp);
}
gtk_widget_destroy(dialog);
if(name == "") return "";
if(name.endswith("/") == false) name.append("/");
return name;
}
}

View File

@ -1,65 +1,60 @@
namespace phoenix { namespace phoenix {
static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, gint response) { static MessageWindow::Response Message(MessageWindow::State &state, GtkMessageType messageStyle) {
GtkWidget *dialog = gtk_message_dialog_new(
state.parent ? GTK_WINDOW(state.parent->p.widget) : (GtkWindow*)nullptr,
GTK_DIALOG_MODAL, messageStyle, GTK_BUTTONS_NONE, "%s", (const char*)state.text
);
if(state.title) gtk_window_set_title(GTK_WINDOW(dialog), state.title);
else if(applicationState.name) gtk_window_set_title(GTK_WINDOW(dialog), applicationState.name);
switch(state.buttons) {
case MessageWindow::Buttons::Ok:
gtk_dialog_add_buttons(GTK_DIALOG(dialog), "Ok", GTK_RESPONSE_OK, nullptr);
break;
case MessageWindow::Buttons::OkCancel:
gtk_dialog_add_buttons(GTK_DIALOG(dialog), "Ok", GTK_RESPONSE_OK, "Cancel", GTK_RESPONSE_CANCEL, nullptr);
break;
case MessageWindow::Buttons::YesNo:
gtk_dialog_add_buttons(GTK_DIALOG(dialog), "Yes", GTK_RESPONSE_YES, "No", GTK_RESPONSE_NO, nullptr);
break;
case MessageWindow::Buttons::YesNoCancel:
gtk_dialog_add_buttons(GTK_DIALOG(dialog), "Yes", GTK_RESPONSE_YES, "No", GTK_RESPONSE_NO, "Cancel", GTK_RESPONSE_CANCEL, nullptr);
break;
}
auto response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
if(response == GTK_RESPONSE_OK) return MessageWindow::Response::Ok; if(response == GTK_RESPONSE_OK) return MessageWindow::Response::Ok;
if(response == GTK_RESPONSE_CANCEL) return MessageWindow::Response::Cancel; if(response == GTK_RESPONSE_CANCEL) return MessageWindow::Response::Cancel;
if(response == GTK_RESPONSE_YES) return MessageWindow::Response::Yes; if(response == GTK_RESPONSE_YES) return MessageWindow::Response::Yes;
if(response == GTK_RESPONSE_NO) return MessageWindow::Response::No; if(response == GTK_RESPONSE_NO) return MessageWindow::Response::No;
if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; //if dialog was closed without choosing a button, choose the most appropriate response
return MessageWindow::Response::Ok; if(state.buttons == MessageWindow::Buttons::Ok) return MessageWindow::Response::Ok;
if(state.buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
if(state.buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No;
if(state.buttons == MessageWindow::Buttons::YesNoCancel) return MessageWindow::Response::Cancel;
throw;
} }
MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::error(MessageWindow::State &state) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK; return Message(state, GTK_MESSAGE_ERROR);
if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
GtkWidget *dialog = gtk_message_dialog_new(
&parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr,
GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, buttonsType, "%s", (const char*)text
);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return MessageWindow_response(buttons, response);
} }
MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::information(MessageWindow::State &state) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK; return Message(state, GTK_MESSAGE_INFO);
if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
GtkWidget *dialog = gtk_message_dialog_new(
&parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr,
GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, buttonsType, "%s", (const char*)text
);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return MessageWindow_response(buttons, response);
} }
MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::question(MessageWindow::State &state) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK; return Message(state, GTK_MESSAGE_QUESTION);
if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
GtkWidget *dialog = gtk_message_dialog_new(
&parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr,
GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, buttonsType, "%s", (const char*)text
);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return MessageWindow_response(buttons, response);
} }
MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::warning(MessageWindow::State &state) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK; return Message(state, GTK_MESSAGE_WARNING);
if(buttons == MessageWindow::Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
if(buttons == MessageWindow::Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
GtkWidget *dialog = gtk_message_dialog_new(
&parent != &Window::none() ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)nullptr,
GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, buttonsType, "%s", (const char*)text
);
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
return MessageWindow_response(buttons, response);
} }
} }

View File

@ -6,7 +6,7 @@
#include "desktop.cpp" #include "desktop.cpp"
#include "keyboard.cpp" #include "keyboard.cpp"
#include "mouse.cpp" #include "mouse.cpp"
#include "dialog-window.cpp" #include "browser-window.cpp"
#include "message-window.cpp" #include "message-window.cpp"
#include "font.cpp" #include "font.cpp"
#include "timer.cpp" #include "timer.cpp"

View File

@ -62,17 +62,17 @@ struct pMouse {
static bool pressed(Mouse::Button button); static bool pressed(Mouse::Button button);
}; };
struct pDialogWindow { struct pBrowserWindow {
static string fileOpen(Window &parent, const string &path, const lstring &filter); static string directory(BrowserWindow::State &state);
static string fileSave(Window &parent, const string &path, const lstring &filter); static string open(BrowserWindow::State &state);
static string folderSelect(Window &parent, const string &path); static string save(BrowserWindow::State &state);
}; };
struct pMessageWindow { struct pMessageWindow {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response error(MessageWindow::State &state);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response information(MessageWindow::State &state);
static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response question(MessageWindow::State &state);
static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response warning(MessageWindow::State &state);
}; };
struct pObject { struct pObject {

View File

@ -0,0 +1,54 @@
namespace phoenix {
string pBrowserWindow::directory(BrowserWindow::State &state) {
QString directory = QFileDialog::getExistingDirectory(
state.parent ? state.parent->p.qtWindow : nullptr,
state.title ? state.title : "Select Directory",
QString::fromUtf8(state.path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
);
string name = directory.toUtf8().constData();
if(name && name.endswith("/") == false) name.append("/");
return name;
}
string pBrowserWindow::open(BrowserWindow::State &state) {
string filters = state.filters.concatenate(";;");
//convert filter list from phoenix to Qt format, example:
//"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)"
signed parentheses = 0;
for(auto &n : filters) {
if(n == '(') parentheses++;
if(n == ')') parentheses--;
if(n == ',' && parentheses) n = ' ';
}
QString filename = QFileDialog::getOpenFileName(
state.parent ? state.parent->p.qtWindow : nullptr,
state.title ? state.title : "Open File",
QString::fromUtf8(state.path), QString::fromUtf8(filters)
);
return filename.toUtf8().constData();
}
string pBrowserWindow::save(BrowserWindow::State &state) {
string filters = state.filters.concatenate(";;");
//convert filter list from phoenix to Qt format, example:
//"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)"
signed parentheses = 0;
for(auto &n : filters) {
if(n == '(') parentheses++;
if(n == ')') parentheses--;
if(n == ',' && parentheses) n = ' ';
}
QString filename = QFileDialog::getSaveFileName(
state.parent ? state.parent->p.qtWindow : nullptr,
state.title ? state.title : "Save File",
QString::fromUtf8(state.path), QString::fromUtf8(filters)
);
return filename.toUtf8().constData();
}
}

View File

@ -1,61 +0,0 @@
namespace phoenix {
string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) {
string filterList;
for(auto &item : filter) {
filterList.append(item);
filterList.append(";;");
}
filterList.rtrim<1>(";;");
//convert filter list from phoenix to Qt format, example:
//"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)"
signed parenthesis = 0;
for(auto &n : filterList) {
if(n == '(') parenthesis++;
if(n == ')') parenthesis--;
if(n == ',' && parenthesis) n = ' ';
}
QString filename = QFileDialog::getOpenFileName(
&parent != &Window::none() ? parent.p.qtWindow : nullptr, "Open File",
QString::fromUtf8(path), QString::fromUtf8(filterList)
);
return filename.toUtf8().constData();
}
string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) {
string filterList;
for(auto &item : filter) {
filterList.append(item);
filterList.append(";;");
}
filterList.rtrim<1>(";;");
//convert filter list from phoenix to Qt format, example:
//"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)"
signed parenthesis = 0;
for(auto &n : filterList) {
if(n == '(') parenthesis++;
if(n == ')') parenthesis--;
if(n == ',' && parenthesis) n = ' ';
}
QString filename = QFileDialog::getSaveFileName(
&parent != &Window::none() ? parent.p.qtWindow : nullptr, "Save File",
QString::fromUtf8(path), QString::fromUtf8(filterList)
);
return filename.toUtf8().constData();
}
string pDialogWindow::folderSelect(Window &parent, const string &path) {
QString directory = QFileDialog::getExistingDirectory(
&parent != &Window::none() ? parent.p.qtWindow : nullptr, "Select Directory",
QString::fromUtf8(path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
);
string name = directory.toUtf8().constData();
if(name != "" && name.endswith("/") == false) name.append("/");
return name;
}
}

View File

@ -5,6 +5,7 @@ static QMessageBox::StandardButtons MessageWindow_buttons(MessageWindow::Buttons
if(buttons == MessageWindow::Buttons::Ok) standardButtons = QMessageBox::Ok; if(buttons == MessageWindow::Buttons::Ok) standardButtons = QMessageBox::Ok;
if(buttons == MessageWindow::Buttons::OkCancel) standardButtons = QMessageBox::Ok | QMessageBox::Cancel; if(buttons == MessageWindow::Buttons::OkCancel) standardButtons = QMessageBox::Ok | QMessageBox::Cancel;
if(buttons == MessageWindow::Buttons::YesNo) standardButtons = QMessageBox::Yes | QMessageBox::No; if(buttons == MessageWindow::Buttons::YesNo) standardButtons = QMessageBox::Yes | QMessageBox::No;
if(buttons == MessageWindow::Buttons::YesNoCancel) standardButtons = QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel;
return standardButtons; return standardButtons;
} }
@ -15,36 +16,39 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
if(response == QMessageBox::No) return MessageWindow::Response::No; if(response == QMessageBox::No) return MessageWindow::Response::No;
//MessageWindow was closed via window manager, rather than by a button; assume a cancel/no response //MessageWindow was closed via window manager, rather than by a button; assume a cancel/no response
if(buttons == MessageWindow::Buttons::Ok) return MessageWindow::Response::Ok;
if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No;
return MessageWindow::Response::Ok; if(buttons == MessageWindow::Buttons::YesNoCancel) return MessageWindow::Response::Cancel;
throw;
} }
MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::error(MessageWindow::State &state) {
return MessageWindow_response( return MessageWindow_response(
buttons, QMessageBox::information(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ", state.buttons, QMessageBox::critical(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons)) QString::fromUtf8(state.text), MessageWindow_buttons(state.buttons))
); );
} }
MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::information(MessageWindow::State &state) {
return MessageWindow_response( return MessageWindow_response(
buttons, QMessageBox::question(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ", state.buttons, QMessageBox::information(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons)) QString::fromUtf8(state.text), MessageWindow_buttons(state.buttons))
); );
} }
MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::question(MessageWindow::State &state) {
return MessageWindow_response( return MessageWindow_response(
buttons, QMessageBox::warning(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ", state.buttons, QMessageBox::question(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons)) QString::fromUtf8(state.text), MessageWindow_buttons(state.buttons))
); );
} }
MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::warning(MessageWindow::State &state) {
return MessageWindow_response( return MessageWindow_response(
buttons, QMessageBox::critical(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ", state.buttons, QMessageBox::warning(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons)) QString::fromUtf8(state.text), MessageWindow_buttons(state.buttons))
); );
} }

View File

@ -7,7 +7,7 @@
#include "desktop.cpp" #include "desktop.cpp"
#include "keyboard.cpp" #include "keyboard.cpp"
#include "mouse.cpp" #include "mouse.cpp"
#include "dialog-window.cpp" #include "browser-window.cpp"
#include "message-window.cpp" #include "message-window.cpp"
#include "font.cpp" #include "font.cpp"
#include "timer.cpp" #include "timer.cpp"

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp' ** Meta object code from reading C++ file 'platform.moc.hpp'
** **
** Created: Thu Mar 14 08:12:31 2013 ** Created: Sat Mar 16 11:52:02 2013
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3) ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!

View File

@ -61,17 +61,17 @@ struct pMouse {
static bool pressed(Mouse::Button button); static bool pressed(Mouse::Button button);
}; };
struct pDialogWindow { struct pBrowserWindow {
static string fileOpen(Window &parent, const string &path, const lstring &filter); static string directory(BrowserWindow::State &state);
static string fileSave(Window &parent, const string &path, const lstring &filter); static string open(BrowserWindow::State &state);
static string folderSelect(Window &parent, const string &path); static string save(BrowserWindow::State &state);
}; };
struct pMessageWindow { struct pMessageWindow {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response error(MessageWindow::State &state);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response information(MessageWindow::State &state);
static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response question(MessageWindow::State &state);
static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response warning(MessageWindow::State &state);
}; };
struct pObject { struct pObject {

View File

@ -0,0 +1,15 @@
namespace phoenix {
string pBrowserWindow::directory(BrowserWindow::State &state) {
return "";
}
string pBrowserWindow::open(BrowserWindow::State &state) {
return "";
}
string pBrowserWindow::save(BrowserWindow::State &state) {
return "";
}
}

View File

@ -0,0 +1,9 @@
namespace phoenix {
struct pBrowserWindow {
static string directory(BrowserWindow::State &state);
static string open(BrowserWindow::State &state);
static string save(BrowserWindow::State &state);
};
}

View File

@ -1,15 +0,0 @@
namespace phoenix {
string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) {
return "";
}
string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) {
return "";
}
string pDialogWindow::folderSelect(Window &parent, const string &path) {
return "";
}
}

View File

@ -1,9 +0,0 @@
namespace phoenix {
struct pDialogWindow {
static string fileOpen(Window &parent, const string &path, const lstring &filter);
static string fileSave(Window &parent, const string &path, const lstring &filter);
static string folderSelect(Window &parent, const string &path);
};
}

View File

@ -1,18 +1,18 @@
namespace phoenix { namespace phoenix {
MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::error(MessageWindow::State &state) {
return MessageWindow::Response::Ok; return MessageWindow::Response::Ok;
} }
MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::information(MessageWindow::State &state) {
return MessageWindow::Response::Ok; return MessageWindow::Response::Ok;
} }
MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::question(MessageWindow::State &state) {
return MessageWindow::Response::Ok; return MessageWindow::Response::Ok;
} }
MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::warning(MessageWindow::State &state) {
return MessageWindow::Response::Ok; return MessageWindow::Response::Ok;
} }

View File

@ -1,10 +1,10 @@
namespace phoenix { namespace phoenix {
struct pMessageWindow { struct pMessageWindow {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response error(MessageWindow::State &state);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response information(MessageWindow::State &state);
static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response question(MessageWindow::State &state);
static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response warning(MessageWindow::State &state);
}; };
} }

View File

@ -3,7 +3,7 @@
#include "desktop.cpp" #include "desktop.cpp"
#include "keyboard.cpp" #include "keyboard.cpp"
#include "mouse.cpp" #include "mouse.cpp"
#include "dialog-window.cpp" #include "browser-window.cpp"
#include "message-window.cpp" #include "message-window.cpp"
#include "font.cpp" #include "font.cpp"
#include "timer.cpp" #include "timer.cpp"

View File

@ -10,7 +10,7 @@ namespace phoenix {
#include "desktop.hpp" #include "desktop.hpp"
#include "keyboard.hpp" #include "keyboard.hpp"
#include "mouse.hpp" #include "mouse.hpp"
#include "dialog-window.hpp" #include "browser-window.hpp"
#include "message-window.hpp" #include "message-window.hpp"
#include "object.hpp" #include "object.hpp"
#include "timer.hpp" #include "timer.hpp"

View File

@ -0,0 +1,105 @@
namespace phoenix {
static int CALLBACK BrowserWindowCallbackProc(HWND hwnd, UINT msg, LPARAM lparam, LPARAM lpdata) {
if(msg == BFFM_INITIALIZED) {
if(lpdata) {
auto state = (BrowserWindow::State*)lpdata;
utf16_t wpath(string{state->path}.transform("/", "\\"));
if(state->title) SetWindowText(hwnd, utf16_t(state->title));
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)(wchar_t*)wpath);
}
}
return 0;
}
static string BrowserWindow_fileDialog(bool save, BrowserWindow::State &state) {
string path = string{path}.replace("/", "\\");
string filters;
for(auto &filter : state.filters) {
lstring part = filter.split("(");
if(part.size() != 2) continue;
part[1].rtrim<1>(")");
part[1].replace(" ", "");
part[1].transform(",", ";");
filters.append(filter, "\t", part[1], "\t");
}
utf16_t wfilters(filters);
wchar_t wname[PATH_MAX + 1] = L"";
utf16_t wpath(path);
utf16_t wtitle(state.title);
wchar_t *p = wfilters;
while(*p != L'\0') {
if(*p == L'\t') *p = L'\0';
p++;
}
if(path.empty() == false) {
//clear COMDLG32 MRU (most recently used) file list
//this is required in order for lpstrInitialDir to be honored in Windows 7 and above
registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/LastVisitedPidlMRU/");
registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/OpenSavePidlMRU/");
}
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = state.parent ? state.parent->p.hwnd : 0;
ofn.lpstrFilter = wfilters;
ofn.lpstrInitialDir = wpath;
ofn.lpstrFile = wname;
ofn.lpstrTitle = wtitle;
ofn.nMaxFile = PATH_MAX;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = L"";
bool result = (save == false ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn));
if(result == false) return "";
string name = (const char*)utf8_t(wname);
name.transform("\\", "/");
return name;
}
string pBrowserWindow::directory(BrowserWindow::State &state) {
wchar_t wname[PATH_MAX + 1] = L"";
BROWSEINFO bi;
bi.hwndOwner = state.parent ? state.parent->p.hwnd : 0;
bi.pidlRoot = NULL;
bi.pszDisplayName = wname;
bi.lpszTitle = L"\nChoose a directory:";
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS;
bi.lpfn = BrowserWindowCallbackProc;
bi.lParam = (LPARAM)&state;
bi.iImage = 0;
bool result = false;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if(pidl) {
if(SHGetPathFromIDList(pidl, wname)) {
result = true;
IMalloc *imalloc = 0;
if(SUCCEEDED(SHGetMalloc(&imalloc))) {
imalloc->Free(pidl);
imalloc->Release();
}
}
}
if(result == false) return "";
string name = (const char*)utf8_t(wname);
if(!name) return "";
name.transform("\\", "/");
if(name.endswith("/") == false) name.append("/");
return name;
}
string pBrowserWindow::open(BrowserWindow::State &state) {
return BrowserWindow_fileDialog(0, state);
}
string pBrowserWindow::save(BrowserWindow::State &state) {
return BrowserWindow_fileDialog(1, state);
}
}

View File

@ -1,102 +0,0 @@
namespace phoenix {
static string FileDialog(bool save, Window &parent, const string &path, const lstring &filter) {
string dir = path;
dir.replace("/", "\\");
string filterList;
for(auto &filterItem : filter) {
lstring part;
part.split("(", filterItem);
if(part.size() != 2) continue;
part[1].rtrim<1>(")");
part[1].replace(" ", "");
part[1].transform(",", ";");
filterList.append(string(filterItem, "\t", part[1], "\t"));
}
utf16_t wfilter(filterList);
utf16_t wdir(dir);
wchar_t wfilename[PATH_MAX + 1] = L"";
wchar_t *p = wfilter;
while(*p != L'\0') {
if(*p == L'\t') *p = L'\0';
p++;
}
if(path.empty() == false) {
//clear COMDLG32 MRU (most recently used) file list
//this is required in order for lpstrInitialDir to be honored in Windows 7 and above
registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/LastVisitedPidlMRU/");
registry::remove("HKCU/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/OpenSavePidlMRU/");
}
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = &parent != &Window::none() ? parent.p.hwnd : 0;
ofn.lpstrFilter = wfilter;
ofn.lpstrInitialDir = wdir;
ofn.lpstrFile = wfilename;
ofn.nMaxFile = PATH_MAX;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
ofn.lpstrDefExt = L"";
bool result = (save == false ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn));
if(result == false) return "";
string name = (const char*)utf8_t(wfilename);
name.transform("\\", "/");
return name;
}
string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) {
return FileDialog(false, parent, path, filter);
}
string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) {
return FileDialog(true, parent, path, filter);
}
static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT msg, LPARAM lparam, LPARAM lpdata) {
if(msg == BFFM_INITIALIZED) {
if(lpdata) SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpdata);
}
return 0;
}
string pDialogWindow::folderSelect(Window &parent, const string &path) {
wchar_t wfilename[PATH_MAX + 1] = L"";
utf16_t wpath(string{path}.transform("/", "\\"));
BROWSEINFO bi;
bi.hwndOwner = &parent != &Window::none() ? parent.p.hwnd : 0;
bi.pidlRoot = NULL;
bi.pszDisplayName = wfilename;
bi.lpszTitle = L"";
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS;
bi.lpfn = BrowseCallbackProc;
bi.lParam = (LPARAM)(wchar_t*)wpath;
bi.iImage = 0;
bool result = false;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if(pidl) {
if(SHGetPathFromIDList(pidl, wfilename)) {
result = true;
IMalloc *imalloc = 0;
if(SUCCEEDED(SHGetMalloc(&imalloc))) {
imalloc->Free(pidl);
imalloc->Release();
}
}
}
if(result == false) return "";
string name = (const char*)utf8_t(wfilename);
if(name == "") return "";
name.transform("\\", "/");
if(name.endswith("/") == false) name.append("/");
return name;
}
}

View File

@ -5,41 +5,50 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
if(response == IDCANCEL) return MessageWindow::Response::Cancel; if(response == IDCANCEL) return MessageWindow::Response::Cancel;
if(response == IDYES) return MessageWindow::Response::Yes; if(response == IDYES) return MessageWindow::Response::Yes;
if(response == IDNO) return MessageWindow::Response::No; if(response == IDNO) return MessageWindow::Response::No;
//default responses if window was closed without a button selected
if(buttons == MessageWindow::Buttons::Ok) return MessageWindow::Response::Ok;
if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel; if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No; if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No;
return MessageWindow::Response::Ok; if(buttons == MessageWindow::Buttons::YesNoCancel) return MessageWindow::Response::Cancel;
throw;
} }
MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { static UINT MessageWindow_buttons(MessageWindow::Buttons buttons) {
UINT flags = MB_ICONINFORMATION; if(buttons == MessageWindow::Buttons::Ok) return MB_OK;
if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; if(buttons == MessageWindow::Buttons::OkCancel) return MB_OKCANCEL;
if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; if(buttons == MessageWindow::Buttons::YesNo) return MB_YESNO;
if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; if(buttons == MessageWindow::Buttons::YesNoCancel) return MB_YESNOCANCEL;
return MessageWindow_response(buttons, MessageBox(&parent != &Window::none() ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); throw;
} }
MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::error(MessageWindow::State &state) {
UINT flags = MB_ICONQUESTION; UINT flags = MB_ICONERROR | MessageWindow_buttons(state.buttons);
if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; return MessageWindow_response(state.buttons, MessageBox(
if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; state.parent ? state.parent->p.hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags
if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; ));
return MessageWindow_response(buttons, MessageBox(&parent != &Window::none() ? parent.p.hwnd : 0, utf16_t(text), L"", flags));
} }
MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::information(MessageWindow::State &state) {
UINT flags = MB_ICONWARNING; UINT flags = MB_ICONINFORMATION | MessageWindow_buttons(state.buttons);
if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; return MessageWindow_response(state.buttons, MessageBox(
if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; state.parent ? state.parent->p.hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags
if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; ));
return MessageWindow_response(buttons, MessageBox(&parent != &Window::none() ? parent.p.hwnd : 0, utf16_t(text), L"", flags));
} }
MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { MessageWindow::Response pMessageWindow::question(MessageWindow::State &state) {
UINT flags = MB_ICONERROR; UINT flags = MB_ICONQUESTION | MessageWindow_buttons(state.buttons);
if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK; return MessageWindow_response(state.buttons, MessageBox(
if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL; state.parent ? state.parent->p.hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags
if(buttons == MessageWindow::Buttons::YesNo) flags |= MB_YESNO; ));
return MessageWindow_response(buttons, MessageBox(&parent != &Window::none() ? parent.p.hwnd : 0, utf16_t(text), L"", flags)); }
MessageWindow::Response pMessageWindow::warning(MessageWindow::State &state) {
UINT flags = MB_ICONWARNING | MessageWindow_buttons(state.buttons);
return MessageWindow_response(state.buttons, MessageBox(
state.parent ? state.parent->p.hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags
));
} }
} }

View File

@ -6,7 +6,7 @@
#include "desktop.cpp" #include "desktop.cpp"
#include "keyboard.cpp" #include "keyboard.cpp"
#include "mouse.cpp" #include "mouse.cpp"
#include "dialog-window.cpp" #include "browser-window.cpp"
#include "message-window.cpp" #include "message-window.cpp"
#include "object.cpp" #include "object.cpp"
#include "font.cpp" #include "font.cpp"

View File

@ -48,17 +48,17 @@ struct pMouse {
static bool pressed(Mouse::Button button); static bool pressed(Mouse::Button button);
}; };
struct pDialogWindow { struct pBrowserWindow {
static string fileOpen(Window &parent, const string &path, const lstring &filter); static string directory(BrowserWindow::State &state);
static string fileSave(Window &parent, const string &path, const lstring &filter); static string open(BrowserWindow::State &state);
static string folderSelect(Window &parent, const string &path); static string save(BrowserWindow::State &state);
}; };
struct pMessageWindow { struct pMessageWindow {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response error(MessageWindow::State &state);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response information(MessageWindow::State &state);
static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response question(MessageWindow::State &state);
static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); static MessageWindow::Response warning(MessageWindow::State &state);
}; };
struct pObject { struct pObject {

View File

@ -1,22 +1,33 @@
rubyflags := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c) ifeq ($(platform),osx)
rubyflags = $(objcppflags) $(flags)
else
rubyflags = $(cppflags) $(flags)
endif
rubyflags += $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c)
rubyflags += $(if $(finstring .sdl,$(ruby)),`sdl-config --cflags`) rubyflags += $(if $(finstring .sdl,$(ruby)),`sdl-config --cflags`)
rubylink := rubylink =
rubylink += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
rubylink += $(if $(findstring video.cgl,$(ruby)),-framework OpenGL)
rubylink += $(if $(findstring video.direct3d,$(ruby)),-ld3d9) rubylink += $(if $(findstring video.direct3d,$(ruby)),-ld3d9)
rubylink += $(if $(findstring video.directdraw,$(ruby)),-lddraw) rubylink += $(if $(findstring video.directdraw,$(ruby)),-lddraw)
rubylink += $(if $(findstring video.glx,$(ruby)),-lGL) rubylink += $(if $(findstring video.glx,$(ruby)),-lGL)
rubylink += $(if $(findstring video.wgl,$(ruby)),-lopengl32) rubylink += $(if $(findstring video.wgl,$(ruby)),-lopengl32)
rubylink += $(if $(findstring video.xv,$(ruby)),-lXv) rubylink += $(if $(findstring video.xv,$(ruby)),-lXv)
rubylink += $(if $(findstring audio.alsa,$(ruby)),-lasound) rubylink += $(if $(findstring audio.alsa,$(ruby)),-lasound)
rubylink += $(if $(findstring audio.ao,$(ruby)),-lao) rubylink += $(if $(findstring audio.ao,$(ruby)),-lao)
rubylink += $(if $(findstring audio.directsound,$(ruby)),-ldsound) rubylink += $(if $(findstring audio.directsound,$(ruby)),-ldsound)
rubylink += $(if $(findstring audio.pulseaudio,$(ruby)),-lpulse) rubylink += $(if $(findstring audio.pulseaudio,$(ruby)),-lpulse)
rubylink += $(if $(findstring audio.pulseaudiosimple,$(ruby)),-lpulse-simple) rubylink += $(if $(findstring audio.pulseaudiosimple,$(ruby)),-lpulse-simple)
rubylink += $(if $(findstring audio.xaudio2,$(ruby)),-lole32) rubylink += $(if $(findstring audio.xaudio2,$(ruby)),-lole32)
rubylink += $(if $(findstring input.directinput,$(ruby)),-ldinput8 -ldxguid) rubylink += $(if $(findstring input.directinput,$(ruby)),-ldinput8 -ldxguid)
rubylink += $(if $(findstring input.rawinput,$(ruby)),-ldinput8 -ldxguid) rubylink += $(if $(findstring input.rawinput,$(ruby)),-ldinput8 -ldxguid)
rubylink += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
ifeq ($(platform),x) ifeq ($(platform),x)
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal) rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal)
else ifeq ($(platform),osx) else ifeq ($(platform),osx)

View File

@ -27,6 +27,10 @@ void VideoInterface::driver(const char *driver) {
if(0); if(0);
#ifdef VIDEO_CGL
else if(!strcmp(driver, "OpenGL")) p = new VideoCGL();
#endif
#ifdef VIDEO_DIRECT3D #ifdef VIDEO_DIRECT3D
else if(!strcmp(driver, "Direct3D")) p = new VideoD3D(); else if(!strcmp(driver, "Direct3D")) p = new VideoD3D();
#endif #endif
@ -80,6 +84,8 @@ const char* VideoInterface::default_driver() {
return "DirectDraw"; return "DirectDraw";
#elif defined(VIDEO_GDI) #elif defined(VIDEO_GDI)
return "GDI"; return "GDI";
#elif defined(VIDEO_CGL)
return "OpenGL";
#elif defined(VIDEO_XSHM) #elif defined(VIDEO_XSHM)
return "XShm"; return "XShm";
#elif defined(VIDEO_QTOPENGL) #elif defined(VIDEO_QTOPENGL)
@ -119,6 +125,12 @@ const char* VideoInterface::driver_list() {
"GDI;" "GDI;"
#endif #endif
//OS X
#if defined(VIDEO_CGL)
"OpenGL;"
#endif
//Linux //Linux
#if defined(VIDEO_GLX) #if defined(VIDEO_GLX)
@ -327,6 +339,10 @@ void InputInterface::driver(const char *driver) {
else if(!strcmp(driver, "RawInput")) p = new InputRaw(); else if(!strcmp(driver, "RawInput")) p = new InputRaw();
#endif #endif
#ifdef INPUT_CARBON
else if(!strcmp(driver, "Carbon")) p = new InputCarbon();
#endif
#ifdef INPUT_SDL #ifdef INPUT_SDL
else if(!strcmp(driver, "SDL")) p = new InputSDL(); else if(!strcmp(driver, "SDL")) p = new InputSDL();
#endif #endif
@ -335,10 +351,6 @@ void InputInterface::driver(const char *driver) {
else if(!strcmp(driver, "X-Windows")) p = new InputX(); else if(!strcmp(driver, "X-Windows")) p = new InputX();
#endif #endif
#ifdef INPUT_CARBON
else if(!strcmp(driver, "Carbon")) p = new InputCarbon();
#endif
else p = new Input(); else p = new Input();
} }
@ -348,12 +360,12 @@ const char* InputInterface::default_driver() {
return "RawInput"; return "RawInput";
#elif defined(INPUT_DIRECTINPUT) #elif defined(INPUT_DIRECTINPUT)
return "DirectInput"; return "DirectInput";
#elif defined(INPUT_CARBON)
return "Carbon";
#elif defined(INPUT_SDL) #elif defined(INPUT_SDL)
return "SDL"; return "SDL";
#elif defined(INPUT_X) #elif defined(INPUT_X)
return "X-Windows"; return "X-Windows";
#elif defined(INPUT_CARBON)
return "Carbon";
#else #else
return "none"; return "none";
#endif #endif
@ -372,6 +384,12 @@ const char* InputInterface::driver_list() {
"DirectInput;" "DirectInput;"
#endif #endif
//OS X
#if defined(INPUT_CARBON)
"Carbon;"
#endif
//Linux //Linux
#if defined(INPUT_SDL) #if defined(INPUT_SDL)
@ -382,12 +400,6 @@ const char* InputInterface::driver_list() {
"X-Windows;" "X-Windows;"
#endif #endif
//OS X
#if defined(INPUT_CARBON)
"Carbon;"
#endif
"None"; "None";
} }

View File

@ -18,6 +18,7 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
#elif defined(PLATFORM_OSX) #elif defined(PLATFORM_OSX)
#define __INTEL_COMPILER #define __INTEL_COMPILER
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
#elif defined(PLATFORM_WINDOWS) #elif defined(PLATFORM_WINDOWS)
#define _WIN32_WINNT 0x0501 #define _WIN32_WINNT 0x0501
@ -50,6 +51,10 @@ using namespace nall;
pVideo##Name &p; \ pVideo##Name &p; \
}; };
#ifdef VIDEO_CGL
#include <ruby/video/cgl.cpp>
#endif
#ifdef VIDEO_DIRECT3D #ifdef VIDEO_DIRECT3D
#include <ruby/video/direct3d.cpp> #include <ruby/video/direct3d.cpp>
#endif #endif
@ -175,6 +180,10 @@ using namespace nall;
#include <ruby/input/rawinput.cpp> #include <ruby/input/rawinput.cpp>
#endif #endif
#ifdef INPUT_CARBON
#include <ruby/input/carbon.cpp>
#endif
#ifdef INPUT_SDL #ifdef INPUT_SDL
#include <ruby/input/sdl.cpp> #include <ruby/input/sdl.cpp>
#endif #endif
@ -182,7 +191,3 @@ using namespace nall;
#ifdef INPUT_X #ifdef INPUT_X
#include <ruby/input/x.cpp> #include <ruby/input/x.cpp>
#endif #endif
#ifdef INPUT_CARBON
#include <ruby/input/carbon.cpp>
#endif

174
higan/ruby/video/cgl.cpp Normal file
View File

@ -0,0 +1,174 @@
#include "opengl.hpp"
namespace ruby {
class pVideoCGL : public OpenGL {
public:
NSOpenGLView *view;
struct {
NSView *handle;
bool synchronize;
unsigned filter;
string shader;
unsigned width;
unsigned height;
} settings;
bool cap(const string &name) {
if(name == Video::Handle) return true;
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
if(name == Video::Shader) return true;
return false;
}
any get(const string &name) {
if(name == Video::Handle) return (uintptr_t)settings.handle;
if(name == Video::Synchronize) return settings.synchronize;
if(name == Video::Filter) return settings.filter;
return false;
}
bool set(const string &name, const any &value) {
if(name == Video::Handle) {
settings.handle = (NSView*)any_cast<uintptr_t>(value);
return true;
}
if(name == Video::Synchronize) {
if(settings.synchronize != any_cast<bool>(value)) {
settings.synchronize = any_cast<bool>(value);
if(view) {
@autoreleasepool {
[[view openGLContext] makeCurrentContext];
init();
OpenGL::set_shader(settings.shader);
}
}
}
return true;
}
if(name == Video::Filter) {
settings.filter = any_cast<unsigned>(value);
return true;
}
if(name == Video::Shader) {
settings.shader = any_cast<const char*>(value);
@autoreleasepool {
[[view openGLContext] makeCurrentContext];
OpenGL::set_shader(settings.shader);
settings.filter = OpenGL::fragmentfilter;
}
return true;
}
return false;
}
bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) {
resize(width, height);
settings.width = width;
settings.height = height;
return OpenGL::lock(data, pitch);
}
void unlock() {
}
void clear() {
@autoreleasepool {
[view lockFocus];
OpenGL::clear();
[[view openGLContext] flushBuffer];
[view unlockFocus];
}
}
void refresh() {
@autoreleasepool {
if([view lockFocusIfCanDraw]) {
auto area = [view frame];
OpenGL::refresh(
settings.filter == Video::FilterLinear,
settings.width, settings.height,
area.size.width, area.size.height
);
[[view openGLContext] flushBuffer];
[view unlockFocus];
}
}
}
bool init() {
term();
@autoreleasepool {
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFAColorSize, 24,
NSOpenGLPFAAccelerated,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAWindow,
0
};
auto size = [settings.handle frame].size;
auto format = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
view = [[NSOpenGLView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0) pixelFormat:format];
[view setFrame:NSMakeRect(0, 0, size.width, size.height)];
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[settings.handle addSubview:view];
[view lockFocus];
OpenGL::init();
settings.width = 256;
settings.height = 256;
auto context = (CGLContextObj)[[view openGLContext] CGLContextObj];
int synchronize = settings.synchronize;
CGLSetParameter(context, kCGLCPSwapInterval, &synchronize);
[view unlockFocus];
}
return true;
}
void term() {
OpenGL::term();
@autoreleasepool {
[view removeFromSuperview];
[view release];
view = nil;
}
}
pVideoCGL() {
view = nil;
settings.handle = nil;
settings.synchronize = false;
settings.filter = 0;
iformat = GL_UNSIGNED_INT_8_8_8_8_REV;
ibpp = 4;
}
~pVideoCGL() {
term();
}
};
DeclareVideo(CGL)
}

View File

@ -1,28 +1,32 @@
#include <GL/gl.h>
#if defined(PLATFORM_X) #if defined(PLATFORM_X)
#include <GL/gl.h>
#include <GL/glx.h> #include <GL/glx.h>
#define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name)) #define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name))
#elif defined(PLATFORM_OSX)
#include <OpenGL/gl.h>
#elif defined(PLATFORM_WIN) #elif defined(PLATFORM_WIN)
#include <GL/gl.h>
#include <GL/glext.h> #include <GL/glext.h>
#define glGetProcAddress(name) wglGetProcAddress(name) #define glGetProcAddress(name) wglGetProcAddress(name)
#else #else
#error "ruby::OpenGL: unsupported platform" #error "ruby::OpenGL: unsupported platform"
#endif #endif
PFNGLCREATEPROGRAMPROC glCreateProgram = 0; #if !defined(PLATFORM_OSX)
PFNGLUSEPROGRAMPROC glUseProgram = 0; PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
PFNGLCREATESHADERPROC glCreateShader = 0; PFNGLUSEPROGRAMPROC glUseProgram = nullptr;
PFNGLDELETESHADERPROC glDeleteShader = 0; PFNGLCREATESHADERPROC glCreateShader = nullptr;
PFNGLSHADERSOURCEPROC glShaderSource = 0; PFNGLDELETESHADERPROC glDeleteShader = nullptr;
PFNGLCOMPILESHADERPROC glCompileShader = 0; PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
PFNGLATTACHSHADERPROC glAttachShader = 0; PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
PFNGLDETACHSHADERPROC glDetachShader = 0; PFNGLATTACHSHADERPROC glAttachShader = nullptr;
PFNGLLINKPROGRAMPROC glLinkProgram = 0; PFNGLDETACHSHADERPROC glDetachShader = nullptr;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = 0; PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
PFNGLUNIFORM1IPROC glUniform1i = 0; PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
PFNGLUNIFORM2FVPROC glUniform2fv = 0; PFNGLUNIFORM1IPROC glUniform1i = nullptr;
PFNGLUNIFORM4FVPROC glUniform4fv = 0; PFNGLUNIFORM2FVPROC glUniform2fv = nullptr;
PFNGLUNIFORM4FVPROC glUniform4fv = nullptr;
#endif
class OpenGL { class OpenGL {
public: public:
@ -177,6 +181,9 @@ public:
glEnable(GL_DITHER); glEnable(GL_DITHER);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
#if defined(PLATFORM_OSX)
shader_support = true;
#else
//bind shader functions //bind shader functions
glCreateProgram = (PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgram"); glCreateProgram = (PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgram");
glUseProgram = (PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgram"); glUseProgram = (PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgram");
@ -196,6 +203,7 @@ public:
&& glDeleteShader && glShaderSource && glCompileShader && glAttachShader && glDeleteShader && glShaderSource && glCompileShader && glAttachShader
&& glDetachShader && glLinkProgram && glGetUniformLocation && glDetachShader && glLinkProgram && glGetUniformLocation
&& glUniform1i && glUniform2fv && glUniform4fv; && glUniform1i && glUniform2fv && glUniform4fv;
#endif
if(shader_support) glprogram = glCreateProgram(); if(shader_support) glprogram = glCreateProgram();
@ -211,7 +219,7 @@ public:
if(buffer) { if(buffer) {
delete[] buffer; delete[] buffer;
buffer = 0; buffer = nullptr;
iwidth = 0; iwidth = 0;
iheight = 0; iheight = 0;
} }
@ -224,7 +232,7 @@ public:
fragmentfilter = 0; fragmentfilter = 0;
vertexshader = 0; vertexshader = 0;
buffer = 0; buffer = nullptr;
iwidth = 0; iwidth = 0;
iheight = 0; iheight = 0;
} }

View File

@ -20,7 +20,7 @@ ifeq ($(platform),x)
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
ruby += input.sdl input.x ruby += input.sdl input.x
else ifeq ($(platform),osx) else ifeq ($(platform),osx)
ruby := ruby := video.cgl
ruby += audio.openal ruby += audio.openal
ruby += input.carbon ruby += input.carbon
else ifeq ($(platform),win) else ifeq ($(platform),win)
@ -52,10 +52,10 @@ obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/)
obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/) obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/)
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*) obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
$(call compile,$(rubyflags)) $(compiler) $(rubyflags) -c $< -o $@
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*) obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*)
$(call compile,$(phoenixflags)) $(compiler) $(phoenixflags) -c $< -o $@
obj/resource.o: $(ui)/resource.rc obj/resource.o: $(ui)/resource.rc
ifeq ($(arch),win32) ifeq ($(arch),win32)
@ -67,13 +67,19 @@ endif
# targets # targets
build: $(objects) build: $(objects)
ifeq ($(platform),x) ifeq ($(platform),x)
$(strip $(cpp) -o out/$(name) $(objects) $(link)) $(strip $(compiler) -o out/$(name) $(objects) $(link))
else ifeq ($(platform),win)
$(strip $(cpp) -shared -o out/phoenix.dll obj/phoenix.o $(phoenixlink))
$(strip $(cpp) -o out/$(name) $(subst obj/phoenix.o,,$(objects)) $(link) -Lout -lphoenix)
else ifeq ($(platform),osx) else ifeq ($(platform),osx)
test -d ../$(name).app || mkdir -p ../$(name).app/Contents/MacOS if [ -d out/$(name).app ]; then rm -r out/$(name).app; fi
$(strip $(cpp) -o ../$(name).app/Contents/MacOS/$(name) $(objects) $(link)) mkdir out/$(name).app
mkdir out/$(name).app/Contents
mkdir out/$(name).app/Contents/MacOS
mkdir out/$(name).app/Contents/Resources
cp data/Info.plist out/$(name).app/Contents/Info.plist
sips -s format icns data/higan512.png --out out/$(name).app/Contents/Resources/higan.icns
$(strip $(compiler) -o out/$(name).app/Contents/MacOS/$(name) $(objects) $(link))
else ifeq ($(platform),win)
$(strip $(compiler) -shared -o out/phoenix.dll obj/phoenix.o $(phoenixlink))
$(strip $(compiler) -o out/$(name) $(subst obj/phoenix.o,,$(objects)) $(link) -Lout -lphoenix)
endif endif
resource: resource:

View File

@ -54,7 +54,7 @@ Program::Program(int argc, char **argv) {
if(Intrinsics::platform() == Intrinsics::Platform::OSX) { if(Intrinsics::platform() == Intrinsics::Platform::OSX) {
normalFont = Font::sans(12); normalFont = Font::sans(12);
boldFont = Font::sans(12, "Bold"); boldFont = Font::sans(12, "Bold");
titleFont = Font::sans(24, "Bold"); titleFont = Font::sans(20, "Bold");
monospaceFont = Font::monospace(8); monospaceFont = Font::monospace(8);
} else { } else {
normalFont = Font::sans(8); normalFont = Font::sans(8);
@ -130,7 +130,24 @@ int main(int argc, char **argv) {
#endif #endif
Application::setName("higan"); Application::setName("higan");
Application::Cocoa::onQuit = &Application::quit; Application::Cocoa::onQuit = &Application::quit;
Application::Cocoa::onPreferences = [&] {
settings->setVisible();
settings->panelList.setFocused();
};
Application::Cocoa::onAbout = [&] {
MessageWindow()
.setTitle({"About ", Emulator::Name})
.setText({
Emulator::Name, " v", Emulator::Version, "\n",
"Author: ", Emulator::Author, "\n",
"License: ", Emulator::License, "\n",
"Website: ", Emulator::Website
})
.information();
};
new Program(argc, argv); new Program(argc, argv);
delete program; delete program;
return 0; return 0;

View File

@ -98,8 +98,10 @@ Presentation::Presentation() : active(nullptr) {
for(auto &shader : shaderList) shaderMenu.append(*shader); for(auto &shader : shaderList) shaderMenu.append(*shader);
settingsMenu.append(*new Separator); settingsMenu.append(*new Separator);
settingsMenu.append(synchronizeVideo, synchronizeAudio, muteAudio); settingsMenu.append(synchronizeVideo, synchronizeAudio, muteAudio);
settingsMenu.append(*new Separator); if(Intrinsics::platform() != Intrinsics::Platform::OSX) {
settingsMenu.append(configurationSettings); settingsMenu.append(*new Separator);
settingsMenu.append(configurationSettings);
}
append(toolsMenu); append(toolsMenu);
toolsMenu.append(saveStateMenu); toolsMenu.append(saveStateMenu);
for(unsigned n = 0; n < 5; n++) saveStateMenu.append(saveStateItem[n]); for(unsigned n = 0; n < 5; n++) saveStateMenu.append(saveStateItem[n]);

View File

@ -124,5 +124,5 @@ string Interface::server() {
} }
void Interface::notify(const string &text) { void Interface::notify(const string &text) {
MessageWindow::information(*presentation, text); MessageWindow().setParent(*presentation).setText(text).information();
} }

View File

@ -27,9 +27,9 @@ AdvancedSettings::AdvancedSettings() {
infoLabel.setText({ infoLabel.setText({
Emulator::Name, " v", Emulator::Version, "\n", Emulator::Name, " v", Emulator::Version, "\n",
" ", profile, " Profile\n", " ", profile, " Profile\n",
" Author: byuu\n", " Author: ", Emulator::Author, "\n",
" Website: http://byuu.org/\n", " License: ", Emulator::License, "\n",
" License: GPLv3" " Website: ", Emulator::Website
}); });
lstring list; lstring list;
@ -65,15 +65,17 @@ AdvancedSettings::AdvancedSettings() {
libraryLayout.append(libraryLabel, {0, 0}, 5); libraryLayout.append(libraryLabel, {0, 0}, 5);
libraryLayout.append(libraryPath, {~0, 0}, 5); libraryLayout.append(libraryPath, {~0, 0}, 5);
libraryLayout.append(libraryBrowse, {80, 0}); libraryLayout.append(libraryBrowse, {80, 0});
append(spacer, {~0, ~0}); if(Intrinsics::platform() != Intrinsics::Platform::OSX) {
append(infoLabel, {~0, 0}); append(spacer, {~0, ~0});
append(infoLabel, {~0, 0});
}
videoDriver.onChange = [&] { config->video.driver = videoDriver.text(); }; videoDriver.onChange = [&] { config->video.driver = videoDriver.text(); };
audioDriver.onChange = [&] { config->audio.driver = audioDriver.text(); }; audioDriver.onChange = [&] { config->audio.driver = audioDriver.text(); };
inputDriver.onChange = [&] { config->input.driver = inputDriver.text(); }; inputDriver.onChange = [&] { config->input.driver = inputDriver.text(); };
libraryBrowse.onActivate = [&] { libraryBrowse.onActivate = [&] {
string path = DialogWindow::folderSelect(Window::none(), userpath()); string path = BrowserWindow().setParent(*settings).setPath(userpath()).directory();
if(path.empty()) return; if(path.empty()) return;
file::write({configpath(), "higan/library.cfg"}, path); file::write({configpath(), "higan/library.cfg"}, path);
libraryPath.setText(path); libraryPath.setText(path);

View File

@ -134,8 +134,8 @@ void InputSettings::inputChanged() {
} }
void InputSettings::resetInput() { void InputSettings::resetInput() {
if(MessageWindow::question(*settings, "All inputs will be erased. Are you sure you want to do this?") if(MessageWindow().setParent(*settings).setText("All inputs will be erased. Are you sure you want to do this?")
== MessageWindow::Response::No) return; .question() == MessageWindow::Response::No) return;
auto &device = activeDevice(); auto &device = activeDevice();
unsigned length = device.input.size(); unsigned length = device.input.size();

View File

@ -50,14 +50,14 @@ void CheatDatabase::findCodes() {
return; return;
} }
MessageWindow::information(*cheatEditor, "Sorry, no cheat codes were found."); MessageWindow().setParent(*cheatEditor).setText("Sorry, no cheat codes were found.").information();
} }
void CheatDatabase::addCodes() { void CheatDatabase::addCodes() {
for(unsigned n = 0; n < cheat.size(); n++) { for(unsigned n = 0; n < cheat.size(); n++) {
if(cheatList.checked(n) == false) continue; if(cheatList.checked(n) == false) continue;
if(cheatEditor->import(cheat[n].code, cheat[n].desc) == false) { if(cheatEditor->import(cheat[n].code, cheat[n].desc) == false) {
MessageWindow::warning(*this, "Ran out of empty slots for cheat codes.\nNot all cheat codes were added."); MessageWindow().setParent(*this).setText("Ran out of empty slots for cheat codes.\nNot all cheat codes were added.").warning();
break; break;
} }
} }

View File

@ -40,8 +40,8 @@ CheatEditor::CheatEditor() {
descEdit.onChange = {&CheatEditor::updateDesc, this}; descEdit.onChange = {&CheatEditor::updateDesc, this};
findButton.onActivate = {&CheatDatabase::findCodes, cheatDatabase}; findButton.onActivate = {&CheatDatabase::findCodes, cheatDatabase};
resetButton.onActivate = [&] { resetButton.onActivate = [&] {
if(MessageWindow::question(*this, "All codes will be erased. Are you sure you want to do this?") if(MessageWindow().setParent(*this).setText("All codes will be erased. Are you sure you want to do this?")
== MessageWindow::Response::Yes) reset(); .question() == MessageWindow::Response::Yes) reset();
}; };
eraseButton.onActivate = {&CheatEditor::erase, this}; eraseButton.onActivate = {&CheatEditor::erase, this};

View File

@ -34,8 +34,8 @@ StateManager::StateManager() {
saveButton.onActivate = {&StateManager::slotSave, this}; saveButton.onActivate = {&StateManager::slotSave, this};
loadButton.onActivate = {&StateManager::slotLoad, this}; loadButton.onActivate = {&StateManager::slotLoad, this};
resetButton.onActivate = [&] { resetButton.onActivate = [&] {
if(MessageWindow::question(*this, "All states will be erased. Are you sure you want to do this?") if(MessageWindow().setParent(*this).setText("All states will be erased. Are you sure you want to do this?")
== MessageWindow::Response::Yes) reset(); .question() == MessageWindow::Response::Yes) reset();
}; };
eraseButton.onActivate = {&StateManager::slotErase, this}; eraseButton.onActivate = {&StateManager::slotErase, this};

View File

@ -34,7 +34,7 @@ void Utility::loadMedia(string pathname) {
} }
} }
MessageWindow::warning(Window::none(), "Unable to determine media type."); MessageWindow().setText("Unable to determine media type.").warning();
} }
//load menu option selected //load menu option selected