Update to v096r02 (OS X Preview for Developers) release.

byuu says:

Warning: this is not for the faint of heart. This is a very early,
unpolished, buggy release. But help testing/fixing bugs would be greatly
appreciated for anyone willing.

Requirements:
- Mac OS X 10.7+
- Xcode 7.2+

Installation Commands:

    cd higan
    gmake -j 4
    gmake install
    cd ../icarus
    gmake -j 4
    gmake install

(gmake install is absolutely required, sorry. You'll be missing key
files in key places if you don't run it, and nothing will work.)

(gmake uninstall also exists, or you can just delete the .app bundles
from your Applications folder, and the Dev folder on your desktop.)

If you want to use the GBA emulation, then you need to drop the GBA BIOS
into ~/Emulation/System/Game\ Boy\ Advance.sys\bios.rom

Usage:
You'll now find higan.app and icarus.app in your Applications folders.
First, run icarus.app, navigate to where you keep your game ROMs. Now
click the settings button at the bottom right, and check "Create
Manifests", and click OK. (You'll need to do this every time you run
icarus because there's some sort of bug on OSX saving the settings.) Now
click "Import", and let it bring in your games into ~/Emulation.

Note: "Create Manifests" is required. I don't yet have a pipe
implementation on OS X for higan to invoke icarus yet. If you don't
check this box, it won't create manifest.bml files, and your games won't
run at all.

Now you can run higan.app. The first thing you'll want to do is go to
higan->Preferences... and assign inputs for your gamepads. At the very
least, do it for the default controller for all the systems you want to
emulate.

Now this is very important ... close the application at this point so
that it writes your config file to disk. There's a serious crashing bug,
and if you trigger it, you'll lose your input bindings.

Now the really annoying part ... go to Library->{System} and pick the
game you want to play. Right now, there's a ~50% chance the application
will bomb. It seems the hiro::pListView object is getting destroyed, yet
somehow the internal Cocoa callbacks are being triggered anyway. I don't
know how this is possible, and my attempts to debug with lldb have been
a failure :(

If you're unlucky, the application will crash. Restart and try again. If
it crashes every single time, then you can try launching your game from
the command-line instead. Example:

    open /Applications/higan.app \
	--args ~/Emulation/Super\ Famicom/Zelda3.sfc/

Help wanted:
I could really, really, really use some help with that crashing on game
loading. There's a lot of rough edges, but they're all cosmetic. This
one thing is pretty much the only major show-stopping issue at the
moment, preventing a wider general audience pre-compiled binary preview.
This commit is contained in:
Tim Allen 2016-01-05 13:59:19 +11:00
parent 47d4bd4d81
commit 4d193d7d94
50 changed files with 1070 additions and 473 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
ananke/libananke.so
icarus/icarus

View File

@ -7,7 +7,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "096.01";
static const string Version = "096.02";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -21,7 +21,7 @@ ifeq ($(platform),windows)
else ifeq ($(platform),macosx)
ruby += video.cgl
ruby += audio.openal
ruby += input.carbon
ruby += input.quartz input.carbon
else ifeq ($(platform),linux)
ruby += video.glx video.xv video.xshm video.sdl
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
@ -67,12 +67,25 @@ obj/ui-resource.o:
# targets
build: $(objects)
$(strip $(compiler) -o out/$(name) $(objects) $(link))
ifeq ($(platform),macosx)
@if [ -d out/higan.app ]; then rm -r out/higan.app; fi
mkdir -p out/higan.app/Contents/MacOS/
mkdir -p out/higan.app/Contents/Resources/
mv out/$(name) out/higan.app/Contents/MacOS/higan
cp data/higan.plist out/higan.app/Contents/Info.plist
sips -s format icns data/higan.png --out out/higan.app/Contents/Resources/higan.icns
endif
install:
ifeq ($(shell id -un),root)
$(error "make install should not be run as root")
else ifeq ($(platform),windows)
else ifeq ($(platform),macosx)
mkdir -p ~/Library/Application\ Support/$(name)/
mkdir -p ~/Emulation/System/
cp -R out/higan.app /Applications/higan.app
cp data/cheats.bml ~/Library/Application\ Support/$(name)/
cp -R profile/* ~/Emulation/System/
else
mkdir -p $(prefix)/bin/
mkdir -p $(prefix)/share/icons/
@ -89,6 +102,7 @@ ifeq ($(shell id -un),root)
$(error "make uninstall should not be run as root")
else ifeq ($(platform),windows)
else ifeq ($(platform),macosx)
if [ -d /Applications/higan.app ]; then rm -r /Applications/higan.app; fi
else
if [ -f $(prefix)/bin/$(name) ]; then rm $(prefix)/bin/$(name); fi
if [ -f $(prefix)/share/icons/$(name).png ]; then rm $(prefix)/share/icons/$(name).png; fi

View File

@ -105,6 +105,16 @@ Presentation::Presentation() {
stateManager.setText("State Manager").onActivate([&] { toolsManager->show(1); });
manifestViewer.setText("Manifest Viewer").onActivate([&] { toolsManager->show(2); });
helpMenu.setText("Help");
about.setText("About ...").onActivate([&] {
MessageDialog().setParent(*this).setTitle("About higan ...").setText({
Emulator::Name, " v", Emulator::Version, " (", Emulator::Profile, ")\n\n",
"Author: ", Emulator::Author, "\n",
"License: ", Emulator::License, "\n",
"Website: ", Emulator::Website
}).information();
});
statusBar.setFont(Font().setBold());
statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean());
@ -115,6 +125,17 @@ Presentation::Presentation() {
setBackgroundColor({0, 0, 0});
resizeViewport();
setCentered();
#if defined(PLATFORM_MACOSX)
showConfigurationSeparator.setVisible(false);
showConfiguration.setVisible(false);
helpMenu.setVisible(false);
Application::Cocoa::onAbout([&] { about.doActivate(); });
Application::Cocoa::onActivate([&] { setFocused(); });
Application::Cocoa::onPreferences([&] { showConfiguration.doActivate(); });
Application::Cocoa::onQuit([&] { doClose(); });
#endif
}
auto Presentation::updateEmulator() -> void {

View File

@ -36,12 +36,12 @@ struct Presentation : Window {
Menu videoShaderMenu{&settingsMenu};
MenuRadioItem videoShaderNone{&videoShaderMenu};
Group videoShaders{&videoShaderNone};
MenuSeparator settingsMenuSeparator1{&settingsMenu};
MenuSeparator videoSettingsSeparator{&settingsMenu};
MenuCheckItem synchronizeVideo{&settingsMenu};
MenuCheckItem synchronizeAudio{&settingsMenu};
MenuCheckItem muteAudio{&settingsMenu};
MenuCheckItem showStatusBar{&settingsMenu};
MenuSeparator settingsMenuSeparator2{&settingsMenu};
MenuSeparator showConfigurationSeparator{&settingsMenu};
MenuItem showConfiguration{&settingsMenu};
Menu toolsMenu{&menuBar};
Menu saveStateMenu{&toolsMenu};
@ -60,6 +60,8 @@ struct Presentation : Window {
MenuItem cheatEditor{&toolsMenu};
MenuItem stateManager{&toolsMenu};
MenuItem manifestViewer{&toolsMenu};
Menu helpMenu{&menuBar};
MenuItem about{&helpMenu};
FixedLayout layout{this};
Viewport viewport{&layout, Geometry{0, 0, 1, 1}};

View File

@ -1,7 +1,9 @@
ifeq ($(platform),)
hiroflags = $(cppflags) $(flags) -DHIRO_REFERENCE
hirolink =
else ifeq ($(platform),windows)
endif
ifeq ($(platform),windows)
ifeq ($(hiro),)
hiro := windows
endif
@ -15,16 +17,20 @@ else ifeq ($(platform),windows)
hiroflags = $(cppflags) $(flags) -DHIRO_GTK $(shell pkg-config --cflags gtk+-2.0 gtksourceview-2.0)
hirolink = $(shell pkg-config --libs gtk+-2.0 gtksourceview-2.0)
endif
else ifeq ($(platform),macosx)
endif
ifeq ($(platform),macosx)
ifeq ($(hiro),)
hiro := cocoa
endif
ifeq ($(hiro),cocoa)
hiroflags = $(objcppflags) $(flags) -DHIRO_COCOA
hiroflags = $(objcppflags) $(flags) -w -DHIRO_COCOA
hirolink = -framework Cocoa -framework Carbon
endif
else
endif
ifneq ($(filter $(platform),linux bsd),)
ifeq ($(hiro),)
hiro := gtk
endif

View File

@ -39,20 +39,24 @@ auto pMenu::destruct() -> void {
auto pMenu::append(sAction action) -> void {
@autoreleasepool {
// [[cocoaAction cocoaMenu] addItem:action.p.cocoaAction];
if(auto pAction = action->self()) {
[[cocoaAction cocoaMenu] addItem:pAction->cocoaAction];
}
}
}
auto pMenu::remove(sAction action) -> void {
@autoreleasepool {
// [[cocoaAction cocoaMenu] removeItem:action.p.cocoaAction];
if(auto pAction = action->self()) {
[[cocoaAction cocoaMenu] removeItem:pAction->cocoaAction];
}
}
}
auto pMenu::setImage(const Image& image) -> void {
@autoreleasepool {
uint size = 15; //there is no API to retrieve the optimal size
// [cocoaAction setImage:NSMakeImage(image, size, size)];
[cocoaAction setImage:NSMakeImage(image, size, size)];
}
}

View File

@ -10,6 +10,24 @@ auto pLayout::destruct() -> void {
for(auto& sizable : state().sizables) sizable->destruct();
}
auto pLayout::setEnabled(bool enabled) -> void {
for(auto& sizable : state().sizables) {
if(auto self = sizable->self()) self->setEnabled(enabled && sizable->enabled(true));
}
}
auto pLayout::setFont(const Font& font) -> void {
for(auto& sizable : state().sizables) {
if(auto self = sizable->self()) self->setFont(font ? font : sizable->font(true));
}
}
auto pLayout::setVisible(bool visible) -> void {
for(auto& sizable : state().sizables) {
if(auto self = sizable->self()) self->setVisible(visible && sizable->visible(true));
}
}
}
#endif

View File

@ -4,6 +4,10 @@ namespace hiro {
struct pLayout : pSizable {
Declare(Layout, Sizable);
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setVisible(bool visible) -> void override;
};
}

View File

@ -9,9 +9,30 @@ auto pMenuBar::destruct() -> void {
}
auto pMenuBar::append(sMenu menu) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
if(auto pMenu = menu->self()) {
[[parent->cocoaWindow menuBar] addItem:pMenu->cocoaAction];
}
}
}
}
auto pMenuBar::remove(sMenu menu) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
if(auto pMenu = menu->self()) {
[[parent->cocoaWindow menuBar] removeItem:pMenu->cocoaAction];
}
}
}
}
auto pMenuBar::_parent() -> maybe<pWindow&> {
if(auto parent = self().parentWindow()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}

View File

@ -7,6 +7,8 @@ struct pMenuBar : pObject {
auto append(sMenu menu) -> void;
auto remove(sMenu menu) -> void;
auto _parent() -> maybe<pWindow&>;
};
}

View File

@ -8,7 +8,43 @@ auto pStatusBar::construct() -> void {
auto pStatusBar::destruct() -> void {
}
auto pStatusBar::setEnabled(bool enabled) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[[parent->cocoaWindow statusBar] setEnabled:enabled];
}
}
}
auto pStatusBar::setFont(const Font& font) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[[parent->cocoaWindow statusBar] setFont:pFont::create(font)];
}
}
}
auto pStatusBar::setText(const string& text) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[[parent->cocoaWindow statusBar] setStringValue:[NSString stringWithUTF8String:state().text]];
}
}
}
auto pStatusBar::setVisible(bool visible) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[[parent->cocoaWindow statusBar] setHidden:!visible];
}
}
}
auto pStatusBar::_parent() -> maybe<pWindow&> {
if(auto parent = self().parentWindow()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}

View File

@ -5,7 +5,12 @@ namespace hiro {
struct pStatusBar : pObject {
Declare(StatusBar, Object)
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setText(const string& text) -> void;
auto setVisible(bool visible) -> void override;
auto _parent() -> maybe<pWindow&>;
};
}

View File

@ -1,3 +1,7 @@
auto NSMakeColor(const hiro::Color& color) -> NSColor* {
return [NSColor colorWithRed:(color.red() / 255.0) green:(color.green() / 255.0) blue:(color.blue() / 255.0) alpha:(color.alpha() / 255.0)];
}
auto NSMakeImage(hiro::Image image, uint scaleWidth = 0, uint scaleHeight = 0) -> NSImage* {
if(!image.state.data) return nil;

View File

@ -30,16 +30,22 @@ auto pFrame::destruct() -> void {
}
}
auto pFrame::append(sLayout layout) -> void {
}
auto pFrame::remove(sLayout layout) -> void {
}
auto pFrame::setEnabled(bool enabled) -> void {
if(auto layout = _layout()) layout->setEnabled(layout->self().enabled(true));
pWidget::setEnabled(enabled);
if(auto layout = _layout()) layout->setEnabled(layout->self().enabled(true));
}
auto pFrame::setFont(const Font& font) -> void {
@autoreleasepool {
if(auto layout = _layout()) layout->setFont(layout->self().font(true));
[cocoaView setTitleFont:pFont::create(font)];
}
if(auto layout = _layout()) layout->setFont(layout->self().font(true));
}
auto pFrame::setGeometry(Geometry geometry) -> void {
@ -49,12 +55,11 @@ auto pFrame::setGeometry(Geometry geometry) -> void {
geometry.x() - 3, geometry.y() - (empty ? size.height() - 2 : 1),
geometry.width() + 6, geometry.height() + (empty ? size.height() + 2 : 5)
});
if(auto layout = _layout()) {
geometry.setX(geometry.x() + 1);
geometry.setY(geometry.y() + (empty ? 1 : size.height() - 2));
geometry.setWidth(geometry.width() - 2);
geometry.setHeight(geometry.height() - (empty ? 1 : size.height() - 1));
layout->setGeometry(geometry);
if(auto layout = state().layout) {
layout->setGeometry({
geometry.x() + 1, geometry.y() + (empty ? 1 : size.height() - 2),
geometry.width() - 2, geometry.height() - (empty ? 1 : size.height() - 1)
});
}
}
@ -65,8 +70,8 @@ auto pFrame::setText(const string& text) -> void {
}
auto pFrame::setVisible(bool visible) -> void {
if(auto layout = _layout()) layout->setVisible(layout->self().visible(true));
pWidget::setVisible(visible);
if(auto layout = _layout()) layout->setVisible(layout->self().visible(true));
}
auto pFrame::_layout() -> maybe<pLayout&> {

View File

@ -12,6 +12,8 @@ namespace hiro {
struct pFrame : pWidget {
Declare(Frame, Widget)
auto append(sLayout layout) -> void;
auto remove(sLayout layout) -> void;
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setGeometry(Geometry geometry) -> void override;

View File

@ -1,15 +1,14 @@
#if defined(Hiro_Label)
@implementation CocoaLabel : NSTextField
@implementation CocoaLabel : NSTextView
-(id) initWith:(hiro::mLabel&)labelReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
label = &labelReference;
[self setAlignment:NSLeftTextAlignment];
[self setBordered:NO];
[self setDrawsBackground:NO];
[self setEditable:NO];
[self setRichText:NO];
}
return self;
}
@ -23,6 +22,7 @@ auto pLabel::construct() -> void {
cocoaView = cocoaLabel = [[CocoaLabel alloc] initWith:self()];
pWidget::construct();
setAlignment(state().alignment);
setText(state().text);
}
}
@ -38,29 +38,36 @@ auto pLabel::minimumSize() const -> Size {
}
auto pLabel::setAlignment(Alignment alignment) -> void {
@autoreleasepool {
NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.alignment = NSTextAlignmentCenter;
if(alignment.horizontal() < 0.333) paragraphStyle.alignment = NSTextAlignmentLeft;
if(alignment.horizontal() > 0.666) paragraphStyle.alignment = NSTextAlignmentRight;
[cocoaView setDefaultParagraphStyle:paragraphStyle];
}
}
auto pLabel::setGeometry(Geometry geometry) -> void {
//NSTextField does not support vertical text centering:
//NSTextView does not support vertical text centering:
//simulate this by adjusting the geometry placement (reduce height, move view down)
uint height = pFont::size(self().font(true), " ").height();
uint height = pFont::size(self().font(true), state().text).height();
auto offset = geometry;
if(geometry.height() > height) {
uint diff = geometry.height() - height;
offset.setY(offset.y() + diff >> 1);
offset.setHeight(offset.height() - diff >> 1);
offset.setY(offset.y() + (diff >> 1));
offset.setHeight(offset.height() - (diff >> 1));
}
pWidget::setGeometry({
offset.x() - 3, offset.y() - 3,
offset.width() + 6, offset.height() + 6
offset.x() - 6, offset.y(),
offset.width() + 12, offset.height()
});
}
auto pLabel::setText(const string& text) -> void {
@autoreleasepool {
[cocoaView setStringValue:[NSString stringWithUTF8String:text]];
[cocoaView setString:[NSString stringWithUTF8String:text]];
}
}

View File

@ -1,6 +1,6 @@
#if defined(Hiro_Label)
@interface CocoaLabel : NSTextField {
@interface CocoaLabel : NSTextView {
@public
hiro::mLabel* label;
}

View File

@ -27,6 +27,22 @@ auto pListViewCell::setImage(const Image& image) -> void {
}
auto pListViewCell::setText(const string& text) -> void {
@autoreleasepool {
if(auto pListView = _grandparent()) {
[[pListView->cocoaView content] reloadData];
}
}
}
auto pListViewCell::_grandparent() -> maybe<pListView&> {
if(auto parent = _parent()) return parent->_parent();
}
auto pListViewCell::_parent() -> maybe<pListViewItem&> {
if(auto parent = self().parentListViewItem()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}

View File

@ -12,6 +12,9 @@ struct pListViewCell : pObject {
auto setForegroundColor(Color color) -> void;
auto setImage(const Image& image) -> void;
auto setText(const string& text) -> void;
auto _grandparent() -> maybe<pListView&>;
auto _parent() -> maybe<pListViewItem&>;
};
}

View File

@ -3,9 +3,19 @@
namespace hiro {
auto pListViewColumn::construct() -> void {
@autoreleasepool {
if(auto listView = _grandparent()) {
[listView->cocoaView reloadColumns];
}
}
}
auto pListViewColumn::destruct() -> void {
@autoreleasepool {
if(auto listView = _grandparent()) {
[listView->cocoaView reloadColumns];
}
}
}
auto pListViewColumn::setActive() -> void {
@ -42,6 +52,13 @@ auto pListViewColumn::setSortable(bool sortable) -> void {
}
auto pListViewColumn::setText(const string& text) -> void {
@autoreleasepool {
if(auto pListView = _grandparent()) {
NSTableColumn* tableColumn = [[pListView->cocoaView content] tableColumnWithIdentifier:[[NSNumber numberWithInteger:self().offset()] stringValue]];
[[tableColumn headerCell] setStringValue:[NSString stringWithUTF8STring:text]];
[[pListView->cocoaView headerView] setNeedsDisplay:YES];
}
}
}
auto pListViewColumn::setVerticalAlignment(double alignment) -> void {
@ -53,6 +70,18 @@ auto pListViewColumn::setVisible(bool visible) -> void {
auto pListViewColumn::setWidth(signed width) -> void {
}
auto pListViewColumn::_grandparent() -> maybe<pListView&> {
if(auto parent = _parent()) return parent->_parent();
return nothing;
}
auto pListViewColumn::_parent() -> maybe<pListViewHeader&> {
if(auto parent = self().parentListViewHeader()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

View File

@ -20,6 +20,9 @@ struct pListViewColumn : pObject {
auto setVerticalAlignment(double) -> void;
auto setVisible(bool visible) -> void override;
auto setWidth(signed width) -> void;
auto _grandparent() -> maybe<pListView&>;
auto _parent() -> maybe<pListViewHeader&>;
};
}

View File

@ -14,6 +14,25 @@ auto pListViewHeader::append(sListViewColumn column) -> void {
auto pListViewHeader::remove(sListViewColumn column) -> void {
}
auto pListViewHeader::setVisible(bool visible) -> void {
@autoreleasepool {
if(auto pListView = _parent()) {
if(visible) {
[[pListView->cocoaView content] setHeaderView:[[[NSTableHeaderView alloc] init] autorelease]];
} else {
[[pListView->cocoaView content] setHeaderView:nil];
}
}
}
}
auto pListViewHeader::_parent() -> maybe<pListView&> {
if(auto parent = self().parentListView()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

View File

@ -7,6 +7,9 @@ struct pListViewHeader : pObject {
auto append(sListViewColumn column) -> void;
auto remove(sListViewColumn column) -> void;
auto setVisible(bool visible) -> void override;
auto _parent() -> maybe<pListView&>;
};
}

View File

@ -9,9 +9,19 @@ auto pListViewItem::destruct() -> void {
}
auto pListViewItem::append(sListViewCell cell) -> void {
@autoreleasepool {
if(auto listView = _parent()) {
[[listView->cocoaView content] reloadData];
}
}
}
auto pListViewItem::remove(sListViewCell cell) -> void {
@autoreleasepool {
if(auto listView = _parent()) {
[[listView->cocoaView content] reloadData];
}
}
}
auto pListViewItem::setAlignment(Alignment alignment) -> void {
@ -29,6 +39,13 @@ auto pListViewItem::setForegroundColor(Color color) -> void {
auto pListViewItem::setSelected(bool selected) -> void {
}
auto pListViewItem::_parent() -> maybe<pListView&> {
if(auto parent = self().parentListView()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

View File

@ -12,6 +12,8 @@ struct pListViewItem : pObject {
auto setFocused() -> void;
auto setForegroundColor(Color color) -> void;
auto setSelected(bool selected) -> void;
auto _parent() -> maybe<pListView&>;
};
}

View File

@ -20,7 +20,6 @@
[content setAllowsColumnResizing:YES];
[content setAllowsColumnSelection:NO];
[content setAllowsEmptySelection:YES];
[content setAllowsMultipleSelection:NO];
[content setColumnAutoresizingStyle:NSTableViewLastColumnOnlyAutoresizingStyle];
font = nil;
@ -60,31 +59,13 @@
[content removeTableColumn:[[content tableColumns] lastObject]];
}
if(false) { //listView->state.checkable) {
NSTableColumn* tableColumn = [[NSTableColumn alloc] initWithIdentifier:@"check"];
NSTableHeaderCell* headerCell = [[NSTableHeaderCell alloc] initTextCell:@""];
NSButtonCell* dataCell = [[NSButtonCell alloc] initTextCell:@""];
if(auto listViewHeader = listView->state.header) {
for(auto& listViewColumn : listViewHeader->state.columns) {
auto column = listViewColumn->offset();
[dataCell setButtonType:NSSwitchButton];
[dataCell setControlSize:NSSmallControlSize];
[dataCell setRefusesFirstResponder:YES];
[tableColumn setResizingMask:NSTableColumnNoResizing];
[tableColumn setHeaderCell:headerCell];
[tableColumn setDataCell:dataCell];
[tableColumn setWidth:20.0];
[content addTableColumn:tableColumn];
}
lstring headers; // = listView->state.headerText;
if(headers.size() == 0) headers.append("");
//[content setUsesAlternatingRowBackgroundColors:headers.size() >= 2];
for(auto column : range(headers)) {
NSTableColumn* tableColumn = [[NSTableColumn alloc] initWithIdentifier:[[NSNumber numberWithInteger:column] stringValue]];
NSTableHeaderCell* headerCell = [[NSTableHeaderCell alloc] initTextCell:[NSString stringWithUTF8String:headers(column)]];
CocoaListViewCell* dataCell = [[CocoaListViewCell alloc] initTextCell:@""];
NSTableHeaderCell* headerCell = [[NSTableHeaderCell alloc] initTextCell:[NSString stringWithUTF8String:listViewColumn->state.text]];
CocoaListViewCell* dataCell = [[CocoaListViewCell alloc] initWith:*listView];
[dataCell setEditable:NO];
@ -95,25 +76,20 @@
[content addTableColumn:tableColumn];
}
}
}
-(NSInteger) numberOfRowsInTableView:(NSTableView*)table {
return 0; //listView->state.text.size();
return listView->state.items.size();
}
-(id) tableView:(NSTableView*)table objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row {
if([[tableColumn identifier] isEqualToString:@"check"]) {
auto checked = false; //listView->state.checked(row) ? NSOnState : NSOffState;
return [NSNumber numberWithInteger:checked];
if(auto listViewItem = listView->item(row)) {
if(auto listViewCell = listViewItem->cell([[tableColumn identifier] integerValue])) {
NSString* text = [NSString stringWithUTF8String:listViewCell->state.text];
return @{ @"text":text }; //used by type-ahead
}
NSInteger column = [[tableColumn identifier] integerValue];
uint height = [table rowHeight];
NSString* text = nil; //[NSString stringWithUTF8String:listView->state.text(row)(column)];
NSImage* image = nil; //NSMakeImage(listView->state.image(row)(column), height, height);
if(image) return @{ @"text":text, @"image":image };
return @{ @"text":text };
}
return @{};
}
-(BOOL) tableView:(NSTableView*)table shouldShowCellExpansionForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row {
@ -124,20 +100,14 @@
return nil;
}
-(void) tableView:(NSTableView*)table setObjectValue:(id)object forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row {
if([[tableColumn identifier] isEqualToString:@"check"]) {
//listView->state.checked(row) = [object integerValue] != NSOffState;
//listView->doToggle(row);
}
}
-(void) tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row {
[cell setFont:[self font]];
}
-(void) tableViewSelectionDidChange:(NSNotification*)notification {
//listView->state.selected = true;
//listView->state.selection = [content selectedRow];
for(auto& listViewItem : listView->state.items) {
listViewItem->state.selected = listViewItem->offset() == [content selectedRow];
}
listView->doChange();
}
@ -169,7 +139,19 @@
@end
@implementation CocoaListViewCell : NSTextFieldCell
@implementation CocoaListViewCell : NSCell
-(id) initWith:(hiro::mListView&)listViewReference {
if(self = [super initTextCell:@""]) {
listView = &listViewReference;
buttonCell = [[NSButtonCell alloc] initTextCell:@""];
[buttonCell setButtonType:NSSwitchButton];
[buttonCell setControlSize:NSSmallControlSize];
[buttonCell setRefusesFirstResponder:YES];
[buttonCell setTarget:self];
}
return self;
}
//used by type-ahead
-(NSString*) stringValue {
@ -177,35 +159,95 @@
}
-(void) drawWithFrame:(NSRect)frame inView:(NSView*)view {
NSString* text = [[self objectValue] objectForKey:@"text"];
NSImage* image = [[self objectValue] objectForKey:@"image"];
uint textDisplacement = 0;
if(auto listViewItem = listView->item([view rowAtPoint:frame.origin])) {
if(auto listViewCell = listViewItem->cell([view columnAtPoint:frame.origin])) {
NSColor* backgroundColor = nil;
if([self isHighlighted]) backgroundColor = [NSColor alternateSelectedControlColor];
else if(auto color = listViewCell->state.backgroundColor) backgroundColor = NSMakeColor(color);
else backgroundColor = [NSColor controlBackgroundColor];
if(image) {
[backgroundColor set];
[NSBezierPath fillRect:frame];
if(listViewCell->state.checkable) {
[buttonCell setHighlighted:YES];
[buttonCell setState:(listViewCell->state.checked ? NSOnState : NSOffState)];
[buttonCell drawWithFrame:frame inView:view];
frame.origin.x += frame.size.height + 2;
frame.size.width -= frame.size.height + 2;
}
if(listViewCell->state.image) {
NSImage* image = NSMakeImage(listViewCell->state.image, frame.size.height, frame.size.height);
[[NSGraphicsContext currentContext] saveGraphicsState];
NSRect targetRect = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.height, frame.size.height);
NSRect sourceRect = NSMakeRect(0, 0, [image size].width, [image size].height);
[image drawInRect:targetRect fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil];
[[NSGraphicsContext currentContext] restoreGraphicsState];
textDisplacement = frame.size.height + 2;
frame.origin.x += frame.size.height + 2;
frame.size.width -= frame.size.height + 2;
}
NSRect textRect = NSMakeRect(
frame.origin.x + textDisplacement, frame.origin.y,
frame.size.width - textDisplacement, frame.size.height
);
NSColor* textColor = [self isHighlighted]
? [NSColor alternateSelectedControlTextColor]
: [NSColor textColor];
[text drawInRect:textRect withAttributes:@{
NSForegroundColorAttributeName:textColor,
NSFontAttributeName:[self font]
if(listViewCell->state.text) {
NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.alignment = NSTextAlignmentCenter;
if(listViewCell->state.alignment.horizontal() < 0.333) paragraphStyle.alignment = NSTextAlignmentLeft;
if(listViewCell->state.alignment.horizontal() > 0.666) paragraphStyle.alignment = NSTextAlignmentRight;
NSColor* foregroundColor = nil;
if([self isHighlighted]) foregroundColor = [NSColor alternateSelectedControlTextColor];
else if(auto color = listViewCell->state.foregroundColor) foregroundColor = NSMakeColor(color);
else foregroundColor = [NSColor textColor];
NSString* text = [NSString stringWithUTF8String:listViewCell->state.text];
[text drawInRect:frame withAttributes:@{
NSBackgroundColorAttributeName:backgroundColor,
NSForegroundColorAttributeName:foregroundColor,
NSFontAttributeName:hiro::pFont::create(listViewCell->font(true)),
NSParagraphStyleAttributeName:paragraphStyle
}];
}
}
}
}
//needed to trigger trackMouse events
-(NSUInteger) hitTestForEvent:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view {
NSUInteger hitTest = [super hitTestForEvent:event inRect:frame ofView:view];
NSPoint point = [view convertPointFromBase:[event locationInWindow]];
NSRect rect = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.height, frame.size.height);
if(NSMouseInRect(point, rect, [view isFlipped])) {
hitTest |= NSCellHitTrackableArea;
}
return hitTest;
}
//I am unable to get startTrackingAt:, continueTracking:, stopTracking: to work
//so instead, I have to run a modal loop on events until the mouse button is released
-(BOOL) trackMouse:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view untilMouseUp:(BOOL)flag {
if([event type] == NSLeftMouseDown) {
NSWindow* window = [view window];
NSEvent* nextEvent;
while((nextEvent = [window nextEventMatchingMask:(NSLeftMouseDragged | NSLeftMouseUp)])) {
if([nextEvent type] == NSLeftMouseUp) {
NSPoint point = [view convertPointFromBase:[nextEvent locationInWindow]];
NSRect rect = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.height, frame.size.height);
if(NSMouseInRect(point, rect, [view isFlipped])) {
if(auto listViewItem = listView->item([view rowAtPoint:point])) {
if(auto listViewCell = listViewItem->cell([view columnAtPoint:point])) {
listViewCell->state.checked = !listViewCell->state.checked;
listView->doToggle(listViewCell->instance);
}
}
}
break;
}
}
}
return YES;
}
+(BOOL) prefersTrackingUntilMouseUp {
return YES;
}
@end
@ -232,18 +274,60 @@ auto pListView::destruct() -> void {
}
auto pListView::append(sListViewHeader header) -> void {
@autoreleasepool {
[cocoaView reloadColumns];
header->setVisible(header->visible());
}
}
auto pListView::append(sListViewItem item) -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
}
}
auto pListView::remove(sListViewHeader header) -> void {
@autoreleasepool {
[cocoaView reloadColumns];
}
}
auto pListView::remove(sListViewItem item) -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
}
}
auto pListView::resizeColumns() -> void {
@autoreleasepool {
if(auto& header = state().header) {
vector<int> widths;
int minimumWidth = 0;
int expandable = 0;
for(auto column : range(header->columnCount())) {
int width = _width(column);
widths.append(width);
minimumWidth += width;
if(header->column(column).expandable()) expandable++;
}
int maximumWidth = self().geometry().width() - 18; //include margin for vertical scroll bar
int expandWidth = 0;
if(expandable && maximumWidth > minimumWidth) {
expandWidth = (maximumWidth - minimumWidth) / expandable;
}
for(auto column : range(header->columnCount())) {
if(auto self = header->state.columns[column]->self()) {
int width = widths[column];
if(self->state().expandable) width += expandWidth;
NSTableColumn* tableColumn = [[cocoaView content] tableColumnWithIdentifier:[[NSNumber numberWithInteger:column] stringValue]];
[tableColumn setWidth:width];
}
}
}
}
}
auto pListView::setAlignment(Alignment alignment) -> void {
@ -253,6 +337,9 @@ auto pListView::setBackgroundColor(Color color) -> void {
}
auto pListView::setBatchable(bool batchable) -> void {
@autoreleasepool {
[[cocoaView content] setAllowsMultipleSelection:(batchable ? YES : NO)];
}
}
auto pListView::setBordered(bool bordered) -> void {
@ -267,13 +354,54 @@ auto pListView::setFont(const Font& font) -> void {
auto pListView::setForegroundColor(Color color) -> void {
}
/*
auto pListView::append(const lstring& text) -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
auto pListView::_cellWidth(uint row, uint column) -> uint {
uint width = 8;
if(auto pListViewItem = self().item(row)) {
if(auto pListViewCell = pListViewItem->cell(column)) {
if(pListViewCell->state.checkable) {
width += 24;
}
if(auto& image = pListViewCell->state.image) {
width += image.width() + 2;
}
if(auto& text = pListViewCell->state.text) {
width += pFont::size(pListViewCell->font(true), text).width();
}
}
}
return width;
}
auto pListView::_columnWidth(uint column) -> uint {
uint width = 8;
if(auto& header = state().header) {
if(auto pListViewColumn = header->column(column)) {
if(auto& image = pListViewColumn->state.image) {
width += image.width() + 2;
}
if(auto& text = pListViewColumn->state.text) {
width += pFont::size(pListViewColumn->font(true), text).width();
}
}
}
return width;
}
auto pListView::_width(uint column) -> uint {
if(auto& header = state().header) {
if(auto width = header->column(column).width()) return width;
uint width = 1;
if(!header->column(column).visible()) return width;
if(header->visible()) width = max(width, _columnWidth(column));
for(auto row : range(state().items)) {
width = max(width, _cellWidth(row, column));
}
return width;
}
return 1;
}
/*
auto pListView::autoSizeColumns() -> void {
@autoreleasepool {
if(listView.state.checkable) {
@ -297,52 +425,6 @@ auto pListView::autoSizeColumns() -> void {
}
}
auto pListView::remove(unsigned selection) -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
}
}
auto pListView::reset() -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
}
}
auto pListView::setCheckable(bool checkable) -> void {
@autoreleasepool {
[cocoaView reloadColumns];
}
}
auto pListView::setChecked(unsigned selection, bool checked) -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
}
}
auto pListView::setHeaderText(const lstring& text) -> void {
@autoreleasepool {
[cocoaView reloadColumns];
}
}
auto pListView::setHeaderVisible(bool visible) -> void {
@autoreleasepool {
if(visible) {
[[cocoaView content] setHeaderView:[[[NSTableHeaderView alloc] init] autorelease]];
} else {
[[cocoaView content] setHeaderView:nil];
}
}
}
auto pListView::setImage(unsigned selection, unsigned position, const image& image) -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
}
}
auto pListView::setSelected(bool selected) -> void {
@autoreleasepool {
if(selected == false) {
@ -356,12 +438,6 @@ auto pListView::setSelection(unsigned selection) -> void {
[[cocoaView content] selectRowIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(selection, 1)] byExtendingSelection:NO];
}
}
auto pListView::setText(unsigned selection, unsigned position, const string text) -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
}
}
*/
}

View File

@ -18,7 +18,6 @@
-(id) tableView:(NSTableView*)table objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row;
-(BOOL) tableView:(NSTableView*)table shouldShowCellExpansionForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row;
-(NSString*) tableView:(NSTableView*)table toolTipForCell:(NSCell*)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation;
-(void) tableView:(NSTableView*)table setObjectValue:(id)object forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row;
-(void) tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row;
-(void) tableViewSelectionDidChange:(NSNotification*)notification;
-(IBAction) activate:(id)sender;
@ -30,10 +29,16 @@
-(void) keyDown:(NSEvent*)event;
@end
@interface CocoaListViewCell : NSTextFieldCell {
@interface CocoaListViewCell : NSCell {
hiro::mListView* listView;
NSButtonCell* buttonCell;
}
-(id) initWith:(hiro::mListView&)listViewReference;
-(NSString*) stringValue;
-(void) drawWithFrame:(NSRect)frame inView:(NSView*)view;
-(NSUInteger) hitTestForEvent:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view;
-(BOOL) trackMouse:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view untilMouseUp:(BOOL)flag;
+(BOOL) prefersTrackingUntilMouseUp;
@end
namespace hiro {
@ -53,6 +58,10 @@ struct pListView : pWidget {
auto setFont(const Font& font) -> void override;
auto setForegroundColor(Color color) -> void;
auto _cellWidth(uint row, uint column) -> uint;
auto _columnWidth(uint column) -> uint;
auto _width(uint column) -> uint;
CocoaListView* cocoaListView = nullptr;
};

View File

@ -24,9 +24,24 @@ auto pTabFrameItem::setMovable(bool movable) -> void {
}
auto pTabFrameItem::setSelected() -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[parent->cocoaView selectTabViewItem:cocoaTabFrameItem];
}
}
}
auto pTabFrameItem::setText(const string& text) -> void {
@autoreleasepool {
[cocoaTabFrameItem setLabel:[NSString stringWithUTF8String:state().text]];
}
}
auto pTabFrameItem::_parent() -> maybe<pTabFrame&> {
if(auto parent = self().parentTabFrame()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}

View File

@ -12,6 +12,10 @@ struct pTabFrameItem : pObject {
auto setMovable(bool movable) -> void;
auto setSelected() -> void;
auto setText(const string& text) -> void;
CocoaTabFrameItem* cocoaTabFrameItem = nullptr;
auto _parent() -> maybe<pTabFrame&>;
};
}

