Merge branch 'master' into console_flash
|
@ -0,0 +1,3 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: LIJI32
|
|
@ -4,7 +4,7 @@ case `echo $1 | cut -d '-' -f 1` in
|
|||
sudo apt-get install -yq bison libpng-dev pkg-config libsdl2-dev
|
||||
(
|
||||
cd `mktemp -d`
|
||||
curl -L https://github.com/rednex/rgbds/archive/v0.4.0.zip > rgbds.zip
|
||||
curl -L https://github.com/rednex/rgbds/archive/v0.6.0.zip > rgbds.zip
|
||||
unzip rgbds.zip
|
||||
cd rgbds-*
|
||||
make -sj
|
||||
|
@ -12,9 +12,22 @@ case `echo $1 | cut -d '-' -f 1` in
|
|||
cd ..
|
||||
rm -rf *
|
||||
)
|
||||
|
||||
(
|
||||
cd `mktemp -d`
|
||||
curl -L https://github.com/BR903/cppp/archive/refs/heads/master.zip > cppp.zip
|
||||
unzip cppp.zip
|
||||
cd cppp-*
|
||||
make -sj
|
||||
sudo make install
|
||||
cd ..
|
||||
rm -rf *
|
||||
)
|
||||
|
||||
|
||||
;;
|
||||
macos)
|
||||
brew install rgbds sdl2
|
||||
brew install rgbds sdl2 cppp
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported OS"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
./build/bin/tester/sameboy_tester --jobs 5 \
|
||||
|
@ -7,7 +9,7 @@ set -e
|
|||
--dmg --length 45 .github/actions/dmg_sound-2.gb \
|
||||
--dmg --length 20 .github/actions/oam_bug-2.gb
|
||||
|
||||
mv .github/actions/dmg{,-mode}-acid2.bmp
|
||||
mv .github/actions/dmg-acid2.bmp .github/actions/dmg-mode-acid2.bmp
|
||||
|
||||
./build/bin/tester/sameboy_tester \
|
||||
--dmg --length 10 .github/actions/dmg-acid2.gb
|
||||
|
@ -16,10 +18,10 @@ set +e
|
|||
|
||||
FAILED_TESTS=`
|
||||
shasum .github/actions/*.bmp | grep -E -v \(\
|
||||
5283564df0cf5bb78a7a90aff026c1a4692fd39e\ \ .github/actions/cgb-acid2.bmp\|\
|
||||
64c3fd9a5fe9aee40fe15f3371029c0d2f20f5bc\ \ .github/actions/cgb-acid2.bmp\|\
|
||||
dbcc438dcea13b5d1b80c5cd06bda2592cc5d9e0\ \ .github/actions/cgb_sound.bmp\|\
|
||||
0caadf9634e40247ae9c15ff71992e8f77bbf89e\ \ .github/actions/dmg-acid2.bmp\|\
|
||||
a732077f98f43d9231453b1764d9f797a836924d\ \ .github/actions/dmg-mode-acid2.bmp\|\
|
||||
fbdb5e342bfdd2edda3ea5601d35d0ca60d18034\ \ .github/actions/dmg-mode-acid2.bmp\|\
|
||||
c9e944b7e01078bdeba1819bc2fa9372b111f52d\ \ .github/actions/dmg_sound-2.bmp\|\
|
||||
f0172cc91867d3343fbd113a2bb98100074be0de\ \ .github/actions/oam_bug-2.bmp\
|
||||
\)`
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
set -ex
|
||||
|
||||
git fetch --tags
|
||||
LATEST=$(git tag --sort=-creatordate | grep "^v" | grep -v libretro | head -n 1)
|
||||
|
||||
if [ $(git tag -l "$LATEST"-libretro) ]; then
|
||||
echo "The libretro branch is already up-to-date"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git config --global --add --bool push.autoSetupRemote true
|
||||
git config --global user.name 'Libretro Updater'
|
||||
git config --global user.email '<>'
|
||||
|
||||
cp libretro/gitlab-ci.yml .gitlab-ci.yml
|
||||
|
||||
echo "Switching to tag $LATEST"
|
||||
git branch --delete libretro || true
|
||||
git checkout tags/$LATEST -b libretro
|
||||
|
||||
echo "Building boot ROMs..."
|
||||
make -j bootroms
|
||||
|
||||
echo "Updating branch"
|
||||
mv build/bin/BootROMs BootROMs/prebuilt
|
||||
git add BootROMs/prebuilt/* .gitlab-ci.yml
|
||||
git commit -m "Update libretro branch to $LATEST"
|
||||
git tag "$LATEST"-libretro
|
||||
git push --force
|
||||
git push --tags
|
|
@ -0,0 +1,28 @@
|
|||
name: "libretro branch update"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
libretro-prebuilt-update:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
name: Checkout
|
||||
with:
|
||||
repository: LIJI32/SameBoy
|
||||
token: ${{ secrets.WEBSITETOKEN }}
|
||||
submodules: false
|
||||
- name: Install Deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/actions/install_deps.sh ${{ matrix.os }}
|
||||
- name: Build Boot ROMs and Push
|
||||
run: |
|
||||
./.github/actions/update_libretro.sh
|
|
@ -1,36 +1,44 @@
|
|||
name: "Bulidability and Sanity"
|
||||
on: push
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '*'
|
||||
- '!libretro'
|
||||
|
||||
jobs:
|
||||
sanity:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, ubuntu-18.04]
|
||||
os: [macos-latest, ubuntu-latest, ubuntu-20.04]
|
||||
cc: [gcc, clang]
|
||||
include:
|
||||
- os: macos-latest
|
||||
cc: clang
|
||||
extra_target: cocoa
|
||||
extra_targets: cocoa ios-ipa ios-deb
|
||||
exclude:
|
||||
- os: macos-latest
|
||||
cc: gcc
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/actions/install_deps.sh ${{ matrix.os }}
|
||||
- name: Build
|
||||
run: |
|
||||
${{ matrix.cc }} -v; (make -j sdl tester libretro ${{ matrix.extra_target }} CONF=release CC=${{ matrix.cc }} || (echo "==== Build Failed ==="; make sdl tester libretro ${{ matrix.extra_target }} CONF=release CC=${{ matrix.cc }}))
|
||||
${{ matrix.cc }} -v; (make -j all CONF=release CC=${{ matrix.cc }} || (echo "==== Build Failed ==="; make all CONF=release CC=${{ matrix.cc }}))
|
||||
- name: Sanity tests
|
||||
shell: bash
|
||||
run: |
|
||||
./.github/actions/sanity_tests.sh
|
||||
- name: Upload binaries
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sameboy-canary-${{ matrix.os }}-${{ matrix.cc }}
|
||||
path: build/bin
|
||||
path: |
|
||||
build/bin
|
||||
build/lib
|
||||
build/include
|
||||
|
|
|
@ -35,30 +35,43 @@ static OSStatus render(
|
|||
// kAudioUnitSubType_DefaultOutput on Mac OS X)
|
||||
AudioComponentDescription defaultOutputDescription;
|
||||
defaultOutputDescription.componentType = kAudioUnitType_Output;
|
||||
#if TARGET_OS_IPHONE
|
||||
defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
#else
|
||||
defaultOutputDescription.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
#endif
|
||||
defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
defaultOutputDescription.componentFlags = 0;
|
||||
defaultOutputDescription.componentFlagsMask = 0;
|
||||
|
||||
// Get the default playback output unit
|
||||
AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription);
|
||||
NSAssert(defaultOutput, @"Can't find default output");
|
||||
if (!defaultOutput) {
|
||||
NSLog(@"Can't find default output");
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Create a new unit based on this that we'll use for output
|
||||
OSErr err = AudioComponentInstanceNew(defaultOutput, &audioUnit);
|
||||
NSAssert1(audioUnit, @"Error creating unit: %hd", err);
|
||||
if (!audioUnit) {
|
||||
NSLog(@"Error creating unit: %hd", err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Set our tone rendering function on the unit
|
||||
AURenderCallbackStruct input;
|
||||
input.inputProc = (void*)render;
|
||||
input.inputProcRefCon = (__bridge void * _Nullable)(self);
|
||||
input.inputProcRefCon = (__bridge void *)(self);
|
||||
err = AudioUnitSetProperty(audioUnit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&input,
|
||||
sizeof(input));
|
||||
NSAssert1(err == noErr, @"Error setting callback: %hd", err);
|
||||
if (err) {
|
||||
NSLog(@"Error setting callback: %hd", err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
AudioStreamBasicDescription streamFormat;
|
||||
streamFormat.mSampleRate = rate;
|
||||
|
@ -76,9 +89,16 @@ static OSStatus render(
|
|||
0,
|
||||
&streamFormat,
|
||||
sizeof(AudioStreamBasicDescription));
|
||||
NSAssert1(err == noErr, @"Error setting stream format: %hd", err);
|
||||
|
||||
if (err) {
|
||||
NSLog(@"Error setting stream format: %hd", err);
|
||||
return nil;
|
||||
}
|
||||
err = AudioUnitInitialize(audioUnit);
|
||||
NSAssert1(err == noErr, @"Error initializing unit: %hd", err);
|
||||
if (err) {
|
||||
NSLog(@"Error initializing unit: %hd", err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.renderBlock = block;
|
||||
_rate = rate;
|
||||
|
@ -89,7 +109,10 @@ static OSStatus render(
|
|||
-(void) start
|
||||
{
|
||||
OSErr err = AudioOutputUnitStart(audioUnit);
|
||||
NSAssert1(err == noErr, @"Error starting unit: %hd", err);
|
||||
if (err) {
|
||||
NSLog(@"Error starting unit: %hd", err);
|
||||
return;
|
||||
}
|
||||
_playing = true;
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#import <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#define NSView UIView
|
||||
#import <UIKit/UIKit.h>
|
||||
#else
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
|
||||
#import <Core/gb.h>
|
||||
|
||||
typedef enum {
|
||||
GB_FRAME_BLENDING_MODE_DISABLED,
|
||||
GB_FRAME_BLENDING_MODE_SIMPLE,
|
||||
GB_FRAME_BLENDING_MODE_ACCURATE,
|
||||
GB_FRAME_BLENDING_MODE_ACCURATE_EVEN = GB_FRAME_BLENDING_MODE_ACCURATE,
|
||||
GB_FRAME_BLENDING_MODE_ACCURATE_ODD,
|
||||
} GB_frame_blending_mode_t;
|
||||
|
||||
@interface GBViewBase : NSView
|
||||
{
|
||||
@public
|
||||
GB_gameboy_t *_gb;
|
||||
}
|
||||
|
||||
@property (nonatomic) GB_gameboy_t *gb;
|
||||
@property (nonatomic) GB_frame_blending_mode_t frameBlendingMode;
|
||||
@property (nonatomic, strong) NSView *internalView;
|
||||
- (void) flip;
|
||||
- (uint32_t *) pixels;
|
||||
- (void)screenSizeChanged;
|
||||
- (void) createInternalView;
|
||||
- (uint32_t *)currentBuffer;
|
||||
- (uint32_t *)previousBuffer;
|
||||
|
||||
@end
|
|
@ -0,0 +1,85 @@
|
|||
#import "GBViewBase.h"
|
||||
|
||||
@implementation GBViewBase
|
||||
{
|
||||
uint32_t *_imageBuffers[3];
|
||||
unsigned _currentBuffer;
|
||||
GB_frame_blending_mode_t _frameBlendingMode;
|
||||
bool _oddFrame;
|
||||
}
|
||||
|
||||
- (void)screenSizeChanged
|
||||
{
|
||||
if (_imageBuffers[0]) free(_imageBuffers[0]);
|
||||
if (_imageBuffers[1]) free(_imageBuffers[1]);
|
||||
if (_imageBuffers[2]) free(_imageBuffers[2]);
|
||||
|
||||
size_t buffer_size = sizeof(_imageBuffers[0][0]) * GB_get_screen_width(_gb) * GB_get_screen_height(_gb);
|
||||
|
||||
_imageBuffers[0] = calloc(1, buffer_size);
|
||||
_imageBuffers[1] = calloc(1, buffer_size);
|
||||
_imageBuffers[2] = calloc(1, buffer_size);
|
||||
}
|
||||
|
||||
- (void)flip
|
||||
{
|
||||
_currentBuffer = (_currentBuffer + 1) % self.numberOfBuffers;
|
||||
_oddFrame = GB_is_odd_frame(_gb);
|
||||
}
|
||||
|
||||
- (unsigned) numberOfBuffers
|
||||
{
|
||||
return _frameBlendingMode? 3 : 2;
|
||||
}
|
||||
|
||||
- (void) createInternalView
|
||||
{
|
||||
assert(false && "createInternalView must not be inherited");
|
||||
}
|
||||
|
||||
- (uint32_t *)currentBuffer
|
||||
{
|
||||
return _imageBuffers[_currentBuffer];
|
||||
}
|
||||
|
||||
- (uint32_t *)previousBuffer
|
||||
{
|
||||
return _imageBuffers[(_currentBuffer + 2) % self.numberOfBuffers];
|
||||
}
|
||||
|
||||
- (uint32_t *) pixels
|
||||
{
|
||||
return _imageBuffers[(_currentBuffer + 1) % self.numberOfBuffers];
|
||||
}
|
||||
|
||||
- (void) setFrameBlendingMode:(GB_frame_blending_mode_t)frameBlendingMode
|
||||
{
|
||||
_frameBlendingMode = frameBlendingMode;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (GB_frame_blending_mode_t)frameBlendingMode
|
||||
{
|
||||
if (_frameBlendingMode == GB_FRAME_BLENDING_MODE_ACCURATE) {
|
||||
if (!_gb || GB_is_sgb(_gb)) {
|
||||
return GB_FRAME_BLENDING_MODE_SIMPLE;
|
||||
}
|
||||
return _oddFrame ? GB_FRAME_BLENDING_MODE_ACCURATE_ODD : GB_FRAME_BLENDING_MODE_ACCURATE_EVEN;
|
||||
}
|
||||
return _frameBlendingMode;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(_imageBuffers[0]);
|
||||
free(_imageBuffers[1]);
|
||||
free(_imageBuffers[2]);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
- (void)setNeedsDisplay
|
||||
{
|
||||
[self setNeedsDisplay:true];
|
||||
}
|
||||
#endif
|
||||
@end
|
|
@ -0,0 +1,11 @@
|
|||
#import <TargetConditionals.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#import "../iOS/GBView.h"
|
||||
#else
|
||||
#import "../Cocoa/GBView.h"
|
||||
#endif
|
||||
|
||||
@interface GBViewMetal : GBView<MTKViewDelegate>
|
||||
+ (bool) isSupported;
|
||||
@end
|
|
@ -1,7 +1,9 @@
|
|||
#import <CoreImage/CoreImage.h>
|
||||
#import "GBViewMetal.h"
|
||||
#pragma clang diagnostic ignored "-Wpartial-availability"
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
#import "../Cocoa/NSObject+DefaultsObserver.h"
|
||||
#endif
|
||||
|
||||
static const vector_float2 rect[] =
|
||||
{
|
||||
|
@ -13,27 +15,32 @@ static const vector_float2 rect[] =
|
|||
|
||||
@implementation GBViewMetal
|
||||
{
|
||||
id<MTLDevice> device;
|
||||
id<MTLTexture> texture, previous_texture;
|
||||
id<MTLBuffer> vertices;
|
||||
id<MTLRenderPipelineState> pipeline_state;
|
||||
id<MTLCommandQueue> command_queue;
|
||||
id<MTLBuffer> frame_blending_mode_buffer;
|
||||
id<MTLBuffer> output_resolution_buffer;
|
||||
vector_float2 output_resolution;
|
||||
id<MTLDevice> _device;
|
||||
id<MTLTexture> _texture, _previousTexture;
|
||||
id<MTLBuffer> _vertices;
|
||||
id<MTLRenderPipelineState> _pipelineState;
|
||||
id<MTLCommandQueue> _commandQueue;
|
||||
id<MTLBuffer> _frameBlendingModeBuffer;
|
||||
id<MTLBuffer> _outputResolutionBuffer;
|
||||
vector_float2 _outputResolution;
|
||||
id<MTLCommandBuffer> _commandBuffer;
|
||||
bool _waitedForFrame;
|
||||
}
|
||||
|
||||
+ (bool)isSupported
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
return true;
|
||||
#else
|
||||
if (MTLCopyAllDevices) {
|
||||
return [MTLCopyAllDevices() count];
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void) allocateTextures
|
||||
{
|
||||
if (!device) return;
|
||||
if (!_device) return;
|
||||
|
||||
MTLTextureDescriptor *texture_descriptor = [[MTLTextureDescriptor alloc] init];
|
||||
|
||||
|
@ -42,39 +49,44 @@ static const vector_float2 rect[] =
|
|||
texture_descriptor.width = GB_get_screen_width(self.gb);
|
||||
texture_descriptor.height = GB_get_screen_height(self.gb);
|
||||
|
||||
texture = [device newTextureWithDescriptor:texture_descriptor];
|
||||
previous_texture = [device newTextureWithDescriptor:texture_descriptor];
|
||||
_texture = [_device newTextureWithDescriptor:texture_descriptor];
|
||||
_previousTexture = [_device newTextureWithDescriptor:texture_descriptor];
|
||||
|
||||
}
|
||||
|
||||
- (void)createInternalView
|
||||
{
|
||||
MTKView *view = [[MTKView alloc] initWithFrame:self.frame device:(device = MTLCreateSystemDefaultDevice())];
|
||||
MTKView *view = [[MTKView alloc] initWithFrame:self.frame device:(_device = MTLCreateSystemDefaultDevice())];
|
||||
view.delegate = self;
|
||||
self.internalView = view;
|
||||
view.paused = true;
|
||||
view.enableSetNeedsDisplay = true;
|
||||
view.framebufferOnly = false;
|
||||
|
||||
vertices = [device newBufferWithBytes:rect
|
||||
_vertices = [_device newBufferWithBytes:rect
|
||||
length:sizeof(rect)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
static const GB_frame_blending_mode_t default_blending_mode = GB_FRAME_BLENDING_MODE_DISABLED;
|
||||
frame_blending_mode_buffer = [device newBufferWithBytes:&default_blending_mode
|
||||
_frameBlendingModeBuffer = [_device newBufferWithBytes:&default_blending_mode
|
||||
length:sizeof(default_blending_mode)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
output_resolution_buffer = [device newBufferWithBytes:&output_resolution
|
||||
length:sizeof(output_resolution)
|
||||
_outputResolutionBuffer = [_device newBufferWithBytes:&_outputResolution
|
||||
length:sizeof(_outputResolution)
|
||||
options:MTLResourceStorageModeShared];
|
||||
|
||||
output_resolution = (simd_float2){view.drawableSize.width, view.drawableSize.height};
|
||||
_outputResolution = (simd_float2){view.drawableSize.width, view.drawableSize.height};
|
||||
/* TODO: NSObject+DefaultsObserver can replace the less flexible `addDefaultObserver` in iOS */
|
||||
#if TARGET_OS_IPHONE
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadShader) name:@"GBFilterChanged" object:nil];
|
||||
[self loadShader];
|
||||
#else
|
||||
[self observeStandardDefaultsKey:@"GBFilter" selector:@selector(loadShader)];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void) loadShader
|
||||
- (void)loadShader
|
||||
{
|
||||
NSError *error = nil;
|
||||
NSString *shader_source = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"MasterShader"
|
||||
|
@ -95,7 +107,7 @@ static const vector_float2 rect[] =
|
|||
|
||||
MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
|
||||
options.fastMathEnabled = true;
|
||||
id<MTLLibrary> library = [device newLibraryWithSource:shader_source
|
||||
id<MTLLibrary> library = [_device newLibraryWithSource:shader_source
|
||||
options:options
|
||||
error:&error];
|
||||
if (error) {
|
||||
|
@ -115,19 +127,19 @@ static const vector_float2 rect[] =
|
|||
pipeline_state_descriptor.colorAttachments[0].pixelFormat = ((MTKView *)self.internalView).colorPixelFormat;
|
||||
|
||||
error = nil;
|
||||
pipeline_state = [device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor
|
||||
_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipeline_state_descriptor
|
||||
error:&error];
|
||||
if (error) {
|
||||
NSLog(@"Failed to created pipeline state, error %@", error);
|
||||
return;
|
||||
}
|
||||
|
||||
command_queue = [device newCommandQueue];
|
||||
_commandQueue = [_device newCommandQueue];
|
||||
}
|
||||
|
||||
- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size
|
||||
{
|
||||
output_resolution = (vector_float2){size.width, size.height};
|
||||
_outputResolution = (vector_float2){size.width, size.height};
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[(MTKView *)self.internalView draw];
|
||||
});
|
||||
|
@ -135,90 +147,107 @@ static const vector_float2 rect[] =
|
|||
|
||||
- (void)drawInMTKView:(MTKView *)view
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (!(view.window.occlusionState & NSWindowOcclusionStateVisible)) return;
|
||||
#endif
|
||||
if (!self.gb) return;
|
||||
if (texture.width != GB_get_screen_width(self.gb) ||
|
||||
texture.height != GB_get_screen_height(self.gb)) {
|
||||
if (_texture.width != GB_get_screen_width(self.gb) ||
|
||||
_texture.height != GB_get_screen_height(self.gb)) {
|
||||
[self allocateTextures];
|
||||
}
|
||||
|
||||
MTLRegion region = {
|
||||
{0, 0, 0}, // MTLOrigin
|
||||
{texture.width, texture.height, 1} // MTLSize
|
||||
{_texture.width, _texture.height, 1} // MTLSize
|
||||
};
|
||||
|
||||
/* Don't start rendering if the previous frame hasn't finished yet. Either wait, or skip the frame */
|
||||
if (_commandBuffer && _commandBuffer.status != MTLCommandBufferStatusCompleted) {
|
||||
if (_waitedForFrame) return;
|
||||
[_commandBuffer waitUntilCompleted];
|
||||
_waitedForFrame = true;
|
||||
}
|
||||
else {
|
||||
_waitedForFrame = false;
|
||||
}
|
||||
|
||||
[texture replaceRegion:region
|
||||
GB_frame_blending_mode_t mode = [self frameBlendingMode];
|
||||
|
||||
[_texture replaceRegion:region
|
||||
mipmapLevel:0
|
||||
withBytes:[self currentBuffer]
|
||||
bytesPerRow:texture.width * 4];
|
||||
if ([self frameBlendingMode]) {
|
||||
[previous_texture replaceRegion:region
|
||||
bytesPerRow:_texture.width * 4];
|
||||
|
||||
if (mode) {
|
||||
[_previousTexture replaceRegion:region
|
||||
mipmapLevel:0
|
||||
withBytes:[self previousBuffer]
|
||||
bytesPerRow:texture.width * 4];
|
||||
bytesPerRow:_texture.width * 4];
|
||||
}
|
||||
|
||||
MTLRenderPassDescriptor *render_pass_descriptor = view.currentRenderPassDescriptor;
|
||||
id<MTLCommandBuffer> command_buffer = [command_queue commandBuffer];
|
||||
|
||||
if (render_pass_descriptor != nil) {
|
||||
*(GB_frame_blending_mode_t *)[frame_blending_mode_buffer contents] = [self frameBlendingMode];
|
||||
*(vector_float2 *)[output_resolution_buffer contents] = output_resolution;
|
||||
|
||||
id<MTLRenderCommandEncoder> render_encoder =
|
||||
[command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor];
|
||||
|
||||
[render_encoder setViewport:(MTLViewport){0.0, 0.0,
|
||||
output_resolution.x,
|
||||
output_resolution.y,
|
||||
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
|
||||
_commandBuffer = [_commandQueue commandBuffer];
|
||||
|
||||
if (renderPassDescriptor) {
|
||||
*(GB_frame_blending_mode_t *)[_frameBlendingModeBuffer contents] = mode;
|
||||
*(vector_float2 *)[_outputResolutionBuffer contents] = _outputResolution;
|
||||
|
||||
id<MTLRenderCommandEncoder> renderEncoder =
|
||||
[_commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
||||
|
||||
[renderEncoder setViewport:(MTLViewport){0.0, 0.0,
|
||||
_outputResolution.x,
|
||||
_outputResolution.y,
|
||||
-1.0, 1.0}];
|
||||
|
||||
[render_encoder setRenderPipelineState:pipeline_state];
|
||||
[renderEncoder setRenderPipelineState:_pipelineState];
|
||||
|
||||
[render_encoder setVertexBuffer:vertices
|
||||
[renderEncoder setVertexBuffer:_vertices
|
||||
offset:0
|
||||
atIndex:0];
|
||||
|
||||
[render_encoder setFragmentBuffer:frame_blending_mode_buffer
|
||||
[renderEncoder setFragmentBuffer:_frameBlendingModeBuffer
|
||||
offset:0
|
||||
atIndex:0];
|
||||
|
||||
[render_encoder setFragmentBuffer:output_resolution_buffer
|
||||
[renderEncoder setFragmentBuffer:_outputResolutionBuffer
|
||||
offset:0
|
||||
atIndex:1];
|
||||
|
||||
[render_encoder setFragmentTexture:texture
|
||||
[renderEncoder setFragmentTexture:_texture
|
||||
atIndex:0];
|
||||
|
||||
[render_encoder setFragmentTexture:previous_texture
|
||||
[renderEncoder setFragmentTexture:_previousTexture
|
||||
atIndex:1];
|
||||
|
||||
[render_encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
|
||||
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
|
||||
vertexStart:0
|
||||
vertexCount:4];
|
||||
|
||||
[render_encoder endEncoding];
|
||||
[renderEncoder endEncoding];
|
||||
|
||||
[command_buffer presentDrawable:view.currentDrawable];
|
||||
[_commandBuffer presentDrawable:view.currentDrawable];
|
||||
}
|
||||
|
||||
|
||||
[command_buffer commit];
|
||||
[_commandBuffer commit];
|
||||
}
|
||||
|
||||
- (void)flip
|
||||
{
|
||||
[super flip];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[(MTKView *)self.internalView setNeedsDisplay:true];
|
||||
[(MTKView *)self.internalView draw];
|
||||
});
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
- (NSImage *)renderToImage
|
||||
{
|
||||
CIImage *ciImage = [CIImage imageWithMTLTexture:[[(MTKView *)self.internalView currentDrawable] texture]
|
||||
options:@{
|
||||
kCIImageColorSpace: (__bridge_transfer id)CGColorSpaceCreateDeviceRGB()
|
||||
kCIImageColorSpace: (__bridge_transfer id)CGColorSpaceCreateDeviceRGB(),
|
||||
kCIImageProperties: [NSNull null]
|
||||
}];
|
||||
ciImage = [ciImage imageByApplyingTransform:CGAffineTransformTranslate(CGAffineTransformMakeScale(1, -1),
|
||||
0, ciImage.extent.size.height)];
|
||||
|
@ -228,5 +257,6 @@ static const vector_float2 rect[] =
|
|||
CGImageRelease(cgImage);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
42
BESS.md
|
@ -176,6 +176,48 @@ The length of this block is 0x11 bytes long and it follows the following structu
|
|||
| 0x0E | Scheduled alarm time days (16-bit) |
|
||||
| 0x10 | Alarm enabled flag (8-bits, either 0 or 1) |
|
||||
|
||||
#### TPP1 block
|
||||
The TPP1 block uses the `'TPP1'` identifier, and is an optional block that is used while emulating a TPP1 cartridge to store RTC information. This block can be omitted if the ROM header does not specify the inclusion of a RTC.
|
||||
|
||||
The length of this block is 0x11 bytes long and it follows the following structure:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|-------------------------------------------------------|
|
||||
| 0x00 | UNIX timestamp at the time of the save state (64-bit) |
|
||||
| 0x08 | The current RTC data (4 bytes) |
|
||||
| 0x0C | The latched RTC data (4 bytes) |
|
||||
| 0x10 | The value of the MR4 register (8-bits) |
|
||||
|
||||
|
||||
#### MBC7 block
|
||||
The MBC7 block uses the `'MBC7'` identifier, and is an optional block that is used while emulating an MBC7 cartridge to store the EEPROM communication state and motion control state.
|
||||
|
||||
The length of this block is 0xA bytes long and it follows the following structure:
|
||||
|
||||
| Offset | Content |
|
||||
|--------|-------------------------------------------------------|
|
||||
| 0x00 | Flags (8-bits) |
|
||||
| 0x01 | Argument bits left (8-bits) |
|
||||
| 0x02 | Current EEPROM command (16-bits) |
|
||||
| 0x04 | Pending bits to read (16-bits) |
|
||||
| 0x06 | Latched gyro X value (16-bits) |
|
||||
| 0x08 | Latched gyro Y value (16-bits) |
|
||||
|
||||
The meaning of the individual bits in flags are:
|
||||
* Bit 0: Latch ready; set after writing `0x55` to `0xAX0X` and reset after writing `0xAA` to `0xAX1X`
|
||||
* Bit 1: EEPROM DO line
|
||||
* Bit 2: EEPROM DI line
|
||||
* Bit 3: EEPROM CLK line
|
||||
* Bit 4: EEPROM CS line
|
||||
* Bit 5: EEPROM write enable; set after an `EWEN` command, reset after an `EWDS` command
|
||||
* Bits 6-7: Unused.
|
||||
|
||||
The current EEPROM command field has bits pushed to its LSB first, padded with zeros. For example, if the ROM clocked a single `1` bit, this field should contain `0b1`; if the ROM later clocks a `0` bit, this field should contain `0b10`.
|
||||
|
||||
If the currently transmitted command has an argument, the "Argument bits left" field should contain the number argument bits remaining. Otherwise, it should contain 0.
|
||||
|
||||
The "Pending bits to read" field contains the pending bits waiting to be shifted into the DO signal, MSB first, padded with ones.
|
||||
|
||||
#### SGB block
|
||||
|
||||
The SGB block uses the `'SGB '` identifier, and is an optional block that is only used while emulating an SGB or SGB2 *and* SGB commands enabled. Implementations must not save this block on other models or when SGB commands are disabled, and should assume SGB commands are disabled if this block is missing.
|
||||
|
|
Before Width: | Height: | Size: 479 B After Width: | Height: | Size: 477 B |
|
@ -1,2 +1,2 @@
|
|||
AGB EQU 1
|
||||
include "cgb_boot.asm"
|
||||
DEF AGB = 1
|
||||
include "cgb_boot.asm"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
CGB0 EQU 1
|
||||
include "cgb_boot.asm"
|
||||
DEF CGB0 = 1
|
||||
include "cgb_boot.asm"
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
FAST EQU 1
|
||||
include "cgb_boot.asm"
|
||||
DEF FAST = 1
|
||||
include "cgb_boot.asm"
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
; SameBoy DMG bootstrap ROM
|
||||
; Todo: use friendly names for HW registers instead of magic numbers
|
||||
SECTION "BootCode", ROM0[$0]
|
||||
|
||||
include "sameboot.inc"
|
||||
|
||||
SECTION "BootCode", ROM0[$0000]
|
||||
Start:
|
||||
; Init stack pointer
|
||||
ld sp, $fffe
|
||||
ld sp, $FFFE
|
||||
|
||||
; Clear memory VRAM
|
||||
ld hl, $8000
|
||||
ld hl, _VRAM
|
||||
xor a
|
||||
|
||||
.clearVRAMLoop
|
||||
ldi [hl], a
|
||||
|
@ -14,24 +17,25 @@ Start:
|
|||
jr z, .clearVRAMLoop
|
||||
|
||||
; Init Audio
|
||||
ld a, $80
|
||||
ldh [$26], a
|
||||
ldh [$11], a
|
||||
ld a, $f3
|
||||
ldh [$12], a
|
||||
ldh [$25], a
|
||||
ld a, AUDENA_ON
|
||||
ldh [rNR52], a
|
||||
assert AUDENA_ON == AUDLEN_DUTY_50
|
||||
ldh [rNR11], a
|
||||
ld a, $F3
|
||||
ldh [rNR12], a ; Envelope $F, decreasing, sweep $3
|
||||
ldh [rNR51], a ; Channels 1+2+3+4 left, channels 1+2 right
|
||||
ld a, $77
|
||||
ldh [$24], a
|
||||
ldh [rNR50], a ; Volume $7, left and right
|
||||
|
||||
; Init BG palette
|
||||
ld a, $54
|
||||
ldh [$47], a
|
||||
ld a, %01_01_01_00
|
||||
ldh [rBGP], a
|
||||
|
||||
; Load logo from ROM.
|
||||
; A nibble represents a 4-pixels line, 2 bytes represent a 4x4 tile, scaled to 8x8.
|
||||
; Tiles are ordered left to right, top to bottom.
|
||||
ld de, $104 ; Logo start
|
||||
ld hl, $8010 ; This is where we load the tiles in VRAM
|
||||
ld de, NintendoLogo
|
||||
ld hl, _VRAM + $10 ; This is where we load the tiles in VRAM
|
||||
|
||||
.loadLogoLoop
|
||||
ld a, [de] ; Read 2 rows
|
||||
|
@ -40,92 +44,92 @@ Start:
|
|||
call DoubleBitsAndWriteRow
|
||||
inc de
|
||||
ld a, e
|
||||
xor $34 ; End of logo
|
||||
xor LOW(NintendoLogoEnd)
|
||||
jr nz, .loadLogoLoop
|
||||
|
||||
; Load trademark symbol
|
||||
ld de, TrademarkSymbol
|
||||
ld c,$08
|
||||
ld c, TrademarkSymbolEnd - TrademarkSymbol
|
||||
.loadTrademarkSymbolLoop:
|
||||
ld a,[de]
|
||||
ld a, [de]
|
||||
inc de
|
||||
ldi [hl],a
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
dec c
|
||||
jr nz, .loadTrademarkSymbolLoop
|
||||
|
||||
; Set up tilemap
|
||||
ld a,$19 ; Trademark symbol
|
||||
ld [$9910], a ; ... put in the superscript position
|
||||
ld hl,$992f ; Bottom right corner of the logo
|
||||
ld c,$c ; Tiles in a logo row
|
||||
ld a, $19 ; Trademark symbol tile ID
|
||||
ld [_SCRN0 + 8 * SCRN_VX_B + 16], a ; ... put in the superscript position
|
||||
ld hl, _SCRN0 + 9 * SCRN_VX_B + 15 ; Bottom right corner of the logo
|
||||
ld c, 12 ; Tiles in a logo row
|
||||
.tilemapLoop
|
||||
dec a
|
||||
jr z, .tilemapDone
|
||||
ldd [hl], a
|
||||
dec c
|
||||
jr nz, .tilemapLoop
|
||||
ld l,$0f ; Jump to top row
|
||||
ld l, $0F ; Jump to top row
|
||||
jr .tilemapLoop
|
||||
.tilemapDone
|
||||
|
||||
ld a, 30
|
||||
ldh [$ff42], a
|
||||
|
||||
; Turn on LCD
|
||||
ld a, $91
|
||||
ldh [$40], a
|
||||
ldh [rSCY], a
|
||||
|
||||
ld d, (-119) & $FF
|
||||
; Turn on LCD
|
||||
ld a, LCDCF_ON | LCDCF_BLK01 | LCDCF_BGON
|
||||
ldh [rLCDC], a
|
||||
|
||||
ld d, LOW(-119)
|
||||
ld c, 15
|
||||
|
||||
|
||||
.animate
|
||||
call WaitFrame
|
||||
ld a, d
|
||||
sra a
|
||||
sra a
|
||||
ldh [$ff42], a
|
||||
ldh [rSCY], a
|
||||
ld a, d
|
||||
add c
|
||||
ld d, a
|
||||
ld a, c
|
||||
cp 8
|
||||
jr nz, .noPaletteChange
|
||||
ld a, $A8
|
||||
ldh [$47], a
|
||||
ld a, %10_10_10_00
|
||||
ldh [rBGP], a
|
||||
.noPaletteChange
|
||||
dec c
|
||||
jr nz, .animate
|
||||
ld a, $fc
|
||||
ldh [$47], a
|
||||
|
||||
ld a, %11_11_11_00
|
||||
ldh [rBGP], a
|
||||
|
||||
; Play first sound
|
||||
ld a, $83
|
||||
call PlaySound
|
||||
ld b, 5
|
||||
call WaitBFrames
|
||||
; Play second sound
|
||||
ld a, $c1
|
||||
ld a, $C1
|
||||
call PlaySound
|
||||
|
||||
|
||||
|
||||
|
||||
; Wait ~1 second
|
||||
ld b, 60
|
||||
call WaitBFrames
|
||||
|
||||
|
||||
; Set registers to match the original DMG boot
|
||||
IF DEF(MGB)
|
||||
ld hl, $FFB0
|
||||
lb hl, BOOTUP_A_MGB, %10110000
|
||||
ELSE
|
||||
ld hl, $01B0
|
||||
lb hl, BOOTUP_A_DMG, %10110000
|
||||
ENDC
|
||||
push hl
|
||||
pop af
|
||||
ld hl, $014D
|
||||
ld bc, $0013
|
||||
ld de, $00D8
|
||||
|
||||
ld hl, HeaderChecksum
|
||||
lb bc, 0, LOW(rNR13) ; $0013
|
||||
lb de, 0, $D8 ; $00D8
|
||||
|
||||
; Boot the game
|
||||
jp BootGame
|
||||
|
||||
|
@ -152,7 +156,7 @@ DoubleBitsAndWriteRow:
|
|||
|
||||
WaitFrame:
|
||||
push hl
|
||||
ld hl, $FF0F
|
||||
ld hl, rIF
|
||||
res 0, [hl]
|
||||
.wait
|
||||
bit 0, [hl]
|
||||
|
@ -167,15 +171,26 @@ WaitBFrames:
|
|||
ret
|
||||
|
||||
PlaySound:
|
||||
ldh [$13], a
|
||||
ld a, $87
|
||||
ldh [$14], a
|
||||
ldh [rNR13], a
|
||||
ld a, AUDHIGH_RESTART | $7
|
||||
ldh [rNR14], a
|
||||
ret
|
||||
|
||||
|
||||
TrademarkSymbol:
|
||||
db $3c,$42,$b9,$a5,$b9,$a5,$42,$3c
|
||||
pusho
|
||||
opt b.X
|
||||
db %..XXXX..
|
||||
db %.X....X.
|
||||
db %X.XXX..X
|
||||
db %X.X..X.X
|
||||
db %X.XXX..X
|
||||
db %X.X..X.X
|
||||
db %.X....X.
|
||||
db %..XXXX..
|
||||
popo
|
||||
TrademarkSymbolEnd:
|
||||
|
||||
SECTION "BootGame", ROM0[$fe]
|
||||
SECTION "BootGame", ROM0[$00FE]
|
||||
BootGame:
|
||||
ldh [$50], a
|
||||
ldh [rBANK], a ; unmap boot ROM
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
MGB EQU 1
|
||||
include "dmg_boot.asm"
|
||||
DEF MGB = 1
|
||||
include "dmg_boot.asm"
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
void opts(uint8_t byte, uint8_t *options)
|
||||
static void opts(uint8_t byte, uint8_t *options)
|
||||
{
|
||||
*(options++) = byte | ((byte << 1) & 0xff);
|
||||
*(options++) = byte & (byte << 1);
|
||||
|
@ -13,7 +13,7 @@ void opts(uint8_t byte, uint8_t *options)
|
|||
*(options++) = byte & (byte >> 1);
|
||||
}
|
||||
|
||||
void write_all(int fd, const void *buf, size_t count) {
|
||||
static void write_all(int fd, const void *buf, size_t count) {
|
||||
while (count) {
|
||||
ssize_t written = write(fd, buf, count);
|
||||
if (written < 0) {
|
||||
|
@ -25,7 +25,7 @@ void write_all(int fd, const void *buf, size_t count) {
|
|||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
int main(void)
|
||||
{
|
||||
static uint8_t source[0x4000];
|
||||
size_t size = read(STDIN_FILENO, &source, sizeof(source));
|
||||
|
@ -87,7 +87,7 @@ int main()
|
|||
prev[1] = byte;
|
||||
if (bits >= 8) {
|
||||
uint8_t outctl = control >> (bits - 8);
|
||||
assert(outctl != 1);
|
||||
assert(outctl != 1); // 1 is reserved as the end byte
|
||||
write_all(STDOUT_FILENO, &outctl, 1);
|
||||
write_all(STDOUT_FILENO, literals, literals_size);
|
||||
bits -= 8;
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
IF !DEF(SAMEBOY_INC)
|
||||
DEF SAMEBOY_INC EQU 1
|
||||
|
||||
include "hardware.inc"
|
||||
|
||||
DEF rKEY0 EQU $FF4C
|
||||
DEF rBANK EQU $FF50
|
||||
|
||||
DEF rJOYP EQU rP1
|
||||
|
||||
|
||||
MACRO lb ; r16, high, low
|
||||
ld \1, LOW(\2) << 8 | LOW(\3)
|
||||
ENDM
|
||||
|
||||
|
||||
MACRO header_section ; name, address
|
||||
PUSHS
|
||||
SECTION "\1", ROM0[\2]
|
||||
\1:
|
||||
POPS
|
||||
ENDM
|
||||
header_section EntryPoint, $0100
|
||||
header_section NintendoLogo, $0104
|
||||
header_section NintendoLogoEnd, $0134
|
||||
header_section Title, $0134
|
||||
header_section ManufacturerCode, $013F
|
||||
header_section CGBFlag, $0143
|
||||
header_section NewLicenseeCode, $0144
|
||||
header_section SGBFlag, $0146
|
||||
header_section CartridgeType, $0147
|
||||
header_section ROMSize, $0148
|
||||
header_section RAMSize, $0149
|
||||
header_section DestinationCode, $014A
|
||||
header_section OldLicenseeCode, $014B
|
||||
header_section MaskRomVersion, $014C
|
||||
header_section HeaderChecksum, $014D
|
||||
header_section GlobalChecksum, $014E
|
||||
|
||||
ENDC
|
|
@ -1,2 +1,2 @@
|
|||
SGB2 EQU 1
|
||||
include "sgb_boot.asm"
|
||||
DEF SGB2 = 1
|
||||
include "sgb_boot.asm"
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
; SameBoy SGB bootstrap ROM
|
||||
; Todo: use friendly names for HW registers instead of magic numbers
|
||||
SECTION "BootCode", ROM0[$0]
|
||||
|
||||
include "sameboot.inc"
|
||||
|
||||
SECTION "BootCode", ROM0[$0000]
|
||||
Start:
|
||||
; Init stack pointer
|
||||
ld sp, $fffe
|
||||
ld sp, $FFFE
|
||||
|
||||
; Clear memory VRAM
|
||||
ld hl, $8000
|
||||
ld hl, _VRAM
|
||||
xor a
|
||||
|
||||
.clearVRAMLoop
|
||||
ldi [hl], a
|
||||
|
@ -14,24 +17,25 @@ Start:
|
|||
jr z, .clearVRAMLoop
|
||||
|
||||
; Init Audio
|
||||
ld a, $80
|
||||
ldh [$26], a
|
||||
ldh [$11], a
|
||||
ld a, $f3
|
||||
ldh [$12], a
|
||||
ldh [$25], a
|
||||
ld a, AUDENA_ON
|
||||
ldh [rNR52], a
|
||||
assert AUDENA_ON == AUDLEN_DUTY_50
|
||||
ldh [rNR11], a
|
||||
ld a, $F3
|
||||
ldh [rNR12], a ; Envelope $F, decreasing, sweep $3
|
||||
ldh [rNR51], a ; Channels 1+2+3+4 left, channels 1+2 right
|
||||
ld a, $77
|
||||
ldh [$24], a
|
||||
ldh [rNR50], a ; Volume $7, left and right
|
||||
|
||||
; Init BG palette to white
|
||||
ld a, $0
|
||||
ldh [$47], a
|
||||
ld a, %00_00_00_00
|
||||
ldh [rBGP], a
|
||||
|
||||
; Load logo from ROM.
|
||||
; A nibble represents a 4-pixels line, 2 bytes represent a 4x4 tile, scaled to 8x8.
|
||||
; Tiles are ordered left to right, top to bottom.
|
||||
ld de, $104 ; Logo start
|
||||
ld hl, $8010 ; This is where we load the tiles in VRAM
|
||||
ld de, NintendoLogo
|
||||
ld hl, _VRAM + $10 ; This is where we load the tiles in VRAM
|
||||
|
||||
.loadLogoLoop
|
||||
ld a, [de] ; Read 2 rows
|
||||
|
@ -40,43 +44,43 @@ Start:
|
|||
call DoubleBitsAndWriteRow
|
||||
inc de
|
||||
ld a, e
|
||||
xor $34 ; End of logo
|
||||
xor LOW(NintendoLogoEnd)
|
||||
jr nz, .loadLogoLoop
|
||||
|
||||
; Load trademark symbol
|
||||
ld de, TrademarkSymbol
|
||||
ld c,$08
|
||||
ld c, TrademarkSymbolEnd - TrademarkSymbol
|
||||
.loadTrademarkSymbolLoop:
|
||||
ld a,[de]
|
||||
ld a, [de]
|
||||
inc de
|
||||
ldi [hl],a
|
||||
ldi [hl], a
|
||||
inc hl
|
||||
dec c
|
||||
jr nz, .loadTrademarkSymbolLoop
|
||||
|
||||
; Set up tilemap
|
||||
ld a,$19 ; Trademark symbol
|
||||
ld [$9910], a ; ... put in the superscript position
|
||||
ld hl,$992f ; Bottom right corner of the logo
|
||||
ld c,$c ; Tiles in a logo row
|
||||
ld a, $19 ; Trademark symbol tile ID
|
||||
ld [_SCRN0 + 8 * SCRN_VX_B + 16], a ; ... put in the superscript position
|
||||
ld hl, _SCRN0 + 9 * SCRN_VX_B + 15 ; Bottom right corner of the logo
|
||||
ld c, 12 ; Tiles in a logo row
|
||||
.tilemapLoop
|
||||
dec a
|
||||
jr z, .tilemapDone
|
||||
ldd [hl], a
|
||||
dec c
|
||||
jr nz, .tilemapLoop
|
||||
ld l,$0f ; Jump to top row
|
||||
ld l, $0F ; Jump to top row
|
||||
jr .tilemapLoop
|
||||
.tilemapDone
|
||||
|
||||
; Turn on LCD
|
||||
ld a, $91
|
||||
ldh [$40], a
|
||||
ld a, LCDCF_ON | LCDCF_BLK01 | LCDCF_BGON
|
||||
ldh [rLCDC], a
|
||||
|
||||
ld a, $F1 ; Packet magic, increases by 2 for every packet
|
||||
ldh [hCommand], a
|
||||
ld hl, NintendoLogo ; Header start
|
||||
|
||||
ld a, $f1 ; Packet magic, increases by 2 for every packet
|
||||
ldh [$80], a
|
||||
ld hl, $104 ; Header start
|
||||
|
||||
xor a
|
||||
ld c, a ; JOYP
|
||||
|
||||
|
@ -85,66 +89,79 @@ Start:
|
|||
ld [c], a
|
||||
ld a, $30
|
||||
ld [c], a
|
||||
|
||||
ldh a, [$80]
|
||||
|
||||
ldh a, [hCommand]
|
||||
call SendByte
|
||||
push hl
|
||||
ld b, $e
|
||||
|
||||
ld b, 14
|
||||
ld d, 0
|
||||
|
||||
.checksumLoop
|
||||
call ReadHeaderByte
|
||||
add d
|
||||
ld d, a
|
||||
dec b
|
||||
jr nz, .checksumLoop
|
||||
|
||||
|
||||
; Send checksum
|
||||
call SendByte
|
||||
pop hl
|
||||
|
||||
ld b, $e
|
||||
|
||||
ld b, 14
|
||||
.sendLoop
|
||||
call ReadHeaderByte
|
||||
call SendByte
|
||||
dec b
|
||||
jr nz, .sendLoop
|
||||
|
||||
|
||||
; Done bit
|
||||
ld a, $20
|
||||
ld [c], a
|
||||
ld a, $30
|
||||
ld [c], a
|
||||
|
||||
|
||||
; Wait 4 frames
|
||||
ld e, 4
|
||||
ld a, 1
|
||||
ldh [rIE], a
|
||||
xor a
|
||||
.waitLoop
|
||||
ldh [rIF], a
|
||||
halt
|
||||
nop
|
||||
dec e
|
||||
jr nz, .waitLoop
|
||||
ldh [rIE], a
|
||||
|
||||
; Update command
|
||||
ldh a, [$80]
|
||||
ldh a, [hCommand]
|
||||
add 2
|
||||
ldh [$80], a
|
||||
|
||||
ldh [hCommand], a
|
||||
|
||||
ld a, $58
|
||||
cp l
|
||||
jr nz, .sendCommand
|
||||
|
||||
|
||||
; Write to sound registers for DMG compatibility
|
||||
ld c, $13
|
||||
ld a, $c1
|
||||
ld c, LOW(rNR13)
|
||||
ld a, $C1
|
||||
ld [c], a
|
||||
inc c
|
||||
ld a, 7
|
||||
ld a, $7
|
||||
ld [c], a
|
||||
|
||||
|
||||
; Init BG palette
|
||||
ld a, $fc
|
||||
ldh [$47], a
|
||||
|
||||
ld a, %11_11_11_00
|
||||
ldh [rBGP], a
|
||||
|
||||
; Set registers to match the original SGB boot
|
||||
IF DEF(SGB2)
|
||||
ld a, $FF
|
||||
ld a, BOOTUP_A_MGB
|
||||
ELSE
|
||||
ld a, 1
|
||||
ld a, BOOTUP_A_DMG
|
||||
ENDC
|
||||
ld hl, $c060
|
||||
|
||||
ld hl, $C060
|
||||
|
||||
; Boot the game
|
||||
jp BootGame
|
||||
|
||||
|
@ -195,19 +212,24 @@ DoubleBitsAndWriteRow:
|
|||
inc hl
|
||||
ret
|
||||
|
||||
WaitFrame:
|
||||
push hl
|
||||
ld hl, $FF0F
|
||||
res 0, [hl]
|
||||
.wait
|
||||
bit 0, [hl]
|
||||
jr z, .wait
|
||||
pop hl
|
||||
ret
|
||||
|
||||
TrademarkSymbol:
|
||||
db $3c,$42,$b9,$a5,$b9,$a5,$42,$3c
|
||||
pusho
|
||||
opt b.X
|
||||
db %..XXXX..
|
||||
db %.X....X.
|
||||
db %X.XXX..X
|
||||
db %X.X..X.X
|
||||
db %X.XXX..X
|
||||
db %X.X..X.X
|
||||
db %.X....X.
|
||||
db %..XXXX..
|
||||
popo
|
||||
TrademarkSymbolEnd:
|
||||
|
||||
SECTION "BootGame", ROM0[$fe]
|
||||
SECTION "BootGame", ROM0[$00FE]
|
||||
BootGame:
|
||||
ldh [$50], a
|
||||
ldh [rBANK], a
|
||||
|
||||
SECTION "HRAM", HRAM[_HRAM]
|
||||
hCommand:
|
||||
ds 1
|
||||
|
|
|
@ -24,7 +24,7 @@ SameBoy's main target compiler is Clang, but GCC is also supported when targetin
|
|||
|
||||
### Third Party Libraries and Tools
|
||||
|
||||
Avoid adding new required dependencies; run-time and compile-time dependencies alike. Most importantly, avoid linking against GPL licensed libraries (LGPL libraries are fine), so SameBoy can retain its MIT license.
|
||||
Avoid adding new required dependencies; run-time and compile-time dependencies alike. Most importantly, avoid linking against GPL licensed libraries (LGPL libraries are fine), so SameBoy can retain its Expat license.
|
||||
|
||||
### Spacing, Indentation and Formatting
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14868" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14868"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="Document">
|
||||
<connections>
|
||||
<outlet property="audioFormatButton" destination="knX-AW-zt5" id="fKt-eI-H0y"/>
|
||||
<outlet property="audioRecordingAccessoryView" destination="c22-O7-iKe" id="XD8-Gi-qOC"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="354" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Atq-RE-328">
|
||||
<rect key="frame" x="18" y="10" width="56" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Format:" id="dso-NS-JlD">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="knX-AW-zt5">
|
||||
<rect key="frame" x="81" y="4" width="256" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Apple AIFF" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="M3Z-UN-VKZ" id="tLM-Di-Dy3">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<menu key="menu" id="gqn-SL-AA5">
|
||||
<items>
|
||||
<menuItem title="Apple AIFF" state="on" tag="1" id="M3Z-UN-VKZ"/>
|
||||
<menuItem title="RIFF WAVE" tag="2" id="zA0-Np-4XD"/>
|
||||
<menuItem title="Raw PCM (Stereo 96KHz, 16-bit LE)" id="r9J-4k-XH5"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="audioFormatChanged:" target="-2" id="I1k-d9-afp"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="75" y="19"/>
|
||||
</customView>
|
||||
</objects>
|
||||
</document>
|
After Width: | Height: | Size: 201 B |
After Width: | Height: | Size: 336 B |
|
@ -1,6 +1,4 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#ifndef BigSurToolbar_h
|
||||
#define BigSurToolbar_h
|
||||
|
||||
/* Backport the toolbarStyle property to allow compilation with older SDKs*/
|
||||
#ifndef __MAC_10_16
|
||||
|
@ -26,5 +24,3 @@ typedef NS_ENUM(NSInteger, NSWindowToolbarStyle) {
|
|||
@end
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
BIN
Cocoa/CPU.png
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 1.1 KiB |
BIN
Cocoa/CPU@2x.png
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 283 B |
After Width: | Height: | Size: 565 B |
After Width: | Height: | Size: 290 B |
After Width: | Height: | Size: 584 B |
After Width: | Height: | Size: 197 B |
After Width: | Height: | Size: 314 B |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 462 B |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 849 B |
After Width: | Height: | Size: 231 B |
After Width: | Height: | Size: 435 B |
After Width: | Height: | Size: 234 B |
After Width: | Height: | Size: 433 B |
117
Cocoa/Document.h
|
@ -1,57 +1,76 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#include "GBView.h"
|
||||
#include "GBImageView.h"
|
||||
#include "GBSplitView.h"
|
||||
#include "GBVisualizerView.h"
|
||||
#include "GBOSDView.h"
|
||||
#import "GBView.h"
|
||||
#import "GBImageView.h"
|
||||
#import "GBSplitView.h"
|
||||
#import "GBVisualizerView.h"
|
||||
#import "GBOSDView.h"
|
||||
#import "GBDebuggerButton.h"
|
||||
|
||||
@class GBCheatWindowController;
|
||||
@class GBPaletteView;
|
||||
@class GBObjectView;
|
||||
|
||||
@interface Document : NSDocument <NSWindowDelegate, GBImageViewDelegate, NSTableViewDataSource, NSTableViewDelegate, NSSplitViewDelegate>
|
||||
@property (nonatomic, readonly) GB_gameboy_t *gb;
|
||||
@property (nonatomic, strong) IBOutlet GBView *view;
|
||||
@property (nonatomic, strong) IBOutlet NSTextView *consoleOutput;
|
||||
@property (nonatomic, strong) IBOutlet NSPanel *consoleWindow;
|
||||
@property (nonatomic, strong) IBOutlet NSTextField *consoleInput;
|
||||
@property (nonatomic, strong) IBOutlet NSWindow *mainWindow;
|
||||
@property (nonatomic, strong) IBOutlet NSView *memoryView;
|
||||
@property (nonatomic, strong) IBOutlet NSPanel *memoryWindow;
|
||||
@property (nonatomic, readonly) GB_gameboy_t *gameboy;
|
||||
@property (nonatomic, strong) IBOutlet NSTextField *memoryBankInput;
|
||||
@property (nonatomic, strong) IBOutlet NSToolbarItem *memoryBankItem;
|
||||
@property (nonatomic, strong) IBOutlet GBImageView *tilesetImageView;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *tilesetPaletteButton;
|
||||
@property (nonatomic, strong) IBOutlet GBImageView *tilemapImageView;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *tilemapPaletteButton;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *tilemapMapButton;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *TilemapSetButton;
|
||||
@property (nonatomic, strong) IBOutlet NSButton *gridButton;
|
||||
@property (nonatomic, strong) IBOutlet NSTabView *vramTabView;
|
||||
@property (nonatomic, strong) IBOutlet NSPanel *vramWindow;
|
||||
@property (nonatomic, strong) IBOutlet NSTextField *vramStatusLabel;
|
||||
@property (nonatomic, strong) IBOutlet NSTableView *paletteTableView;
|
||||
@property (nonatomic, strong) IBOutlet NSTableView *objectsTableView;
|
||||
@property (nonatomic, strong) IBOutlet NSPanel *printerFeedWindow;
|
||||
@property (nonatomic, strong) IBOutlet NSImageView *feedImageView;
|
||||
@property (nonatomic, strong) IBOutlet NSTextView *debuggerSideViewInput;
|
||||
@property (nonatomic, strong) IBOutlet NSTextView *debuggerSideView;
|
||||
@property (nonatomic, strong) IBOutlet GBSplitView *debuggerSplitView;
|
||||
@property (nonatomic, strong) IBOutlet NSBox *debuggerVerticalLine;
|
||||
@property (nonatomic, strong) IBOutlet NSPanel *cheatsWindow;
|
||||
@property (nonatomic, strong) IBOutlet GBCheatWindowController *cheatWindowController;
|
||||
@property (nonatomic, readonly) Document *partner;
|
||||
@property (nonatomic, readonly) bool isSlave;
|
||||
@property (strong) IBOutlet NSView *gbsPlayerView;
|
||||
@property (strong) IBOutlet NSTextField *gbsTitle;
|
||||
@property (strong) IBOutlet NSTextField *gbsAuthor;
|
||||
@property (strong) IBOutlet NSTextField *gbsCopyright;
|
||||
@property (strong) IBOutlet NSPopUpButton *gbsTracks;
|
||||
@property (strong) IBOutlet NSButton *gbsPlayPauseButton;
|
||||
@property (strong) IBOutlet NSButton *gbsRewindButton;
|
||||
@property (strong) IBOutlet NSSegmentedControl *gbsNextPrevButton;
|
||||
@property (strong) IBOutlet GBVisualizerView *gbsVisualizer;
|
||||
@property (strong) IBOutlet GBOSDView *osdView;
|
||||
@interface Document : NSDocument <NSWindowDelegate, GBImageViewDelegate, NSSplitViewDelegate>
|
||||
@property (readonly) GB_gameboy_t *gb;
|
||||
@property IBOutlet GBView *view;
|
||||
@property IBOutlet NSTextView *consoleOutput;
|
||||
@property IBOutlet NSPanel *consoleWindow;
|
||||
@property IBOutlet NSTextField *consoleInput;
|
||||
@property IBOutlet NSWindow *mainWindow;
|
||||
@property IBOutlet NSView *memoryView;
|
||||
@property IBOutlet NSPanel *memoryWindow;
|
||||
@property (readonly) GB_gameboy_t *gameboy;
|
||||
@property IBOutlet NSTextField *memoryBankInput;
|
||||
@property IBOutlet NSToolbarItem *memoryBankItem;
|
||||
@property IBOutlet NSPopUpButton *memorySpaceButton;
|
||||
@property IBOutlet GBImageView *tilesetImageView;
|
||||
@property IBOutlet NSPopUpButton *tilesetPaletteButton;
|
||||
@property IBOutlet GBImageView *tilemapImageView;
|
||||
@property IBOutlet NSPopUpButton *tilemapPaletteButton;
|
||||
@property IBOutlet NSPopUpButton *tilemapMapButton;
|
||||
@property IBOutlet NSPopUpButton *TilemapSetButton;
|
||||
@property IBOutlet NSButton *gridButton;
|
||||
@property IBOutlet NSTabView *vramTabView;
|
||||
@property IBOutlet NSPanel *vramWindow;
|
||||
@property IBOutlet NSTextField *vramStatusLabel;
|
||||
@property IBOutlet GBPaletteView *paletteView;
|
||||
@property IBOutlet GBObjectView *objectView;
|
||||
@property IBOutlet NSPanel *printerFeedWindow;
|
||||
@property IBOutlet NSProgressIndicator *printerSpinner;
|
||||
@property IBOutlet NSImageView *feedImageView;
|
||||
@property IBOutlet NSTextView *debuggerSideViewInput;
|
||||
@property IBOutlet NSTextView *debuggerSideView;
|
||||
@property IBOutlet GBSplitView *debuggerSplitView;
|
||||
@property IBOutlet NSBox *debuggerVerticalLine;
|
||||
@property IBOutlet NSPanel *cheatsWindow;
|
||||
@property IBOutlet GBCheatWindowController *cheatWindowController;
|
||||
@property (readonly) Document *partner;
|
||||
@property (readonly) bool isSlave;
|
||||
@property IBOutlet NSView *gbsPlayerView;
|
||||
@property IBOutlet NSTextField *gbsTitle;
|
||||
@property IBOutlet NSTextField *gbsAuthor;
|
||||
@property IBOutlet NSTextField *gbsCopyright;
|
||||
@property IBOutlet NSPopUpButton *gbsTracks;
|
||||
@property IBOutlet NSButton *gbsPlayPauseButton;
|
||||
@property IBOutlet NSButton *gbsRewindButton;
|
||||
@property IBOutlet NSSegmentedControl *gbsNextPrevButton;
|
||||
@property IBOutlet GBVisualizerView *gbsVisualizer;
|
||||
@property IBOutlet GBOSDView *osdView;
|
||||
@property (readonly) GB_oam_info_t *oamInfo;
|
||||
@property uint8_t oamCount;
|
||||
@property uint8_t oamHeight;
|
||||
@property IBOutlet NSView *audioRecordingAccessoryView;
|
||||
@property IBOutlet NSPopUpButton *audioFormatButton;
|
||||
@property IBOutlet NSVisualEffectView *debuggerSidebarEffectView API_AVAILABLE(macos(10.10));
|
||||
|
||||
@property IBOutlet GBDebuggerButton *debuggerContinueButton;
|
||||
@property IBOutlet GBDebuggerButton *debuggerNextButton;
|
||||
@property IBOutlet GBDebuggerButton *debuggerStepButton;
|
||||
@property IBOutlet GBDebuggerButton *debuggerFinishButton;
|
||||
@property (strong) IBOutlet GBDebuggerButton *debuggerBackstepButton;
|
||||
|
||||
|
||||
+ (NSImage *) imageFromData:(NSData *)data width:(NSUInteger) width height:(NSUInteger) height scale:(double) scale;
|
||||
-(uint8_t) readMemory:(uint16_t) addr;
|
||||
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
|
||||
-(void) performAtomicBlock: (void (^)())block;
|
||||
|
|
2060
Cocoa/Document.m
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14868" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14868"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
|
||||
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
@ -14,21 +15,29 @@
|
|||
<outlet property="consoleInput" destination="l22-S8-uji" id="Heu-am-YgB"/>
|
||||
<outlet property="consoleOutput" destination="doS-dM-hnl" id="Gn5-ju-Wb0"/>
|
||||
<outlet property="consoleWindow" destination="21F-Ah-yHX" id="eQ4-ug-LsT"/>
|
||||
<outlet property="debuggerBackstepButton" destination="onn-R8-3vg" id="gi1-dC-tJj"/>
|
||||
<outlet property="debuggerContinueButton" destination="G4h-KO-Z3g" id="Dad-5e-XYM"/>
|
||||
<outlet property="debuggerFinishButton" destination="vtb-n5-Qlz" id="9vv-fJ-gxp"/>
|
||||
<outlet property="debuggerNextButton" destination="cOi-Rs-9gS" id="Xjx-uM-D0u"/>
|
||||
<outlet property="debuggerSideView" destination="JgV-7E-iwp" id="RaA-fw-3i1"/>
|
||||
<outlet property="debuggerSideViewInput" destination="w0g-eK-jM4" id="GBf-WK-ryI"/>
|
||||
<outlet property="debuggerSidebarEffectView" destination="4Z2-33-dYY" id="Ja6-bC-rQg"/>
|
||||
<outlet property="debuggerSplitView" destination="pUc-ZN-vl5" id="0sG-0D-cID"/>
|
||||
<outlet property="debuggerStepButton" destination="DsN-Ce-QoH" id="Ts4-uK-pvI"/>
|
||||
<outlet property="debuggerVerticalLine" destination="7bR-gM-1At" id="rfy-7Z-388"/>
|
||||
<outlet property="feedImageView" destination="Ar0-nN-eop" id="wHa-St-o4G"/>
|
||||
<outlet property="gridButton" destination="fL6-2S-Rgd" id="jtV-jh-GHC"/>
|
||||
<outlet property="mainWindow" destination="xOd-HO-29H" id="h8M-YB-vcC"/>
|
||||
<outlet property="memoryBankInput" destination="rdV-q6-hc6" id="KBx-9T-2mX"/>
|
||||
<outlet property="memoryBankItem" destination="bWC-FW-IYP" id="Lf2-dh-z32"/>
|
||||
<outlet property="memorySpaceButton" destination="vfJ-vu-gqJ" id="ris-gF-9U7"/>
|
||||
<outlet property="memoryView" destination="8hr-8o-3rN" id="fF0-rh-8ND"/>
|
||||
<outlet property="memoryWindow" destination="mRm-dL-mCj" id="VPR-lu-vtI"/>
|
||||
<outlet property="objectsTableView" destination="TOc-XJ-w9w" id="O4R-4Z-9hU"/>
|
||||
<outlet property="objectView" destination="fIM-GT-QXJ" id="jzs-q8-Z2U"/>
|
||||
<outlet property="osdView" destination="MX4-l2-7NE" id="Am7-fq-uvu"/>
|
||||
<outlet property="paletteTableView" destination="gfC-d3-dmq" id="fTC-eL-Qg3"/>
|
||||
<outlet property="paletteView" destination="ZuP-AU-0pA" id="ef6-27-Bci"/>
|
||||
<outlet property="printerFeedWindow" destination="NdE-0B-WCf" id="yVK-cS-NOJ"/>
|
||||
<outlet property="printerSpinner" destination="rrz-Uh-Nae" id="CI8-Y2-s3l"/>
|
||||
<outlet property="tilemapImageView" destination="LlK-tV-bjv" id="nSY-Xd-BjZ"/>
|
||||
<outlet property="tilemapMapButton" destination="YIJ-Qc-SIZ" id="BB7-Gg-7XP"/>
|
||||
<outlet property="tilemapPaletteButton" destination="loB-0k-Qff" id="2Or-7l-6vn"/>
|
||||
|
@ -43,11 +52,11 @@
|
|||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="xOd-HO-29H" userLabel="Window">
|
||||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" tabbingMode="disallowed" id="xOd-HO-29H" userLabel="Window">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="160" height="144"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
|
||||
<value key="minSize" type="size" width="160" height="144"/>
|
||||
<view key="contentView" id="gIp-Ho-8D9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="160" height="144"/>
|
||||
|
@ -77,60 +86,41 @@
|
|||
</connections>
|
||||
<point key="canvasLocation" x="293" y="347"/>
|
||||
</window>
|
||||
<window title="Debug Console" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="21F-Ah-yHX" customClass="NSPanel">
|
||||
<window title="Debug Console" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="21F-Ah-yHX" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" utility="YES" HUD="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" fullScreenAuxiliary="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="921" height="400"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
|
||||
<value key="minSize" type="size" width="921" height="400"/>
|
||||
<view key="contentView" id="dCP-E5-7Fi">
|
||||
<view key="contentView" id="dCP-E5-7Fi" customClass="GBOptionalVisualEffectView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="921" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="l22-S8-uji">
|
||||
<rect key="frame" x="0.0" y="0.0" width="921" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" focusRingType="none" id="p3j-nS-44f" customClass="GBTerminalTextFieldCell">
|
||||
<font key="font" metaFont="fixedUser" size="11"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="backgroundColor" red="0.16470588235294117" green="0.16470588235294117" blue="0.16470588235294117" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="consoleInput:" target="-2" id="ylQ-vw-ARS"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="960-dL-7ZY">
|
||||
<rect key="frame" x="0.0" y="23" width="921" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
</box>
|
||||
<box horizontalHuggingPriority="750" boxType="separator" id="7bR-gM-1At">
|
||||
<rect key="frame" x="590" y="25" width="5" height="376"/>
|
||||
<rect key="frame" x="590" y="0.0" width="5" height="401"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
</box>
|
||||
<splitView dividerStyle="thin" vertical="YES" id="pUc-ZN-vl5" customClass="GBSplitView">
|
||||
<rect key="frame" x="0.0" y="25" width="921" height="376"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="921" height="401"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<customView fixedFrame="YES" id="2rj-7i-kxc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="591" height="376"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="591" height="401"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oTo-zx-o6N">
|
||||
<rect key="frame" x="0.0" y="0.0" width="591" height="376"/>
|
||||
<rect key="frame" x="0.0" y="52" width="591" height="349"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="EQe-Ad-L7S">
|
||||
<rect key="frame" x="0.0" y="0.0" width="591" height="376"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="EQe-Ad-L7S">
|
||||
<rect key="frame" x="0.0" y="0.0" width="591" height="349"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView ambiguous="YES" editable="NO" drawsBackground="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" baseWritingDirection="leftToRight" findStyle="bar" allowsNonContiguousLayout="YES" id="doS-dM-hnl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="591" height="376"/>
|
||||
<textView editable="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" baseWritingDirection="leftToRight" findStyle="bar" allowsNonContiguousLayout="YES" id="doS-dM-hnl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="591" height="349"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="0.14901960784313725" green="0.14901960784313725" blue="0.14901960784313725" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<size key="minSize" width="591" height="376"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.25" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<size key="minSize" width="591" height="349"/>
|
||||
<size key="maxSize" width="1160" height="10000000"/>
|
||||
<color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
|
@ -138,31 +128,126 @@
|
|||
</allowedInputSourceLocales>
|
||||
</textView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.16470588235294117" green="0.16470588235294117" blue="0.16470588235294117" alpha="1" colorSpace="calibratedRGB"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="3fZ-tl-Zi7">
|
||||
<rect key="frame" x="-100" y="-100" width="87" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="cwi-6E-rbh">
|
||||
<rect key="frame" x="575" y="0.0" width="16" height="376"/>
|
||||
<rect key="frame" x="575" y="0.0" width="16" height="349"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" mirrorLayoutDirectionWhenInternationalizing="never" id="l22-S8-uji">
|
||||
<rect key="frame" x="0.0" y="0.0" width="593" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" focusRingType="none" drawsBackground="YES" id="p3j-nS-44f" customClass="GBTerminalTextFieldCell">
|
||||
<font key="font" metaFont="fixedUser" size="11"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.25" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="consoleInput:" target="-2" id="ylQ-vw-ARS"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="xJr-K6-B4B">
|
||||
<rect key="frame" x="0.0" y="49" width="591" height="4"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
</box>
|
||||
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="9DF-fj-a2v">
|
||||
<rect key="frame" x="0.0" y="24" width="591" height="4"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
</box>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="G4h-KO-Z3g" customClass="GBDebuggerButton">
|
||||
<rect key="frame" x="2" y="26" width="26" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<buttonCell key="cell" type="bevel" title="Interrupt" alternateTitle="interrupt" bezelStyle="rounded" image="InterruptTemplate" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="wfO-32-eG5">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<color key="contentTintColor" name="controlAccentColor" catalog="System" colorSpace="catalog"/>
|
||||
<connections>
|
||||
<action selector="debuggerButtonPressed:" target="-2" id="SjG-90-8dJ"/>
|
||||
<outlet property="textField" destination="l22-S8-uji" id="NZ8-eJ-Uyd"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cOi-Rs-9gS" customClass="GBDebuggerButton">
|
||||
<rect key="frame" x="28" y="26" width="26" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<buttonCell key="cell" type="bevel" title="Step Over" alternateTitle="next" bezelStyle="rounded" image="NextTemplate" imagePosition="only" alignment="center" enabled="NO" imageScaling="proportionallyDown" inset="2" id="buW-ke-lgF">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="debuggerButtonPressed:" target="-2" id="g7E-UM-SHV"/>
|
||||
<outlet property="textField" destination="l22-S8-uji" id="1uM-AA-yHi"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DsN-Ce-QoH" customClass="GBDebuggerButton">
|
||||
<rect key="frame" x="54" y="26" width="26" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<buttonCell key="cell" type="bevel" title="Step Into" alternateTitle="step" bezelStyle="rounded" image="StepTemplate" imagePosition="only" alignment="center" enabled="NO" imageScaling="proportionallyDown" inset="2" id="ATJ-Vx-zbo">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="debuggerButtonPressed:" target="-2" id="QMw-82-HKJ"/>
|
||||
<outlet property="textField" destination="l22-S8-uji" id="qaF-TF-cwg"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vtb-n5-Qlz" customClass="GBDebuggerButton">
|
||||
<rect key="frame" x="78" y="26" width="26" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<buttonCell key="cell" type="bevel" title="Step Out" alternateTitle="finish" bezelStyle="rounded" image="FinishTemplate" imagePosition="only" alignment="center" enabled="NO" imageScaling="proportionallyDown" inset="2" id="8mF-ii-5Hx">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="debuggerButtonPressed:" target="-2" id="krr-9m-Jfz"/>
|
||||
<outlet property="textField" destination="l22-S8-uji" id="uYK-tU-BnO"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oCa-UH-1mi" customClass="GBDebuggerButton">
|
||||
<rect key="frame" x="563" y="26" width="26" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<buttonCell key="cell" type="bevel" title="Help" alternateTitle="help" bezelStyle="rounded" image="HelpTemplate" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="tvn-kY-8FO">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="debuggerButtonPressed:" target="-2" id="PwN-rf-AcB"/>
|
||||
<outlet property="textField" destination="l22-S8-uji" id="blK-B3-MWI"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="onn-R8-3vg" customClass="GBDebuggerButton">
|
||||
<rect key="frame" x="102" y="26" width="26" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<buttonCell key="cell" type="bevel" title="Step Backwards" alternateTitle="backstep" bezelStyle="rounded" image="BackstepTemplate" imagePosition="only" alignment="center" enabled="NO" imageScaling="proportionallyDown" inset="2" id="WtK-kD-bf6">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="debuggerButtonPressed:" target="-2" id="S9a-jV-Z6g"/>
|
||||
<outlet property="textField" destination="l22-S8-uji" id="1gw-Lc-QFS"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</customView>
|
||||
<customView fixedFrame="YES" id="4Z2-33-dYY">
|
||||
<rect key="frame" x="592" y="0.0" width="329" height="376"/>
|
||||
<customView fixedFrame="YES" id="4Z2-33-dYY" customClass="GBOptionalVisualEffectView">
|
||||
<rect key="frame" x="592" y="0.0" width="329" height="401"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" scrollerKnobStyle="dark" translatesAutoresizingMaskIntoConstraints="NO" id="V9U-Ua-F4z">
|
||||
<rect key="frame" x="0.0" y="329" width="329" height="47"/>
|
||||
<rect key="frame" x="0.0" y="354" width="329" height="47"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="YHx-TM-zIC">
|
||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="YHx-TM-zIC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="329" height="47"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView ambiguous="YES" drawsBackground="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" allowsCharacterPickerTouchBarItem="NO" allowsUndo="YES" allowsNonContiguousLayout="YES" textCompletion="NO" spellingCorrection="YES" id="w0g-eK-jM4">
|
||||
<textView drawsBackground="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" allowsCharacterPickerTouchBarItem="NO" allowsUndo="YES" allowsNonContiguousLayout="YES" textCompletion="NO" spellingCorrection="YES" id="w0g-eK-jM4">
|
||||
<rect key="frame" x="0.0" y="0.0" width="329" height="47"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -186,22 +271,22 @@
|
|||
</scroller>
|
||||
</scrollView>
|
||||
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="5qI-qZ-nkh">
|
||||
<rect key="frame" x="0.0" y="327" width="327" height="5"/>
|
||||
<rect key="frame" x="0.0" y="352" width="329" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
</box>
|
||||
<scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vts-CC-ZjQ">
|
||||
<rect key="frame" x="0.0" y="2" width="329" height="328"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="329" height="354"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="Cs9-3x-ATg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="329" height="328"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="Cs9-3x-ATg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="329" height="354"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView ambiguous="YES" editable="NO" drawsBackground="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" baseWritingDirection="leftToRight" findStyle="bar" allowsNonContiguousLayout="YES" spellingCorrection="YES" id="JgV-7E-iwp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="329" height="328"/>
|
||||
<textView editable="NO" drawsBackground="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" baseWritingDirection="leftToRight" findStyle="bar" allowsNonContiguousLayout="YES" spellingCorrection="YES" id="JgV-7E-iwp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="329" height="354"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" red="0.14901960780000001" green="0.14901960780000001" blue="0.14901960780000001" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<size key="minSize" width="329" height="328"/>
|
||||
<size key="minSize" width="329" height="354"/>
|
||||
<size key="maxSize" width="1160" height="10000000"/>
|
||||
<color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
|
@ -216,7 +301,7 @@
|
|||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="4jm-Gm-D2R">
|
||||
<rect key="frame" x="313" y="0.0" width="16" height="328"/>
|
||||
<rect key="frame" x="313" y="0.0" width="16" height="354"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
|
@ -235,11 +320,11 @@
|
|||
</view>
|
||||
<point key="canvasLocation" x="347.5" y="-29"/>
|
||||
</window>
|
||||
<window title="Memory" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="mRm-dL-mCj" customClass="NSPanel">
|
||||
<window title="Memory" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" toolbarStyle="expanded" id="mRm-dL-mCj" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" fullScreenAuxiliary="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="528" height="320"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
|
||||
<view key="contentView" id="8hr-8o-3rN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="528" height="320"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
@ -318,11 +403,11 @@
|
|||
<point key="canvasLocation" x="-185" y="61"/>
|
||||
</window>
|
||||
<menuItem title="Cartridge RAM" id="ylM-ah-PNQ"/>
|
||||
<window title="VRAM Viewer" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="mbr-db-iZh" customClass="NSPanel">
|
||||
<window title="VRAM Viewer" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" toolbarStyle="expanded" id="mbr-db-iZh" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" fullScreenAuxiliary="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
|
||||
<view key="contentView" id="GYW-dv-Um1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
@ -341,17 +426,17 @@
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<tabView fixedFrame="YES" drawsBackground="NO" type="noTabsNoBorder" initialItem="pXb-od-Wb1" translatesAutoresizingMaskIntoConstraints="NO" id="AZz-Mh-rPA">
|
||||
<rect key="frame" x="0.0" y="24" width="512" height="408"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<tabViewItems>
|
||||
<tabViewItem label="Tileset" identifier="1" id="pXb-od-Wb1">
|
||||
<view key="view" ambiguous="YES" id="lCG-Gt-XMF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<view key="view" id="lCG-Gt-XMF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="QcQ-ex-36R" customClass="GBImageView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="384"/>
|
||||
<rect key="frame" x="0.0" y="24" width="512" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="axesIndependently" id="pXc-O8-jg5"/>
|
||||
<connections>
|
||||
|
@ -360,7 +445,7 @@
|
|||
</connections>
|
||||
</imageView>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TLv-xS-X5K">
|
||||
<rect key="frame" x="4" y="388" width="128" height="17"/>
|
||||
<rect key="frame" x="4" y="412" width="128" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundRect" title="None" bezelStyle="roundedRect" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" selectedItem="G8p-CH-PlV" id="1jI-s4-4YY">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
|
@ -392,7 +477,7 @@
|
|||
</connections>
|
||||
</popUpButton>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fL6-2S-Rgd">
|
||||
<rect key="frame" x="452" y="388" width="56" height="17"/>
|
||||
<rect key="frame" x="452" y="412" width="56" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="roundRect" title="Grid" bezelStyle="roundedRect" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="pDn-9a-Se6">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
|
||||
|
@ -407,11 +492,11 @@
|
|||
</tabViewItem>
|
||||
<tabViewItem label="Tilemap" identifier="2" id="kaY-Wy-Yt1">
|
||||
<view key="view" id="c6j-cM-dDx">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DhM-Em-hj7">
|
||||
<rect key="frame" x="385" y="388" width="63" height="17"/>
|
||||
<rect key="frame" x="385" y="412" width="63" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="roundRect" title="Scrolling" bezelStyle="roundedRect" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="P2E-5t-BN9">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
|
||||
|
@ -422,7 +507,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LlK-tV-bjv" customClass="GBImageView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="384"/>
|
||||
<rect key="frame" x="0.0" y="24" width="512" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="axesIndependently" id="RvP-El-ILj"/>
|
||||
<connections>
|
||||
|
@ -431,7 +516,7 @@
|
|||
</connections>
|
||||
</imageView>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="loB-0k-Qff">
|
||||
<rect key="frame" x="4" y="388" width="128" height="17"/>
|
||||
<rect key="frame" x="4" y="412" width="128" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundRect" title="Effective Palettes" bezelStyle="roundedRect" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" selectedItem="oUH-Sa-Ec1" id="Eij-Cp-URa">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
|
@ -464,7 +549,7 @@
|
|||
</connections>
|
||||
</popUpButton>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="YIJ-Qc-SIZ">
|
||||
<rect key="frame" x="135" y="388" width="96" height="17"/>
|
||||
<rect key="frame" x="135" y="412" width="96" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundRect" title="Effective Tilemap" bezelStyle="roundedRect" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" selectedItem="XRF-Vj-3gs" id="3W1-Db-wDn">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
|
@ -482,7 +567,7 @@
|
|||
</connections>
|
||||
</popUpButton>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="k4c-Vg-MBu">
|
||||
<rect key="frame" x="235" y="388" width="96" height="17"/>
|
||||
<rect key="frame" x="235" y="412" width="96" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundRect" title="Effective Tileset" bezelStyle="roundedRect" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" selectedItem="CRe-dX-rzY" id="h53-sb-Odg">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
|
@ -504,250 +589,45 @@
|
|||
</tabViewItem>
|
||||
<tabViewItem label="Objects" identifier="" id="a08-eg-Maw">
|
||||
<view key="view" id="EiO-p0-3xn">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView fixedFrame="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="20" horizontalPageScroll="10" verticalLineScroll="20" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="krD-gH-o5I">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vhq-K4-baH">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" id="3VT-AA-xVT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<clipView key="contentView" ambiguous="YES" id="JYu-CM-49p">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="none" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="18" headerView="of1-KC-dXC" id="TOc-XJ-w9w">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="391"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="32" minWidth="32" maxWidth="1000" id="hRp-Kh-nWC">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<imageCell key="dataCell" scrollable="YES" lineBreakMode="clipping" refusesFirstResponder="YES" alignment="left" id="Jhk-KW-Hoc" customClass="GBImageCell"/>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="28" minWidth="28" maxWidth="1000" id="Vrl-in-npm">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="X">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" id="czf-Bn-nZN">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="28" minWidth="28" maxWidth="1000" id="636-Td-Zcm">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="Y">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" id="zh6-hI-Ss8">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="28" minWidth="28" maxWidth="1000" id="vMj-ya-pGG">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="Tile">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" id="0s8-eF-rgd">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="68" minWidth="40" maxWidth="1000" id="U5B-eh-aer">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="Tile Addr.">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" id="PtW-wF-c0o">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="68" minWidth="40" maxWidth="1000" id="LSg-Sc-Sdr">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="OAM Addr.">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" id="a7k-83-iPE">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="65" minWidth="40" maxWidth="1000" id="S9B-Hc-6Ee">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="Attributes">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" id="sJa-oU-QZp">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="168" minWidth="40" maxWidth="1000" id="8fQ-EC-E5K">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" selectable="YES" editable="YES" id="YSL-O0-ZwU">
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="-2" id="ypl-SU-g5n"/>
|
||||
<outlet property="delegate" destination="-2" id="HzE-pT-cX5"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<view ambiguous="YES" id="fIM-GT-QXJ" customClass="GBObjectView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="706"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<nil key="backgroundColor"/>
|
||||
<edgeInsets key="contentInsets" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="n53-qA-NpY">
|
||||
<rect key="frame" x="0.0" y="392" width="512" height="16"/>
|
||||
<edgeInsets key="contentInsets" left="0.0" right="0.0" top="0.0" bottom="0.0"/>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="zUB-xg-cXq">
|
||||
<rect key="frame" x="-100" y="-100" width="512" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="mqp-NY-g8d">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="jMe-gO-ERw">
|
||||
<rect key="frame" x="496" y="0.0" width="16" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<tableHeaderView key="headerView" id="of1-KC-dXC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableHeaderView>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
<tabViewItem label="Palettes" identifier="" id="vLb-Nh-UYE">
|
||||
<view key="view" id="qIg-ci-WTA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="20" horizontalPageScroll="10" verticalLineScroll="20" verticalPageScroll="10" hasHorizontalScroller="NO" hasVerticalScroller="NO" usesPredominantAxisScrolling="NO" horizontalScrollElasticity="none" verticalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="iSs-Ow-wwb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZuP-AU-0pA" customClass="GBPaletteView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" id="bP9-su-zQw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="18" id="gfC-d3-dmq">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="408"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableViewGridLines key="gridStyleMask" dashed="YES"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="125" minWidth="40" maxWidth="1000" id="Aje-FQ-fUw">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" title="Text Cell" id="Ygb-xo-X8v">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="93" minWidth="40" maxWidth="1000" id="4EN-0j-lda">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" title="Text Cell" id="3a2-A4-XQW" customClass="GBColorCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="93" minWidth="10" maxWidth="3.4028234663852886e+38" id="syl-os-nSf">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" alignment="left" title="Text Cell" id="3ql-bn-AxP" customClass="GBColorCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="93" minWidth="10" maxWidth="3.4028234663852886e+38" id="Qw3-u2-c1s">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" title="Text Cell" id="9at-mH-PWc" customClass="GBColorCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="93" minWidth="10" maxWidth="3.4028234663852886e+38" id="gTl-gN-qLn">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" refusesFirstResponder="YES" alignment="left" title="Text Cell" id="dY8-Zu-d4t" customClass="GBColorCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="-2" id="F2f-nK-QTN"/>
|
||||
<outlet property="delegate" destination="-2" id="7hn-MM-DDD"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="OS3-sw-bjv">
|
||||
<rect key="frame" x="-100" y="-100" width="510" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="4HA-2m-8TZ">
|
||||
<rect key="frame" x="-100" y="-100" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
</customView>
|
||||
</subviews>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
|
@ -792,7 +672,7 @@
|
|||
<window title="Printer Feed" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="NdE-0B-WCf" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="320" height="288"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
|
||||
<value key="minSize" type="size" width="320" height="16"/>
|
||||
<view key="contentView" id="RRS-aa-bPT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="288"/>
|
||||
|
@ -808,18 +688,33 @@
|
|||
<toolbar key="toolbar" implicitIdentifier="1FF86A2B-6637-4EE6-A25A-7298D79AE84E" autosavesConfiguration="NO" allowsUserCustomization="NO" displayMode="iconAndLabel" sizeMode="regular" id="gH3-SH-7il">
|
||||
<allowedToolbarItems>
|
||||
<toolbarItem implicitItemIdentifier="15EB8D49-8C6E-42F2-9F7F-F7D7A0BBDAAF" label="Save" paletteLabel="Save" tag="-1" image="NSFolder" id="CBz-1N-o0Q">
|
||||
<size key="minSize" width="22" height="22"/>
|
||||
<size key="maxSize" width="22" height="22"/>
|
||||
<connections>
|
||||
<action selector="savePrinterFeed:" target="-2" id="Dm3-h0-ch4"/>
|
||||
</connections>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarPrintItem" explicitItemIdentifier="Print" id="mtd-zS-DXa"/>
|
||||
<toolbarItem implicitItemIdentifier="0496ED81-2A03-445D-9818-97386BC78CBC" label="Print" paletteLabel="Print" tag="-1" image="printer" catalog="system" bordered="YES" id="L6N-6G-UWl">
|
||||
<size key="minSize" width="30" height="25"/>
|
||||
<size key="maxSize" width="30" height="25"/>
|
||||
<connections>
|
||||
<action selector="printDocument:" target="-1" id="RLy-7k-iIR"/>
|
||||
</connections>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="AoG-LH-J4b"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="Q0x-n5-Q2Y"/>
|
||||
<toolbarItem implicitItemIdentifier="E8F74F8F-6DE2-4774-A690-F71D92CD932E" label="" paletteLabel="" tag="-1" sizingBehavior="auto" id="CJX-Ff-7iQ">
|
||||
<nil key="toolTip"/>
|
||||
<progressIndicator key="view" wantsLayer="YES" maxValue="100" displayedWhenStopped="NO" indeterminate="YES" controlSize="small" style="spinning" id="rrz-Uh-Nae">
|
||||
<rect key="frame" x="0.0" y="14" width="16" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</progressIndicator>
|
||||
</toolbarItem>
|
||||
</allowedToolbarItems>
|
||||
<defaultToolbarItems>
|
||||
<toolbarItem reference="CJX-Ff-7iQ"/>
|
||||
<toolbarItem reference="CBz-1N-o0Q"/>
|
||||
<toolbarItem reference="Q0x-n5-Q2Y"/>
|
||||
<toolbarItem reference="mtd-zS-DXa"/>
|
||||
<toolbarItem reference="L6N-6G-UWl"/>
|
||||
</defaultToolbarItems>
|
||||
</toolbar>
|
||||
<point key="canvasLocation" x="-159" y="356"/>
|
||||
|
@ -827,7 +722,7 @@
|
|||
<window title="Cheats" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="4Yb-Np-JrF" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="692" height="272"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
|
||||
<view key="contentView" id="gBP-5p-BTh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="692" height="272"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
|
@ -840,7 +735,7 @@
|
|||
<rect key="frame" x="16" y="174" width="154" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="To value:" id="Ycx-oE-aA4">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
@ -909,7 +804,7 @@
|
|||
</connections>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" id="C3V-Ep-bMj">
|
||||
<rect key="frame" x="202.5" y="12" width="83" height="23"/>
|
||||
<rect key="frame" x="203" y="12" width="83" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Import" bezelStyle="texturedRounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mMP-KW-YNy">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
|
@ -931,7 +826,6 @@
|
|||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="consoleInput:" target="-2" id="sMf-aM-OvR"/>
|
||||
<outlet property="delegate" destination="v7q-gT-jHT" id="79v-33-R1X"/>
|
||||
</connections>
|
||||
</textField>
|
||||
|
@ -947,7 +841,6 @@
|
|||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="consoleInput:" target="-2" id="SYC-cW-RjC"/>
|
||||
<outlet property="delegate" destination="v7q-gT-jHT" id="P69-nT-oOt"/>
|
||||
</connections>
|
||||
</textField>
|
||||
|
@ -963,7 +856,6 @@
|
|||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="consoleInput:" target="-2" id="io6-ha-QNb"/>
|
||||
<outlet property="delegate" destination="v7q-gT-jHT" id="6RH-dg-SL7"/>
|
||||
</connections>
|
||||
</textField>
|
||||
|
@ -971,7 +863,7 @@
|
|||
<rect key="frame" x="16" y="204" width="152" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Change byte at address:" id="xwa-TF-eY1">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
@ -982,11 +874,11 @@
|
|||
<rect key="frame" x="293" y="-1" width="400" height="275"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" id="mzf-yu-RID">
|
||||
<rect key="frame" x="1" y="0.0" width="398" height="274"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<rect key="frame" x="1" y="1" width="398" height="273"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="none" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" headerView="pvX-uJ-qK5" id="tA3-8T-bxb">
|
||||
<rect key="frame" x="0.0" y="0.0" width="398" height="249"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="398" height="256"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -994,19 +886,17 @@
|
|||
<tableColumns>
|
||||
<tableColumn width="32" minWidth="32" maxWidth="1000" id="JNd-HW-LvS">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<buttonCell key="dataCell" type="bevel" bezelStyle="regularSquare" image="NSStopProgressFreestandingTemplate" imagePosition="only" inset="2" id="5xh-hN-jHH">
|
||||
<buttonCell key="dataCell" type="inline" bezelStyle="inline" image="NSStopProgressFreestandingTemplate" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="5xh-hN-jHH">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="60" minWidth="40" maxWidth="1000" id="9DZ-oW-Scx">
|
||||
<tableColumn width="40" minWidth="40" maxWidth="1000" id="9DZ-oW-Scx">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Enabled">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
|
@ -1016,9 +906,8 @@
|
|||
</buttonCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn editable="NO" width="160" minWidth="40" maxWidth="1000" id="4Qa-FQ-QWY">
|
||||
<tableColumn editable="NO" width="142" minWidth="40" maxWidth="1000" id="4Qa-FQ-QWY">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Description">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
|
@ -1031,7 +920,6 @@
|
|||
</tableColumn>
|
||||
<tableColumn editable="NO" width="134" minWidth="40" maxWidth="1000" id="ACq-gU-K36">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Action">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
|
@ -1051,15 +939,15 @@
|
|||
</subviews>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="3Hg-LL-VqH">
|
||||
<rect key="frame" x="1" y="258" width="398" height="16"/>
|
||||
<rect key="frame" x="1" y="119" width="223" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="zET-KH-qF4">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<tableHeaderView key="headerView" id="pvX-uJ-qK5">
|
||||
<rect key="frame" x="0.0" y="0.0" width="398" height="25"/>
|
||||
<tableHeaderView key="headerView" wantsLayer="YES" id="pvX-uJ-qK5">
|
||||
<rect key="frame" x="0.0" y="0.0" width="398" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableHeaderView>
|
||||
</scrollView>
|
||||
|
@ -1082,7 +970,14 @@
|
|||
</customObject>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="BackstepTemplate" width="14" height="14"/>
|
||||
<image name="FinishTemplate" width="14" height="14"/>
|
||||
<image name="HelpTemplate" width="14" height="14"/>
|
||||
<image name="InterruptTemplate" width="14" height="14"/>
|
||||
<image name="NSFolder" width="32" height="32"/>
|
||||
<image name="NSStopProgressFreestandingTemplate" width="14" height="14"/>
|
||||
<image name="NSStopProgressFreestandingTemplate" width="15" height="15"/>
|
||||
<image name="NextTemplate" width="14" height="14"/>
|
||||
<image name="StepTemplate" width="14" height="14"/>
|
||||
<image name="printer" catalog="system" width="18" height="16"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
After Width: | Height: | Size: 166 B |
After Width: | Height: | Size: 298 B |
|
@ -1,7 +1,8 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#import <JoyKit/JoyKit.h>
|
||||
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate, NSUserNotificationCenterDelegate, NSMenuDelegate, WebUIDelegate, WebPolicyDelegate, WebFrameLoadDelegate>
|
||||
@interface GBApp : NSApplication <NSApplicationDelegate, NSUserNotificationCenterDelegate, NSMenuDelegate, WebUIDelegate, WebPolicyDelegate, WebFrameLoadDelegate, JOYListener>
|
||||
|
||||
@property (nonatomic, strong) IBOutlet NSWindow *preferencesWindow;
|
||||
@property (nonatomic, strong) IBOutlet NSView *graphicsTab;
|
|
@ -1,10 +1,13 @@
|
|||
#import "AppDelegate.h"
|
||||
#include "GBButtons.h"
|
||||
#include "GBView.h"
|
||||
#include <Core/gb.h>
|
||||
#import "GBApp.h"
|
||||
#import "GBButtons.h"
|
||||
#import "GBView.h"
|
||||
#import "Document.h"
|
||||
#import "GBJoyConManager.h"
|
||||
#import <Core/gb.h>
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <JoyKit/JoyKit.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#import <mach-o/dyld.h>
|
||||
|
||||
#define UPDATE_SERVER "https://sameboy.github.io"
|
||||
|
||||
|
@ -16,10 +19,9 @@ static uint32_t color_to_int(NSColor *color)
|
|||
((unsigned)(color.blueComponent * 0xFF));
|
||||
}
|
||||
|
||||
@implementation AppDelegate
|
||||
@implementation GBApp
|
||||
{
|
||||
NSWindow *preferences_window;
|
||||
NSArray<NSView *> *preferences_tabs;
|
||||
NSArray<NSView *> *_preferencesTabs;
|
||||
NSString *_lastVersion;
|
||||
NSString *_updateURL;
|
||||
NSURLSessionDownloadTask *_updateTask;
|
||||
|
@ -31,10 +33,15 @@ static uint32_t color_to_int(NSColor *color)
|
|||
UPDATE_FAILED,
|
||||
} _updateState;
|
||||
NSString *_downloadDirectory;
|
||||
AuthorizationRef _auth;
|
||||
bool _simulatingMenuEvent;
|
||||
}
|
||||
|
||||
- (void) applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
// Refresh icon if launched via a software update
|
||||
[NSApplication sharedApplication].applicationIconImage = [NSImage imageNamed:@"AppIcon"];
|
||||
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
for (unsigned i = 0; i < GBButtonCount; i++) {
|
||||
if ([[defaults objectForKey:button_to_preference_name(i, 0)] isKindOfClass:[NSString class]]) {
|
||||
|
@ -57,13 +64,14 @@ static uint32_t color_to_int(NSColor *color)
|
|||
@"GBSlow-Motion": @(kVK_Shift),
|
||||
|
||||
@"GBFilter": @"NearestNeighbor",
|
||||
@"GBColorCorrection": @(GB_COLOR_CORRECTION_EMULATE_HARDWARE),
|
||||
@"GBHighpassFilter": @(GB_HIGHPASS_REMOVE_DC_OFFSET),
|
||||
@"GBRewindLength": @(10),
|
||||
@"GBColorCorrection": @(GB_COLOR_CORRECTION_MODERN_BALANCED),
|
||||
@"GBHighpassFilter": @(GB_HIGHPASS_ACCURATE),
|
||||
@"GBRewindLength": @(120),
|
||||
@"GBFrameBlendingMode": @([defaults boolForKey:@"DisableFrameBlending"]? GB_FRAME_BLENDING_MODE_DISABLED : GB_FRAME_BLENDING_MODE_ACCURATE),
|
||||
|
||||
@"GBDMGModel": @(GB_MODEL_DMG_B),
|
||||
@"GBCGBModel": @(GB_MODEL_CGB_E),
|
||||
@"GBAGBModel": @(GB_MODEL_AGB_A),
|
||||
@"GBSGBModel": @(GB_MODEL_SGB2),
|
||||
@"GBRumbleMode": @(GB_RUMBLE_CARTRIDGE_ONLY),
|
||||
|
||||
|
@ -71,6 +79,72 @@ static uint32_t color_to_int(NSColor *color)
|
|||
|
||||
@"GBMBC7JoystickOverride": @NO,
|
||||
@"GBMBC7AllowMouse": @YES,
|
||||
|
||||
@"GBJoyConAutoPair": @YES,
|
||||
@"GBJoyConsDefaultsToHorizontal": @YES,
|
||||
|
||||
// Default themes
|
||||
@"GBThemes": @{
|
||||
@"Desert": @{
|
||||
@"BrightnessBias": @0.0,
|
||||
@"Colors": @[@0xff302f3e, @0xff576674, @0xff839ba4, @0xffb1d0d2, @0xffb7d7d8],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.10087773904382469,
|
||||
@"HueBiasStrength": @0.062142056772908363,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Evening": @{
|
||||
@"BrightnessBias": @-0.10168700106441975,
|
||||
@"Colors": @[@0xff362601, @0xff695518, @0xff899853, @0xffa6e4ae, @0xffa9eebb],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.60027079191058874,
|
||||
@"HueBiasStrength": @0.33816297305747867,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Fog": @{
|
||||
@"BrightnessBias": @0.0,
|
||||
@"Colors": @[@0xff373c34, @0xff737256, @0xff9da386, @0xffc3d2bf, @0xffc7d8c6],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.55750435756972117,
|
||||
@"HueBiasStrength": @0.18424738545816732,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Magic Eggplant": @{
|
||||
@"BrightnessBias": @0.0,
|
||||
@"Colors": @[@0xff3c2136, @0xff942e84, @0xffc7699d, @0xfff1e4b0, @0xfff6f9b2],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.87717878486055778,
|
||||
@"HueBiasStrength": @0.65018052788844627,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Radioactive Pea": @{
|
||||
@"BrightnessBias": @-0.48079556772908372,
|
||||
@"Colors": @[@0xff215200, @0xff1f7306, @0xff169e34, @0xff03ceb8, @0xff00d4d1],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.3795131972111554,
|
||||
@"HueBiasStrength": @0.34337649402390436,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Seaweed": @{
|
||||
@"BrightnessBias": @-0.28532744023904377,
|
||||
@"Colors": @[@0xff3f0015, @0xff426532, @0xff58a778, @0xff95e0df, @0xffa0e7ee],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.2694067480079681,
|
||||
@"HueBiasStrength": @0.51565612549800799,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
@"Twilight": @{
|
||||
@"BrightnessBias": @-0.091789093625498031,
|
||||
@"Colors": @[@0xff3f0015, @0xff461286, @0xff6254bd, @0xff97d3e9, @0xffa0e7ee],
|
||||
@"DisabledLCDColor": @YES,
|
||||
@"HueBias": @0.0,
|
||||
@"HueBiasStrength": @0.49710532868525897,
|
||||
@"Manual": @NO,
|
||||
},
|
||||
},
|
||||
|
||||
@"NSToolbarItemForcesStandardSize": @YES, // Forces Monterey to resepect toolbar item sizes
|
||||
@"NSToolbarItemWarnOnMinMaxSize": @NO, // Not going to use Constraints, Apple
|
||||
}];
|
||||
|
||||
[JOYController startOnRunLoop:[NSRunLoop currentRunLoop] withOptions:@{
|
||||
|
@ -78,6 +152,10 @@ static uint32_t color_to_int(NSColor *color)
|
|||
JOYHatsEmulateButtonsKey: @YES,
|
||||
}];
|
||||
|
||||
[GBJoyConManager sharedInstance]; // Starts handling Joy-Cons
|
||||
|
||||
[JOYController registerListener:self];
|
||||
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBNotificationsUsed"]) {
|
||||
[NSUserNotificationCenter defaultUserNotificationCenter].delegate = self;
|
||||
}
|
||||
|
@ -101,10 +179,10 @@ static uint32_t color_to_int(NSColor *color)
|
|||
|
||||
- (IBAction)switchPreferencesTab:(id)sender
|
||||
{
|
||||
for (NSView *view in preferences_tabs) {
|
||||
for (NSView *view in _preferencesTabs) {
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
NSView *tab = preferences_tabs[[sender tag]];
|
||||
NSView *tab = _preferencesTabs[[sender tag]];
|
||||
NSRect old = [_preferencesWindow frame];
|
||||
NSRect new = [_preferencesWindow frameRectForContentRect:tab.frame];
|
||||
new.origin.x = old.origin.x;
|
||||
|
@ -148,12 +226,16 @@ static uint32_t color_to_int(NSColor *color)
|
|||
[[NSBundle mainBundle] loadNibNamed:@"Preferences" owner:self topLevelObjects:&objects];
|
||||
NSToolbarItem *first_toolbar_item = [_preferencesWindow.toolbar.items firstObject];
|
||||
_preferencesWindow.toolbar.selectedItemIdentifier = [first_toolbar_item itemIdentifier];
|
||||
preferences_tabs = @[self.emulationTab, self.graphicsTab, self.audioTab, self.controlsTab, self.updatesTab];
|
||||
_preferencesTabs = @[self.emulationTab, self.graphicsTab, self.audioTab, self.controlsTab, self.updatesTab];
|
||||
[self switchPreferencesTab:first_toolbar_item];
|
||||
[_preferencesWindow center];
|
||||
#ifndef UPDATE_SUPPORT
|
||||
[_preferencesWindow.toolbar removeItemAtIndex:4];
|
||||
#endif
|
||||
if (@available(macOS 11.0, *)) {
|
||||
[_preferencesWindow.toolbar insertItemWithItemIdentifier:NSToolbarFlexibleSpaceItemIdentifier atIndex:0];
|
||||
[_preferencesWindow.toolbar insertItemWithItemIdentifier:NSToolbarFlexibleSpaceItemIdentifier atIndex:_preferencesWindow.toolbar.items.count];
|
||||
}
|
||||
}
|
||||
[_preferencesWindow makeKeyAndOrderFront:self];
|
||||
}
|
||||
|
@ -203,7 +285,15 @@ static uint32_t color_to_int(NSColor *color)
|
|||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSArray *objects;
|
||||
[[NSBundle mainBundle] loadNibNamed:@"UpdateWindow" owner:self topLevelObjects:&objects];
|
||||
self.updateChanges.preferences.standardFontFamily = [NSFont systemFontOfSize:0].familyName;
|
||||
if (@available(macOS 10.11, *)) {
|
||||
self.updateChanges.preferences.standardFontFamily = @"-apple-system";
|
||||
}
|
||||
else if (@available(macOS 10.10, *)) {
|
||||
self.updateChanges.preferences.standardFontFamily = @"Helvetica Neue";
|
||||
}
|
||||
else {
|
||||
self.updateChanges.preferences.standardFontFamily = @"Lucida Grande";
|
||||
}
|
||||
self.updateChanges.preferences.fixedFontFamily = @"Menlo";
|
||||
self.updateChanges.drawsBackground = false;
|
||||
[self.updateChanges.mainFrame loadHTMLString:html baseURL:nil];
|
||||
|
@ -297,18 +387,65 @@ static uint32_t color_to_int(NSColor *color)
|
|||
[self.updateWindow performClose:sender];
|
||||
}
|
||||
|
||||
- (bool)executePath:(NSString *)path withArguments:(NSArray <NSString *> *)arguments
|
||||
{
|
||||
if (!_auth) {
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
task.launchPath = path;
|
||||
task.arguments = arguments;
|
||||
[task launch];
|
||||
[task waitUntilExit];
|
||||
return task.terminationStatus == 0 && task.terminationReason == NSTaskTerminationReasonExit;
|
||||
}
|
||||
|
||||
char *argv[arguments.count + 1];
|
||||
argv[arguments.count] = NULL;
|
||||
for (unsigned i = 0; i < arguments.count; i++) {
|
||||
argv[i] = (char *)arguments[i].UTF8String;
|
||||
}
|
||||
|
||||
return AuthorizationExecuteWithPrivileges(_auth, path.UTF8String, kAuthorizationFlagDefaults, argv, NULL) == errAuthorizationSuccess;
|
||||
}
|
||||
|
||||
- (void)deauthorize
|
||||
{
|
||||
if (_auth) {
|
||||
AuthorizationFree(_auth, kAuthorizationFlagDefaults);
|
||||
_auth = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)installUpdate:(id)sender
|
||||
{
|
||||
bool needsAuthorization = false;
|
||||
if ([self executePath:@"/usr/sbin/spctl" withArguments:@[@"--status"]]) { // Succeeds when GateKeeper is on
|
||||
// GateKeeper is on, we need to --add ourselves as root, else we might get a GateKeeper crash
|
||||
needsAuthorization = true;
|
||||
}
|
||||
else if (access(_dyld_get_image_name(0), W_OK)) {
|
||||
// We don't have write access, so we need authorization to update as root
|
||||
needsAuthorization = true;
|
||||
}
|
||||
|
||||
if (needsAuthorization && !_auth) {
|
||||
AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagPreAuthorize | kAuthorizationFlagInteractionAllowed, &_auth);
|
||||
// Make sure we can modify the bundle
|
||||
if (![self executePath:@"/usr/sbin/chown" withArguments:@[@"-R", [NSString stringWithFormat:@"%d:%d", getuid(), getgid()], [NSBundle mainBundle].bundlePath]]) {
|
||||
[self deauthorize];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[self.updateProgressSpinner startAnimation:nil];
|
||||
self.updateProgressButton.title = @"Cancel";
|
||||
self.updateProgressButton.enabled = true;
|
||||
self.updateProgressLabel.stringValue = @"Downloading update...";
|
||||
self.updateProgressLabel.stringValue = @"Downloading update…";
|
||||
_updateState = UPDATE_DOWNLOADING;
|
||||
_updateTask = [[NSURLSession sharedSession] downloadTaskWithURL: [NSURL URLWithString:_updateURL] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
|
||||
_updateTask = nil;
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Extracting update...";
|
||||
self.updateProgressLabel.stringValue = @"Extracting update…";
|
||||
_updateState = UPDATE_EXTRACTING;
|
||||
});
|
||||
|
||||
|
@ -317,8 +454,8 @@ static uint32_t color_to_int(NSColor *color)
|
|||
appropriateForURL:[[NSBundle mainBundle] bundleURL]
|
||||
create:true
|
||||
error:nil] path];
|
||||
NSTask *unzipTask;
|
||||
if (!_downloadDirectory) {
|
||||
[self deauthorize];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Failed to extract update.";
|
||||
|
@ -330,12 +467,14 @@ static uint32_t color_to_int(NSColor *color)
|
|||
return;
|
||||
}
|
||||
|
||||
NSTask *unzipTask;
|
||||
unzipTask = [[NSTask alloc] init];
|
||||
unzipTask.launchPath = @"/usr/bin/unzip";
|
||||
unzipTask.arguments = @[location.path, @"-d", _downloadDirectory];
|
||||
[unzipTask launch];
|
||||
[unzipTask waitUntilExit];
|
||||
if (unzipTask.terminationStatus != 0 || unzipTask.terminationReason != NSTaskTerminationReasonExit) {
|
||||
[self deauthorize];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
self.updateProgressButton.enabled = false;
|
||||
|
@ -368,7 +507,7 @@ static uint32_t color_to_int(NSColor *color)
|
|||
- (void)performUpgrade
|
||||
{
|
||||
self.updateProgressButton.enabled = false;
|
||||
self.updateProgressLabel.stringValue = @"Instaling update...";
|
||||
self.updateProgressLabel.stringValue = @"Instaling update…";
|
||||
_updateState = UPDATE_INSTALLING;
|
||||
self.updateProgressButton.enabled = false;
|
||||
[self.updateProgressSpinner startAnimation:nil];
|
||||
|
@ -380,6 +519,7 @@ static uint32_t color_to_int(NSColor *color)
|
|||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] moveItemAtPath:contentsPath toPath:contentsTempPath error:&error];
|
||||
if (error) {
|
||||
[self deauthorize];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
|
||||
_downloadDirectory = nil;
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
|
@ -394,6 +534,7 @@ static uint32_t color_to_int(NSColor *color)
|
|||
}
|
||||
[[NSFileManager defaultManager] moveItemAtPath:updateContentsPath toPath:contentsPath error:&error];
|
||||
if (error) {
|
||||
[self deauthorize];
|
||||
[[NSFileManager defaultManager] moveItemAtPath:contentsTempPath toPath:contentsPath error:nil];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
|
||||
_downloadDirectory = nil;
|
||||
|
@ -440,6 +581,84 @@ static uint32_t color_to_int(NSColor *color)
|
|||
}
|
||||
}
|
||||
|
||||
- (void)orderFrontAboutPanel:(id)sender
|
||||
{
|
||||
// NSAboutPanelOptionApplicationIcon is not available prior to 10.13, but the key is still there and working.
|
||||
[[NSApplication sharedApplication] orderFrontStandardAboutPanelWithOptions:@{
|
||||
@"ApplicationIcon": [NSImage imageNamed:@"Icon"]
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)controller:(JOYController *)controller buttonChangedState:(JOYButton *)button
|
||||
{
|
||||
if (!button.isPressed) return;
|
||||
NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"JoyKitInstanceMapping"][controller.uniqueID];
|
||||
if (!mapping) {
|
||||
mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"JoyKitNameMapping"][controller.deviceName];
|
||||
}
|
||||
|
||||
JOYButtonUsage usage = ((JOYButtonUsage)[mapping[n2s(button.uniqueID)] unsignedIntValue]) ?: -1;
|
||||
if (!mapping && usage >= JOYButtonUsageGeneric0) {
|
||||
usage = GB_inline_const(JOYButtonUsage[], {JOYButtonUsageY, JOYButtonUsageA, JOYButtonUsageB, JOYButtonUsageX})[(usage - JOYButtonUsageGeneric0) & 3];
|
||||
}
|
||||
|
||||
if (usage == GBJoyKitHotkey1 || usage == GBJoyKitHotkey2) {
|
||||
if (_preferencesWindow && self.keyWindow == _preferencesWindow) {
|
||||
return;
|
||||
}
|
||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"GBAllowBackgroundControllers"] && !self.keyWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *keyEquivalent = [[NSUserDefaults standardUserDefaults] stringForKey:usage == GBJoyKitHotkey1? @"GBJoypadHotkey1" : @"GBJoypadHotkey2"];
|
||||
NSEventModifierFlags flags = NSEventModifierFlagCommand;
|
||||
if ([keyEquivalent hasPrefix:@"^"]) {
|
||||
flags |= NSEventModifierFlagShift;
|
||||
[keyEquivalent substringFromIndex:1];
|
||||
}
|
||||
_simulatingMenuEvent = true;
|
||||
[[NSApplication sharedApplication] sendEvent:[NSEvent keyEventWithType:NSEventTypeKeyDown
|
||||
location:(NSPoint){0,}
|
||||
modifierFlags:flags
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:NULL
|
||||
characters:keyEquivalent
|
||||
charactersIgnoringModifiers:keyEquivalent
|
||||
isARepeat:false
|
||||
keyCode:0]];
|
||||
_simulatingMenuEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSWindow *)keyWindow
|
||||
{
|
||||
NSWindow *ret = [super keyWindow];
|
||||
if (!ret && _simulatingMenuEvent) {
|
||||
ret = [(Document *)self.orderedDocuments.firstObject mainWindow];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (NSWindow *)mainWindow
|
||||
{
|
||||
NSWindow *ret = [super mainWindow];
|
||||
if (!ret && _simulatingMenuEvent) {
|
||||
ret = [(Document *)self.orderedDocuments.firstObject mainWindow];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (IBAction)openDebuggerHelp:(id)sender
|
||||
{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://sameboy.github.io/debugger/"]];
|
||||
}
|
||||
|
||||
- (IBAction)openSponsor:(id)sender
|
||||
{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://github.com/sponsors/LIJI32"]];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_downloadDirectory) {
|
|
@ -1,7 +1,4 @@
|
|||
#ifndef GBButtons_h
|
||||
#define GBButtons_h
|
||||
|
||||
typedef enum : NSUInteger {
|
||||
typedef enum {
|
||||
GBRight,
|
||||
GBLeft,
|
||||
GBUp,
|
||||
|
@ -13,11 +10,17 @@ typedef enum : NSUInteger {
|
|||
GBTurbo,
|
||||
GBRewind,
|
||||
GBUnderclock,
|
||||
GBButtonCount,
|
||||
GBHotkey1,
|
||||
GBHotkey2,
|
||||
GBJoypadButtonCount,
|
||||
GBButtonCount = GBUnderclock + 1,
|
||||
GBGameBoyButtonCount = GBStart + 1,
|
||||
} GBButton;
|
||||
|
||||
extern NSString const *GBButtonNames[GBButtonCount];
|
||||
#define GBJoyKitHotkey1 JOYButtonUsageGeneric0 + 0x100
|
||||
#define GBJoyKitHotkey2 JOYButtonUsageGeneric0 + 0x101
|
||||
|
||||
extern NSString const *GBButtonNames[GBJoypadButtonCount];
|
||||
|
||||
static inline NSString *n2s(uint64_t number)
|
||||
{
|
||||
|
@ -31,5 +34,3 @@ static inline NSString *button_to_preference_name(GBButton button, unsigned play
|
|||
}
|
||||
return [NSString stringWithFormat:@"GB%@", GBButtonNames[button]];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "GBButtons.h"
|
||||
|
||||
NSString const *GBButtonNames[] = {@"Right", @"Left", @"Up", @"Down", @"A", @"B", @"Select", @"Start", @"Turbo", @"Rewind", @"Slow-Motion"};
|
||||
NSString const *GBButtonNames[] = {@"Right", @"Left", @"Up", @"Down", @"A", @"B", @"Select", @"Start", @"Turbo", @"Rewind", @"Slow-Motion", @"Hotkey 1", @"Hotkey 2"};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
@implementation GBCheatTextView
|
||||
|
||||
- (bool)_insertText:(NSString *)string replacementRange:(NSRange)range
|
||||
- (bool)_internalInsertText:(NSString *)string replacementRange:(NSRange)range
|
||||
{
|
||||
if (range.location == NSNotFound) {
|
||||
range = self.selectedRange;
|
||||
|
@ -60,19 +60,19 @@
|
|||
return true;
|
||||
}
|
||||
if (([string isEqualToString:@"$"] || [string isEqualToString:@":"]) && range.length == 0 && range.location == 0) {
|
||||
if ([self _insertText:@"$00:" replacementRange:range]) {
|
||||
if ([self _internalInsertText:@"$00:" replacementRange:range]) {
|
||||
self.selectedRange = NSMakeRange(1, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ([string isEqualToString:@":"] && range.length + range.location == self.string.length) {
|
||||
if ([self _insertText:@":$0" replacementRange:range]) {
|
||||
if ([self _internalInsertText:@":$0" replacementRange:range]) {
|
||||
self.selectedRange = NSMakeRange(self.string.length - 2, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ([string isEqualToString:@"$"]) {
|
||||
if ([self _insertText:@"$0" replacementRange:range]) {
|
||||
if ([self _internalInsertText:@"$0" replacementRange:range]) {
|
||||
self.selectedRange = NSMakeRange(range.location + 1, 1);
|
||||
return true;
|
||||
}
|
||||
|
@ -88,8 +88,10 @@
|
|||
|
||||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
if (![self _insertText:string replacementRange:replacementRange]) {
|
||||
NSBeep();
|
||||
if (![self _internalInsertText:string replacementRange:replacementRange]) {
|
||||
if (![self _internalInsertText:[@"$" stringByAppendingString:string] replacementRange:replacementRange]) {
|
||||
NSBeep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
size_t cheatCount;
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
|
@ -58,7 +58,7 @@
|
|||
return @NO;
|
||||
|
||||
case 2:
|
||||
return @"Add Cheat...";
|
||||
return @"Add Cheat…";
|
||||
|
||||
case 3:
|
||||
return @"";
|
||||
|
@ -92,14 +92,18 @@
|
|||
self.importCodeField.stringValue.UTF8String,
|
||||
self.importDescriptionField.stringValue.UTF8String,
|
||||
true)) {
|
||||
self.importCodeField.stringValue = @"";
|
||||
self.importDescriptionField.stringValue = @"";
|
||||
[self.cheatsTable reloadData];
|
||||
[self tableViewSelectionDidChange:nil];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.importCodeField.stringValue = @"";
|
||||
self.importDescriptionField.stringValue = @"";
|
||||
[self.cheatsTable reloadData];
|
||||
[self tableViewSelectionDidChange:nil];
|
||||
});
|
||||
}
|
||||
else {
|
||||
NSBeep();
|
||||
[GBWarningPopover popoverWithContents:@"This code is not a valid GameShark or GameGenie code" onView:self.importCodeField];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSBeep();
|
||||
[GBWarningPopover popoverWithContents:@"This code is not a valid GameShark or GameGenie code" onView:self.importCodeField];
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBColorCell : NSTextFieldCell
|
||||
|
||||
@end
|
|
@ -1,49 +0,0 @@
|
|||
#import "GBColorCell.h"
|
||||
|
||||
static inline double scale_channel(uint8_t x)
|
||||
{
|
||||
x &= 0x1f;
|
||||
return x / 31.0;
|
||||
}
|
||||
|
||||
@implementation GBColorCell
|
||||
{
|
||||
NSInteger _integerValue;
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)objectValue
|
||||
{
|
||||
_integerValue = [objectValue integerValue];
|
||||
uint8_t r = _integerValue & 0x1F,
|
||||
g = (_integerValue >> 5) & 0x1F,
|
||||
b = (_integerValue >> 10) & 0x1F;
|
||||
super.objectValue = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"$%04x", (uint16_t)(_integerValue & 0x7FFF)] attributes:@{
|
||||
NSForegroundColorAttributeName: r * 3 + g * 4 + b * 2 > 120? [NSColor blackColor] : [NSColor whiteColor],
|
||||
NSFontAttributeName: [NSFont userFixedPitchFontOfSize:12]
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSInteger)integerValue
|
||||
{
|
||||
return _integerValue;
|
||||
}
|
||||
|
||||
- (int)intValue
|
||||
{
|
||||
return (int)_integerValue;
|
||||
}
|
||||
|
||||
|
||||
- (NSColor *) backgroundColor
|
||||
{
|
||||
/* Todo: color correction */
|
||||
uint16_t color = self.integerValue;
|
||||
return [NSColor colorWithRed:scale_channel(color) green:scale_channel(color >> 5) blue:scale_channel(color >> 10) alpha:1.0];
|
||||
}
|
||||
|
||||
- (BOOL)drawsBackground
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,7 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class GBDocument;
|
||||
@interface GBDebuggerButton : NSButton
|
||||
@property (weak) IBOutlet NSTextField *textField;
|
||||
@end
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#import "GBDebuggerButton.h"
|
||||
|
||||
@implementation GBDebuggerButton
|
||||
{
|
||||
NSTrackingArea *_trackingArea;
|
||||
}
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
self.toolTip = self.title;
|
||||
self.imagePosition = NSImageOnly; // Newer versions of AppKit refuse to respect the value from the nib file
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(NSEvent *)event
|
||||
{
|
||||
if (@available(macOS 10.10, *)) {
|
||||
NSDictionary *attributes = @{
|
||||
NSForegroundColorAttributeName: [NSColor colorWithWhite:1.0 alpha:0.5],
|
||||
NSFontAttributeName: self.textField.font
|
||||
};
|
||||
self.textField.placeholderAttributedString =
|
||||
[[NSAttributedString alloc] initWithString:self.alternateTitle attributes:attributes];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent *)event
|
||||
{
|
||||
if (@available(macOS 10.10, *)) {
|
||||
if ([self.textField.placeholderAttributedString.string isEqualToString:self.alternateTitle]) {
|
||||
self.textField.placeholderAttributedString = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
[super updateTrackingAreas];
|
||||
if (_trackingArea) {
|
||||
[self removeTrackingArea:_trackingArea];
|
||||
}
|
||||
|
||||
_trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
|
||||
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:_trackingArea];
|
||||
}
|
||||
@end
|
|
@ -163,7 +163,7 @@ void main(void) {\n\
|
|||
|
||||
/* OpenGL is black magic. Closing one view causes others to be completely black unless we reload their shaders */
|
||||
/* We're probably not freeing thing in the right place. */
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBFilterChanged" object:nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBFilterChanged$DefaultsObserver" object:nil];
|
||||
}
|
||||
|
||||
+ (GLuint)shaderWithContents:(NSString*)contents type:(GLenum)type
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#import <Core/gb.h>
|
||||
#import <HexFiend/HFRepresenter.h>
|
||||
|
||||
|
||||
@interface GBHexStatusBarRepresenter : HFRepresenter
|
||||
@property GB_gameboy_t *gb;
|
||||
@property (nonatomic) bool useDecimalLength;
|
||||
@property (nonatomic) uint16_t bankForDescription;
|
||||
@property (nonatomic) uint16_t baseAddress;
|
||||
@end
|
|
@ -0,0 +1,220 @@
|
|||
#import "GBHexStatusBarRepresenter.h"
|
||||
#import <HexFiend/HFFunctions.h>
|
||||
|
||||
@interface GBHexStatusBarView : NSView
|
||||
{
|
||||
NSCell *_cell;
|
||||
NSSize _cellSize;
|
||||
GBHexStatusBarRepresenter *_representer;
|
||||
NSDictionary *_cellAttributes;
|
||||
bool _registeredForAppNotifications;
|
||||
}
|
||||
|
||||
- (void)setRepresenter:(GBHexStatusBarRepresenter *)rep;
|
||||
- (void)setString:(NSString *)string;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation GBHexStatusBarView
|
||||
|
||||
- (void)_sharedInitStatusBarView
|
||||
{
|
||||
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||
[style setAlignment:NSCenterTextAlignment];
|
||||
style.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||
_cellAttributes = @{
|
||||
NSForegroundColorAttributeName: [NSColor windowFrameTextColor],
|
||||
NSFontAttributeName: [NSFont labelFontOfSize:[NSFont smallSystemFontSize]],
|
||||
NSParagraphStyleAttributeName: style,
|
||||
};
|
||||
_cell = [[NSCell alloc] initTextCell:@""];
|
||||
[_cell setAlignment:NSCenterTextAlignment];
|
||||
[_cell setBackgroundStyle:NSBackgroundStyleRaised];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(NSRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
[self _sharedInitStatusBarView];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
[self _sharedInitStatusBarView];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isFlipped
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)setRepresenter:(GBHexStatusBarRepresenter *)rep
|
||||
{
|
||||
_representer = rep;
|
||||
}
|
||||
|
||||
- (void)setString:(NSString *)string
|
||||
{
|
||||
[_cell setAttributedStringValue:[[NSAttributedString alloc] initWithString:string attributes:_cellAttributes]];
|
||||
_cellSize = [_cell cellSize];
|
||||
[self setNeedsDisplay:true];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)clip
|
||||
{
|
||||
NSRect bounds = [self bounds];
|
||||
NSRect cellRect = NSMakeRect(NSMinX(bounds), HFCeil(NSMidY(bounds) - _cellSize.height / 2), NSWidth(bounds), _cellSize.height);
|
||||
[_cell drawWithFrame:cellRect inView:self];
|
||||
}
|
||||
|
||||
- (void)setFrame:(NSRect)frame
|
||||
{
|
||||
[super setFrame:frame];
|
||||
[self.window setContentBorderThickness:frame.origin.y + frame.size.height forEdge:NSMinYEdge];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)event
|
||||
{
|
||||
_representer.useDecimalLength ^= true;
|
||||
}
|
||||
|
||||
- (void)windowDidChangeKeyStatus:(NSNotification *)note
|
||||
{
|
||||
[self setNeedsDisplay:true];
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
HFRegisterViewForWindowAppearanceChanges(self, @selector(windowDidChangeKeyStatus:), !_registeredForAppNotifications);
|
||||
_registeredForAppNotifications = true;
|
||||
[self.window setContentBorderThickness:self.frame.origin.y + self.frame.size.height forEdge:NSMinYEdge];
|
||||
[super viewDidMoveToWindow];
|
||||
}
|
||||
|
||||
- (void)viewWillMoveToWindow:(NSWindow *)newWindow
|
||||
{
|
||||
HFUnregisterViewForWindowAppearanceChanges(self, NO);
|
||||
[super viewWillMoveToWindow:newWindow];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
HFUnregisterViewForWindowAppearanceChanges(self, _registeredForAppNotifications);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GBHexStatusBarRepresenter
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSView *)createView {
|
||||
GBHexStatusBarView *view = [[GBHexStatusBarView alloc] initWithFrame:NSMakeRect(0, 0, 100, 18)];
|
||||
[view setRepresenter:self];
|
||||
[view setAutoresizingMask:NSViewWidthSizable];
|
||||
return view;
|
||||
}
|
||||
|
||||
- (NSString *)describeLength:(unsigned long long)length
|
||||
{
|
||||
if (self.useDecimalLength) {
|
||||
return [NSString stringWithFormat:@"%llu byte%s", length, length == 1 ? "" : "s"];
|
||||
}
|
||||
return [NSString stringWithFormat:@"$%llX byte%s", length, length == 1 ? "" : "s"];
|
||||
}
|
||||
|
||||
- (NSString *)describeOffset:(unsigned long long)offset isRangeEnd:(bool)isRangeEnd
|
||||
{
|
||||
if (!_gb) {
|
||||
return [NSString stringWithFormat:@"$%llX", offset];
|
||||
}
|
||||
return @(GB_debugger_describe_address(_gb, offset + _baseAddress, _bankForDescription, false, isRangeEnd));
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)stringForEmptySelectionAtOffset:(unsigned long long)offset length:(unsigned long long)length
|
||||
{
|
||||
return [self describeOffset:offset isRangeEnd:false];
|
||||
}
|
||||
|
||||
- (NSString *)stringForSingleByteSelectionAtOffset:(unsigned long long)offset length:(unsigned long long)length
|
||||
{
|
||||
return [NSString stringWithFormat:@"Byte %@ selected", [self describeOffset:offset isRangeEnd:false]];
|
||||
}
|
||||
|
||||
- (NSString *)stringForSingleRangeSelection:(HFRange)range length:(unsigned long long)length
|
||||
{
|
||||
return [NSString stringWithFormat:@"Range %@ to %@ selected (%@)",
|
||||
[self describeOffset:range.location isRangeEnd:false],
|
||||
[self describeOffset:range.location + range.length isRangeEnd:true],
|
||||
[self describeLength:range.length]];
|
||||
}
|
||||
|
||||
|
||||
- (void)updateString
|
||||
{
|
||||
NSString *string = nil;
|
||||
HFController *controller = [self controller];
|
||||
if (controller) {
|
||||
unsigned long long length = [controller contentsLength];
|
||||
NSArray *ranges = [controller selectedContentsRanges];
|
||||
NSUInteger rangeCount = [ranges count];
|
||||
if (rangeCount == 1) {
|
||||
HFRange range = [ranges[0] HFRange];
|
||||
if (range.length == 0) {
|
||||
string = [self stringForEmptySelectionAtOffset:range.location length:length];
|
||||
}
|
||||
else if (range.length == 1) {
|
||||
string = [self stringForSingleByteSelectionAtOffset:range.location length:length];
|
||||
}
|
||||
else {
|
||||
string = [self stringForSingleRangeSelection:range length:length];
|
||||
}
|
||||
}
|
||||
else {
|
||||
string = @"Multiple ranges selected";
|
||||
}
|
||||
}
|
||||
if (! string) string = @"";
|
||||
[[self view] setString:string];
|
||||
}
|
||||
|
||||
- (void)setUseDecimalLength:(bool)useDecimalLength
|
||||
{
|
||||
_useDecimalLength = useDecimalLength;
|
||||
[self updateString];
|
||||
}
|
||||
|
||||
- (void)setBaseAddress:(uint16_t)baseAddress
|
||||
{
|
||||
_baseAddress = baseAddress;
|
||||
[self updateString];
|
||||
}
|
||||
|
||||
- (void) setBankForDescription:(uint16_t)bankForDescription
|
||||
{
|
||||
_bankForDescription = bankForDescription;
|
||||
[self updateString];
|
||||
}
|
||||
|
||||
- (void)controllerDidChange:(HFControllerPropertyBits)bits
|
||||
{
|
||||
if (bits & (HFControllerContentLength | HFControllerSelectedRanges)) {
|
||||
[self updateString];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSPoint)defaultLayoutPosition
|
||||
{
|
||||
return NSMakePoint(0, -1);
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,5 +0,0 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBImageCell : NSImageCell
|
||||
|
||||
@end
|
|
@ -1,10 +0,0 @@
|
|||
#import "GBImageCell.h"
|
||||
|
||||
@implementation GBImageCell
|
||||
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
|
||||
{
|
||||
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
|
||||
[super drawWithFrame:cellFrame inView:controlView];
|
||||
}
|
||||
@end
|
|
@ -10,18 +10,18 @@
|
|||
}
|
||||
@end
|
||||
|
||||
@implementation GBImageView
|
||||
{
|
||||
NSTrackingArea *trackingArea;
|
||||
}
|
||||
@interface GBGridView : NSView
|
||||
@end
|
||||
|
||||
@implementation GBGridView
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
|
||||
[super drawRect:dirtyRect];
|
||||
CGFloat y_ratio = self.frame.size.height / self.image.size.height;
|
||||
CGFloat x_ratio = self.frame.size.width / self.image.size.width;
|
||||
for (GBImageViewGridConfiguration *conf in self.verticalGrids) {
|
||||
GBImageView *parent = (GBImageView *)self.superview;
|
||||
|
||||
CGFloat y_ratio = parent.frame.size.height / parent.image.size.height;
|
||||
CGFloat x_ratio = parent.frame.size.width / parent.image.size.width;
|
||||
for (GBImageViewGridConfiguration *conf in parent.verticalGrids) {
|
||||
[conf.color set];
|
||||
for (CGFloat y = conf.size * y_ratio; y < self.frame.size.height; y += conf.size * y_ratio) {
|
||||
NSBezierPath *line = [NSBezierPath bezierPath];
|
||||
|
@ -32,7 +32,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
for (GBImageViewGridConfiguration *conf in self.horizontalGrids) {
|
||||
for (GBImageViewGridConfiguration *conf in parent.horizontalGrids) {
|
||||
[conf.color set];
|
||||
for (CGFloat x = conf.size * x_ratio; x < self.frame.size.width; x += conf.size * x_ratio) {
|
||||
NSBezierPath *line = [NSBezierPath bezierPath];
|
||||
|
@ -43,11 +43,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (self.displayScrollRect) {
|
||||
if (parent.displayScrollRect) {
|
||||
NSBezierPath *path = [NSBezierPath bezierPathWithRect:CGRectInfinite];
|
||||
for (unsigned x = 0; x < 2; x++) {
|
||||
for (unsigned y = 0; y < 2; y++) {
|
||||
NSRect rect = self.scrollRect;
|
||||
NSRect rect = parent.scrollRect;
|
||||
rect.origin.x *= x_ratio;
|
||||
rect.origin.y *= y_ratio;
|
||||
rect.size.width *= x_ratio;
|
||||
|
@ -56,7 +56,7 @@
|
|||
|
||||
rect.origin.x -= self.frame.size.width * x;
|
||||
rect.origin.y += self.frame.size.height * y;
|
||||
|
||||
|
||||
|
||||
NSBezierPath *subpath = [NSBezierPath bezierPathWithRect:rect];
|
||||
[path appendBezierPath:subpath];
|
||||
|
@ -72,36 +72,62 @@
|
|||
[path stroke];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GBImageView
|
||||
{
|
||||
NSTrackingArea *_trackingArea;
|
||||
GBGridView *_gridView;
|
||||
NSRect _scrollRect;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
self.wantsLayer = true;
|
||||
_gridView = [[GBGridView alloc] initWithFrame:self.bounds];
|
||||
_gridView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
[self addSubview:_gridView];
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)viewWillDraw
|
||||
{
|
||||
[super viewWillDraw];
|
||||
for (CALayer *layer in self.layer.sublayers) {
|
||||
layer.magnificationFilter = kCAFilterNearest;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setHorizontalGrids:(NSArray *)horizontalGrids
|
||||
{
|
||||
self->_horizontalGrids = horizontalGrids;
|
||||
[self setNeedsDisplay];
|
||||
[_gridView setNeedsDisplay:true];
|
||||
}
|
||||
|
||||
- (void)setVerticalGrids:(NSArray *)verticalGrids
|
||||
{
|
||||
self->_verticalGrids = verticalGrids;
|
||||
[self setNeedsDisplay];
|
||||
[_gridView setNeedsDisplay:true];
|
||||
}
|
||||
|
||||
- (void)setDisplayScrollRect:(bool)displayScrollRect
|
||||
{
|
||||
self->_displayScrollRect = displayScrollRect;
|
||||
[self setNeedsDisplay];
|
||||
[_gridView setNeedsDisplay:true];
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
if (trackingArea != nil) {
|
||||
[self removeTrackingArea:trackingArea];
|
||||
if (_trackingArea != nil) {
|
||||
[self removeTrackingArea:_trackingArea];
|
||||
}
|
||||
|
||||
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
|
||||
_trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
|
||||
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingMouseMoved
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:trackingArea];
|
||||
[self addTrackingArea:_trackingArea];
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent *)theEvent
|
||||
|
@ -124,4 +150,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setScrollRect:(NSRect)scrollRect
|
||||
{
|
||||
if (memcmp(&scrollRect, &_scrollRect, sizeof(scrollRect)) != 0) {
|
||||
_scrollRect = scrollRect;
|
||||
[_gridView setNeedsDisplay:true];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSRect)scrollRect
|
||||
{
|
||||
return _scrollRect;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <JoyKit/JoyKit.h>
|
||||
|
||||
@interface GBJoyConManager : NSObject<JOYListener, NSTableViewDataSource, NSTableViewDelegate>
|
||||
+ (instancetype)sharedInstance;
|
||||
- (IBAction)autopair:(id)sender;
|
||||
|
||||
@property (nonatomic) bool arrangementMode;
|
||||
@property (weak) IBOutlet NSTableView *tableView;
|
||||
@end
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
#import "GBJoyConManager.h"
|
||||
#import "GBTintedImageCell.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation GBJoyConManager
|
||||
{
|
||||
GBTintedImageCell *_tintedImageCell;
|
||||
NSImageCell *_imageCell;
|
||||
NSMutableDictionary<NSString *, NSString *> *_pairings;
|
||||
NSMutableDictionary<NSString *, NSNumber *> *_gripSettings;
|
||||
bool _unpairing;
|
||||
}
|
||||
|
||||
+ (instancetype)sharedInstance
|
||||
{
|
||||
static GBJoyConManager *manager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
manager = [[self alloc] _init];
|
||||
});
|
||||
return manager;
|
||||
}
|
||||
|
||||
- (NSArray <JOYController *> *)joycons
|
||||
{
|
||||
NSMutableArray *ret = [[JOYController allControllers] mutableCopy];
|
||||
for (JOYController *controller in [JOYController allControllers]) {
|
||||
if (controller.joyconType == JOYJoyConTypeNone) {
|
||||
[ret removeObject:controller];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self.class sharedInstance];
|
||||
}
|
||||
|
||||
- (instancetype) _init
|
||||
{
|
||||
self = [super init];
|
||||
_imageCell = [[NSImageCell alloc] init];
|
||||
_tintedImageCell = [[GBTintedImageCell alloc] init];
|
||||
if (@available(macOS 10.14, *)) {
|
||||
_tintedImageCell.tint = [NSColor controlAccentColor];
|
||||
}
|
||||
else {
|
||||
_tintedImageCell.tint = [NSColor selectedMenuItemColor];
|
||||
}
|
||||
_pairings = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoyConPairings"] ?: @{} mutableCopy];
|
||||
_gripSettings = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoyConGrips"] ?: @{} mutableCopy];
|
||||
|
||||
// Sanity check the pairings
|
||||
for (NSString *key in _pairings) {
|
||||
if (![_pairings[_pairings[key]] isEqualToString:key]) {
|
||||
[_pairings removeAllObjects];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[JOYController registerListener:self];
|
||||
for (JOYController *controller in [JOYController allControllers]) {
|
||||
[self controllerConnected:controller];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
return self.joycons.count;
|
||||
}
|
||||
|
||||
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
if (row >= [self numberOfRowsInTableView:tableView]) return nil;
|
||||
|
||||
unsigned columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
JOYController *controller = self.joycons[row];
|
||||
switch (columnIndex) {
|
||||
case 0: {
|
||||
switch (controller.joyconType) {
|
||||
case JOYJoyConTypeNone:
|
||||
return nil;
|
||||
case JOYJoyConTypeLeft:
|
||||
return [NSImage imageNamed:[NSString stringWithFormat:@"%sJoyConLeftTemplate", controller.usesHorizontalJoyConGrip? "Horizontal" :""]];
|
||||
case JOYJoyConTypeRight:
|
||||
return [NSImage imageNamed:[NSString stringWithFormat:@"%sJoyConRightTemplate", controller.usesHorizontalJoyConGrip? "Horizontal" :""]];
|
||||
case JOYJoyConTypeDual:
|
||||
return [NSImage imageNamed:@"JoyConDualTemplate"];
|
||||
}
|
||||
}
|
||||
case 1: {
|
||||
NSMutableAttributedString *ret = [[NSMutableAttributedString alloc] initWithString:controller.deviceName
|
||||
attributes:@{NSFontAttributeName:
|
||||
[NSFont systemFontOfSize:[NSFont systemFontSize]]}];
|
||||
|
||||
[ret appendAttributedString:[[NSAttributedString alloc] initWithString:[@"\n" stringByAppendingString:controller.uniqueID]
|
||||
attributes:@{NSFontAttributeName:
|
||||
[NSFont systemFontOfSize:[NSFont smallSystemFontSize]],
|
||||
NSForegroundColorAttributeName:[NSColor disabledControlTextColor]}]];
|
||||
return ret;
|
||||
}
|
||||
case 2:
|
||||
return @([(_gripSettings[controller.uniqueID] ?: @(-1)) unsignedIntValue] + 1);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)updateGripForController:(JOYController *)controller
|
||||
{
|
||||
NSNumber *grip = _gripSettings[controller.uniqueID];
|
||||
if (!grip) {
|
||||
controller.usesHorizontalJoyConGrip = [[NSUserDefaults standardUserDefaults] boolForKey:@"GBJoyConsDefaultsToHorizontal"];
|
||||
return;
|
||||
}
|
||||
controller.usesHorizontalJoyConGrip = [grip unsignedIntValue] == 1;
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
unsigned columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
if (columnIndex != 2) return;
|
||||
if (row >= [self numberOfRowsInTableView:tableView]) return;
|
||||
JOYController *controller = self.joycons[row];
|
||||
if (controller.joyconType == JOYJoyConTypeDual) {
|
||||
return;
|
||||
}
|
||||
switch ([object unsignedIntValue]) {
|
||||
case 0:
|
||||
[_gripSettings removeObjectForKey:controller.uniqueID];
|
||||
break;
|
||||
case 1:
|
||||
_gripSettings[controller.uniqueID] = @(0);
|
||||
break;
|
||||
case 2:
|
||||
_gripSettings[controller.uniqueID] = @(1);
|
||||
break;
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:_gripSettings forKey:@"GBJoyConGrips"];
|
||||
[self updateGripForController:controller];
|
||||
}
|
||||
|
||||
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
if (row >= [self numberOfRowsInTableView:tableView]) return [[NSCell alloc] init];
|
||||
|
||||
unsigned columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
if (columnIndex == 2) {
|
||||
JOYCombinedController *controller = (JOYCombinedController *)self.joycons[row];
|
||||
if (controller.joyconType == JOYJoyConTypeDual) {
|
||||
NSButtonCell *cell = [[NSButtonCell alloc] initTextCell:@"Separate Joy-Cons"];
|
||||
cell.bezelStyle = NSBezelStyleRounded;
|
||||
cell.action = @selector(invoke);
|
||||
id block = ^(void) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
for (JOYController *child in controller.children) {
|
||||
[_pairings removeObjectForKey:child.uniqueID];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:_pairings forKey:@"GBJoyConPairings"];
|
||||
_unpairing = true;
|
||||
[controller breakApart];
|
||||
_unpairing = false;
|
||||
});
|
||||
};
|
||||
// To retain the block
|
||||
objc_setAssociatedObject(cell, @selector(breakApart), block, OBJC_ASSOCIATION_RETAIN);
|
||||
cell.target = block;
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
if (columnIndex == 0) {
|
||||
JOYController *controller = self.joycons[row];
|
||||
for (JOYButton *button in controller.buttons) {
|
||||
if (button.isPressed) {
|
||||
return _tintedImageCell;
|
||||
}
|
||||
}
|
||||
return _imageCell;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)controllerConnected:(JOYController *)controller
|
||||
{
|
||||
[self updateGripForController:controller];
|
||||
for (JOYController *partner in [JOYController allControllers]) {
|
||||
if ([partner.uniqueID isEqualToString:_pairings[controller.uniqueID]]) {
|
||||
[self pairJoyCon:controller withJoyCon:partner];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (controller.joyconType == JOYJoyConTypeLeft || controller.joyconType == JOYJoyConTypeRight) {
|
||||
[self autopair:nil];
|
||||
}
|
||||
if (_arrangementMode) {
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)autopair:(id)sender
|
||||
{
|
||||
if (_unpairing) return;
|
||||
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"GBJoyConAutoPair"]) return;
|
||||
NSArray<JOYController *> *controllers = [[JOYController allControllers] copy];
|
||||
for (JOYController *first in controllers) {
|
||||
if (_pairings[first.uniqueID]) continue; // Has an established partner
|
||||
if (first.joyconType != JOYJoyConTypeLeft) continue;
|
||||
for (JOYController *second in controllers) {
|
||||
if (_pairings[second.uniqueID]) continue; // Has an established partner
|
||||
if (second.joyconType != JOYJoyConTypeRight) continue;
|
||||
[self pairJoyCon:first withJoyCon:second];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_arrangementMode) {
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)controllerDisconnected:(JOYController *)controller
|
||||
{
|
||||
if (_arrangementMode) {
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
unsigned columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
return columnIndex == 2;
|
||||
}
|
||||
|
||||
- (JOYCombinedController *)pairJoyCon:(JOYController *)first withJoyCon:(JOYController *)second
|
||||
{
|
||||
if (first.joyconType != JOYJoyConTypeLeft && first.joyconType != JOYJoyConTypeRight) return nil; // Not a Joy-Con
|
||||
if (second.joyconType != JOYJoyConTypeLeft && second.joyconType != JOYJoyConTypeRight) return nil; // Not a Joy-Con
|
||||
if (first.joyconType == second.joyconType) return nil; // Not a sensible pair
|
||||
|
||||
_pairings[first.uniqueID] = second.uniqueID;
|
||||
_pairings[second.uniqueID] = first.uniqueID;
|
||||
first.usesHorizontalJoyConGrip = false;
|
||||
second.usesHorizontalJoyConGrip = false;
|
||||
[[NSUserDefaults standardUserDefaults] setObject:_pairings forKey:@"GBJoyConPairings"];
|
||||
return [[JOYCombinedController alloc] initWithChildren:@[first, second]];
|
||||
}
|
||||
|
||||
- (void)controller:(JOYController *)controller buttonChangedState:(JOYButton *)button
|
||||
{
|
||||
if (!_arrangementMode) return;
|
||||
if (controller.joyconType == JOYJoyConTypeNone) return;
|
||||
[self.tableView setNeedsDisplay:true];
|
||||
if (controller.joyconType != JOYJoyConTypeLeft && controller.joyconType != JOYJoyConTypeRight) return;
|
||||
if (button.usage != JOYButtonUsageL1 && button.usage != JOYButtonUsageR1) return;
|
||||
|
||||
|
||||
// L or R were pressed on a single Joy-Con, try and pair available Joy-Cons
|
||||
JOYController *left = nil;
|
||||
JOYController *right = nil;
|
||||
for (JOYController *controller in [JOYController allControllers]) {
|
||||
if (!left && controller.joyconType == JOYJoyConTypeLeft) {
|
||||
for (JOYButton *button in controller.buttons) {
|
||||
if (button.usage == JOYButtonUsageL1 && button.isPressed) {
|
||||
left = controller;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!right && controller.joyconType == JOYJoyConTypeRight) {
|
||||
for (JOYButton *button in controller.buttons) {
|
||||
if (button.usage == JOYButtonUsageR1 && button.isPressed) {
|
||||
right = controller;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (left && right) {
|
||||
[self pairJoyCon:left withJoyCon:right];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)toggleHorizontalDefault:(NSButton *)sender
|
||||
{
|
||||
for (JOYController *controller in self.joycons) {
|
||||
[self updateGripForController:controller];
|
||||
}
|
||||
if (_arrangementMode) {
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setArrangementMode:(bool)arrangementMode
|
||||
{
|
||||
_arrangementMode = arrangementMode;
|
||||
if (arrangementMode) {
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,4 +1,3 @@
|
|||
#define GB_INTERNAL // Todo: Some memory accesses are being done using the struct directly
|
||||
#import "GBMemoryByteArray.h"
|
||||
#import "GBCompleteByteSlice.h"
|
||||
|
||||
|
@ -32,69 +31,110 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (uint16_t)base
|
||||
{
|
||||
switch (_mode) {
|
||||
case GBMemoryEntireSpace: return 0;
|
||||
case GBMemoryROM: return 0;
|
||||
case GBMemoryVRAM: return 0x8000;
|
||||
case GBMemoryExternalRAM: return 0xA000;
|
||||
case GBMemoryRAM: return 0xC000;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)copyBytes:(unsigned char *)dst range:(HFRange)range
|
||||
{
|
||||
__block uint16_t addr = (uint16_t) range.location;
|
||||
__block unsigned long long length = range.length;
|
||||
if (_mode == GBMemoryEntireSpace) {
|
||||
while (length) {
|
||||
*(dst++) = [_document readMemory:addr++];
|
||||
length--;
|
||||
}
|
||||
// Do everything in 0x1000 chunks, never cross a 0x1000 boundary
|
||||
if ((range.location & 0xF000) != ((range.location + range.length) & 0xF000)) {
|
||||
size_t partial = 0x1000 - (range.location & 0xFFF);
|
||||
[self copyBytes:dst + partial range:HFRangeMake(range.location + partial, range.length - partial)];
|
||||
range.length = partial;
|
||||
}
|
||||
else {
|
||||
[_document performAtomicBlock:^{
|
||||
unsigned char *_dst = dst;
|
||||
uint16_t bank_backup = 0;
|
||||
GB_gameboy_t *gb = _document.gameboy;
|
||||
switch (_mode) {
|
||||
case GBMemoryROM:
|
||||
bank_backup = gb->mbc_rom_bank;
|
||||
gb->mbc_rom_bank = self.selectedBank;
|
||||
break;
|
||||
case GBMemoryVRAM:
|
||||
bank_backup = gb->cgb_vram_bank;
|
||||
if (GB_is_cgb(gb)) {
|
||||
gb->cgb_vram_bank = self.selectedBank;
|
||||
range.location += self.base;
|
||||
|
||||
GB_gameboy_t *gb = _document.gameboy;
|
||||
|
||||
switch (range.location >> 12) {
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x3: {
|
||||
uint16_t bank;
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_ROM0, NULL, &bank);
|
||||
memcpy(dst, data + bank * 0x4000 + range.location, range.length);
|
||||
break;
|
||||
}
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7: {
|
||||
uint16_t bank;
|
||||
size_t size;
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_ROM, &size, &bank);
|
||||
if (_mode != GBMemoryEntireSpace) {
|
||||
bank = self.selectedBank & (size / 0x4000 - 1);
|
||||
}
|
||||
memcpy(dst, data + bank * 0x4000 + range.location - 0x4000, range.length);
|
||||
break;
|
||||
}
|
||||
case 0x8:
|
||||
case 0x9: {
|
||||
uint16_t bank;
|
||||
size_t size;
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_VRAM, &size, &bank);
|
||||
if (_mode != GBMemoryEntireSpace) {
|
||||
bank = self.selectedBank & (size / 0x2000 - 1);
|
||||
}
|
||||
memcpy(dst, data + bank * 0x2000 + range.location - 0x8000, range.length);
|
||||
break;
|
||||
}
|
||||
case 0xA:
|
||||
case 0xB: {
|
||||
// Some carts are special, use memory read directly in full mem mode
|
||||
if (_mode == GBMemoryEntireSpace) {
|
||||
case 0xF:
|
||||
slow_path:
|
||||
[_document performAtomicBlock:^{
|
||||
for (unsigned i = 0; i < range.length; i++) {
|
||||
dst[i] = GB_safe_read_memory(gb, range.location + i);
|
||||
}
|
||||
addr += 0x8000;
|
||||
break;
|
||||
case GBMemoryExternalRAM:
|
||||
bank_backup = gb->mbc_ram_bank;
|
||||
gb->mbc_ram_bank = self.selectedBank;
|
||||
addr += 0xA000;
|
||||
break;
|
||||
case GBMemoryRAM:
|
||||
bank_backup = gb->cgb_ram_bank;
|
||||
if (GB_is_cgb(gb)) {
|
||||
gb->cgb_ram_bank = self.selectedBank;
|
||||
}
|
||||
addr += 0xC000;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}];
|
||||
break;
|
||||
}
|
||||
while (length) {
|
||||
*(_dst++) = [_document readMemory:addr++];
|
||||
length--;
|
||||
else {
|
||||
uint16_t bank;
|
||||
size_t size;
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_CART_RAM, &size, &bank);
|
||||
bank = self.selectedBank & (size / 0x2000 - 1);
|
||||
if (size == 0) {
|
||||
memset(dst, 0xFF, range.length);
|
||||
}
|
||||
else if (range.location + range.length - 0xA000 > size) {
|
||||
goto slow_path;
|
||||
}
|
||||
else {
|
||||
memcpy(dst, data + bank * 0x2000 + range.location - 0xA000, range.length);
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (_mode) {
|
||||
case GBMemoryROM:
|
||||
gb->mbc_rom_bank = bank_backup;
|
||||
break;
|
||||
case GBMemoryVRAM:
|
||||
gb->cgb_vram_bank = bank_backup;
|
||||
break;
|
||||
case GBMemoryExternalRAM:
|
||||
gb->mbc_ram_bank = bank_backup;
|
||||
break;
|
||||
case GBMemoryRAM:
|
||||
gb->cgb_ram_bank = bank_backup;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
case 0xC:
|
||||
case 0xE: {
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_RAM, NULL, NULL);
|
||||
memcpy(dst, data + (range.location & 0xFFF), range.length);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xD: {
|
||||
uint16_t bank;
|
||||
size_t size;
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_RAM, &size, &bank);
|
||||
if (_mode != GBMemoryEntireSpace) {
|
||||
bank = self.selectedBank & (size / 0x1000 - 1);
|
||||
}
|
||||
}];
|
||||
memcpy(dst, data + bank * 0x1000 + range.location - 0xD000, range.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,65 +153,104 @@
|
|||
return ret;
|
||||
}
|
||||
|
||||
- (void)insertByteSlice:(HFByteSlice *)slice inRange:(HFRange)lrange
|
||||
- (void)insertByteSlice:(HFByteSlice *)slice inRange:(HFRange)range
|
||||
{
|
||||
if (slice.length != lrange.length) return; /* Insertion is not allowed, only overwriting. */
|
||||
[_document performAtomicBlock:^{
|
||||
uint16_t addr = (uint16_t) lrange.location;
|
||||
uint16_t bank_backup = 0;
|
||||
GB_gameboy_t *gb = _document.gameboy;
|
||||
switch (_mode) {
|
||||
case GBMemoryROM:
|
||||
bank_backup = gb->mbc_rom_bank;
|
||||
gb->mbc_rom_bank = self.selectedBank;
|
||||
if (slice.length != range.length) return; /* Insertion is not allowed, only overwriting. */
|
||||
// Do everything in 0x1000 chunks, never cross a 0x1000 boundary
|
||||
if ((range.location & 0xF000) != ((range.location + range.length) & 0xF000)) {
|
||||
size_t partial = 0x1000 - (range.location & 0xFFF);
|
||||
if (slice.length - partial) {
|
||||
[self insertByteSlice:[slice subsliceWithRange:HFRangeMake(partial, slice.length - partial)]
|
||||
inRange:HFRangeMake(range.location + partial, range.length - partial)];
|
||||
}
|
||||
range.length = partial;
|
||||
}
|
||||
range.location += self.base;
|
||||
|
||||
GB_gameboy_t *gb = _document.gameboy;
|
||||
|
||||
|
||||
switch (range.location >> 12) {
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x3:
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7: {
|
||||
return; // ROM not writeable
|
||||
}
|
||||
case 0x8:
|
||||
case 0x9: {
|
||||
uint16_t bank;
|
||||
size_t size;
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_VRAM, &size, &bank);
|
||||
if (_mode != GBMemoryEntireSpace) {
|
||||
bank = self.selectedBank & (size / 0x2000 - 1);
|
||||
}
|
||||
uint8_t sliceData[range.length];
|
||||
[slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
|
||||
memcpy(data + bank * 0x2000 + range.location - 0x8000, sliceData, range.length);
|
||||
break;
|
||||
}
|
||||
case 0xA:
|
||||
case 0xB: {
|
||||
// Some carts are special, use memory write directly in full mem mode
|
||||
if (_mode == GBMemoryEntireSpace) {
|
||||
case 0xF:
|
||||
slow_path:
|
||||
[_document performAtomicBlock:^{
|
||||
uint8_t sliceData[range.length];
|
||||
[slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
|
||||
for (unsigned i = 0; i < range.length; i++) {
|
||||
GB_write_memory(gb, range.location + i, sliceData[i]);
|
||||
}
|
||||
}];
|
||||
break;
|
||||
case GBMemoryVRAM:
|
||||
bank_backup = gb->cgb_vram_bank;
|
||||
if (GB_is_cgb(gb)) {
|
||||
gb->cgb_vram_bank = self.selectedBank;
|
||||
}
|
||||
else {
|
||||
uint16_t bank;
|
||||
size_t size;
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_CART_RAM, &size, &bank);
|
||||
bank = self.selectedBank & (size / 0x2000 - 1);
|
||||
if (size == 0) {
|
||||
// Nothing to write to
|
||||
}
|
||||
addr += 0x8000;
|
||||
break;
|
||||
case GBMemoryExternalRAM:
|
||||
bank_backup = gb->mbc_ram_bank;
|
||||
gb->mbc_ram_bank = self.selectedBank;
|
||||
addr += 0xA000;
|
||||
break;
|
||||
case GBMemoryRAM:
|
||||
bank_backup = gb->cgb_ram_bank;
|
||||
if (GB_is_cgb(gb)) {
|
||||
gb->cgb_ram_bank = self.selectedBank;
|
||||
else if (range.location + range.length - 0xA000 > size) {
|
||||
goto slow_path;
|
||||
}
|
||||
else {
|
||||
uint8_t sliceData[range.length];
|
||||
[slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
|
||||
memcpy(data + bank * 0x2000 + range.location - 0xA000, sliceData, range.length);
|
||||
}
|
||||
addr += 0xC000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint8_t values[lrange.length];
|
||||
[slice copyBytes:values range:HFRangeMake(0, lrange.length)];
|
||||
uint8_t *src = values;
|
||||
unsigned long long length = lrange.length;
|
||||
while (length) {
|
||||
[_document writeMemory:addr++ value:*(src++)];
|
||||
length--;
|
||||
case 0xC:
|
||||
case 0xE: {
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_RAM, NULL, NULL);
|
||||
uint8_t sliceData[range.length];
|
||||
[slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
|
||||
memcpy(data + (range.location & 0xFFF), sliceData, range.length);
|
||||
break;
|
||||
}
|
||||
switch (_mode) {
|
||||
case GBMemoryROM:
|
||||
gb->mbc_rom_bank = bank_backup;
|
||||
break;
|
||||
case GBMemoryVRAM:
|
||||
gb->cgb_vram_bank = bank_backup;
|
||||
break;
|
||||
case GBMemoryExternalRAM:
|
||||
gb->mbc_ram_bank = bank_backup;
|
||||
break;
|
||||
case GBMemoryRAM:
|
||||
gb->cgb_ram_bank = bank_backup;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
case 0xD: {
|
||||
uint16_t bank;
|
||||
size_t size;
|
||||
uint8_t *data = GB_get_direct_access(gb, GB_DIRECT_ACCESS_RAM, &size, &bank);
|
||||
if (_mode != GBMemoryEntireSpace) {
|
||||
bank = self.selectedBank & (size / 0x1000 - 1);
|
||||
}
|
||||
uint8_t sliceData[range.length];
|
||||
[slice copyBytes:sliceData range:HFRangeMake(0, range.length)];
|
||||
|
||||
memcpy(data + bank * 0x1000 + range.location - 0xD000, sliceData, range.length);
|
||||
break;
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import "Document.h"
|
||||
|
||||
@interface GBObjectView : NSView
|
||||
- (void)reloadData:(Document *)document;
|
||||
@end
|
|
@ -0,0 +1,124 @@
|
|||
#import "GBObjectView.h"
|
||||
|
||||
@interface GBObjectViewItem : NSObject
|
||||
@property IBOutlet NSView *view;
|
||||
@property IBOutlet NSImageView *image;
|
||||
@property IBOutlet NSTextField *oamAddress;
|
||||
@property IBOutlet NSTextField *position;
|
||||
@property IBOutlet NSTextField *attributes;
|
||||
@property IBOutlet NSTextField *tile;
|
||||
@property IBOutlet NSTextField *tileAddress;
|
||||
@property IBOutlet NSImageView *warningIcon;
|
||||
@property IBOutlet NSBox *verticalLine;
|
||||
@end
|
||||
|
||||
@implementation GBObjectViewItem
|
||||
{
|
||||
@public
|
||||
uint32_t _lastImageData[128];
|
||||
uint8_t _lastHeight;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GBObjectView
|
||||
{
|
||||
NSMutableArray<GBObjectViewItem *> *_items;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
_items = [NSMutableArray array];
|
||||
CGFloat height = self.frame.size.height;
|
||||
for (unsigned i = 0; i < 40; i++) {
|
||||
GBObjectViewItem *item = [[GBObjectViewItem alloc] init];
|
||||
[_items addObject:item];
|
||||
[[NSBundle mainBundle] loadNibNamed:@"GBObjectViewItem" owner:item topLevelObjects:nil];
|
||||
item.view.hidden = true;
|
||||
[self addSubview:item.view];
|
||||
[item.view setFrameOrigin:NSMakePoint((i % 4) * 120, height - (i / 4 * 68) - 68)];
|
||||
item.oamAddress.toolTip = @"OAM address";
|
||||
item.position.toolTip = @"Position";
|
||||
item.attributes.toolTip = @"Attributes";
|
||||
item.tile.toolTip = @"Tile index";
|
||||
item.tileAddress.toolTip = @"Tile address";
|
||||
item.warningIcon.toolTip = @"Dropped: too many objects in line";
|
||||
if ((i % 4) == 3) {
|
||||
[item.verticalLine removeFromSuperview];
|
||||
}
|
||||
item.view.autoresizingMask = NSViewMaxXMargin | NSViewMinYMargin;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)reloadData:(Document *)document
|
||||
{
|
||||
GB_oam_info_t *info = document.oamInfo;
|
||||
uint8_t length = document.oamCount;
|
||||
bool cgb = GB_is_cgb(document.gb);
|
||||
uint8_t height = document.oamHeight;
|
||||
for (unsigned i = 0; i < 40; i++) {
|
||||
GBObjectViewItem *item = _items[i];
|
||||
if (i >= length) {
|
||||
item.view.hidden = true;
|
||||
}
|
||||
else {
|
||||
item.view.hidden = false;
|
||||
item.oamAddress.stringValue = [NSString stringWithFormat:@"$%04X", info[i].oam_addr];
|
||||
item.position.stringValue = [NSString stringWithFormat:@"(%d, %d)",
|
||||
((signed)(unsigned)info[i].x) - 8,
|
||||
((signed)(unsigned)info[i].y) - 16];
|
||||
item.tile.stringValue = [NSString stringWithFormat:@"$%02X", info[i].tile];
|
||||
item.tileAddress.stringValue = [NSString stringWithFormat:@"$%04X", 0x8000 + info[i].tile * 0x10];
|
||||
item.warningIcon.hidden = !info[i].obscured_by_line_limit;
|
||||
if (cgb) {
|
||||
item.attributes.stringValue = [NSString stringWithFormat:@"%c%c%c%d%d",
|
||||
info[i].flags & 0x80? 'P' : '-',
|
||||
info[i].flags & 0x40? 'Y' : '-',
|
||||
info[i].flags & 0x20? 'X' : '-',
|
||||
info[i].flags & 0x08? 1 : 0,
|
||||
info[i].flags & 0x07];
|
||||
}
|
||||
else {
|
||||
item.attributes.stringValue = [NSString stringWithFormat:@"%c%c%c%d",
|
||||
info[i].flags & 0x80? 'P' : '-',
|
||||
info[i].flags & 0x40? 'Y' : '-',
|
||||
info[i].flags & 0x20? 'X' : '-',
|
||||
info[i].flags & 0x10? 1 : 0];
|
||||
}
|
||||
size_t imageSize = 8 * 4 * height;
|
||||
if (height == item->_lastHeight && memcmp(item->_lastImageData, info[i].image, imageSize) == 0) {
|
||||
continue;
|
||||
}
|
||||
memcpy(item->_lastImageData, info[i].image, imageSize);
|
||||
item->_lastHeight = height;
|
||||
item.image.image = [Document imageFromData:[NSData dataWithBytesNoCopy:info[i].image
|
||||
length:64 * 4 * 2
|
||||
freeWhenDone:false]
|
||||
width:8
|
||||
height:height
|
||||
scale:32.0 / height];
|
||||
}
|
||||
}
|
||||
|
||||
NSRect frame = self.frame;
|
||||
CGFloat newHeight = MAX(68 * ((length + 3) / 4), self.superview.frame.size.height);
|
||||
frame.origin.y -= newHeight - frame.size.height;
|
||||
frame.size.height = newHeight;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
if (@available(macOS 10.14, *)) {
|
||||
[[NSColor alternatingContentBackgroundColors].lastObject setFill];
|
||||
}
|
||||
else {
|
||||
[[NSColor colorWithDeviceWhite:0.96 alpha:1] setFill];
|
||||
}
|
||||
NSRect frame = self.frame;
|
||||
for (unsigned i = 1; i <= 5; i++) {
|
||||
NSRectFill(NSMakeRect(0, frame.size.height - i * 68 * 2, frame.size.width, 68));
|
||||
}
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14868" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14868"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="GBObjectViewItem">
|
||||
<connections>
|
||||
<outlet property="attributes" destination="AVH-lh-aVu" id="F5l-vc-9YB"/>
|
||||
<outlet property="image" destination="GWF-Vk-eLx" id="cQa-lM-SqU"/>
|
||||
<outlet property="oamAddress" destination="HiB-x7-HCb" id="LLX-HU-t00"/>
|
||||
<outlet property="position" destination="bxJ-ig-rox" id="woq-X2-lCK"/>
|
||||
<outlet property="tile" destination="Kco-1J-bKc" id="C8u-jH-bCh"/>
|
||||
<outlet property="tileAddress" destination="ptE-vl-9HD" id="9K3-Oq-1vs"/>
|
||||
<outlet property="verticalLine" destination="Q91-eq-oeo" id="6kc-qh-cFx"/>
|
||||
<outlet property="view" destination="c22-O7-iKe" id="50f-xf-9Gg"/>
|
||||
<outlet property="warningIcon" destination="dQV-cO-218" id="Rxi-Wq-Upl"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="120" height="68"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Kco-1J-bKc">
|
||||
<rect key="frame" x="44" y="4" width="58" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" selectable="YES" alignment="left" title="$32" id="Aps-81-wR7">
|
||||
<font key="font" size="11" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ptE-vl-9HD">
|
||||
<rect key="frame" x="0.0" y="4" width="44" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" selectable="YES" alignment="center" title="$8320" id="t2G-E2-vt5">
|
||||
<font key="font" size="11" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bxJ-ig-rox">
|
||||
<rect key="frame" x="44" y="36" width="76" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" selectable="YES" title="(32,16)" id="oac-yZ-h47">
|
||||
<font key="font" size="11" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AVH-lh-aVu">
|
||||
<rect key="frame" x="44" y="20" width="76" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" selectable="YES" title="---04" id="tJX-6t-5Kx">
|
||||
<font key="font" size="11" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HiB-x7-HCb">
|
||||
<rect key="frame" x="44" y="52" width="76" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" selectable="YES" alignment="left" title="$FE32" id="ysm-jq-PKy">
|
||||
<font key="font" size="11" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" id="GWF-Vk-eLx" customClass="GBImageView">
|
||||
<rect key="frame" x="2" y="24" width="40" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" id="AJz-KH-eeo"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dQV-cO-218">
|
||||
<rect key="frame" x="100" y="4" width="16" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSCaution" id="TQB-Vp-9Jm"/>
|
||||
</imageView>
|
||||
<box horizontalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="Q91-eq-oeo">
|
||||
<rect key="frame" x="116" y="4" width="5" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</box>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="132" y="149"/>
|
||||
</customView>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="NSCaution" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
|
@ -1,6 +1,7 @@
|
|||
#import "GBOpenGLView.h"
|
||||
#import "GBView.h"
|
||||
#include <OpenGL/gl.h>
|
||||
#import "NSObject+DefaultsObserver.h"
|
||||
#import <OpenGL/gl.h>
|
||||
|
||||
@implementation GBOpenGLView
|
||||
|
||||
|
@ -27,13 +28,12 @@
|
|||
|
||||
- (instancetype)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat *)format
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(filterChanged) name:@"GBFilterChanged" object:nil];
|
||||
__unsafe_unretained GBOpenGLView *weakSelf = self;
|
||||
[self observeStandardDefaultsKey:@"GBFilter" withBlock:^(id newValue) {
|
||||
weakSelf.shader = nil;
|
||||
[weakSelf setNeedsDisplay:true];
|
||||
|
||||
}];
|
||||
return [super initWithFrame:frameRect pixelFormat:format];
|
||||
}
|
||||
|
||||
- (void) filterChanged
|
||||
{
|
||||
self.shader = nil;
|
||||
[self setNeedsDisplay:true];
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import "Document.h"
|
||||
|
||||
@interface GBPaletteView : NSView
|
||||
- (void)reloadData:(Document *)document;
|
||||
@end
|
|
@ -0,0 +1,91 @@
|
|||
#import "GBPaletteView.h"
|
||||
|
||||
@interface GBPaletteViewItem : NSObject
|
||||
@property IBOutlet NSView *view;
|
||||
@property (strong) IBOutlet NSTextField *label;
|
||||
@property (strong) IBOutlet NSTextField *color0;
|
||||
@property (strong) IBOutlet NSTextField *color1;
|
||||
@property (strong) IBOutlet NSTextField *color2;
|
||||
@property (strong) IBOutlet NSTextField *color3;
|
||||
@end
|
||||
|
||||
@implementation GBPaletteViewItem
|
||||
@end
|
||||
|
||||
@implementation GBPaletteView
|
||||
{
|
||||
NSMutableArray<NSTextField *> *_colors;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
_colors = [NSMutableArray array];
|
||||
CGFloat height = self.frame.size.height;
|
||||
for (unsigned i = 0; i < 16; i++) {
|
||||
GBPaletteViewItem *item = [[GBPaletteViewItem alloc] init];
|
||||
[[NSBundle mainBundle] loadNibNamed:@"GBPaletteViewRow" owner:item topLevelObjects:nil];
|
||||
[self addSubview:item.view];
|
||||
[item.view setFrameOrigin:NSMakePoint(0, height - (i * 24) - 24)];
|
||||
item.label.stringValue = [NSString stringWithFormat:@"%@ %d", i < 8? @"Background" : @"Object", i % 8];
|
||||
item.view.autoresizingMask = NSViewMaxXMargin | NSViewMinYMargin;
|
||||
[_colors addObject:item.color0];
|
||||
[_colors addObject:item.color1];
|
||||
[_colors addObject:item.color2];
|
||||
[_colors addObject:item.color3];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)reloadData:(Document *)document
|
||||
{
|
||||
GB_gameboy_t *gb = document.gb;
|
||||
uint8_t *bg = GB_get_direct_access(gb, GB_DIRECT_ACCESS_BGP, NULL, NULL);
|
||||
uint8_t *obj = GB_get_direct_access(gb, GB_DIRECT_ACCESS_OBP, NULL, NULL);
|
||||
|
||||
for (unsigned i = 0; i < 4 * 8 * 2; i++) {
|
||||
uint8_t index = i % (4 * 8);
|
||||
uint8_t *palette = i >= 4 * 8 ? obj : bg;
|
||||
uint16_t color = (palette[(index << 1) + 1] << 8) | palette[(index << 1)];
|
||||
uint32_t nativeColor = GB_convert_rgb15(gb, color, false);
|
||||
|
||||
uint8_t r = color & 0x1F,
|
||||
g = (color >> 5) & 0x1F,
|
||||
b = (color >> 10) & 0x1F;
|
||||
|
||||
NSTextField *field = _colors[i];
|
||||
field.stringValue = [NSString stringWithFormat:@"$%04X", color];
|
||||
field.textColor = r * 3 + g * 4 + b * 2 > 120? [NSColor blackColor] : [NSColor whiteColor];
|
||||
field.toolTip = [NSString stringWithFormat:@"Red: %d, Green: %d, Blue: %d", r, g, b];
|
||||
field.backgroundColor = [NSColor colorWithRed:(nativeColor & 0xFF) / 255.0
|
||||
green:((nativeColor >> 8) & 0xFF) / 255.0
|
||||
blue:((nativeColor >> 16) & 0xFF) / 255.0
|
||||
alpha:1.0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
NSRect frame = self.frame;
|
||||
if (@available(macOS 10.14, *)) {
|
||||
[[NSColor alternatingContentBackgroundColors].lastObject setFill];
|
||||
}
|
||||
else {
|
||||
[[NSColor colorWithDeviceWhite:0.96 alpha:1] setFill];
|
||||
}
|
||||
for (unsigned i = 1; i <= 8; i++) {
|
||||
NSRectFill(NSMakeRect(0, frame.size.height - i * 24 * 2, frame.size.width, 24));
|
||||
}
|
||||
|
||||
if (@available(macOS 10.14, *)) {
|
||||
[[NSColor alternatingContentBackgroundColors].firstObject setFill];
|
||||
}
|
||||
else {
|
||||
[[NSColor controlBackgroundColor] setFill];
|
||||
}
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
NSRectFill(NSMakeRect(0, frame.size.height - i * 24 * 2 - 24, frame.size.width, 24));
|
||||
}
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14868" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14868"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="GBPaletteViewItem">
|
||||
<connections>
|
||||
<outlet property="color0" destination="ypt-t4-Mf3" id="Bam-dX-hHk"/>
|
||||
<outlet property="color1" destination="KkX-Z8-Sqi" id="uCl-UT-PWu"/>
|
||||
<outlet property="color2" destination="jDk-Ej-4yI" id="Xjs-el-m3s"/>
|
||||
<outlet property="color3" destination="7PI-YE-fTk" id="7J8-aH-LEO"/>
|
||||
<outlet property="label" destination="NOK-yI-LKh" id="AK3-g5-H7a"/>
|
||||
<outlet property="view" destination="c22-O7-iKe" id="DPx-8k-YQB"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ypt-t4-Mf3">
|
||||
<rect key="frame" x="131" y="0.0" width="96" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" sendsActionOnEndEditing="YES" borderStyle="border" alignment="center" title="$7FFF" drawsBackground="YES" id="sKu-Uy-2LG">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KkX-Z8-Sqi">
|
||||
<rect key="frame" x="226" y="0.0" width="96" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" sendsActionOnEndEditing="YES" borderStyle="border" alignment="center" title="$7FFF" drawsBackground="YES" id="9LH-TF-W1L">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jDk-Ej-4yI">
|
||||
<rect key="frame" x="321" y="0.0" width="96" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" sendsActionOnEndEditing="YES" borderStyle="border" alignment="center" title="$7FFF" drawsBackground="YES" id="arE-i5-zCC">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7PI-YE-fTk">
|
||||
<rect key="frame" x="416" y="0.0" width="96" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" sendsActionOnEndEditing="YES" borderStyle="border" alignment="center" title="$7FFF" drawsBackground="YES" id="ZbU-nE-FsE">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NOK-yI-LKh">
|
||||
<rect key="frame" x="4" y="0.0" width="121" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Background 0" id="qM4-cY-SDE">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="139" y="31"/>
|
||||
</customView>
|
||||
</objects>
|
||||
</document>
|
|
@ -0,0 +1,6 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBPreferenceButton : NSButton
|
||||
@property (nonatomic) IBInspectable NSString *preferenceName;
|
||||
@property IBInspectable BOOL invertValue;
|
||||
@end
|
|
@ -0,0 +1,30 @@
|
|||
#import "GBPreferenceButton.h"
|
||||
#import "NSObject+DefaultsObserver.h"
|
||||
|
||||
@implementation GBPreferenceButton
|
||||
|
||||
- (BOOL)sendAction:(SEL)action to:(id)target
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool:self.state ^ self.invertValue forKey:_preferenceName];
|
||||
return [super sendAction:action to:target];
|
||||
}
|
||||
|
||||
- (void)updateValue
|
||||
{
|
||||
if (!_preferenceName) return;
|
||||
self.state = [[NSUserDefaults standardUserDefaults] boolForKey:_preferenceName] ^ self.invertValue;
|
||||
}
|
||||
|
||||
- (void)setPreferenceName:(NSString *)preferenceName
|
||||
{
|
||||
_preferenceName = preferenceName;
|
||||
[self observeStandardDefaultsKey:_preferenceName selector:@selector(updateValue)];
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
[super viewDidMoveToWindow];
|
||||
[self updateValue];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,9 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBPreferenceMenuItem : NSMenuItem
|
||||
@property (nonatomic) IBInspectable NSString *preferenceValue;
|
||||
@end
|
||||
|
||||
@interface GBPreferencePopUpButton : NSPopUpButton
|
||||
@property (nonatomic) IBInspectable NSString *preferenceName;
|
||||
@end
|
|
@ -0,0 +1,51 @@
|
|||
#import "GBPreferencePopUpButton.h"
|
||||
#import "NSObject+DefaultsObserver.h"
|
||||
|
||||
@implementation GBPreferenceMenuItem
|
||||
@end
|
||||
|
||||
@implementation GBPreferencePopUpButton
|
||||
|
||||
- (BOOL)sendAction:(SEL)action to:(id)target
|
||||
{
|
||||
GBPreferenceMenuItem *item = (GBPreferenceMenuItem *)self.selectedItem;
|
||||
if ([item isKindOfClass:[GBPreferenceMenuItem class]]) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:item.preferenceValue forKey:_preferenceName];
|
||||
}
|
||||
else {
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:item.tag forKey:_preferenceName];
|
||||
}
|
||||
return [super sendAction:action to:target];
|
||||
}
|
||||
|
||||
- (void)updateValue
|
||||
{
|
||||
if (!_preferenceName) return;
|
||||
NSString *stringValue = [[NSUserDefaults standardUserDefaults] objectForKey:_preferenceName];
|
||||
if ([stringValue isKindOfClass:[NSString class]]) {
|
||||
for (GBPreferenceMenuItem *item in self.menu.itemArray) {
|
||||
if ([item isKindOfClass:[GBPreferenceMenuItem class]] &&
|
||||
[item.preferenceValue isEqualToString:stringValue]) {
|
||||
[self selectItem:item];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
[self selectItemWithTag:[[NSUserDefaults standardUserDefaults] integerForKey:_preferenceName]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPreferenceName:(NSString *)preferenceName
|
||||
{
|
||||
_preferenceName = preferenceName;
|
||||
[self observeStandardDefaultsKey:_preferenceName selector:@selector(updateValue)];
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
[super viewDidMoveToWindow];
|
||||
[self updateValue];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,6 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBPreferencesSlider : NSSlider
|
||||
@property (nonatomic) IBInspectable NSString *preferenceName;
|
||||
@property IBInspectable unsigned denominator;
|
||||
@end
|
|
@ -0,0 +1,29 @@
|
|||
#import "GBPreferencesSlider.h"
|
||||
#import "NSObject+DefaultsObserver.h"
|
||||
|
||||
@implementation GBPreferencesSlider
|
||||
|
||||
- (BOOL)sendAction:(SEL)action to:(id)target
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:self.doubleValue / (self.denominator ?: 1) forKey:_preferenceName];
|
||||
return [super sendAction:action to:target];
|
||||
}
|
||||
|
||||
- (void)updateValue
|
||||
{
|
||||
if (!_preferenceName) return;
|
||||
self.doubleValue = [[NSUserDefaults standardUserDefaults] doubleForKey:_preferenceName] * (self.denominator ?: 1);
|
||||
}
|
||||
|
||||
- (void)setPreferenceName:(NSString *)preferenceName
|
||||
{
|
||||
_preferenceName = preferenceName;
|
||||
[self observeStandardDefaultsKey:_preferenceName selector:@selector(updateValue)];
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
[super viewDidMoveToWindow];
|
||||
[self updateValue];
|
||||
}
|
||||
@end
|
|
@ -3,35 +3,19 @@
|
|||
#import "GBPaletteEditorController.h"
|
||||
|
||||
@interface GBPreferencesWindow : NSWindow <NSTableViewDelegate, NSTableViewDataSource, JOYListener>
|
||||
@property (nonatomic, strong) IBOutlet NSTableView *controlsTableView;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *graphicsFilterPopupButton;
|
||||
@property (nonatomic, strong) IBOutlet NSButton *analogControlsCheckbox;
|
||||
@property (nonatomic, strong) IBOutlet NSButton *aspectRatioCheckbox;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *highpassFilterPopupButton;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *colorCorrectionPopupButton;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *frameBlendingModePopupButton;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *colorPalettePopupButton;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *displayBorderPopupButton;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *rewindPopupButton;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *rtcPopupButton;
|
||||
@property (nonatomic, strong) IBOutlet NSButton *configureJoypadButton;
|
||||
@property (nonatomic, strong) IBOutlet NSButton *skipButton;
|
||||
@property (nonatomic, strong) IBOutlet NSMenuItem *bootROMsFolderItem;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButtonCell *bootROMsButton;
|
||||
@property (nonatomic, strong) IBOutlet NSPopUpButton *rumbleModePopupButton;
|
||||
@property (nonatomic, weak) IBOutlet NSSlider *temperatureSlider;
|
||||
@property (nonatomic, weak) IBOutlet NSSlider *interferenceSlider;
|
||||
@property (nonatomic, weak) IBOutlet NSPopUpButton *dmgPopupButton;
|
||||
@property (nonatomic, weak) IBOutlet NSPopUpButton *sgbPopupButton;
|
||||
@property (nonatomic, weak) IBOutlet NSPopUpButton *cgbPopupButton;
|
||||
@property (nonatomic, weak) IBOutlet NSPopUpButton *preferredJoypadButton;
|
||||
@property (nonatomic, weak) IBOutlet NSPopUpButton *playerListButton;
|
||||
@property (nonatomic, weak) IBOutlet NSButton *autoUpdatesCheckbox;
|
||||
@property (weak) IBOutlet NSSlider *volumeSlider;
|
||||
@property (weak) IBOutlet NSButton *OSDCheckbox;
|
||||
@property (weak) IBOutlet NSButton *screenshotFilterCheckbox;
|
||||
@property (weak) IBOutlet GBPaletteEditorController *paletteEditorController;
|
||||
@property (strong) IBOutlet NSWindow *paletteEditor;
|
||||
@property (weak) IBOutlet NSButton *joystickMBC7Checkbox;
|
||||
@property (weak) IBOutlet NSButton *mouseMBC7Checkbox;
|
||||
@property IBOutlet NSTableView *controlsTableView;
|
||||
@property IBOutlet NSButton *configureJoypadButton;
|
||||
@property IBOutlet NSButton *skipButton;
|
||||
@property IBOutlet NSMenuItem *bootROMsFolderItem;
|
||||
@property IBOutlet NSPopUpButtonCell *bootROMsButton;
|
||||
@property IBOutlet NSPopUpButton *preferredJoypadButton;
|
||||
@property IBOutlet NSPopUpButton *playerListButton;
|
||||
@property IBOutlet GBPaletteEditorController *paletteEditorController;
|
||||
@property IBOutlet NSWindow *paletteEditor;
|
||||
@property IBOutlet NSWindow *joyconsSheet;
|
||||
@property IBOutlet NSPopUpButton *colorCorrectionPopupButton;
|
||||
@property IBOutlet NSPopUpButton *highpassFilterPopupButton;
|
||||
@property IBOutlet NSPopUpButton *colorPalettePopupButton;
|
||||
@property IBOutlet NSPopUpButton *hotkey1PopupButton;
|
||||
@property IBOutlet NSPopUpButton *hotkey2PopupButton;
|
||||
@end
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#import "GBPreferencesWindow.h"
|
||||
#import "GBJoyConManager.h"
|
||||
#import "NSString+StringForKey.h"
|
||||
#import "GBButtons.h"
|
||||
#import "BigSurToolbar.h"
|
||||
#import "GBViewMetal.h"
|
||||
#import "GBWarningPopover.h"
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
@implementation GBPreferencesWindow
|
||||
|
@ -13,59 +15,12 @@
|
|||
NSString *joystick_being_configured;
|
||||
bool joypad_wait;
|
||||
|
||||
NSPopUpButton *_graphicsFilterPopupButton;
|
||||
NSPopUpButton *_highpassFilterPopupButton;
|
||||
NSPopUpButton *_colorCorrectionPopupButton;
|
||||
NSPopUpButton *_frameBlendingModePopupButton;
|
||||
NSPopUpButton *_colorPalettePopupButton;
|
||||
NSPopUpButton *_displayBorderPopupButton;
|
||||
NSPopUpButton *_rewindPopupButton;
|
||||
NSPopUpButton *_rtcPopupButton;
|
||||
NSButton *_aspectRatioCheckbox;
|
||||
NSButton *_analogControlsCheckbox;
|
||||
NSEventModifierFlags previousModifiers;
|
||||
|
||||
NSPopUpButton *_dmgPopupButton, *_sgbPopupButton, *_cgbPopupButton;
|
||||
NSPopUpButton *_preferredJoypadButton;
|
||||
NSPopUpButton *_rumbleModePopupButton;
|
||||
NSSlider *_temperatureSlider;
|
||||
NSSlider *_interferenceSlider;
|
||||
NSSlider *_volumeSlider;
|
||||
NSButton *_autoUpdatesCheckbox;
|
||||
NSButton *_OSDCheckbox;
|
||||
NSButton *_screenshotFilterCheckbox;
|
||||
NSButton *_joystickMBC7Checkbox;
|
||||
NSButton *_mouseMBC7Checkbox;
|
||||
}
|
||||
|
||||
+ (NSArray *)filterList
|
||||
{
|
||||
/* The filter list as ordered in the popup button */
|
||||
static NSArray * filters = nil;
|
||||
if (!filters) {
|
||||
filters = @[
|
||||
@"NearestNeighbor",
|
||||
@"Bilinear",
|
||||
@"SmoothBilinear",
|
||||
@"MonoLCD",
|
||||
@"LCD",
|
||||
@"CRT",
|
||||
@"Scale2x",
|
||||
@"Scale4x",
|
||||
@"AAScale2x",
|
||||
@"AAScale4x",
|
||||
@"HQ2x",
|
||||
@"OmniScale",
|
||||
@"OmniScaleLegacy",
|
||||
@"AAOmniScaleLegacy",
|
||||
];
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
- (NSWindowToolbarStyle)toolbarStyle
|
||||
{
|
||||
return NSWindowToolbarStylePreference;
|
||||
return NSWindowToolbarStyleExpanded;
|
||||
}
|
||||
|
||||
- (void)close
|
||||
|
@ -77,151 +32,9 @@
|
|||
[super close];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)graphicsFilterPopupButton
|
||||
static inline NSString *keyEquivalentString(NSMenuItem *item)
|
||||
{
|
||||
return _graphicsFilterPopupButton;
|
||||
}
|
||||
|
||||
- (void)setGraphicsFilterPopupButton:(NSPopUpButton *)graphicsFilterPopupButton
|
||||
{
|
||||
_graphicsFilterPopupButton = graphicsFilterPopupButton;
|
||||
NSString *filter = [[NSUserDefaults standardUserDefaults] objectForKey:@"GBFilter"];
|
||||
[_graphicsFilterPopupButton selectItemAtIndex:[[[self class] filterList] indexOfObject:filter]];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)highpassFilterPopupButton
|
||||
{
|
||||
return _highpassFilterPopupButton;
|
||||
}
|
||||
|
||||
- (void)setColorCorrectionPopupButton:(NSPopUpButton *)colorCorrectionPopupButton
|
||||
{
|
||||
_colorCorrectionPopupButton = colorCorrectionPopupButton;
|
||||
NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorCorrection"];
|
||||
[_colorCorrectionPopupButton selectItemAtIndex:mode];
|
||||
}
|
||||
|
||||
|
||||
- (NSPopUpButton *)colorCorrectionPopupButton
|
||||
{
|
||||
return _colorCorrectionPopupButton;
|
||||
}
|
||||
|
||||
- (void)setTemperatureSlider:(NSSlider *)temperatureSlider
|
||||
{
|
||||
_temperatureSlider = temperatureSlider;
|
||||
[temperatureSlider setDoubleValue:[[NSUserDefaults standardUserDefaults] doubleForKey:@"GBLightTemperature"] * 256];
|
||||
}
|
||||
|
||||
- (NSSlider *)temperatureSlider
|
||||
{
|
||||
return _temperatureSlider;
|
||||
}
|
||||
|
||||
- (void)setInterferenceSlider:(NSSlider *)interferenceSlider
|
||||
{
|
||||
_interferenceSlider = interferenceSlider;
|
||||
[interferenceSlider setDoubleValue:[[NSUserDefaults standardUserDefaults] doubleForKey:@"GBInterferenceVolume"] * 256];
|
||||
}
|
||||
|
||||
- (NSSlider *)interferenceSlider
|
||||
{
|
||||
return _interferenceSlider;
|
||||
}
|
||||
|
||||
- (void)setVolumeSlider:(NSSlider *)volumeSlider
|
||||
{
|
||||
_volumeSlider = volumeSlider;
|
||||
[volumeSlider setDoubleValue:[[NSUserDefaults standardUserDefaults] doubleForKey:@"GBVolume"] * 256];
|
||||
}
|
||||
|
||||
- (NSSlider *)volumeSlider
|
||||
{
|
||||
return _volumeSlider;
|
||||
}
|
||||
|
||||
- (void)setFrameBlendingModePopupButton:(NSPopUpButton *)frameBlendingModePopupButton
|
||||
{
|
||||
_frameBlendingModePopupButton = frameBlendingModePopupButton;
|
||||
NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBFrameBlendingMode"];
|
||||
[_frameBlendingModePopupButton selectItemAtIndex:mode];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)frameBlendingModePopupButton
|
||||
{
|
||||
return _frameBlendingModePopupButton;
|
||||
}
|
||||
|
||||
- (void)setColorPalettePopupButton:(NSPopUpButton *)colorPalettePopupButton
|
||||
{
|
||||
_colorPalettePopupButton = colorPalettePopupButton;
|
||||
[self updatePalettesMenu];
|
||||
NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorPalette"];
|
||||
if (mode >= 0) {
|
||||
[_colorPalettePopupButton selectItemWithTag:mode];
|
||||
}
|
||||
else {
|
||||
[_colorPalettePopupButton selectItemWithTitle:[[NSUserDefaults standardUserDefaults] stringForKey:@"GBCurrentTheme"] ?: @""];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)colorPalettePopupButton
|
||||
{
|
||||
return _colorPalettePopupButton;
|
||||
}
|
||||
|
||||
- (void)setDisplayBorderPopupButton:(NSPopUpButton *)displayBorderPopupButton
|
||||
{
|
||||
_displayBorderPopupButton = displayBorderPopupButton;
|
||||
NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBBorderMode"];
|
||||
[_displayBorderPopupButton selectItemWithTag:mode];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)displayBorderPopupButton
|
||||
{
|
||||
return _displayBorderPopupButton;
|
||||
}
|
||||
|
||||
- (void)setRumbleModePopupButton:(NSPopUpButton *)rumbleModePopupButton
|
||||
{
|
||||
_rumbleModePopupButton = rumbleModePopupButton;
|
||||
NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBRumbleMode"];
|
||||
[_rumbleModePopupButton selectItemWithTag:mode];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)rumbleModePopupButton
|
||||
{
|
||||
return _rumbleModePopupButton;
|
||||
}
|
||||
|
||||
- (void)setRewindPopupButton:(NSPopUpButton *)rewindPopupButton
|
||||
{
|
||||
_rewindPopupButton = rewindPopupButton;
|
||||
NSInteger length = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBRewindLength"];
|
||||
[_rewindPopupButton selectItemWithTag:length];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)rewindPopupButton
|
||||
{
|
||||
return _rewindPopupButton;
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)rtcPopupButton
|
||||
{
|
||||
return _rtcPopupButton;
|
||||
}
|
||||
|
||||
- (void)setRtcPopupButton:(NSPopUpButton *)rtcPopupButton
|
||||
{
|
||||
_rtcPopupButton = rtcPopupButton;
|
||||
NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBRTCMode"];
|
||||
[_rtcPopupButton selectItemAtIndex:mode];
|
||||
}
|
||||
|
||||
- (void)setHighpassFilterPopupButton:(NSPopUpButton *)highpassFilterPopupButton
|
||||
{
|
||||
_highpassFilterPopupButton = highpassFilterPopupButton;
|
||||
[_highpassFilterPopupButton selectItemAtIndex:[[[NSUserDefaults standardUserDefaults] objectForKey:@"GBHighpassFilter"] unsignedIntegerValue]];
|
||||
return [NSString stringWithFormat:@"%s%@", (item.keyEquivalentModifierMask & NSEventModifierFlagShift)? "^":"", item.keyEquivalent];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
|
@ -253,7 +66,7 @@
|
|||
}
|
||||
|
||||
if (is_button_being_modified && button_being_modified == row) {
|
||||
return @"Select a new key...";
|
||||
return @"Select a new key…";
|
||||
}
|
||||
|
||||
NSNumber *key = [[NSUserDefaults standardUserDefaults] valueForKey:button_to_preference_name(row, self.playerListButton.selectedTag)];
|
||||
|
@ -312,82 +125,6 @@
|
|||
previousModifiers = event.modifierFlags;
|
||||
}
|
||||
|
||||
- (IBAction)graphicFilterChanged:(NSPopUpButton *)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[[self class] filterList][[sender indexOfSelectedItem]]
|
||||
forKey:@"GBFilter"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBFilterChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)highpassFilterChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem])
|
||||
forKey:@"GBHighpassFilter"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBHighpassFilterChanged" object:nil];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)changeMBC7JoystickOverride:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool: [(NSButton *)sender state] == NSOnState
|
||||
forKey:@"GBMBC7JoystickOverride"];
|
||||
}
|
||||
|
||||
- (IBAction)changeMBC7AllowMouse:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool: [(NSButton *)sender state] == NSOnState
|
||||
forKey:@"GBMBC7AllowMouse"];
|
||||
}
|
||||
|
||||
- (IBAction)changeAnalogControls:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool: [(NSButton *)sender state] == NSOnState
|
||||
forKey:@"GBAnalogControls"];
|
||||
}
|
||||
|
||||
- (IBAction)changeAspectRatio:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool: [(NSButton *)sender state] != NSOnState
|
||||
forKey:@"GBAspectRatioUnkept"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBAspectChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)colorCorrectionChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem])
|
||||
forKey:@"GBColorCorrection"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBColorCorrectionChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)lightTemperatureChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender doubleValue] / 256.0)
|
||||
forKey:@"GBLightTemperature"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBLightTemperatureChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)interferenceVolumeChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender doubleValue] / 256.0)
|
||||
forKey:@"GBInterferenceVolume"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBInterferenceVolumeChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)volumeChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender doubleValue] / 256.0)
|
||||
forKey:@"GBVolume"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBVolumeChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)franeBlendingModeChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem])
|
||||
forKey:@"GBFrameBlendingMode"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBFrameBlendingModeChanged" object:nil];
|
||||
|
||||
}
|
||||
|
||||
- (void)updatePalettesMenu
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
@ -436,40 +173,18 @@
|
|||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBColorPaletteChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)displayBorderChanged:(id)sender
|
||||
- (IBAction)hotkey1Changed:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedItem].tag)
|
||||
forKey:@"GBBorderMode"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBBorderModeChanged" object:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:keyEquivalentString([sender selectedItem])
|
||||
forKey:@"GBJoypadHotkey1"];
|
||||
}
|
||||
|
||||
- (IBAction)rumbleModeChanged:(id)sender
|
||||
- (IBAction)hotkey2Changed:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedItem].tag)
|
||||
forKey:@"GBRumbleMode"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBRumbleModeChanged" object:nil];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:keyEquivalentString([sender selectedItem])
|
||||
forKey:@"GBJoypadHotkey2"];
|
||||
}
|
||||
|
||||
- (IBAction)rewindLengthChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])
|
||||
forKey:@"GBRewindLength"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBRewindLengthChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)rtcModeChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender indexOfSelectedItem])
|
||||
forKey:@"GBRTCMode"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBRTCModeChanged" object:nil];
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)changeAutoUpdates:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool: [(NSButton *)sender state] == NSOnState
|
||||
forKey:@"GBAutoUpdatesEnabled"];
|
||||
}
|
||||
|
||||
- (IBAction) configureJoypad:(id)sender
|
||||
{
|
||||
|
@ -490,7 +205,7 @@
|
|||
if (joystick_configuration_state == GBUnderclock) {
|
||||
[self.configureJoypadButton setTitle:@"Press Button for Slo-Mo"]; // Full name is too long :<
|
||||
}
|
||||
else if (joystick_configuration_state < GBButtonCount) {
|
||||
else if (joystick_configuration_state < GBJoypadButtonCount) {
|
||||
[self.configureJoypadButton setTitle:[NSString stringWithFormat:@"Press Button for %@", GBButtonNames[joystick_configuration_state]]];
|
||||
}
|
||||
else {
|
||||
|
@ -512,7 +227,7 @@
|
|||
|
||||
if (!button.isPressed) return;
|
||||
if (joystick_configuration_state == -1) return;
|
||||
if (joystick_configuration_state == GBButtonCount) return;
|
||||
if (joystick_configuration_state == GBJoypadButtonCount) return;
|
||||
if (!joystick_being_configured) {
|
||||
joystick_being_configured = controller.uniqueID;
|
||||
}
|
||||
|
@ -554,6 +269,8 @@
|
|||
[GBTurbo] = JOYButtonUsageL1,
|
||||
[GBRewind] = JOYButtonUsageL2,
|
||||
[GBUnderclock] = JOYButtonUsageR1,
|
||||
[GBHotkey1] = GBJoyKitHotkey1,
|
||||
[GBHotkey2] = GBJoyKitHotkey2,
|
||||
};
|
||||
|
||||
if (joystick_configuration_state == GBUnderclock) {
|
||||
|
@ -587,50 +304,6 @@
|
|||
[self advanceConfigurationStateMachine];
|
||||
}
|
||||
|
||||
- (NSButton *)joystickMBC7Checkbox
|
||||
{
|
||||
return _joystickMBC7Checkbox;
|
||||
}
|
||||
|
||||
- (void)setJoystickMBC7Checkbox:(NSButton *)joystickMBC7Checkbox
|
||||
{
|
||||
_joystickMBC7Checkbox = joystickMBC7Checkbox;
|
||||
[_joystickMBC7Checkbox setState: [[NSUserDefaults standardUserDefaults] boolForKey:@"GBMBC7JoystickOverride"]];
|
||||
}
|
||||
|
||||
- (NSButton *)mouseMBC7Checkbox
|
||||
{
|
||||
return _mouseMBC7Checkbox;
|
||||
}
|
||||
|
||||
- (void)setMouseMBC7Checkbox:(NSButton *)mouseMBC7Checkbox
|
||||
{
|
||||
_mouseMBC7Checkbox = mouseMBC7Checkbox;
|
||||
[_mouseMBC7Checkbox setState: [[NSUserDefaults standardUserDefaults] boolForKey:@"GBMBC7AllowMouse"]];
|
||||
}
|
||||
|
||||
- (NSButton *)analogControlsCheckbox
|
||||
{
|
||||
return _analogControlsCheckbox;
|
||||
}
|
||||
|
||||
- (void)setAnalogControlsCheckbox:(NSButton *)analogControlsCheckbox
|
||||
{
|
||||
_analogControlsCheckbox = analogControlsCheckbox;
|
||||
[_analogControlsCheckbox setState: [[NSUserDefaults standardUserDefaults] boolForKey:@"GBAnalogControls"]];
|
||||
}
|
||||
|
||||
- (NSButton *)aspectRatioCheckbox
|
||||
{
|
||||
return _aspectRatioCheckbox;
|
||||
}
|
||||
|
||||
- (void)setAspectRatioCheckbox:(NSButton *)aspectRatioCheckbox
|
||||
{
|
||||
_aspectRatioCheckbox = aspectRatioCheckbox;
|
||||
[_aspectRatioCheckbox setState: ![[NSUserDefaults standardUserDefaults] boolForKey:@"GBAspectRatioUnkept"]];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
|
@ -638,6 +311,32 @@
|
|||
[[NSDistributedNotificationCenter defaultCenter] addObserver:self.controlsTableView selector:@selector(reloadData) name:(NSString*)kTISNotifySelectedKeyboardInputSourceChanged object:nil];
|
||||
[JOYController registerListener:self];
|
||||
joystick_configuration_state = -1;
|
||||
[self refreshJoypadMenu:nil];
|
||||
|
||||
NSString *keyEquivalent = [[NSUserDefaults standardUserDefaults] stringForKey:@"GBJoypadHotkey1"];
|
||||
for (NSMenuItem *item in _hotkey1PopupButton.menu.itemArray) {
|
||||
if ([keyEquivalent isEqualToString:keyEquivalentString(item)]) {
|
||||
[_hotkey1PopupButton selectItem:item];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
keyEquivalent = [[NSUserDefaults standardUserDefaults] stringForKey:@"GBJoypadHotkey2"];
|
||||
for (NSMenuItem *item in _hotkey2PopupButton.menu.itemArray) {
|
||||
if ([keyEquivalent isEqualToString:keyEquivalentString(item)]) {
|
||||
[_hotkey2PopupButton selectItem:item];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[self updatePalettesMenu];
|
||||
NSInteger mode = [[NSUserDefaults standardUserDefaults] integerForKey:@"GBColorPalette"];
|
||||
if (mode >= 0) {
|
||||
[_colorPalettePopupButton selectItemWithTag:mode];
|
||||
}
|
||||
else {
|
||||
[_colorPalettePopupButton selectItemWithTitle:[[NSUserDefaults standardUserDefaults] stringForKey:@"GBCurrentTheme"] ?: @""];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
@ -690,77 +389,6 @@
|
|||
[self updateBootROMFolderButton];
|
||||
}
|
||||
|
||||
- (void)setDmgPopupButton:(NSPopUpButton *)dmgPopupButton
|
||||
{
|
||||
_dmgPopupButton = dmgPopupButton;
|
||||
[_dmgPopupButton selectItemWithTag:[[NSUserDefaults standardUserDefaults] integerForKey:@"GBDMGModel"]];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)dmgPopupButton
|
||||
{
|
||||
return _dmgPopupButton;
|
||||
}
|
||||
|
||||
- (void)setSgbPopupButton:(NSPopUpButton *)sgbPopupButton
|
||||
{
|
||||
_sgbPopupButton = sgbPopupButton;
|
||||
[_sgbPopupButton selectItemWithTag:[[NSUserDefaults standardUserDefaults] integerForKey:@"GBSGBModel"]];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)sgbPopupButton
|
||||
{
|
||||
return _sgbPopupButton;
|
||||
}
|
||||
|
||||
- (void)setCgbPopupButton:(NSPopUpButton *)cgbPopupButton
|
||||
{
|
||||
_cgbPopupButton = cgbPopupButton;
|
||||
[_cgbPopupButton selectItemWithTag:[[NSUserDefaults standardUserDefaults] integerForKey:@"GBCGBModel"]];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)cgbPopupButton
|
||||
{
|
||||
return _cgbPopupButton;
|
||||
}
|
||||
|
||||
- (IBAction)dmgModelChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])
|
||||
forKey:@"GBDMGModel"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBDMGModelChanged" object:nil];
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)sgbModelChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])
|
||||
forKey:@"GBSGBModel"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBSGBModelChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)cgbModelChanged:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@([sender selectedTag])
|
||||
forKey:@"GBCGBModel"];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBCGBModelChanged" object:nil];
|
||||
}
|
||||
|
||||
- (IBAction)reloadButtonsData:(id)sender
|
||||
{
|
||||
[self.controlsTableView reloadData];
|
||||
}
|
||||
|
||||
- (void)setPreferredJoypadButton:(NSPopUpButton *)preferredJoypadButton
|
||||
{
|
||||
_preferredJoypadButton = preferredJoypadButton;
|
||||
[self refreshJoypadMenu:nil];
|
||||
}
|
||||
|
||||
- (NSPopUpButton *)preferredJoypadButton
|
||||
{
|
||||
return _preferredJoypadButton;
|
||||
}
|
||||
|
||||
- (void)controllerConnected:(JOYController *)controller
|
||||
{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
|
@ -824,55 +452,48 @@
|
|||
[[NSUserDefaults standardUserDefaults] setObject:default_joypads forKey:@"JoyKitDefaultControllers"];
|
||||
}
|
||||
|
||||
- (NSButton *)autoUpdatesCheckbox
|
||||
- (IBAction)displayColorCorrectionHelp:(id)sender
|
||||
{
|
||||
return _autoUpdatesCheckbox;
|
||||
[GBWarningPopover popoverWithContents:
|
||||
GB_inline_const(NSString *[], {
|
||||
[GB_COLOR_CORRECTION_DISABLED] = @"Colors are directly interpreted as sRGB, resulting in unbalanced colors and inaccurate hues.",
|
||||
[GB_COLOR_CORRECTION_CORRECT_CURVES] = @"Colors have their brightness corrected, but hues remain unbalanced.",
|
||||
[GB_COLOR_CORRECTION_MODERN_BALANCED] = @"Emulates a modern display. Blue contrast is moderately enhanced at the cost of slight hue inaccuracy.",
|
||||
[GB_COLOR_CORRECTION_MODERN_BOOST_CONTRAST] = @"Like Modern – Balanced, but further boosts the contrast of greens and magentas that is lacking on the original hardware.",
|
||||
[GB_COLOR_CORRECTION_REDUCE_CONTRAST] = @"Slightly reduce the contrast to better represent the tint and contrast of the original display.",
|
||||
[GB_COLOR_CORRECTION_LOW_CONTRAST] = @"Harshly reduce the contrast to accurately represent the tint and low constrast of the original display.",
|
||||
[GB_COLOR_CORRECTION_MODERN_ACCURATE] = @"Emulates a modern display. Colors have their hues and brightness corrected.",
|
||||
}) [self.colorCorrectionPopupButton.selectedItem.tag]
|
||||
title:self.colorCorrectionPopupButton.selectedItem.title
|
||||
onView:sender
|
||||
timeout:6
|
||||
preferredEdge:NSRectEdgeMaxX];
|
||||
}
|
||||
|
||||
- (void)setAutoUpdatesCheckbox:(NSButton *)autoUpdatesCheckbox
|
||||
- (IBAction)displayHighPassHelp:(id)sender
|
||||
{
|
||||
_autoUpdatesCheckbox = autoUpdatesCheckbox;
|
||||
[_autoUpdatesCheckbox setState: [[NSUserDefaults standardUserDefaults] boolForKey:@"GBAutoUpdatesEnabled"]];
|
||||
[GBWarningPopover popoverWithContents:
|
||||
GB_inline_const(NSString *[], {
|
||||
[GB_HIGHPASS_OFF] = @"No high-pass filter will be applied. DC offset will be kept, pausing and resuming will trigger audio pops.",
|
||||
[GB_HIGHPASS_ACCURATE] = @"An accurate high-pass filter will be applied, removing the DC offset while somewhat attenuating the bass.",
|
||||
[GB_HIGHPASS_REMOVE_DC_OFFSET] = @"A high-pass filter will be applied to the DC offset itself, removing the DC offset while preserving the waveform.",
|
||||
}) [self.highpassFilterPopupButton.selectedItem.tag]
|
||||
title:self.highpassFilterPopupButton.selectedItem.title
|
||||
onView:sender
|
||||
timeout:6
|
||||
preferredEdge:NSRectEdgeMaxX];
|
||||
}
|
||||
|
||||
- (NSButton *)OSDCheckbox
|
||||
- (IBAction)arrangeJoyCons:(id)sender
|
||||
{
|
||||
return _OSDCheckbox;
|
||||
[GBJoyConManager sharedInstance].arrangementMode = true;
|
||||
[self beginSheet:self.joyconsSheet completionHandler:nil];
|
||||
}
|
||||
|
||||
- (void)setOSDCheckbox:(NSButton *)OSDCheckbox
|
||||
- (IBAction)closeJoyConsSheet:(id)sender
|
||||
{
|
||||
_OSDCheckbox = OSDCheckbox;
|
||||
[_OSDCheckbox setState: [[NSUserDefaults standardUserDefaults] boolForKey:@"GBOSDEnabled"]];
|
||||
}
|
||||
|
||||
- (IBAction)changeOSDEnabled:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[(NSButton *)sender state] == NSOnState
|
||||
forKey:@"GBOSDEnabled"];
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)changeFilterScreenshots:(id)sender
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[(NSButton *)sender state] == NSOnState
|
||||
forKey:@"GBFilterScreenshots"];
|
||||
}
|
||||
|
||||
- (NSButton *)screenshotFilterCheckbox
|
||||
{
|
||||
return _screenshotFilterCheckbox;
|
||||
}
|
||||
|
||||
- (void)setScreenshotFilterCheckbox:(NSButton *)screenshotFilterCheckbox
|
||||
{
|
||||
_screenshotFilterCheckbox = screenshotFilterCheckbox;
|
||||
if (![GBViewMetal isSupported]) {
|
||||
[_screenshotFilterCheckbox setEnabled:false];
|
||||
}
|
||||
else {
|
||||
[_screenshotFilterCheckbox setState: [[NSUserDefaults standardUserDefaults] boolForKey:@"GBFilterScreenshots"]];
|
||||
}
|
||||
[self endSheet:self.joyconsSheet];
|
||||
[GBJoyConManager sharedInstance].arrangementMode = false;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qxJ-pH-d0y">
|
||||
<rect key="frame" x="61.5" y="127" width="39" height="23"/>
|
||||
<rect key="frame" x="63.5" y="128" width="38" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="Play" imagePosition="only" alignment="center" alternateImage="Pause" state="on" borderStyle="border" focusRingType="none" inset="2" id="3ZK-br-UrS">
|
||||
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
|
||||
|
@ -54,37 +54,14 @@
|
|||
<action selector="togglePause:" target="-2" id="AUe-I7-nOK"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0yD-Sp-Ilo">
|
||||
<rect key="frame" x="19.5" y="127" width="38" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="Rewind" imagePosition="only" alignment="center" state="on" borderStyle="border" focusRingType="none" inset="2" id="ZIF-TP-Fqn">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="changeGBSTrack:" target="-2" id="jug-AS-bW7"/>
|
||||
</connections>
|
||||
</button>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="I1T-VS-Vse">
|
||||
<rect key="frame" x="106" y="127" width="131" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="YJh-dI-A5D">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="Knp-Ok-Pb4"/>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="changeGBSTrack:" target="-2" id="HET-AT-CfQ"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<segmentedControl verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SRS-M5-VVL">
|
||||
<rect key="frame" x="240.5" y="127" width="72" height="23"/>
|
||||
<rect key="frame" x="244.5" y="128" width="68" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<segmentedCell key="cell" borderStyle="border" alignment="left" style="texturedRounded" trackingMode="momentary" id="cmq-I8-cFL">
|
||||
<font key="font" metaFont="system"/>
|
||||
<segments>
|
||||
<segment toolTip="Previous Track" image="Previous" width="33"/>
|
||||
<segment toolTip="Next Track" image="Next" width="32" tag="1"/>
|
||||
<segment toolTip="Previous Track" image="Previous" width="31"/>
|
||||
<segment toolTip="Next Track" image="Next" width="30" tag="1"/>
|
||||
</segments>
|
||||
</segmentedCell>
|
||||
<connections>
|
||||
|
@ -114,6 +91,29 @@
|
|||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0yD-Sp-Ilo">
|
||||
<rect key="frame" x="20.5" y="128" width="38" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="Rewind" imagePosition="only" alignment="center" state="on" borderStyle="border" focusRingType="none" inset="2" id="ZIF-TP-Fqn">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="changeGBSTrack:" target="-2" id="jug-AS-bW7"/>
|
||||
</connections>
|
||||
</button>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="I1T-VS-Vse">
|
||||
<rect key="frame" x="107" y="127" width="131" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="YJh-dI-A5D">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="Knp-Ok-Pb4"/>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="changeGBSTrack:" target="-2" id="HET-AT-CfQ"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="67" y="292.5"/>
|
||||
</customView>
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14868" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14868"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="Document">
|
||||
<connections>
|
||||
<outlet property="gbsAuthor" destination="gaD-ZH-Beh" id="2i7-BD-bJ2"/>
|
||||
<outlet property="gbsCopyright" destination="2dl-dH-E3J" id="LnT-Vb-pN6"/>
|
||||
<outlet property="gbsNextPrevButton" destination="SRS-M5-VVL" id="YEN-01-wRX"/>
|
||||
<outlet property="gbsPlayPauseButton" destination="qxJ-pH-d0y" id="qk8-8I-9u5"/>
|
||||
<outlet property="gbsPlayerView" destination="c22-O7-iKe" id="A1w-e5-EQE"/>
|
||||
<outlet property="gbsRewindButton" destination="0yD-Sp-Ilo" id="FgR-xd-JW5"/>
|
||||
<outlet property="gbsTitle" destination="H3v-X3-48q" id="DCl-wL-oy8"/>
|
||||
<outlet property="gbsTracks" destination="I1T-VS-Vse" id="Vk4-GP-RjB"/>
|
||||
<outlet property="gbsVisualizer" destination="Q3o-bK-DIN" id="1YC-C5-Je6"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="c22-O7-iKe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="332" height="221"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="H3v-X3-48q">
|
||||
<rect key="frame" x="18" y="192" width="296" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Title" id="BwZ-Zj-sP6">
|
||||
<font key="font" metaFont="systemBold" size="16"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="gaD-ZH-Beh">
|
||||
<rect key="frame" x="18" y="166" width="296" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Author" id="IgT-r1-T38">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qxJ-pH-d0y">
|
||||
<rect key="frame" x="57" y="124" width="50" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" bezelStyle="rounded" image="Play" imagePosition="only" alignment="center" alternateImage="Pause" state="on" borderStyle="border" focusRingType="none" inset="2" id="3ZK-br-UrS">
|
||||
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="togglePause:" target="-2" id="AUe-I7-nOK"/>
|
||||
</connections>
|
||||
</button>
|
||||
<popUpButton focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="I1T-VS-Vse">
|
||||
<rect key="frame" x="105" y="127" width="141" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" borderStyle="border" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="YJh-dI-A5D">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" id="Knp-Ok-Pb4"/>
|
||||
</popUpButtonCell>
|
||||
<connections>
|
||||
<action selector="changeGBSTrack:" target="-2" id="HET-AT-CfQ"/>
|
||||
</connections>
|
||||
</popUpButton>
|
||||
<segmentedControl verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SRS-M5-VVL">
|
||||
<rect key="frame" x="247" y="129" width="68" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="momentary" id="cmq-I8-cFL">
|
||||
<font key="font" metaFont="system"/>
|
||||
<segments>
|
||||
<segment toolTip="Previous Track" image="Previous" width="31"/>
|
||||
<segment toolTip="Next Track" image="Next" width="30" tag="1"/>
|
||||
</segments>
|
||||
</segmentedCell>
|
||||
<connections>
|
||||
<action selector="gbsNextPrevPushed:" target="-2" id="roN-Iy-tDQ"/>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="b9A-cd-ias">
|
||||
<rect key="frame" x="0.0" y="117" width="332" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</box>
|
||||
<customView appearanceType="darkAqua" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tRy-Gw-IaG" customClass="GBOptionalVisualEffectView">
|
||||
<rect key="frame" x="0.0" y="24" width="332" height="95"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q3o-bK-DIN" customClass="GBVisualizerView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="332" height="95"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</customView>
|
||||
</subviews>
|
||||
</customView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="2dl-dH-E3J">
|
||||
<rect key="frame" x="18" y="5" width="296" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="Copyright" id="nM9-oF-OV9">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0yD-Sp-Ilo">
|
||||
<rect key="frame" x="13" y="124" width="50" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" bezelStyle="rounded" image="Rewind" imagePosition="only" alignment="center" state="on" borderStyle="border" focusRingType="none" inset="2" id="ZIF-TP-Fqn">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="changeGBSTrack:" target="-2" id="jug-AS-bW7"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="67" y="292.5"/>
|
||||
</customView>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="Next" width="16" height="10"/>
|
||||
<image name="Pause" width="10" height="10"/>
|
||||
<image name="Play" width="10" height="10"/>
|
||||
<image name="Previous" width="16" height="10"/>
|
||||
<image name="Rewind" width="10" height="10"/>
|
||||
</resources>
|
||||
</document>
|
|
@ -19,6 +19,12 @@
|
|||
return [super dividerColor];
|
||||
}
|
||||
|
||||
- (void)drawDividerInRect:(NSRect)rect
|
||||
{
|
||||
[self.dividerColor set];
|
||||
NSRectFill(rect);
|
||||
}
|
||||
|
||||
/* Mavericks comaptibility */
|
||||
- (NSArray<NSView *> *)arrangedSubviews
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#include <Core/gb.h>
|
||||
#import <Core/gb.h>
|
||||
|
||||
@interface GBTerminalTextFieldCell : NSTextFieldCell
|
||||
@property (nonatomic) GB_gameboy_t *gb;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
#import <Carbon/Carbon.h>
|
||||
#import "GBTerminalTextFieldCell.h"
|
||||
#import "NSTextFieldCell+Inset.h"
|
||||
|
||||
@interface GBTerminalTextView : NSTextView
|
||||
{
|
||||
@public __weak NSTextField *_field;
|
||||
}
|
||||
@property GB_gameboy_t *gb;
|
||||
@end
|
||||
|
||||
|
@ -10,7 +14,7 @@
|
|||
GBTerminalTextView *field_editor;
|
||||
}
|
||||
|
||||
- (NSTextView *)fieldEditorForView:(NSView *)controlView
|
||||
- (NSTextView *)fieldEditorForView:(NSTextField *)controlView
|
||||
{
|
||||
if (field_editor) {
|
||||
field_editor.gb = self.gb;
|
||||
|
@ -19,6 +23,10 @@
|
|||
field_editor = [[GBTerminalTextView alloc] init];
|
||||
[field_editor setFieldEditor:true];
|
||||
field_editor.gb = self.gb;
|
||||
field_editor->_field = (NSTextField *)controlView;
|
||||
((NSTextFieldCell *)controlView.cell).textInset =
|
||||
field_editor.textContainerInset =
|
||||
NSMakeSize(0, 2);
|
||||
return field_editor;
|
||||
}
|
||||
|
||||
|
@ -185,14 +193,21 @@
|
|||
return [super resignFirstResponder];
|
||||
}
|
||||
|
||||
-(void)drawRect:(NSRect)dirtyRect
|
||||
- (NSColor *)backgroundColor
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
[super drawRect:dirtyRect];
|
||||
if (reverse_search_mode && [super string].length == 0) {
|
||||
NSMutableDictionary *attributes = [self.typingAttributes mutableCopy];
|
||||
NSColor *color = [attributes[NSForegroundColorAttributeName] colorWithAlphaComponent:0.5];
|
||||
[attributes setObject:color forKey:NSForegroundColorAttributeName];
|
||||
[[[NSAttributedString alloc] initWithString:@"Reverse search..." attributes:attributes] drawAtPoint:NSMakePoint(2, 0)];
|
||||
[[[NSAttributedString alloc] initWithString:@"Reverse search..." attributes:attributes] drawAtPoint:NSMakePoint(2, 2)];
|
||||
}
|
||||
else {
|
||||
[super drawRect:dirtyRect];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBTintedImageCell : NSImageCell
|
||||
@property NSColor *tint;
|
||||
@end
|
|
@ -0,0 +1,20 @@
|
|||
#import "GBTintedImageCell.h"
|
||||
|
||||
@implementation GBTintedImageCell
|
||||
|
||||
- (NSImage *)image
|
||||
{
|
||||
if (!self.tint || !super.image.isTemplate) {
|
||||
return [super image];
|
||||
}
|
||||
|
||||
NSImage *tinted = [super.image copy];
|
||||
[tinted lockFocus];
|
||||
[self.tint set];
|
||||
NSRectFillUsingOperation((NSRect){.size = tinted.size}, NSCompositeSourceIn);
|
||||
[tinted unlockFocus];
|
||||
tinted.template = false;
|
||||
return tinted;
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,31 +1,16 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#include <Core/gb.h>
|
||||
#import <JoyKit/JoyKit.h>
|
||||
#import "GBOSDView.h"
|
||||
#import "GBViewBase.h"
|
||||
|
||||
|
||||
@class Document;
|
||||
|
||||
typedef enum {
|
||||
GB_FRAME_BLENDING_MODE_DISABLED,
|
||||
GB_FRAME_BLENDING_MODE_SIMPLE,
|
||||
GB_FRAME_BLENDING_MODE_ACCURATE,
|
||||
GB_FRAME_BLENDING_MODE_ACCURATE_EVEN = GB_FRAME_BLENDING_MODE_ACCURATE,
|
||||
GB_FRAME_BLENDING_MODE_ACCURATE_ODD,
|
||||
} GB_frame_blending_mode_t;
|
||||
|
||||
@interface GBView : NSView<JOYListener>
|
||||
- (void) flip;
|
||||
- (uint32_t *) pixels;
|
||||
@interface GBView : GBViewBase<JOYListener>
|
||||
@property (nonatomic, weak) IBOutlet Document *document;
|
||||
@property (nonatomic) GB_gameboy_t *gb;
|
||||
@property (nonatomic) GB_frame_blending_mode_t frameBlendingMode;
|
||||
@property (nonatomic, getter=isMouseHidingEnabled) bool mouseHidingEnabled;
|
||||
@property (nonatomic) bool isRewinding;
|
||||
@property (nonatomic, strong) NSView *internalView;
|
||||
@property (weak) GBOSDView *osdView;
|
||||
- (void) createInternalView;
|
||||
- (uint32_t *)currentBuffer;
|
||||
- (uint32_t *)previousBuffer;
|
||||
- (void)screenSizeChanged;
|
||||
- (void)setRumble: (double)amp;
|
||||
- (NSImage *)renderToImage;
|
||||
- (void)setRumble: (double)amp;
|
||||
@end
|
||||
|
|
224
Cocoa/GBView.m
|
@ -5,6 +5,7 @@
|
|||
#import "GBViewMetal.h"
|
||||
#import "GBButtons.h"
|
||||
#import "NSString+StringForKey.h"
|
||||
#import "NSObject+DefaultsObserver.h"
|
||||
#import "Document.h"
|
||||
|
||||
#define JOYSTICK_HIGH 0x4000
|
||||
|
@ -104,8 +105,6 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
|
||||
@implementation GBView
|
||||
{
|
||||
uint32_t *image_buffers[3];
|
||||
unsigned char current_buffer;
|
||||
bool mouse_hidden;
|
||||
NSTrackingArea *tracking_area;
|
||||
bool _mouseHidingEnabled;
|
||||
|
@ -116,9 +115,10 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
bool analogClockMultiplierValid;
|
||||
NSEventModifierFlags previousModifiers;
|
||||
JOYController *lastController;
|
||||
GB_frame_blending_mode_t _frameBlendingMode;
|
||||
bool _turbo;
|
||||
bool _mouseControlEnabled;
|
||||
NSMutableDictionary<NSNumber *, JOYController *> *_controllerMapping;
|
||||
unsigned _lastPlayerCount;
|
||||
}
|
||||
|
||||
+ (instancetype)alloc
|
||||
|
@ -137,16 +137,17 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
return [super allocWithZone:zone];
|
||||
}
|
||||
|
||||
- (void) createInternalView
|
||||
{
|
||||
assert(false && "createInternalView must not be inherited");
|
||||
}
|
||||
|
||||
- (void) _init
|
||||
{
|
||||
[self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ratioKeepingChanged) name:@"GBAspectChanged" object:nil];
|
||||
__unsafe_unretained GBView *weakSelf = self;
|
||||
[self observeStandardDefaultsKey:@"GBAspectRatioUnkept" withBlock:^(id newValue) {
|
||||
[weakSelf setFrame:weakSelf.superview.frame];
|
||||
}];
|
||||
[self observeStandardDefaultsKey:@"JoyKitDefaultControllers" withBlock:^(id newValue) {
|
||||
[weakSelf reassignControllers];
|
||||
}];
|
||||
tracking_area = [ [NSTrackingArea alloc] initWithRect:(NSRect){}
|
||||
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect | NSTrackingMouseMoved
|
||||
owner:self
|
||||
|
@ -158,57 +159,97 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
self.internalView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
|
||||
[JOYController registerListener:self];
|
||||
_mouseControlEnabled = true;
|
||||
[self reassignControllers];
|
||||
}
|
||||
|
||||
- (void)controllerConnected:(JOYController *)controller
|
||||
{
|
||||
[self reassignControllers];
|
||||
}
|
||||
|
||||
- (void)controllerDisconnected:(JOYController *)controller
|
||||
{
|
||||
[self reassignControllers];
|
||||
}
|
||||
|
||||
- (unsigned)playerCount
|
||||
{
|
||||
if (self.document.partner) {
|
||||
return 2;
|
||||
}
|
||||
if (!_gb) {
|
||||
return 1;
|
||||
}
|
||||
return GB_get_player_count(_gb);
|
||||
}
|
||||
|
||||
- (void)reassignControllers
|
||||
{
|
||||
unsigned playerCount = self.playerCount;
|
||||
/* Don't assign controlelrs if there's only one player, allow all controllers. */
|
||||
if (playerCount == 1) {
|
||||
_controllerMapping = [NSMutableDictionary dictionary];
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_controllerMapping) {
|
||||
_controllerMapping = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
for (NSNumber *player in [_controllerMapping copy]) {
|
||||
if (player.unsignedIntValue >= playerCount || !_controllerMapping[player].connected) {
|
||||
[_controllerMapping removeObjectForKey:player];
|
||||
}
|
||||
}
|
||||
|
||||
_lastPlayerCount = playerCount;
|
||||
for (unsigned i = 0; i < playerCount; i++) {
|
||||
NSString *preferredJoypad = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"JoyKitDefaultControllers"]
|
||||
objectForKey:n2s(i)];
|
||||
for (JOYController *controller in [JOYController allControllers]) {
|
||||
if (!controller.connected) continue;
|
||||
if ([controller.uniqueID isEqual:preferredJoypad]) {
|
||||
_controllerMapping[@(i)] = controller;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tryAssigningController:(JOYController *)controller
|
||||
{
|
||||
unsigned playerCount = self.playerCount;
|
||||
if (playerCount == 1) return;
|
||||
if (_controllerMapping.count == playerCount) return;
|
||||
if ([_controllerMapping.allValues containsObject:controller]) return;
|
||||
for (unsigned i = 0; i < playerCount; i++) {
|
||||
if (!_controllerMapping[@(i)]) {
|
||||
_controllerMapping[@(i)] = controller;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary<NSNumber *, JOYController *> *)controllerMapping
|
||||
{
|
||||
if (_lastPlayerCount != self.playerCount) {
|
||||
[self reassignControllers];
|
||||
}
|
||||
|
||||
return _controllerMapping;
|
||||
}
|
||||
|
||||
- (void)screenSizeChanged
|
||||
{
|
||||
if (image_buffers[0]) free(image_buffers[0]);
|
||||
if (image_buffers[1]) free(image_buffers[1]);
|
||||
if (image_buffers[2]) free(image_buffers[2]);
|
||||
|
||||
size_t buffer_size = sizeof(image_buffers[0][0]) * GB_get_screen_width(_gb) * GB_get_screen_height(_gb);
|
||||
|
||||
image_buffers[0] = calloc(1, buffer_size);
|
||||
image_buffers[1] = calloc(1, buffer_size);
|
||||
image_buffers[2] = calloc(1, buffer_size);
|
||||
[super screenSizeChanged];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self setFrame:self.superview.frame];
|
||||
});
|
||||
}
|
||||
|
||||
- (void) ratioKeepingChanged
|
||||
{
|
||||
[self setFrame:self.superview.frame];
|
||||
}
|
||||
|
||||
- (void) setFrameBlendingMode:(GB_frame_blending_mode_t)frameBlendingMode
|
||||
{
|
||||
_frameBlendingMode = frameBlendingMode;
|
||||
[self setNeedsDisplay:true];
|
||||
}
|
||||
|
||||
|
||||
- (GB_frame_blending_mode_t)frameBlendingMode
|
||||
{
|
||||
if (_frameBlendingMode == GB_FRAME_BLENDING_MODE_ACCURATE) {
|
||||
if (!_gb || GB_is_sgb(_gb)) {
|
||||
return GB_FRAME_BLENDING_MODE_SIMPLE;
|
||||
}
|
||||
return GB_is_odd_frame(_gb)? GB_FRAME_BLENDING_MODE_ACCURATE_ODD : GB_FRAME_BLENDING_MODE_ACCURATE_EVEN;
|
||||
}
|
||||
return _frameBlendingMode;
|
||||
}
|
||||
- (unsigned char) numberOfBuffers
|
||||
{
|
||||
return _frameBlendingMode? 3 : 2;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(image_buffers[0]);
|
||||
free(image_buffers[1]);
|
||||
free(image_buffers[2]);
|
||||
if (mouse_hidden) {
|
||||
mouse_hidden = false;
|
||||
[NSCursor unhide];
|
||||
|
@ -217,6 +258,7 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
[self setRumble:0];
|
||||
[JOYController unregisterListener:self];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
if (!(self = [super initWithCoder:coder])) {
|
||||
|
@ -295,18 +337,13 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
}
|
||||
if ((!analogClockMultiplierValid && clockMultiplier > 1) ||
|
||||
_turbo || (analogClockMultiplierValid && analogClockMultiplier > 1)) {
|
||||
[self.osdView displayText:@"Fast forwarding..."];
|
||||
[self.osdView displayText:@"Fast forwarding…"];
|
||||
}
|
||||
else if ((!analogClockMultiplierValid && clockMultiplier < 1) ||
|
||||
(analogClockMultiplierValid && analogClockMultiplier < 1)) {
|
||||
[self.osdView displayText:@"Slow motion..."];
|
||||
[self.osdView displayText:@"Slow motion…"];
|
||||
}
|
||||
current_buffer = (current_buffer + 1) % self.numberOfBuffers;
|
||||
}
|
||||
|
||||
- (uint32_t *) pixels
|
||||
{
|
||||
return image_buffers[(current_buffer + 1) % self.numberOfBuffers];
|
||||
[super flip];
|
||||
}
|
||||
|
||||
-(void)keyDown:(NSEvent *)theEvent
|
||||
|
@ -474,10 +511,21 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
return true;
|
||||
}
|
||||
|
||||
- (bool)allowController
|
||||
{
|
||||
if ([self.window isMainWindow]) return true;
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBAllowBackgroundControllers"]) {
|
||||
if ([(Document *)[NSApplication sharedApplication].orderedDocuments.firstObject mainWindow] == self.window) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
- (void)controller:(JOYController *)controller movedAxis:(JOYAxis *)axis
|
||||
{
|
||||
if (!_gb) return;
|
||||
if (![self.window isMainWindow]) return;
|
||||
if (![self allowController]) return;
|
||||
|
||||
NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"JoyKitInstanceMapping"][controller.uniqueID];
|
||||
if (!mapping) {
|
||||
|
@ -512,6 +560,28 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
if (!_gb) return;
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBMBC7JoystickOverride"]) return;
|
||||
if (self.mouseControlsActive) return;
|
||||
if (controller != lastController) return;
|
||||
// When using Joy-Cons in dual-controller grip, ignore motion data from the left Joy-Con
|
||||
if (controller.joyconType == JOYJoyConTypeDual) {
|
||||
for (JOYController *child in [(JOYCombinedController *)controller children]) {
|
||||
if (child.joyconType != JOYJoyConTypeRight && [child.axes3D containsObject:axes]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSDictionary<NSNumber *, JOYController *> *controllerMapping = [self controllerMapping];
|
||||
GB_gameboy_t *effectiveGB = _gb;
|
||||
|
||||
if (self.document.partner) {
|
||||
if (controllerMapping[@1] == controller) {
|
||||
effectiveGB = self.document.partner.gb;
|
||||
}
|
||||
if (controllerMapping[@0] != controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (axes.usage == JOYAxes3DUsageOrientation) {
|
||||
for (JOYAxes3D *axes in controller.axes3D) {
|
||||
|
@ -521,37 +591,35 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
}
|
||||
}
|
||||
JOYPoint3D point = axes.normalizedValue;
|
||||
GB_set_accelerometer_values(_gb, point.x, point.z);
|
||||
GB_set_accelerometer_values(effectiveGB, point.x, point.z);
|
||||
}
|
||||
else if (axes.usage == JOYAxes3DUsageAcceleration) {
|
||||
JOYPoint3D point = axes.gUnitsValue;
|
||||
GB_set_accelerometer_values(_gb, point.x, point.z);
|
||||
GB_set_accelerometer_values(effectiveGB, point.x, point.z);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)controller:(JOYController *)controller buttonChangedState:(JOYButton *)button
|
||||
{
|
||||
if (!_gb) return;
|
||||
if (![self.window isMainWindow]) return;
|
||||
if (![self allowController]) return;
|
||||
_mouseControlEnabled = false;
|
||||
if (button.type == JOYButtonTypeAxes2DEmulated && [self shouldControllerUseJoystickForMotion:controller]) return;
|
||||
|
||||
unsigned player_count = GB_get_player_count(_gb);
|
||||
if (self.document.partner) {
|
||||
player_count = 2;
|
||||
}
|
||||
[self tryAssigningController:controller];
|
||||
|
||||
unsigned playerCount = self.playerCount;
|
||||
|
||||
IOPMAssertionID assertionID;
|
||||
IOPMAssertionDeclareUserActivity(CFSTR(""), kIOPMUserActiveLocal, &assertionID);
|
||||
|
||||
for (unsigned player = 0; player < player_count; player++) {
|
||||
NSString *preferred_joypad = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"JoyKitDefaultControllers"]
|
||||
objectForKey:n2s(player)];
|
||||
if (player_count != 1 && // Single player, accpet inputs from all joypads
|
||||
!(player == 0 && !preferred_joypad) && // Multiplayer, but player 1 has no joypad configured, so it takes inputs from all joypads
|
||||
![preferred_joypad isEqualToString:controller.uniqueID]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSDictionary<NSNumber *, JOYController *> *controllerMapping = [self controllerMapping];
|
||||
for (unsigned player = 0; player < playerCount; player++) {
|
||||
JOYController *preferredJoypad = controllerMapping[@(player)];
|
||||
if (preferredJoypad && preferredJoypad != controller) continue; // The player has a different assigned controller
|
||||
if (!preferredJoypad && playerCount != 1) continue; // The player has no assigned controller in multiplayer mode, prevent controller inputs
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[controller setPlayerLEDs:[controller LEDMaskForPlayer:player]];
|
||||
});
|
||||
|
@ -562,7 +630,7 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
|
||||
JOYButtonUsage usage = ((JOYButtonUsage)[mapping[n2s(button.uniqueID)] unsignedIntValue]) ?: button.usage;
|
||||
if (!mapping && usage >= JOYButtonUsageGeneric0) {
|
||||
usage = (const JOYButtonUsage[]){JOYButtonUsageY, JOYButtonUsageA, JOYButtonUsageB, JOYButtonUsageX}[(usage - JOYButtonUsageGeneric0) & 3];
|
||||
usage = GB_inline_const(JOYButtonUsage[], {JOYButtonUsageY, JOYButtonUsageA, JOYButtonUsageB, JOYButtonUsageX})[(usage - JOYButtonUsageGeneric0) & 3];
|
||||
}
|
||||
|
||||
GB_gameboy_t *effectiveGB = _gb;
|
||||
|
@ -740,16 +808,6 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||
previousModifiers = event.modifierFlags;
|
||||
}
|
||||
|
||||
- (uint32_t *)currentBuffer
|
||||
{
|
||||
return image_buffers[current_buffer];
|
||||
}
|
||||
|
||||
- (uint32_t *)previousBuffer
|
||||
{
|
||||
return image_buffers[(current_buffer + 2) % self.numberOfBuffers];
|
||||
}
|
||||
|
||||
-(NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
NSPasteboard *pboard = [sender draggingPasteboard];
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
#import "GBView.h"
|
||||
|
||||
@interface GBViewMetal : GBView<MTKViewDelegate>
|
||||
+ (bool) isSupported;
|
||||
@end
|
|
@ -1,5 +1,5 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
#include <Core/gb.h>
|
||||
#import <Core/gb.h>
|
||||
|
||||
@interface GBVisualizerView : NSView
|
||||
- (void)addSample:(GB_sample_t *)sample;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "GBVisualizerView.h"
|
||||
#import "GBPaletteEditorController.h"
|
||||
#include <Core/gb.h>
|
||||
#import <Core/gb.h>
|
||||
|
||||
#define SAMPLE_COUNT 1024
|
||||
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
|
||||
+ (GBWarningPopover *) popoverWithContents:(NSString *)contents onView:(NSView *)view;
|
||||
+ (GBWarningPopover *) popoverWithContents:(NSString *)contents onWindow:(NSWindow *)window;
|
||||
+ (GBWarningPopover *) popoverWithContents:(NSString *)contents title:(NSString *)title onView:(NSView *)view timeout:(double)seconds preferredEdge:(NSRectEdge)preferredEdge;
|
||||
|
||||
@end
|
||||
|
|
|
@ -4,7 +4,7 @@ static GBWarningPopover *lastPopover;
|
|||
|
||||
@implementation GBWarningPopover
|
||||
|
||||
+ (GBWarningPopover *) popoverWithContents:(NSString *)contents onView:(NSView *)view
|
||||
+ (GBWarningPopover *) popoverWithContents:(NSString *)contents title:(NSString *)title onView:(NSView *)view timeout:(double)seconds preferredEdge:(NSRectEdge)preferredEdge
|
||||
{
|
||||
[lastPopover close];
|
||||
lastPopover = [[self alloc] init];
|
||||
|
@ -13,7 +13,17 @@ static GBWarningPopover *lastPopover;
|
|||
[lastPopover setAnimates:true];
|
||||
lastPopover.contentViewController = [[NSViewController alloc] initWithNibName:@"PopoverView" bundle:nil];
|
||||
NSTextField *field = (NSTextField *)lastPopover.contentViewController.view;
|
||||
[field setStringValue:contents];
|
||||
if (!title) {
|
||||
[field setStringValue:contents];
|
||||
}
|
||||
else {
|
||||
NSMutableAttributedString *fullContents = [[NSMutableAttributedString alloc] initWithString:title
|
||||
attributes:@{NSFontAttributeName: [NSFont boldSystemFontOfSize:[NSFont systemFontSize]]}];
|
||||
[fullContents appendAttributedString:[[NSAttributedString alloc] initWithString:[@"\n" stringByAppendingString:contents]
|
||||
attributes:@{NSFontAttributeName: [NSFont systemFontOfSize:[NSFont systemFontSize]]}]];
|
||||
[field setAttributedStringValue:fullContents];
|
||||
|
||||
}
|
||||
NSSize textSize = [field.cell cellSizeForBounds:[field.cell drawingRectForBounds:NSMakeRect(0, 0, 240, CGFLOAT_MAX)]];
|
||||
textSize.width = ceil(textSize.width) + 16;
|
||||
textSize.height = ceil(textSize.height) + 12;
|
||||
|
@ -25,11 +35,13 @@ static GBWarningPopover *lastPopover;
|
|||
|
||||
[lastPopover showRelativeToRect:view.bounds
|
||||
ofView:view
|
||||
preferredEdge:NSMinYEdge];
|
||||
preferredEdge:preferredEdge];
|
||||
|
||||
NSRect frame = field.frame;
|
||||
frame.origin.x += 8;
|
||||
frame.origin.y -= 6;
|
||||
frame.origin.y += 6;
|
||||
frame.size.width -= 16;
|
||||
frame.size.height -= 12;
|
||||
field.frame = frame;
|
||||
|
||||
|
||||
|
@ -38,6 +50,11 @@ static GBWarningPopover *lastPopover;
|
|||
return lastPopover;
|
||||
}
|
||||
|
||||
+ (GBWarningPopover *) popoverWithContents:(NSString *)contents onView:(NSView *)view
|
||||
{
|
||||
return [self popoverWithContents:contents title:nil onView:view timeout:3.0 preferredEdge:NSMinYEdge];
|
||||
}
|
||||
|
||||
+ (GBWarningPopover *)popoverWithContents:(NSString *)contents onWindow:(NSWindow *)window
|
||||
{
|
||||
return [self popoverWithContents:contents onView:window.contentView.superview.subviews.lastObject];
|
||||
|
|
After Width: | Height: | Size: 183 B |