mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-23 08:59:40 +00:00
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:
parent
47d4bd4d81
commit
4d193d7d94
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
ananke/libananke.so
|
||||
icarus/icarus
|
@ -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/";
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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}};
|
||||
|
@ -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
|
||||
|
@ -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)];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ struct pMenuBar : pObject {
|
||||
|
||||
auto append(sMenu menu) -> void;
|
||||
auto remove(sMenu menu) -> void;
|
||||
|
||||
auto _parent() -> maybe<pWindow&>;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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&>;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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&> {
|
||||
|
@ -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;
|
||||
|
@ -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]];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#if defined(Hiro_Label)
|
||||
|
||||
@interface CocoaLabel : NSTextField {
|
||||
@interface CocoaLabel : NSTextView {
|
||||
@public
|
||||
hiro::mLabel* label;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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&>;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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&>;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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&>;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -12,6 +12,8 @@ struct pListViewItem : pObject {
|
||||
auto setFocused() -> void;
|
||||
auto setForegroundColor(Color color) -> void;
|
||||
auto setSelected(bool selected) -> void;
|
||||
|
||||
auto _parent() -> maybe<pListView&>;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,6 @@
|
||||
[content setAllowsColumnResizing:YES];
|
||||
[content setAllowsColumnSelection:NO];
|
||||
[content setAllowsEmptySelection:YES];
|
||||
[content setAllowsMultipleSelection:NO];
|
||||
[content setColumnAutoresizingStyle:NSTableViewLastColumnOnlyAutoresizingStyle];
|
||||
|
||||
font = nil;
|
||||
@ -60,60 +59,37 @@
|
||||
[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];
|
||||
NSTableColumn* tableColumn = [[NSTableColumn alloc] initWithIdentifier:[[NSNumber numberWithInteger:column] stringValue]];
|
||||
NSTableHeaderCell* headerCell = [[NSTableHeaderCell alloc] initTextCell:[NSString stringWithUTF8String:listViewColumn->state.text]];
|
||||
CocoaListViewCell* dataCell = [[CocoaListViewCell alloc] initWith:*listView];
|
||||
|
||||
[tableColumn setResizingMask:NSTableColumnNoResizing];
|
||||
[tableColumn setHeaderCell:headerCell];
|
||||
[tableColumn setDataCell:dataCell];
|
||||
[tableColumn setWidth:20.0];
|
||||
[dataCell setEditable:NO];
|
||||
|
||||
[content addTableColumn:tableColumn];
|
||||
}
|
||||
[tableColumn setResizingMask:NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask];
|
||||
[tableColumn setHeaderCell:headerCell];
|
||||
[tableColumn setDataCell:dataCell];
|
||||
|
||||
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:@""];
|
||||
|
||||
[dataCell setEditable:NO];
|
||||
|
||||
[tableColumn setResizingMask:NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask];
|
||||
[tableColumn setHeaderCell:headerCell];
|
||||
[tableColumn setDataCell:dataCell];
|
||||
|
||||
[content addTableColumn:tableColumn];
|
||||
[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,34 +159,94 @@
|
||||
}
|
||||
|
||||
-(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) {
|
||||
[[NSGraphicsContext currentContext] saveGraphicsState];
|
||||
[backgroundColor set];
|
||||
[NSBezierPath fillRect:frame];
|
||||
|
||||
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];
|
||||
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;
|
||||
}
|
||||
|
||||
[[NSGraphicsContext currentContext] restoreGraphicsState];
|
||||
textDisplacement = 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];
|
||||
frame.origin.x += frame.size.height + 2;
|
||||
frame.size.width -= frame.size.height + 2;
|
||||
}
|
||||
|
||||
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
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSRect textRect = NSMakeRect(
|
||||
frame.origin.x + textDisplacement, frame.origin.y,
|
||||
frame.size.width - textDisplacement, frame.size.height
|
||||
);
|
||||
//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;
|
||||
}
|
||||
|
||||
NSColor* textColor = [self isHighlighted]
|
||||
? [NSColor alternateSelectedControlTextColor]
|
||||
: [NSColor textColor];
|
||||
//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;
|
||||
}
|
||||
|
||||
[text drawInRect:textRect withAttributes:@{
|
||||
NSForegroundColorAttributeName:textColor,
|
||||
NSFontAttributeName:[self font]
|
||||
}];
|
||||
+(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];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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&>;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
}
|
||||
|
||||
-(void) tabView:(NSTabView*)tabView didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
|
||||
tabFrame->self()->_updateSelected([tabView indexOfTabViewItem:tabViewItem]);
|
||||
tabFrame->self()->_synchronizeLayout();
|
||||
tabFrame->doChange();
|
||||
}
|
||||
@ -32,28 +31,35 @@
|
||||
-(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);
|
||||
[image drawInRect:targetRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil];
|
||||
[[NSGraphicsContext currentContext] restoreGraphicsState];
|
||||
[[NSGraphicsContext currentContext] saveGraphicsState];
|
||||
NSRect targetRect = NSMakeRect(tabRect.origin.x, tabRect.origin.y + 2, iconSize, iconSize);
|
||||
[image drawInRect:targetRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil];
|
||||
[[NSGraphicsContext currentContext] restoreGraphicsState];
|
||||
|
||||
tabRect.origin.x += iconSize + 2;
|
||||
tabRect.size.width -= iconSize + 2;
|
||||
}*/
|
||||
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 {
|
||||
}
|
||||
|
||||
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()) {
|
||||
p->cocoaTabFrameItem = [[CocoaTabFrameItem alloc] initWith:self()];
|
||||
[p->cocoaTabFrameItem setLabel:[NSString stringWithUTF8String:item->state.text]];
|
||||
[cocoaView addTabViewItem:p->cocoaTabFrameItem];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto pTabFrame::remove(unsigned selection) -> void {
|
||||
auto pTabFrame::remove(sTabFrameItem item) -> void {
|
||||
@autoreleasepool {
|
||||
CocoaTabFrameItem* item = tabs[selection];
|
||||
[cocoaView removeTabViewItem:item];
|
||||
tabs.remove(selection);
|
||||
if(auto p = item->self()) {
|
||||
[cocoaView removeTabViewItem:p->cocoaTabFrameItem];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
layout->setGeometry(geometry);
|
||||
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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
1
icarus/out/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
icarus
|
@ -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"
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
158
ruby/input/keyboard/carbon.cpp
Normal file
158
ruby/input/keyboard/carbon.cpp
Normal 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 {
|
||||
}
|
||||
};
|
153
ruby/input/keyboard/quartz.cpp
Normal file
153
ruby/input/keyboard/quartz.cpp
Normal 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 {
|
||||
}
|
||||
};
|
@ -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
43
ruby/input/quartz.cpp
Normal 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();
|
||||
}
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user