View File

@ -12,7 +12,6 @@
}
-(void) tabView:(NSTabView*)tabView didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
tabFrame->self()->_updateSelected([tabView indexOfTabViewItem:tabViewItem]);
tabFrame->self()->_synchronizeLayout();
tabFrame->doChange();
}
@ -32,19 +31,24 @@
-(NSSize) sizeOfLabel:(BOOL)shouldTruncateLabel {
NSSize sizeOfLabel = [super sizeOfLabel:shouldTruncateLabel];
int selection = [cocoaTabFrame indexOfTabViewItem:self];
if(selection < 0) return sizeOfLabel; //should never happen
// if(!tabFrame->state.image[selection].empty()) {
// uint iconSize = hiro::pFont::size(tabFrame->font(true), " ").height();
// sizeOfLabel.width += iconSize + 2;
// }
if(selection >= 0) {
if(auto item = tabFrame->item(selection)) {
if(item->state.image) {
uint iconSize = hiro::pFont::size(tabFrame->font(true), " ").height();
sizeOfLabel.width += iconSize + 2;
}
}
}
return sizeOfLabel;
}
-(void) drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)tabRect {
int selection = [cocoaTabFrame indexOfTabViewItem:self];
/*if(selection >= 0 && !tabFrame->state.image[selection].empty()) {
uint iconSize = phoenix::Font::size(tabFrame->font(), " ").height;
NSImage* image = NSMakeImage(tabFrame->state.image[selection]);
if(selection >= 0) {
if(auto item = tabFrame->item(selection)) {
if(item->state.image) {
uint iconSize = hiro::pFont::size(tabFrame->font(true), " ").height();
NSImage* image = NSMakeImage(item->state.image);
[[NSGraphicsContext currentContext] saveGraphicsState];
NSRect targetRect = NSMakeRect(tabRect.origin.x, tabRect.origin.y + 2, iconSize, iconSize);
@ -53,7 +57,9 @@
tabRect.origin.x += iconSize + 2;
tabRect.size.width -= iconSize + 2;
}*/
}
}
}
[super drawLabel:shouldTruncateLabel inRect:tabRect];
}
@ -77,91 +83,81 @@ auto pTabFrame::destruct() -> void {
}
auto pTabFrame::append(sTabFrameItem item) -> void {
@autoreleasepool {
if(auto p = item->self()) {
p->cocoaTabFrameItem = [[CocoaTabFrameItem alloc] initWith:self()];
[p->cocoaTabFrameItem setLabel:[NSString stringWithUTF8String:item->state.text]];
[cocoaView addTabViewItem:p->cocoaTabFrameItem];
}
}
}
auto pTabFrame::remove(sTabFrameItem item) -> void {
}
/*
auto pTabFrame::append(string text, const image& image) -> void {
@autoreleasepool {
CocoaTabFrameItem* item = [[CocoaTabFrameItem alloc] initWith:tabFrame];
[item setLabel:[NSString stringWithUTF8String:text]];
[cocoaView addTabViewItem:item];
tabs.append(item);
if(auto p = item->self()) {
[cocoaView removeTabViewItem:p->cocoaTabFrameItem];
}
}
auto pTabFrame::remove(unsigned selection) -> void {
@autoreleasepool {
CocoaTabFrameItem* item = tabs[selection];
[cocoaView removeTabViewItem:item];
tabs.remove(selection);
}
}
auto pTabFrame::setEnabled(bool enabled) -> void {
for(auto& layout : tabFrame.state.layout) {
if(layout) layout->setEnabled(layout->enabled());
}
pWidget::setEnabled(enabled);
for(auto& item : state().items) {
if(auto& layout = item->state.layout) {
if(auto self = layout->self()) self->setEnabled(layout->enabled(true));
}
}
}
auto pTabFrame::setFont(const Font& font) -> void {
pWidget::setFont(font);
for(auto& item : state().items) {
if(auto& layout = item->state.layout) {
if(auto self = layout->self()) self->setFont(layout->font(true));
}
}
}
*/
auto pTabFrame::setGeometry(Geometry geometry) -> void {
/*
pWidget::setGeometry({
geometry.x - 7, geometry.y - 5,
geometry.width + 14, geometry.height + 6
geometry.x() - 7, geometry.y() - 5,
geometry.width() + 14, geometry.height() + 6
});
geometry.x += 1, geometry.width -= 2;
geometry.y += 22, geometry.height -= 32;
for(auto& layout : tabFrame.state.layout) {
if(layout == nullptr) continue;
geometry.setGeometry({
geometry.x() + 1, geometry.y() + 22,
geometry.width() - 2, geometry.height() - 32
});
for(auto& item : state().items) {
if(auto& layout = item->state.layout) {
layout->setGeometry(geometry);
}
synchronizeLayout();
*/
}
_synchronizeLayout();
}
auto pTabFrame::setNavigation(Navigation navigation) -> void {
}
/*
auto pTabFrame::setSelection(unsigned selection) -> void {
@autoreleasepool {
CocoaTabFrameItem* item = tabs[selection];
[cocoaView selectTabViewItem:item];
}
synchronizeLayout();
}
auto pTabFrame::setText(unsigned selection, string text) -> void {
@autoreleasepool {
CocoaTabFrameItem* item = tabs[selection];
[item setLabel:[NSString stringWithUTF8String:text]];
}
}
auto pTabFrame::setVisible(bool visible) -> void {
for(auto& layout : tabFrame.state.layout) {
if(layout) layout->setVisible(layout->visible());
}
pWidget::setVisible(visible);
for(auto& item : state().items) {
if(auto& layout = item->state.layout) {
if(auto self = layout->self()) self->setVisible(layout->visible(true));
}
}
}
*/
auto pTabFrame::_synchronizeLayout() -> void {
/*
uint selection = 0;
for(auto& layout : tabFrame.state.layout) {
if(layout) layout->setVisible(selection == tabFrame.state.selection);
selection++;
@autoreleasepool {
NSTabViewItem* tabViewItem = [cocoaView selectedTabViewItem];
int selected = tabViewItem ? [cocoaView indexOfTabViewItem:tabViewItem] : -1;
for(auto& item : state().items) {
item->state.selected = item->offset() == selected;
if(auto& layout = item->state.layout) {
if(auto self = layout->self()) self->setVisible(layout->visible(true) && item->selected());
}
}
*/
}
auto pTabFrame::_updateSelected(int selected) -> void {
}
}

