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
# compiler
flags := -I. -O3 -fomit-frame-pointer
link := -s
flags += -I. -O3 -fomit-frame-pointer
link +=
objects := libco
# profile-guided optimization mode
@ -32,7 +32,9 @@ endif
# platform
ifeq ($(platform),x)
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)
ifeq ($(arch),win32)
flags += -m32
@ -43,7 +45,7 @@ else ifeq ($(platform),win)
else
link += -mwindows
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
else
$(error unsupported platform.)
@ -55,9 +57,9 @@ ui := target-$(target)
compile = \
$(strip \
$(if $(filter %.c,$<), \
$(c) $(flags) $1 -c $< -o $@, \
$(compiler) $(cflags) $(flags) $1 -c $< -o $@, \
$(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 {
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 License[] = "GPLv3";
static const char Website[] = "http://byuu.org/";
}
#include <nall/platform.hpp>

View File

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

View File

@ -37,19 +37,27 @@ endif
ifeq ($(compiler),)
ifeq ($(platform),win)
compiler := g++
flags :=
link :=
else ifeq ($(platform),osx)
compiler := clang
flags := -w -stdlib=libc++
link := -lc++ -lobjc
else
compiler := g++-4.7
flags :=
link :=
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
c := $(compiler) -x c -std=gnu99
cpp := $(compiler) -std=gnu++11
ifeq ($(arch),x86)
c := $(c) -m32
cpp := $(cpp) -m32
flags := -m32 $(flags)
link := -m32 $(link)
endif
ifeq ($(prefix),)

View File

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

View File

@ -4,18 +4,21 @@ ifeq ($(platform),x)
endif
ifeq ($(phoenix),gtk)
phoenixflags := -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`
phoenixlink := `pkg-config --libs gtk+-2.0`
phoenixflags = $(cppflags) $(flags) -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`
phoenixlink = `pkg-config --libs gtk+-2.0`
endif
ifeq ($(phoenix),qt)
phoenixflags := -DPHOENIX_QT `pkg-config --cflags QtCore QtGui`
phoenixlink := `pkg-config --libs QtCore QtGui`
phoenixflags = $(cppflags) $(flags) -DPHOENIX_QT `pkg-config --cflags QtCore QtGui`
phoenixlink = `pkg-config --libs QtCore QtGui`
endif
else ifeq ($(platform),osx)
phoenixflags = $(objcppflags) $(flags) -DPHOENIX_COCOA
phoenixlink = -framework Cocoa -framework Carbon
else ifeq ($(platform),win)
phoenixflags := -DPHOENIX_WINDOWS
phoenixlink := -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi
phoenixflags = $(cppflags) $(flags) -DPHOENIX_WINDOWS
phoenixlink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi
else
phoenixflags := -DPHOENIX_REFERENCE
phoenixlink :=
phoenixflags = $(cppflags) $(flags) -DPHOENIX_REFERENCE
phoenixlink =
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 {
void pSeparator::constructor() {
@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 {
struct pSeparator : public pAction {
Separator &separator;
CocoaSeparator *cocoaSeparator;
NSMenuItem *cocoaSeparator;
pSeparator(Separator &separator) : pAction(separator), separator(separator) {}
void constructor();

View File

@ -1,22 +1,41 @@
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;
@autoreleasepool {
NSMutableArray *filters = [[NSMutableArray alloc] init];
for(auto &rule : filter) {
for(auto &rule : state.filters) {
string pattern = rule.split<1>("(")(1).rtrim<1>(")");
if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]];
}
NSOpenPanel *panel = [NSOpenPanel openPanel];
if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]];
[panel setCanChooseDirectories:NO];
[panel setCanChooseFiles:YES];
[panel setAllowedFileTypes:filters];
if([panel runModalForDirectory:[NSString stringWithUTF8String:path] file:nil] == NSOKButton) {
NSArray *filenames = [panel filenames];
const char *filename = [[filenames objectAtIndex:0] UTF8String];
if(filename) result = filename;
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;
}
[filters release];
}
@ -24,21 +43,22 @@ string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring
return result;
}
string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) {
string pBrowserWindow::save(BrowserWindow::State &state) {
string result;
@autoreleasepool {
NSMutableArray *filters = [[NSMutableArray alloc] init];
for(auto &rule : filter) {
for(auto &rule : state.filters) {
string pattern = rule.split<1>("(")(1).rtrim<1>(")");
if(!pattern.empty()) [filters addObjects:[NSString stringWithUTF8String:pattern]];
}
NSSavePanel *panel = [NSSavePanel savePanel];
if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]];
[panel setAllowedFileTypes:filters];
if([panel runModalForDirectory:[NSString stringWithUTF8String:path] file:nil] == NSOKButton) {
NSArray *filenames = [panel filenames];
const char *filename = [[filenames objectAtIndex:0] UTF8String];
if(filename) result = filename;
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;
}
[filters release];
}
@ -46,21 +66,4 @@ string pDialogWindow::fileSave(Window &parent, const string &path, const lstring
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 {
MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return message(parent, text, buttons, Type::Information);
}
enum class MessageWindowType : unsigned { Error, Information, Question, Warning };
MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
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) {
MessageWindow::Response MessageWindow_dialog(MessageWindow::State &state, MessageWindowType type) {
@autoreleasepool {
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:
[alert addButtonWithTitle:@"Ok"];
break;
@ -41,16 +28,16 @@ MessageWindow::Response pMessageWindow::message(Window &parent, const string &te
}
switch(type) {
case Type::Information: [alert setAlertStyle:NSInformationalAlertStyle]; break;
case Type::Question: [alert setAlertStyle:NSInformationalAlertStyle]; break;
case Type::Warning: [alert setAlertStyle:NSWarningAlertStyle]; break;
case Type::Critical: [alert setAlertStyle:NSCriticalAlertStyle]; break;
case MessageWindowType::Error: [alert setAlertStyle:NSCriticalAlertStyle]; break;
case MessageWindowType::Information: [alert setAlertStyle:NSInformationalAlertStyle]; break;
case MessageWindowType::Question: [alert setAlertStyle:NSInformationalAlertStyle]; break;
case MessageWindowType::Warning: [alert setAlertStyle:NSWarningAlertStyle]; break;
}
NSInteger response = [alert runModal];
//[alert beginSheetModalForWindow:parent.p.cocoaWindow modalDelegate:self didEndSelector:@selector(...) contextInfo:nil];
switch(buttons) {
switch(state.buttons) {
case MessageWindow::Buttons::Ok:
if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Ok;
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 {
struct pMessageWindow {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons);
enum class Type : unsigned { Information, Question, Warning, Critical };
static MessageWindow::Response message(Window &parent, const string &text, MessageWindow::Buttons buttons, Type type);
static MessageWindow::Response error(MessageWindow::State &state);
static MessageWindow::Response information(MessageWindow::State &state);
static MessageWindow::Response question(MessageWindow::State &state);
static MessageWindow::Response warning(MessageWindow::State &state);
};
}

View File

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

View File

@ -10,7 +10,7 @@ namespace phoenix {
#include "desktop.hpp"
#include "keyboard.hpp"
#include "mouse.hpp"
#include "dialog-window.hpp"
#include "browser-window.hpp"
#include "message-window.hpp"
#include "object.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 {
void pHexEdit::setColumns(unsigned columns) {
@ -16,6 +27,15 @@ void pHexEdit::update() {
}
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 {
struct pHexEdit : public pWidget {
HexEdit &hexEdit;
CocoaHexEdit *cocoaHexEdit;
void setColumns(unsigned columns);
void setLength(unsigned length);
@ -11,6 +19,7 @@ struct pHexEdit : public pWidget {
pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {}
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 {
uintptr_t pViewport::handle() {
return 0;
return (uintptr_t)cocoaViewport;
}
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 {
struct pViewport : public pWidget {
Viewport &viewport;
CocoaViewport *cocoaViewport;
uintptr_t handle();
pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {}
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 setTitle:@""];
menu = [[NSMenu alloc] init];
[menu retain];
menuBar = [[NSMenu alloc] init];
NSMenuItem *item;
string text;
@ -22,9 +21,9 @@
rootMenu = [[NSMenu alloc] init];
item = [[[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""] autorelease];
[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];
[rootMenu addItem:item];
[rootMenu addItem:[NSMenuItem separatorItem]];
@ -51,7 +50,7 @@
-(void) windowDidBecomeMain :(NSNotification*)notification {
if(window->state.menu.size() > 0) {
[NSApp setMainMenu:menu];
[NSApp setMainMenu:menuBar];
}
}
@ -70,8 +69,8 @@
return NO;
}
-(NSMenu*) menu {
return menu;
-(NSMenu*) menuBar {
return menuBar;
}
-(void) menuAbout {
@ -107,7 +106,7 @@ void pWindow::append(Layout &layout) {
void pWindow::append(Menu &menu) {
@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) {
@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) {
@autoreleasepool {
[cocoaWindow setLevel:NSNormalWindowLevel];
if(fullScreen == true) {
[NSApp setPresentationOptions:NSApplicationPresentationFullScreen];
[cocoaWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
@ -273,8 +271,12 @@ void pWindow::setTitle(const string &text) {
void pWindow::setVisible(bool visible) {
@autoreleasepool {
if(visible) [cocoaWindow makeKeyAndOrderFront:nil];
else [cocoaWindow orderOut:nil];
if(visible) {
[cocoaWindow makeKeyAndOrderFront:nil];
[cocoaWindow setLevel:NSNormalWindowLevel];
} else {
[cocoaWindow orderOut:nil];
}
}
}

View File

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

View File

@ -166,42 +166,94 @@ bool Mouse::released(Mouse::Button button) {
return !pressed(button);
}
//DialogWindow
//============
//BrowserWindow
//=============
string DialogWindow::fileOpen_(Window &parent, const string &path, const lstring &filter_) {
auto filter = filter_;
if(filter.size() == 0) filter.append("All files (*)");
return pDialogWindow::fileOpen(parent, path, filter);
string BrowserWindow::directory() {
return pBrowserWindow::directory(state);
}
string DialogWindow::fileSave_(Window &parent, const string &path, const lstring &filter_) {
auto filter = filter_;
if(filter.size() == 0) filter.append("All files (*)");
return pDialogWindow::fileSave(parent, path, filter);
string BrowserWindow::open() {
return pBrowserWindow::open(state);
}
string DialogWindow::folderSelect(Window &parent, const string &path) {
return pDialogWindow::folderSelect(parent, path);
string BrowserWindow::save() {
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::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return pMessageWindow::information(parent, text, buttons);
MessageWindow::Response MessageWindow::error(MessageWindow::Buttons buttons) {
state.buttons = buttons;
return pMessageWindow::error(state);
}
MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return pMessageWindow::question(parent, text, buttons);
MessageWindow::Response MessageWindow::information(MessageWindow::Buttons buttons) {
state.buttons = buttons;
return pMessageWindow::information(state);
}
MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return pMessageWindow::warning(parent, text, buttons);
MessageWindow::Response MessageWindow::question(MessageWindow::Buttons buttons) {
state.buttons = buttons;
return pMessageWindow::question(state);
}
MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
return pMessageWindow::critical(parent, text, buttons);
MessageWindow& MessageWindow::setParent(Window &parent) {
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

View File

@ -141,15 +141,21 @@ struct Mouse {
Mouse() = delete;
};
struct DialogWindow {
template<typename... Args> static nall::string fileOpen(Window &parent, const nall::string &path, const Args&... args) { return fileOpen_(parent, path, { 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;
struct BrowserWindow {
template<typename... Args> BrowserWindow& setFilters(const Args&... args) { return setFilters_({args...}); }
private:
static nall::string fileOpen_(Window &parent, const nall::string &path, const nall::lstring& filter);
static nall::string fileSave_(Window &parent, const nall::string &path, const nall::lstring& filter);
nall::string directory();
nall::string open();
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 {
@ -167,11 +173,18 @@ struct MessageWindow {
No,
};
static Response information(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo);
static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok);
MessageWindow() = delete;
Response error(Buttons = Buttons::Ok);
Response information(Buttons = Buttons::Ok);
Response question(Buttons = Buttons::YesNo);
MessageWindow& setParent(Window &parent);
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 {

View File

@ -8,6 +8,20 @@ struct Timer::State {
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 {
bool backgroundColorOverride = false;
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 {
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_CANCEL) return MessageWindow::Response::Cancel;
if(response == GTK_RESPONSE_YES) return MessageWindow::Response::Yes;
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;
return MessageWindow::Response::Ok;
//if dialog was closed without choosing a button, choose the most appropriate response
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) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
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::error(MessageWindow::State &state) {
return Message(state, GTK_MESSAGE_ERROR);
}
MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
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::information(MessageWindow::State &state) {
return Message(state, GTK_MESSAGE_INFO);
}
MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
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::question(MessageWindow::State &state) {
return Message(state, GTK_MESSAGE_QUESTION);
}
MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
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);
MessageWindow::Response pMessageWindow::warning(MessageWindow::State &state) {
return Message(state, GTK_MESSAGE_WARNING);
}
}

View File

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

View File

@ -62,17 +62,17 @@ struct pMouse {
static bool pressed(Mouse::Button button);
};
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);
struct pBrowserWindow {
static string directory(BrowserWindow::State &state);
static string open(BrowserWindow::State &state);
static string save(BrowserWindow::State &state);
};
struct pMessageWindow {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response error(MessageWindow::State &state);
static MessageWindow::Response information(MessageWindow::State &state);
static MessageWindow::Response question(MessageWindow::State &state);
static MessageWindow::Response warning(MessageWindow::State &state);
};
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::OkCancel) standardButtons = QMessageBox::Ok | QMessageBox::Cancel;
if(buttons == MessageWindow::Buttons::YesNo) standardButtons = QMessageBox::Yes | QMessageBox::No;
if(buttons == MessageWindow::Buttons::YesNoCancel) standardButtons = QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel;
return standardButtons;
}
@ -15,36 +16,39 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
if(response == QMessageBox::No) return MessageWindow::Response::No;
//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::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(
buttons, QMessageBox::information(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons))
state.buttons, QMessageBox::critical(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ",
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(
buttons, QMessageBox::question(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons))
state.buttons, QMessageBox::information(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ",
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(
buttons, QMessageBox::warning(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons))
state.buttons, QMessageBox::question(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ",
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(
buttons, QMessageBox::critical(&parent != &Window::none() ? parent.p.qtWindow : nullptr, " ",
QString::fromUtf8(text), MessageWindow_buttons(buttons))
state.buttons, QMessageBox::warning(state.parent ? state.parent->p.qtWindow : nullptr, state.title ? state.title : " ",
QString::fromUtf8(state.text), MessageWindow_buttons(state.buttons))
);
}

View File

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

View File

@ -1,7 +1,7 @@
/****************************************************************************
** 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)
**
** WARNING! All changes made in this file will be lost!

View File

@ -61,17 +61,17 @@ struct pMouse {
static bool pressed(Mouse::Button button);
};
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);
struct pBrowserWindow {
static string directory(BrowserWindow::State &state);
static string open(BrowserWindow::State &state);
static string save(BrowserWindow::State &state);
};
struct pMessageWindow {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response error(MessageWindow::State &state);
static MessageWindow::Response information(MessageWindow::State &state);
static MessageWindow::Response question(MessageWindow::State &state);
static MessageWindow::Response warning(MessageWindow::State &state);
};
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 {
MessageWindow::Response pMessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) {
MessageWindow::Response pMessageWindow::error(MessageWindow::State &state) {
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;
}
MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
MessageWindow::Response pMessageWindow::question(MessageWindow::State &state) {
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;
}

View File

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

View File

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

View File

@ -10,7 +10,7 @@ namespace phoenix {
#include "desktop.hpp"
#include "keyboard.hpp"
#include "mouse.hpp"
#include "dialog-window.hpp"
#include "browser-window.hpp"
#include "message-window.hpp"
#include "object.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 == IDYES) return MessageWindow::Response::Yes;
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::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) {
UINT flags = MB_ICONINFORMATION;
if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK;
if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL;
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));
static UINT MessageWindow_buttons(MessageWindow::Buttons buttons) {
if(buttons == MessageWindow::Buttons::Ok) return MB_OK;
if(buttons == MessageWindow::Buttons::OkCancel) return MB_OKCANCEL;
if(buttons == MessageWindow::Buttons::YesNo) return MB_YESNO;
if(buttons == MessageWindow::Buttons::YesNoCancel) return MB_YESNOCANCEL;
throw;
}
MessageWindow::Response pMessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) {
UINT flags = MB_ICONQUESTION;
if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK;
if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL;
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::error(MessageWindow::State &state) {
UINT flags = MB_ICONERROR | 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
));
}
MessageWindow::Response pMessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) {
UINT flags = MB_ICONWARNING;
if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK;
if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL;
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::information(MessageWindow::State &state) {
UINT flags = MB_ICONINFORMATION | 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
));
}
MessageWindow::Response pMessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) {
UINT flags = MB_ICONERROR;
if(buttons == MessageWindow::Buttons::Ok) flags |= MB_OK;
if(buttons == MessageWindow::Buttons::OkCancel) flags |= MB_OKCANCEL;
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::question(MessageWindow::State &state) {
UINT flags = MB_ICONQUESTION | 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
));
}
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 "keyboard.cpp"
#include "mouse.cpp"
#include "dialog-window.cpp"
#include "browser-window.cpp"
#include "message-window.cpp"
#include "object.cpp"
#include "font.cpp"

View File

@ -48,17 +48,17 @@ struct pMouse {
static bool pressed(Mouse::Button button);
};
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);
struct pBrowserWindow {
static string directory(BrowserWindow::State &state);
static string open(BrowserWindow::State &state);
static string save(BrowserWindow::State &state);
};
struct pMessageWindow {
static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons);
static MessageWindow::Response error(MessageWindow::State &state);
static MessageWindow::Response information(MessageWindow::State &state);
static MessageWindow::Response question(MessageWindow::State &state);
static MessageWindow::Response warning(MessageWindow::State &state);
};
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`)
rubylink :=
rubylink += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
rubylink =
rubylink += $(if $(findstring video.cgl,$(ruby)),-framework OpenGL)
rubylink += $(if $(findstring video.direct3d,$(ruby)),-ld3d9)
rubylink += $(if $(findstring video.directdraw,$(ruby)),-lddraw)
rubylink += $(if $(findstring video.glx,$(ruby)),-lGL)
rubylink += $(if $(findstring video.wgl,$(ruby)),-lopengl32)
rubylink += $(if $(findstring video.xv,$(ruby)),-lXv)
rubylink += $(if $(findstring audio.alsa,$(ruby)),-lasound)
rubylink += $(if $(findstring audio.ao,$(ruby)),-lao)
rubylink += $(if $(findstring audio.directsound,$(ruby)),-ldsound)
rubylink += $(if $(findstring audio.pulseaudio,$(ruby)),-lpulse)
rubylink += $(if $(findstring audio.pulseaudiosimple,$(ruby)),-lpulse-simple)
rubylink += $(if $(findstring audio.xaudio2,$(ruby)),-lole32)
rubylink += $(if $(findstring input.directinput,$(ruby)),-ldinput8 -ldxguid)
rubylink += $(if $(findstring input.rawinput,$(ruby)),-ldinput8 -ldxguid)
rubylink += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
ifeq ($(platform),x)
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal)
else ifeq ($(platform),osx)

View File

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

View File

@ -18,6 +18,7 @@
#include <X11/Xatom.h>
#elif defined(PLATFORM_OSX)
#define __INTEL_COMPILER
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>
#elif defined(PLATFORM_WINDOWS)
#define _WIN32_WINNT 0x0501
@ -50,6 +51,10 @@ using namespace nall;
pVideo##Name &p; \
};
#ifdef VIDEO_CGL
#include <ruby/video/cgl.cpp>
#endif
#ifdef VIDEO_DIRECT3D
#include <ruby/video/direct3d.cpp>
#endif
@ -175,6 +180,10 @@ using namespace nall;
#include <ruby/input/rawinput.cpp>
#endif
#ifdef INPUT_CARBON
#include <ruby/input/carbon.cpp>
#endif
#ifdef INPUT_SDL
#include <ruby/input/sdl.cpp>
#endif
@ -182,7 +191,3 @@ using namespace nall;
#ifdef INPUT_X
#include <ruby/input/x.cpp>
#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)
#include <GL/gl.h>
#include <GL/glx.h>
#define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name))
#elif defined(PLATFORM_OSX)
#include <OpenGL/gl.h>
#elif defined(PLATFORM_WIN)
#include <GL/gl.h>
#include <GL/glext.h>
#define glGetProcAddress(name) wglGetProcAddress(name)
#else
#error "ruby::OpenGL: unsupported platform"
#endif
PFNGLCREATEPROGRAMPROC glCreateProgram = 0;
PFNGLUSEPROGRAMPROC glUseProgram = 0;
PFNGLCREATESHADERPROC glCreateShader = 0;
PFNGLDELETESHADERPROC glDeleteShader = 0;
PFNGLSHADERSOURCEPROC glShaderSource = 0;
PFNGLCOMPILESHADERPROC glCompileShader = 0;
PFNGLATTACHSHADERPROC glAttachShader = 0;
PFNGLDETACHSHADERPROC glDetachShader = 0;
PFNGLLINKPROGRAMPROC glLinkProgram = 0;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = 0;
PFNGLUNIFORM1IPROC glUniform1i = 0;
PFNGLUNIFORM2FVPROC glUniform2fv = 0;
PFNGLUNIFORM4FVPROC glUniform4fv = 0;
#if !defined(PLATFORM_OSX)
PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
PFNGLUSEPROGRAMPROC glUseProgram = nullptr;
PFNGLCREATESHADERPROC glCreateShader = nullptr;
PFNGLDELETESHADERPROC glDeleteShader = nullptr;
PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
PFNGLATTACHSHADERPROC glAttachShader = nullptr;
PFNGLDETACHSHADERPROC glDetachShader = nullptr;
PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
PFNGLUNIFORM1IPROC glUniform1i = nullptr;
PFNGLUNIFORM2FVPROC glUniform2fv = nullptr;
PFNGLUNIFORM4FVPROC glUniform4fv = nullptr;
#endif
class OpenGL {
public:
@ -177,6 +181,9 @@ public:
glEnable(GL_DITHER);
glEnable(GL_TEXTURE_2D);
#if defined(PLATFORM_OSX)
shader_support = true;
#else
//bind shader functions
glCreateProgram = (PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgram");
glUseProgram = (PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgram");
@ -196,6 +203,7 @@ public:
&& glDeleteShader && glShaderSource && glCompileShader && glAttachShader
&& glDetachShader && glLinkProgram && glGetUniformLocation
&& glUniform1i && glUniform2fv && glUniform4fv;
#endif
if(shader_support) glprogram = glCreateProgram();
@ -211,7 +219,7 @@ public:
if(buffer) {
delete[] buffer;
buffer = 0;
buffer = nullptr;
iwidth = 0;
iheight = 0;
}
@ -224,7 +232,7 @@ public:
fragmentfilter = 0;
vertexshader = 0;
buffer = 0;
buffer = nullptr;
iwidth = 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 += input.sdl input.x
else ifeq ($(platform),osx)
ruby :=
ruby := video.cgl
ruby += audio.openal
ruby += input.carbon
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/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
$(call compile,$(rubyflags))
$(compiler) $(rubyflags) -c $< -o $@
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*)
$(call compile,$(phoenixflags))
$(compiler) $(phoenixflags) -c $< -o $@
obj/resource.o: $(ui)/resource.rc
ifeq ($(arch),win32)
@ -67,13 +67,19 @@ endif
# targets
build: $(objects)
ifeq ($(platform),x)
$(strip $(cpp) -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)
$(strip $(compiler) -o out/$(name) $(objects) $(link))
else ifeq ($(platform),osx)
test -d ../$(name).app || mkdir -p ../$(name).app/Contents/MacOS
$(strip $(cpp) -o ../$(name).app/Contents/MacOS/$(name) $(objects) $(link))
if [ -d out/$(name).app ]; then rm -r out/$(name).app; fi
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
resource:

View File

@ -54,7 +54,7 @@ Program::Program(int argc, char **argv) {
if(Intrinsics::platform() == Intrinsics::Platform::OSX) {
normalFont = Font::sans(12);
boldFont = Font::sans(12, "Bold");
titleFont = Font::sans(24, "Bold");
titleFont = Font::sans(20, "Bold");
monospaceFont = Font::monospace(8);
} else {
normalFont = Font::sans(8);
@ -130,7 +130,24 @@ int main(int argc, char **argv) {
#endif
Application::setName("higan");
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);
delete program;
return 0;

View File

@ -98,8 +98,10 @@ Presentation::Presentation() : active(nullptr) {
for(auto &shader : shaderList) shaderMenu.append(*shader);
settingsMenu.append(*new Separator);
settingsMenu.append(synchronizeVideo, synchronizeAudio, muteAudio);
settingsMenu.append(*new Separator);
settingsMenu.append(configurationSettings);
if(Intrinsics::platform() != Intrinsics::Platform::OSX) {
settingsMenu.append(*new Separator);
settingsMenu.append(configurationSettings);
}
append(toolsMenu);
toolsMenu.append(saveStateMenu);
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) {
MessageWindow::information(*presentation, text);
MessageWindow().setParent(*presentation).setText(text).information();
}

View File

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

View File

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

View File

@ -50,14 +50,14 @@ void CheatDatabase::findCodes() {
return;
}
MessageWindow::information(*cheatEditor, "Sorry, no cheat codes were found.");
MessageWindow().setParent(*cheatEditor).setText("Sorry, no cheat codes were found.").information();
}
void CheatDatabase::addCodes() {
for(unsigned n = 0; n < cheat.size(); n++) {
if(cheatList.checked(n) == false) continue;
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;
}
}

View File

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

View File

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