View File

@ -25,11 +25,13 @@ struct pTabFrame : pWidget {
auto append(sTabFrameItem item) -> void;
auto remove(sTabFrameItem item) -> void;
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setGeometry(Geometry geometry) -> void override;
auto setNavigation(Navigation navigation) -> void;
auto setVisible(bool visible) -> void override;
auto _synchronizeLayout() -> void;
auto _updateSelected(int selected) -> void;
CocoaTabFrame* cocoaTabFrame = nullptr;
vector<CocoaTabFrameItem*> tabs;

View File

@ -166,12 +166,13 @@ auto pWindow::append(sLayout layout) -> void {
}
auto pWindow::append(sMenuBar menuBar) -> void {
@autoreleasepool {
// [[cocoaWindow menuBar] addItem:menu.p.cocoaAction];
}
}
auto pWindow::append(sStatusBar statusBar) -> void {
statusBar->setEnabled(statusBar->enabled(true));
statusBar->setFont(statusBar->font(true));
statusBar->setText(statusBar->text());
statusBar->setVisible(statusBar->visible(true));
}
auto pWindow::focused() const -> bool {
@ -187,16 +188,6 @@ auto pWindow::frameMargin() const -> Geometry {
}
}
/*
auto pWindow::geometry() -> Geometry {
@autoreleasepool {
NSRect area = [cocoaWindow contentRectForFrameRect:[cocoaWindow frame]];
area.size.height -= statusBarHeight();
return {area.origin.x, Desktop::size().height - area.origin.y - area.size.height, area.size.width, area.size.height};
}
}
*/
auto pWindow::remove(sLayout layout) -> void {
@autoreleasepool {
[[cocoaWindow contentView] setNeedsDisplay:YES];
@ -204,22 +195,13 @@ auto pWindow::remove(sLayout layout) -> void {
}
auto pWindow::remove(sMenuBar menuBar) -> void {
@autoreleasepool {
// [[cocoaWindow menuBar] removeItem:menu.p.cocoaAction];
}
}
auto pWindow::remove(sStatusBar statusBar) -> void {
}
/*
auto pWindow::remove(Widget& widget) -> void {
@autoreleasepool {
[widget.p.cocoaView removeFromSuperview];
[[cocoaWindow contentView] setNeedsDisplay:YES];
[[cocoaWindow statusBar] setHidden:YES];
}
}
*/
auto pWindow::setBackgroundColor(Color color) -> void {
@autoreleasepool {
@ -308,28 +290,6 @@ auto pWindow::setResizable(bool resizable) -> void {
}
}
/*
auto pWindow::setStatusFont(string font) -> void {
@autoreleasepool {
[[cocoaWindow statusBar] setFont:pFont::cocoaFont(font)];
}
statusBarReposition();
}
auto pWindow::setStatusText(string text) -> void {
@autoreleasepool {
[[cocoaWindow statusBar] setStringValue:[NSString stringWithUTF8String:text]];
}
}
auto pWindow::setStatusVisible(bool visible) -> void {
@autoreleasepool {
[[cocoaWindow statusBar] setHidden:!visible];
setGeometry(geometry());
}
}
*/
auto pWindow::setTitle(const string& text) -> void {
@autoreleasepool {
[cocoaWindow setTitle:[NSString stringWithUTF8String:text]];
@ -376,8 +336,9 @@ auto pWindow::sizeEvent() -> void {
}
auto pWindow::statusBarHeight() -> uint {
if(!state().statusBar) return 0;
//return Font::size(window.state.statusFont, " ").height + 6;
if(auto& statusBar = state().statusBar) {
return pFont::size(statusBar->font(true), " ").height() + 6;
}
return 0;
}
@ -400,6 +361,23 @@ auto pWindow::_append(mWidget& widget) -> void {
}
}
/*
auto pWindow::geometry() -> Geometry {
@autoreleasepool {
NSRect area = [cocoaWindow contentRectForFrameRect:[cocoaWindow frame]];
area.size.height -= statusBarHeight();
return {area.origin.x, Desktop::size().height - area.origin.y - area.size.height, area.size.width, area.size.height};
}
}
auto pWindow::remove(Widget& widget) -> void {
@autoreleasepool {
[widget.p.cocoaView removeFromSuperview];
[[cocoaWindow contentView] setNeedsDisplay:YES];
}
}
*/
}
#endif

View File

@ -15,6 +15,7 @@ auto mFrame::append(sLayout layout) -> type& {
if(auto& layout = state.layout) remove(layout);
state.layout = layout;
layout->setParent(this, 0);
signal(append, layout);
return *this;
}
@ -23,6 +24,7 @@ auto mFrame::layout() const -> Layout {
}
auto mFrame::remove(sLayout layout) -> type& {
signal(remove, layout);
layout->setParent();
state.layout.reset();
return *this;

View File

@ -3,11 +3,18 @@ include ../hiro/GNUmakefile
flags += -I.. -O3
link +=
objects := obj/hiro.o obj/icarus.o
objects := obj/hiro.o
objects += obj/icarus.o
objects += $(if $(call streq,$(platform),windows),obj/resource.o)
all: $(objects)
$(compiler) -o icarus $(objects) $(link) $(hirolink)
$(compiler) -o out/icarus $(objects) $(link) $(hirolink)
ifeq ($(platform),macosx)
@if [ -d out/icarus.app ]; then rm -r out/icarus.app; fi
mkdir -p out/icarus.app/Contents/MacOS/
mv out/icarus out/icarus.app/Contents/MacOS/
endif
obj/hiro.o: ../hiro/hiro.cpp
$(compiler) $(hiroflags) -o obj/hiro.o -c ../hiro/hiro.cpp
@ -19,11 +26,22 @@ obj/resource.o:
windres ../hiro/windows/hiro.rc obj/resource.o
clean:
if [ -f ./icarus ]; then rm ./icarus; fi
$(call delete,obj/*.o)
ifeq ($(platform),macosx)
@if [ -d out/icarus.app ]; then rm out/icarus.app; fi
endif
$(call delete,obj/*)
$(call delete,out/*)
install:
ifeq ($(platform),macosx)
cp -r out/icarus.app /Applications/icarus.app
else
if [ -f ./icarus ]; then cp ./icarus $(prefix)/bin/icarus; fi
endif
uninstall:
ifeq ($(platform),macosx)
if [ -d /Applications/icarus.app ]; then rm -r /Applications/icarus.app; fi
else
if [ -f $(prefix)/bin/icarus ]; then rm $(prefix)/bin/icarus; fi
endif

1
icarus/out/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
icarus

View File

@ -3,6 +3,10 @@
license: public domain
*/
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wparentheses"
#endif
#if defined(__clang__) || defined(__GNUC__)
#if defined(__i386__)
#include "x86.c"

View File

@ -34,6 +34,11 @@ namespace nall {
#pragma clang diagnostic ignored "-Wswitch"
#pragma clang diagnostic ignored "-Wswitch-bool"
#pragma clang diagnostic ignored "-Wtautological-compare"
#pragma clang diagnostic ignored "-Wabsolute-value"
//temporary
#pragma clang diagnostic ignored "-Winconsistent-missing-override"
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif defined(__GNUC__)
#define COMPILER_GCC
auto Intrinsics::compiler() -> Compiler { return Compiler::GCC; }

View File

@ -31,8 +31,18 @@ rubylink += $(if $(findstring .sdl,$(ruby)),$(shell sdl-config --libs))
ifeq ($(platform),windows)
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal32)
else ifeq ($(platform),macosx)
endif
ifeq ($(platform),macosx)
rubylink += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else
endif
ifeq ($(platform),linux)
rubylink += -lX11 -lXext
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal)
endif
ifeq ($(platform),bsd)
rubylink += -lX11 -lXext
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal)
endif

View File

@ -1,16 +1,10 @@
#include "keyboard/carbon.cpp"
struct InputCarbon : Input {
InputKeyboardCarbon carbonKeyboard;
InputCarbon() : carbonKeyboard(*this) {}
~InputCarbon() { term(); }
struct Key {
uint8_t id;
string name;
};
vector<Key> keys;
struct Keyboard {
shared_pointer<HID::Keyboard> hid{new HID::Keyboard};
} kb;
auto cap(const string& name) -> bool {
if(name == Input::KeyboardSupport) return true;
return false;
@ -28,154 +22,22 @@ struct InputCarbon : Input {
auto release() -> bool { return false; }
auto acquired() -> bool { return false; }
auto assign(shared_pointer<HID::Device> hid, unsigned groupID, unsigned inputID, int16_t value) -> void {
auto& group = hid->group(groupID);
if(group.input(inputID).value() == value) return;
if(input.onChange) input.onChange(hid, groupID, inputID, group.input(inputID).value(), value);
group.input(inputID).setValue(value);
}
auto poll() -> vector<shared_pointer<HID::Device>> {
vector<shared_pointer<HID::Device>> devices;
KeyMap keymap;
GetKeys(keymap);
auto buffer = (uint8_t*)keymap;
unsigned inputID = 0;
for(auto& key : keys) {
bool value = buffer[key.id >> 3] & (1 << (key.id & 7));
assign(kb.hid, HID::Keyboard::GroupID::Button, inputID++, value);
}
devices.append(kb.hid);
carbonKeyboard.poll(devices);
return devices;
}
auto rumble(uint64_t id, bool enable) -> bool {
auto rumble(uint64 id, bool enable) -> bool {
return false;
}
auto init() -> bool {
keys.append({0x35, "Escape"});
keys.append({0x7a, "F1"});
keys.append({0x78, "F2"});
keys.append({0x63, "F3"});
keys.append({0x76, "F4"});
keys.append({0x60, "F5"});
keys.append({0x61, "F6"});
keys.append({0x62, "F7"});
keys.append({0x64, "F8"});
keys.append({0x65, "F9"});
keys.append({0x6d, "F10"});
keys.append({0x67, "F11"});
//keys.append({0x??, "F12"});
keys.append({0x69, "PrintScreen"});
//keys.append({0x??, "ScrollLock"});
keys.append({0x71, "Pause"});
keys.append({0x32, "Tilde"});
keys.append({0x12, "Num1"});
keys.append({0x13, "Num2"});
keys.append({0x14, "Num3"});
keys.append({0x15, "Num4"});
keys.append({0x17, "Num5"});
keys.append({0x16, "Num6"});
keys.append({0x1a, "Num7"});
keys.append({0x1c, "Num8"});
keys.append({0x19, "Num9"});
keys.append({0x1d, "Num0"});
keys.append({0x1b, "Dash"});
keys.append({0x18, "Equal"});
keys.append({0x33, "Backspace"});
keys.append({0x72, "Insert"});
keys.append({0x75, "Delete"});
keys.append({0x73, "Home"});
keys.append({0x77, "End"});
keys.append({0x74, "PageUp"});
keys.append({0x79, "PageDown"});
keys.append({0x00, "A"});
keys.append({0x0b, "B"});
keys.append({0x08, "C"});
keys.append({0x02, "D"});
keys.append({0x0e, "E"});
keys.append({0x03, "F"});
keys.append({0x05, "G"});
keys.append({0x04, "H"});
keys.append({0x22, "I"});
keys.append({0x26, "J"});
keys.append({0x28, "K"});
keys.append({0x25, "L"});
keys.append({0x2e, "M"});
keys.append({0x2d, "N"});
keys.append({0x1f, "O"});
keys.append({0x23, "P"});
keys.append({0x0c, "Q"});
keys.append({0x0f, "R"});
keys.append({0x01, "S"});
keys.append({0x11, "T"});
keys.append({0x20, "U"});
keys.append({0x09, "V"});
keys.append({0x0d, "W"});
keys.append({0x07, "X"});
keys.append({0x10, "Y"});
keys.append({0x06, "Z"});
keys.append({0x21, "LeftBracket"});
keys.append({0x1e, "RightBracket"});
keys.append({0x2a, "Backslash"});
keys.append({0x29, "Semicolon"});
keys.append({0x27, "Apostrophe"});
keys.append({0x2b, "Comma"});
keys.append({0x2f, "Period"});
keys.append({0x2c, "Slash"});
keys.append({0x53, "Keypad1"});
keys.append({0x54, "Keypad2"});
keys.append({0x55, "Keypad3"});
keys.append({0x56, "Keypad4"});
keys.append({0x57, "Keypad5"});
keys.append({0x58, "Keypad6"});
keys.append({0x59, "Keypad7"});
keys.append({0x5b, "Keypad8"});
keys.append({0x5c, "Keypad9"});
keys.append({0x52, "Keypad0"});
//keys.append({0x??, "Point"});
keys.append({0x4c, "Enter"});
keys.append({0x45, "Add"});
keys.append({0x4e, "Subtract"});
keys.append({0x43, "Multiply"});
keys.append({0x4b, "Divide"});
keys.append({0x47, "NumLock"});
//keys.append({0x39, "CapsLock"});
keys.append({0x7e, "Up"});
keys.append({0x7d, "Down"});
keys.append({0x7b, "Left"});
keys.append({0x7c, "Right"});
keys.append({0x30, "Tab"});
keys.append({0x24, "Return"});
keys.append({0x31, "Spacebar"});
//keys.append({0x??, "Menu"});
keys.append({0x38, "Shift"});
keys.append({0x3b, "Control"});
keys.append({0x3a, "Alt"});
keys.append({0x37, "Super"});
kb.hid->setID(1);
for(auto& key : keys) kb.hid->buttons().append(key.name);
if(!carbonKeyboard.init()) return false;
return true;
}
auto term() -> void {
carbonKeyboard.term();
}
};

View File

@ -0,0 +1,158 @@
struct InputKeyboardCarbon {
Input& input;
InputKeyboardCarbon(Input& input) : input(input) {}
shared_pointer<HID::Keyboard> hid{new HID::Keyboard};
struct Key {
uint8 id;
string name;
};
vector<Key> keys;
auto assign(uint inputID, bool value) -> void {
auto& group = hid->buttons();
if(group.input(inputID).value() == value) return;
input.doChange(hid, HID::Keyboard::GroupID::Button, inputID, group.input(inputID).value(), value);
group.input(inputID).setValue(value);
}
auto poll(vector<shared_pointer<HID::Device>>& devices) -> void {
KeyMap keymap;
GetKeys(keymap);
auto buffer = (const uint8*)keymap;
uint inputID = 0;
for(auto& key : keys) {
bool value = buffer[key.id >> 3] & (1 << (key.id & 7));
assign(inputID++, value);
}
devices.append(hid);
}
auto init() -> bool {
keys.append({0x35, "Escape"});
keys.append({0x7a, "F1"});
keys.append({0x78, "F2"});
keys.append({0x63, "F3"});
keys.append({0x76, "F4"});
keys.append({0x60, "F5"});
keys.append({0x61, "F6"});
keys.append({0x62, "F7"});
keys.append({0x64, "F8"});
keys.append({0x65, "F9"});
keys.append({0x6d, "F10"});
keys.append({0x67, "F11"});
//keys.append({0x??, "F12"});
keys.append({0x69, "PrintScreen"});
//keys.append({0x??, "ScrollLock"});
keys.append({0x71, "Pause"});
keys.append({0x32, "Tilde"});
keys.append({0x12, "Num1"});
keys.append({0x13, "Num2"});
keys.append({0x14, "Num3"});
keys.append({0x15, "Num4"});
keys.append({0x17, "Num5"});
keys.append({0x16, "Num6"});
keys.append({0x1a, "Num7"});
keys.append({0x1c, "Num8"});
keys.append({0x19, "Num9"});
keys.append({0x1d, "Num0"});
keys.append({0x1b, "Dash"});
keys.append({0x18, "Equal"});
keys.append({0x33, "Backspace"});
keys.append({0x72, "Insert"});
keys.append({0x75, "Delete"});
keys.append({0x73, "Home"});
keys.append({0x77, "End"});
keys.append({0x74, "PageUp"});
keys.append({0x79, "PageDown"});
keys.append({0x00, "A"});
keys.append({0x0b, "B"});
keys.append({0x08, "C"});
keys.append({0x02, "D"});
keys.append({0x0e, "E"});
keys.append({0x03, "F"});
keys.append({0x05, "G"});
keys.append({0x04, "H"});
keys.append({0x22, "I"});
keys.append({0x26, "J"});
keys.append({0x28, "K"});
keys.append({0x25, "L"});
keys.append({0x2e, "M"});
keys.append({0x2d, "N"});
keys.append({0x1f, "O"});
keys.append({0x23, "P"});
keys.append({0x0c, "Q"});
keys.append({0x0f, "R"});
keys.append({0x01, "S"});
keys.append({0x11, "T"});
keys.append({0x20, "U"});
keys.append({0x09, "V"});
keys.append({0x0d, "W"});
keys.append({0x07, "X"});
keys.append({0x10, "Y"});
keys.append({0x06, "Z"});
keys.append({0x21, "LeftBracket"});
keys.append({0x1e, "RightBracket"});
keys.append({0x2a, "Backslash"});
keys.append({0x29, "Semicolon"});
keys.append({0x27, "Apostrophe"});
keys.append({0x2b, "Comma"});
keys.append({0x2f, "Period"});
keys.append({0x2c, "Slash"});
keys.append({0x53, "Keypad1"});
keys.append({0x54, "Keypad2"});
keys.append({0x55, "Keypad3"});
keys.append({0x56, "Keypad4"});
keys.append({0x57, "Keypad5"});
keys.append({0x58, "Keypad6"});
keys.append({0x59, "Keypad7"});
keys.append({0x5b, "Keypad8"});
keys.append({0x5c, "Keypad9"});
keys.append({0x52, "Keypad0"});
//keys.append({0x??, "Point"});
keys.append({0x45, "Add"});
keys.append({0x4e, "Subtract"});
keys.append({0x43, "Multiply"});
keys.append({0x4b, "Divide"});
keys.append({0x4c, "Enter"});
keys.append({0x47, "NumLock"});
//keys.append({0x39, "CapsLock"});
keys.append({0x7e, "Up"});
keys.append({0x7d, "Down"});
keys.append({0x7b, "Left"});
keys.append({0x7c, "Right"});
keys.append({0x30, "Tab"});
keys.append({0x24, "Return"});
keys.append({0x31, "Spacebar"});
//keys.append({0x??, "Menu"});
keys.append({0x38, "Shift"});
keys.append({0x3b, "Control"});
keys.append({0x3a, "Alt"});
keys.append({0x37, "Super"});
hid->setID(1);
for(auto& key : keys) {
hid->buttons().append(key.name);
}
return true;
}
auto term() -> void {
}
};

View File

@ -0,0 +1,153 @@
struct InputKeyboardQuartz {
Input& input;
InputKeyboardQuartz(Input& input) : input(input) {}
shared_pointer<HID::Keyboard> hid{new HID::Keyboard};
struct Key {
string name;
uint id;
};
vector<Key> keys;
auto assign(uint inputID, bool value) -> void {
auto& group = hid->buttons();
if(group.input(inputID).value() == value) return;
input.doChange(hid, HID::Keyboard::GroupID::Button, inputID, group.input(inputID).value(), value);
group.input(inputID).setValue(value);
}
auto poll(vector<shared_pointer<HID::Device>>& devices) -> void {
uint inputID = 0;
for(auto& key : keys) {
bool value = CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, key.id);
assign(inputID++, value);
}
devices.append(hid);
}
auto init() -> bool {
keys.append({"Escape", kVK_Escape});
keys.append({"F1", kVK_F1});
keys.append({"F2", kVK_F2});
keys.append({"F3", kVK_F3});
keys.append({"F4", kVK_F4});
keys.append({"F5", kVK_F5});
keys.append({"F6", kVK_F6});
keys.append({"F7", kVK_F7});
keys.append({"F8", kVK_F8});
keys.append({"F9", kVK_F9});
keys.append({"F10", kVK_F10});
keys.append({"F11", kVK_F11});
keys.append({"F12", kVK_F12});
keys.append({"F13", kVK_F13});
keys.append({"F14", kVK_F14});
keys.append({"F15", kVK_F15});
keys.append({"F16", kVK_F16});
keys.append({"F17", kVK_F17});
keys.append({"F18", kVK_F18});
keys.append({"F19", kVK_F19});
keys.append({"F20", kVK_F20});
keys.append({"Tilde", kVK_ANSI_Grave});
keys.append({"Num1", kVK_ANSI_1});
keys.append({"Num2", kVK_ANSI_2});
keys.append({"Num3", kVK_ANSI_3});
keys.append({"Num4", kVK_ANSI_4});
keys.append({"Num5", kVK_ANSI_5});
keys.append({"Num6", kVK_ANSI_6});
keys.append({"Num7", kVK_ANSI_7});
keys.append({"Num8", kVK_ANSI_8});
keys.append({"Num9", kVK_ANSI_9});
keys.append({"Num0", kVK_ANSI_0});
keys.append({"Dash", kVK_ANSI_Minus});
keys.append({"Equal", kVK_ANSI_Equal});
keys.append({"Delete", kVK_Delete});
keys.append({"Erase", kVK_ForwardDelete});
keys.append({"Home", kVK_Home});
keys.append({"End", kVK_End});
keys.append({"PageUp", kVK_PageUp});
keys.append({"PageDown", kVK_PageDown});
keys.append({"A", kVK_ANSI_A});
keys.append({"B", kVK_ANSI_B});
keys.append({"C", kVK_ANSI_C});
keys.append({"D", kVK_ANSI_D});
keys.append({"E", kVK_ANSI_E});
keys.append({"F", kVK_ANSI_F});
keys.append({"G", kVK_ANSI_G});
keys.append({"H", kVK_ANSI_H});
keys.append({"I", kVK_ANSI_I});
keys.append({"J", kVK_ANSI_J});
keys.append({"K", kVK_ANSI_K});
keys.append({"L", kVK_ANSI_L});
keys.append({"M", kVK_ANSI_M});
keys.append({"N", kVK_ANSI_N});
keys.append({"O", kVK_ANSI_O});
keys.append({"P", kVK_ANSI_P});
keys.append({"Q", kVK_ANSI_Q});
keys.append({"R", kVK_ANSI_R});
keys.append({"S", kVK_ANSI_S});
keys.append({"T", kVK_ANSI_T});
keys.append({"U", kVK_ANSI_U});
keys.append({"V", kVK_ANSI_V});
keys.append({"W", kVK_ANSI_W});
keys.append({"X", kVK_ANSI_X});
keys.append({"Y", kVK_ANSI_Y});
keys.append({"Z", kVK_ANSI_Z});
keys.append({"LeftBracket", kVK_ANSI_LeftBracket});
keys.append({"RightBracket", kVK_ANSI_RightBracket});
keys.append({"Backslash", kVK_ANSI_Backslash});
keys.append({"Semicolon", kVK_ANSI_Semicolon});
keys.append({"Apostrophe", kVK_ANSI_Quote});
keys.append({"Comma", kVK_ANSI_Comma});
keys.append({"Period", kVK_ANSI_Period});
keys.append({"Slash", kVK_ANSI_Slash});
keys.append({"Keypad1", kVK_ANSI_Keypad1});
keys.append({"Keypad2", kVK_ANSI_Keypad2});
keys.append({"Keypad3", kVK_ANSI_Keypad3});
keys.append({"Keypad4", kVK_ANSI_Keypad4});
keys.append({"Keypad5", kVK_ANSI_Keypad5});
keys.append({"Keypad6", kVK_ANSI_Keypad6});
keys.append({"Keypad7", kVK_ANSI_Keypad7});
keys.append({"Keypad8", kVK_ANSI_Keypad8});
keys.append({"Keypad9", kVK_ANSI_Keypad9});
keys.append({"Keypad0", kVK_ANSI_Keypad0});
keys.append({"Clear", kVK_ANSI_KeypadClear});
keys.append({"Equals", kVK_ANSI_KeypadEquals});
keys.append({"Divide", kVK_ANSI_KeypadDivide});
keys.append({"Multiply", kVK_ANSI_KeypadMultiply});
keys.append({"Subtract", kVK_ANSI_KeypadMinus});
keys.append({"Add", kVK_ANSI_KeypadPlus});
keys.append({"Enter", kVK_ANSI_KeypadEnter});
keys.append({"Decimal", kVK_ANSI_KeypadDecimal});
keys.append({"Up", kVK_UpArrow});
keys.append({"Down", kVK_DownArrow});
keys.append({"Left", kVK_LeftArrow});
keys.append({"Right", kVK_RightArrow});
keys.append({"Tab", kVK_Tab});
keys.append({"Return", kVK_Return});
keys.append({"Spacebar", kVK_Space});
keys.append({"Shift", kVK_Shift});
keys.append({"Control", kVK_Control});
keys.append({"Option", kVK_Option});
keys.append({"Command", kVK_Command});
hid->setID(1);
for(auto& key : keys) {
hid->buttons().append(key.name);
}
return true;
}
auto term() -> void {
}
};

View File

@ -11,12 +11,12 @@ struct InputKeyboardXlib {
struct Key {
string name;
unsigned keysym;
unsigned keycode;
uint keysym;
uint keycode;
};
vector<Key> keys;
auto assign(unsigned inputID, bool value) -> void {
auto assign(uint inputID, bool value) -> void {
auto& group = hid->buttons();
if(group.input(inputID).value() == value) return;
input.doChange(hid, HID::Keyboard::GroupID::Button, inputID, group.input(inputID).value(), value);
@ -27,9 +27,10 @@ struct InputKeyboardXlib {
char state[32];
XQueryKeymap(display, state);
for(unsigned n = 0; n < keys.size(); n++) {
bool value = state[keys[n].keycode >> 3] & (1 << (keys[n].keycode & 7));
assign(n, value);
uint inputID = 0;
for(auto& key : keys) {
bool value = state[key.keycode >> 3] & (1 << (key.keycode & 7));
assign(inputID++, value);
}
devices.append(hid);
@ -154,9 +155,9 @@ struct InputKeyboardXlib {
hid->setID(1);
for(unsigned n = 0; n < keys.size(); n++) {
hid->buttons().append(keys[n].name);
keys[n].keycode = XKeysymToKeycode(display, keys[n].keysym);
for(auto& key : keys) {
hid->buttons().append(key.name);
key.keycode = XKeysymToKeycode(display, key.keysym);
}
return true;

43
ruby/input/quartz.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "keyboard/quartz.cpp"
struct InputQuartz : Input {
InputKeyboardQuartz quartzKeyboard;
InputQuartz() : quartzKeyboard(*this) {}
~InputQuartz() { term(); }
auto cap(const string& name) -> bool {
if(name == Input::KeyboardSupport) return true;
return false;
}
auto get(const string& name) -> any {
return {};
}
auto set(const string& name, const any& value) -> bool {
return false;
}
auto acquire() -> bool { return false; }
auto release() -> bool { return false; }
auto acquired() -> bool { return false; }
auto poll() -> vector<shared_pointer<HID::Device>> {
vector<shared_pointer<HID::Device>> devices;
quartzKeyboard.poll(devices);
return devices;
}
auto rumble(uint64 id, bool enable) -> bool {
return false;
}
auto init() -> bool {
if(!quartzKeyboard.init()) return false;
return true;
}
auto term() -> void {
quartzKeyboard.term();
}
};

View File

@ -14,7 +14,7 @@ struct InputXlib : Input {
~InputXlib() { term(); }
struct Settings {
uintptr_t handle = 0;
uintptr handle = 0;
} settings;
auto cap(const string& name) -> bool {
@ -29,8 +29,8 @@ struct InputXlib : Input {
}
auto set(const string& name, const any& value) -> bool {
if(name == Input::Handle && value.is<uintptr_t>()) {
settings.handle = value.get<uintptr_t>();
if(name == Input::Handle && value.is<uintptr>()) {
settings.handle = value.get<uintptr>();
return true;
}
@ -56,7 +56,7 @@ struct InputXlib : Input {
return devices;
}
auto rumble(uint64_t id, bool enable) -> bool {
auto rumble(uint64 id, bool enable) -> bool {
return false;
}

View File

@ -18,9 +18,11 @@ using namespace ruby;
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#elif defined(DISPLAY_QUARTZ)
#define Boolean CocoaBoolean
#define decimal CocoaDecimal
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>
#undef Boolean
#undef decimal
#elif defined(DISPLAY_WINDOWS)
#include <windows.h>
@ -412,6 +414,10 @@ auto Audio::availableDrivers() -> lstring {
#include <ruby/input/carbon.cpp>
#endif
#if defined(INPUT_QUARTZ)
#include <ruby/input/quartz.cpp>
#endif
#if defined(INPUT_SDL)
#include <ruby/input/sdl.cpp>
#endif
@ -443,6 +449,10 @@ auto Input::create(const string& driver) -> Input* {
if(driver == "Windows") return new InputWindows;
#endif
#if defined(INPUT_QUARTZ)
if(driver == "Quartz") return new InputQuartz;
#endif
#if defined(INPUT_CARBON)
if(driver == "Carbon") return new InputCarbon;
#endif
@ -465,6 +475,8 @@ auto Input::create(const string& driver) -> Input* {
auto Input::optimalDriver() -> string {
#if defined(INPUT_WINDOWS)
return "Windows";
#elif defined(INPUT_QUARTZ)
return "Quartz";
#elif defined(INPUT_CARBON)
return "Carbon";
#elif defined(INPUT_UDEV)
@ -481,6 +493,8 @@ auto Input::optimalDriver() -> string {
auto Input::safestDriver() -> string {
#if defined(INPUT_WINDOWS)
return "Windows";
#elif defined(INPUT_QUARTZ)
return "Quartz";
#elif defined(INPUT_CARBON)
return "Carbon";
#elif defined(INPUT_UDEV)
@ -501,6 +515,10 @@ auto Input::availableDrivers() -> lstring {
"Windows",
#endif
#if defined(INPUT_QUARTZ)
"Quartz",
#endif
#if defined(INPUT_CARBON)
"Carbon",
#endif

View File

@ -1,12 +1,13 @@
#define GL_ALPHA_TEST 0x0bc0
#include "opengl/opengl.hpp"
struct VideoCGL;
@interface RubyVideoCGL : NSOpenGLView {
@public
ruby::VideoCGL* video;
VideoCGL* video;
}
-(id) initWith:(ruby::VideoCGL*)video pixelFormat:(NSOpenGLPixelFormat*)pixelFormat;
-(id) initWith:(VideoCGL*)video pixelFormat:(NSOpenGLPixelFormat*)pixelFormat;
-(void) reshape;
@end
@ -18,7 +19,7 @@ struct VideoCGL : Video, OpenGL {
struct {
NSView* handle = nullptr;
bool synchronize = false;
unsigned filter = Video::FilterNearest;
uint filter = Video::FilterNearest;
string shader;
} settings;
@ -31,15 +32,15 @@ struct VideoCGL : Video, OpenGL {
}
auto get(const string& name) -> any {
if(name == Video::Handle) return (uintptr_t)settings.handle;
if(name == Video::Handle) return (uintptr)settings.handle;
if(name == Video::Synchronize) return settings.synchronize;
if(name == Video::Filter) return settings.filter;
return {};
}
auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = (NSView*)value.get<uintptr_t>();
if(name == Video::Handle && value.is<uintptr>()) {
settings.handle = (NSView*)value.get<uintptr>();
return true;
}
@ -58,8 +59,8 @@ struct VideoCGL : Video, OpenGL {
return true;
}
if(name == Video::Filter && value.is<unsigned>()) {
settings.filter = value.get<unsigned>();
if(name == Video::Filter && value.is<uint>()) {
settings.filter = value.get<uint>();
if(!settings.shader) OpenGL::filter = settings.filter ? GL_LINEAR : GL_NEAREST;
return true;
}
@ -77,7 +78,7 @@ struct VideoCGL : Video, OpenGL {
return false;
}
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
auto lock(uint32*& data, uint& pitch, uint width, uint height) -> bool {
OpenGL::size(width, height);
return OpenGL::lock(data, pitch);
}
@ -98,7 +99,8 @@ struct VideoCGL : Video, OpenGL {
@autoreleasepool {
if([view lockFocusIfCanDraw]) {
auto area = [view frame];
outputWidth = area.size.width, outputHeight = area.size.height;
outputWidth = area.size.width;
outputHeight = area.size.height;
OpenGL::refresh();
[[view openGLContext] flushBuffer];
[view unlockFocus];
@ -155,7 +157,7 @@ struct VideoCGL : Video, OpenGL {
@implementation RubyVideoCGL : NSOpenGLView
-(id) initWith:(ruby::VideoCGL*)videoPointer pixelFormat:(NSOpenGLPixelFormat*)pixelFormat {
-(id) initWith:(VideoCGL*)videoPointer pixelFormat:(NSOpenGLPixelFormat*)pixelFormat {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0) pixelFormat:pixelFormat]) {
video = videoPointer;
}

View File

@ -3,7 +3,6 @@
#include <GL/glx.h>
#define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name))
#elif defined(DISPLAY_QUARTZ)
#include <OpenGL/gl.h>
#include <OpenGL/gl3.h>
#elif defined(DISPLAY_WINDOWS)
#include <GL/gl.h>

View File

@ -6,8 +6,8 @@
struct VideoWGL : Video, OpenGL {
~VideoWGL() { term(); }
HGLRC (APIENTRY* wglCreateContextAttribs)(HDC, HGLRC, const int*) = nullptr;
BOOL (APIENTRY* wglSwapInterval)(int) = nullptr;
auto (APIENTRY* wglCreateContextAttribs)(HDC, HGLRC, const int*) -> HGLRC = nullptr;
auto (APIENTRY* wglSwapInterval)(int) -> BOOL = nullptr;
HDC display = nullptr;
HGLRC wglcontext = nullptr;
@ -17,7 +17,7 @@ struct VideoWGL : Video, OpenGL {
struct {
HWND handle = nullptr;
bool synchronize = false;
unsigned filter = Video::FilterNearest;
uint filter = Video::FilterNearest;
string shader;
} settings;
@ -30,15 +30,15 @@ struct VideoWGL : Video, OpenGL {
}
auto get(const string& name) -> any {
if(name == Video::Handle) return (uintptr_t)settings.handle;
if(name == Video::Handle) return (uintptr)settings.handle;
if(name == Video::Synchronize) return settings.synchronize;
if(name == Video::Filter) return settings.filter;
return {};
}
auto set(const string& name, const any& value) -> bool {
if(name == Video::Handle && value.is<uintptr_t>()) {
settings.handle = (HWND)value.get<uintptr_t>();
if(name == Video::Handle && value.is<uintptr>()) {
settings.handle = (HWND)value.get<uintptr>();
return true;
}
@ -53,8 +53,8 @@ struct VideoWGL : Video, OpenGL {
}
}
if(name == Video::Filter && value.is<unsigned>()) {
settings.filter = value.get<unsigned>();
if(name == Video::Filter && value.is<uint>()) {
settings.filter = value.get<uint>();
if(!settings.shader) OpenGL::filter = settings.filter ? GL_LINEAR : GL_NEAREST;
return true;
}
@ -69,7 +69,7 @@ struct VideoWGL : Video, OpenGL {
return false;
}
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
auto lock(uint32*& data, uint& pitch, uint width, uint height) -> bool {
OpenGL::size(width, height);
return OpenGL::lock(data, pitch);
}