(Old stuff) Adds sliders. Rewrote some bits.
This commit is contained in:
parent
7c5ebc89b8
commit
b30e357d08
3 changed files with 189 additions and 89 deletions
|
@ -11,10 +11,13 @@ find_library(FOUNDATION_LIBRARY Foundation)
|
||||||
find_library(COCOA_LIBRARY Cocoa)
|
find_library(COCOA_LIBRARY Cocoa)
|
||||||
find_library(COREGRAPHICS_LIBRARY CoreGraphics)
|
find_library(COREGRAPHICS_LIBRARY CoreGraphics)
|
||||||
find_library(OPENGL_LIBRARY OpenGL)
|
find_library(OPENGL_LIBRARY OpenGL)
|
||||||
|
find_library(QUARTZCORE_LIBRARY QuartzCore)
|
||||||
|
|
||||||
set(libs ${FOUNDATION_LIBRARY} ${COCOA_LIBRARY} ${COREGRAPHICS_LIBRARY} ${OPENGL_LIBRARY})
|
set(libs ${FOUNDATION_LIBRARY} ${COCOA_LIBRARY} ${COREGRAPHICS_LIBRARY} ${OPENGL_LIBRARY} ${QUARTZCORE_LIBRARY})
|
||||||
|
set(${LIBNAME}_LIBRARIES ${LIBNAME} ${libs} CACHE INTERNAL "")
|
||||||
|
|
||||||
target_link_libraries(${LIBNAME} ${libs})
|
target_link_libraries(${LIBNAME} ${libs})
|
||||||
|
target_include_directories(${LIBNAME} PUBLIC ".")
|
||||||
|
|
||||||
install(TARGETS ${LIBNAME} DESTINATION lib)
|
install(TARGETS ${LIBNAME} DESTINATION lib)
|
||||||
install(FILES ${headers} DESTINATION include/J)
|
install(FILES ${headers} DESTINATION include/J)
|
||||||
|
|
|
@ -10,12 +10,18 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <CoreGraphics/CoreGraphics.h>
|
#include <CoreGraphics/CoreGraphics.h>
|
||||||
|
|
||||||
struct GLContext;
|
struct GLContext;
|
||||||
struct ContextParameters{
|
struct ContextParameters{
|
||||||
GLContext & context;
|
GLContext & context;
|
||||||
|
|
||||||
|
// These two functions will be set when invoking the draw_callback (and should be used)
|
||||||
|
std::function<void(void)> bind_framebuffer; // function to bind the systems framebuffer and set the viewport
|
||||||
|
std::function<void(void)> flush_drawable; // function to flush the drawable
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GLViewFunctionality {
|
struct GLViewFunctionality {
|
||||||
|
@ -26,6 +32,16 @@ struct GLViewFunctionality {
|
||||||
std::function<void(ContextParameters, CGFloat, CGFloat)> resize_callback;
|
std::function<void(ContextParameters, CGFloat, CGFloat)> resize_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Control {
|
||||||
|
std::string name = "default";
|
||||||
|
double start = 0, min = 0, max = 1;
|
||||||
|
std::function<void(double)> callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ControlFunctionality {
|
||||||
|
std::vector<Control> sliders;
|
||||||
|
};
|
||||||
|
|
||||||
// returns a GLViewFunctionality with only its draw function set.
|
// returns a GLViewFunctionality with only its draw function set.
|
||||||
GLViewFunctionality simple_draw(std::function<void()> f);
|
GLViewFunctionality simple_draw(std::function<void()> f);
|
||||||
|
|
||||||
|
@ -35,6 +51,7 @@ struct NSAppWrapper {
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
void create_window(GLViewFunctionality const &);
|
void create_window(GLViewFunctionality const &);
|
||||||
|
void create_window(ControlFunctionality const &);
|
||||||
|
|
||||||
std::unique_ptr<struct NSAppWrapperImpl> impl;
|
std::unique_ptr<struct NSAppWrapperImpl> impl;
|
||||||
};
|
};
|
||||||
|
|
196
NSWrapper.mm
196
NSWrapper.mm
|
@ -25,55 +25,128 @@ GLViewFunctionality simple_draw(std::function<void()> f){
|
||||||
@property GLViewFunctionality functionality;
|
@property GLViewFunctionality functionality;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface MySlider : NSSlider
|
||||||
|
- (instancetype) initWithFrame:(NSRect)frame;
|
||||||
|
- (void)action:(MySlider*)sender;
|
||||||
|
@property std::function<void(CGFloat)> callback;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MySlider
|
||||||
|
- (instancetype) initWithFrame:(NSRect)frame{
|
||||||
|
if(self = [super initWithFrame: frame]){
|
||||||
|
self.target = self;
|
||||||
|
self.action = @selector(action:);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)action:(MySlider*)sender{
|
||||||
|
if(self.callback){
|
||||||
|
self.callback(sender.doubleValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
struct NSAppWrapperImpl {
|
struct NSAppWrapperImpl {
|
||||||
NSAppWrapperImpl() {
|
NSAppWrapperImpl() {
|
||||||
app = [NSApplication sharedApplication];
|
app = [NSApplication sharedApplication];
|
||||||
app.activationPolicy = NSApplicationActivationPolicyRegular;
|
app.activationPolicy = NSApplicationActivationPolicyRegular;
|
||||||
appName = [[NSProcessInfo processInfo] processName];
|
appName = [[NSProcessInfo processInfo] processName];
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_up_menu() {
|
void set_up_menu() {
|
||||||
NSMenu* appMenu = [NSMenu new];
|
NSMenu* appMenu = [NSMenu new];
|
||||||
[appMenu addItemWithTitle:[@"Quit " stringByAppendingString:appName]
|
[appMenu addItemWithTitle:[@"Quit " stringByAppendingString:appName]
|
||||||
action:@selector(terminate:)
|
action:@selector(terminate:)
|
||||||
keyEquivalent:@"q"];
|
keyEquivalent:@"q"];
|
||||||
|
|
||||||
NSMenuItem * menuItem = [NSMenuItem new];
|
NSMenuItem * menuItem = [NSMenuItem new];
|
||||||
menuItem.submenu = appMenu;
|
menuItem.submenu = appMenu;
|
||||||
|
|
||||||
app.mainMenu = [NSMenu new];
|
app.mainMenu = [NSMenu new];
|
||||||
[app.mainMenu addItem:menuItem];
|
[app.mainMenu addItem:menuItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_window(GLViewFunctionality const & f) {
|
void create_window(GLViewFunctionality const & f) {
|
||||||
NSWindow * window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 500, 500)
|
NSWindow * window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 500, 500)
|
||||||
styleMask:NSTitledWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask
|
styleMask:NSTitledWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask
|
||||||
backing:NSBackingStoreBuffered
|
backing:NSBackingStoreBuffered
|
||||||
defer:YES];
|
defer:YES];
|
||||||
window.title = appName;
|
window.title = appName;
|
||||||
window.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
|
window.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
|
||||||
[window center];
|
if(windows.empty()){
|
||||||
[window makeKeyAndOrderFront:nil];
|
[window center];
|
||||||
|
} else {
|
||||||
|
NSWindow * previous_window = windows.back();
|
||||||
|
NSPoint top_right = previous_window.frame.origin;
|
||||||
|
top_right.x += previous_window.frame.size.width;
|
||||||
|
top_right.y += previous_window.frame.size.height;
|
||||||
|
[window setFrameTopLeftPoint: top_right];
|
||||||
|
}
|
||||||
|
[window makeKeyAndOrderFront:nil];
|
||||||
|
|
||||||
NSRect frame = [window contentRectForFrameRect:window.frame];
|
NSRect frame = [window contentRectForFrameRect:window.frame];
|
||||||
frame.origin = {0, 0};
|
frame.origin = {0, 0};
|
||||||
GLView * view = [[GLView alloc] initWithFrame:frame];
|
GLView * view = [[GLView alloc] initWithFrame:frame];
|
||||||
|
|
||||||
view.functionality = f;
|
view.functionality = f;
|
||||||
|
|
||||||
window.contentView = view;
|
window.contentView = view;
|
||||||
|
windows.push_back(window);
|
||||||
|
}
|
||||||
|
|
||||||
windows.push_back(window);
|
void create_window(ControlFunctionality const & f) {
|
||||||
}
|
const CGFloat width = 200;
|
||||||
|
NSWindow * window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, 500)
|
||||||
|
styleMask:NSTitledWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask
|
||||||
|
backing:NSBackingStoreBuffered
|
||||||
|
defer:YES];
|
||||||
|
window.title = appName;
|
||||||
|
if(windows.empty()){
|
||||||
|
[window center];
|
||||||
|
} else {
|
||||||
|
NSWindow * previous_window = windows.back();
|
||||||
|
NSPoint top_right = previous_window.frame.origin;
|
||||||
|
top_right.x += previous_window.frame.size.width;
|
||||||
|
top_right.y += previous_window.frame.size.height;
|
||||||
|
[window setFrameTopLeftPoint: top_right];
|
||||||
|
}
|
||||||
|
[window makeKeyAndOrderFront:nil];
|
||||||
|
|
||||||
void run() {
|
NSRect frame = [window contentRectForFrameRect:window.frame];
|
||||||
[app run];
|
frame.origin = {0, 0};
|
||||||
}
|
NSView * view = [[NSView alloc] initWithFrame:frame];
|
||||||
|
|
||||||
NSApplication * app;
|
CGFloat y = 0;
|
||||||
std::vector<NSWindow *> windows;
|
CGFloat h = 20;
|
||||||
NSString * appName;
|
CGFloat padding = 8;
|
||||||
|
for(auto&& c : f.sliders){
|
||||||
|
NSTextField * label = [[NSTextField alloc] initWithFrame:{padding, y+padding, 20, h}];
|
||||||
|
label.editable = NO;
|
||||||
|
label.bezeled = NO;
|
||||||
|
label.drawsBackground = NO;
|
||||||
|
label.stringValue = [NSString stringWithUTF8String: c.name.c_str()];
|
||||||
|
[view addSubview: label];
|
||||||
|
|
||||||
|
MySlider * slider = [[MySlider alloc] initWithFrame:{20+padding, y+padding, width-20-2*padding, h}];
|
||||||
|
slider.minValue = c.min;
|
||||||
|
slider.maxValue = c.max;
|
||||||
|
slider.doubleValue = c.start;
|
||||||
|
slider.callback = c.callback;
|
||||||
|
[view addSubview: slider];
|
||||||
|
y += h;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.contentView = view;
|
||||||
|
windows.push_back(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
[app run];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSApplication * app;
|
||||||
|
std::vector<NSWindow *> windows;
|
||||||
|
NSString * appName;
|
||||||
};
|
};
|
||||||
|
|
||||||
NSAppWrapper::NSAppWrapper()
|
NSAppWrapper::NSAppWrapper()
|
||||||
|
@ -88,7 +161,11 @@ void NSAppWrapper::run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NSAppWrapper::create_window(GLViewFunctionality const & f){
|
void NSAppWrapper::create_window(GLViewFunctionality const & f){
|
||||||
impl->create_window(f);
|
impl->create_window(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSAppWrapper::create_window(ControlFunctionality const & f){
|
||||||
|
impl->create_window(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,11 +186,11 @@ void NSAppWrapper::create_window(GLViewFunctionality const & f){
|
||||||
|
|
||||||
- (id) initWithFrame:(NSRect)frameRect {
|
- (id) initWithFrame:(NSRect)frameRect {
|
||||||
if(self = [super initWithFrame:frameRect]){
|
if(self = [super initWithFrame:frameRect]){
|
||||||
context = std::unique_ptr<GLContext>(new GLContext);
|
context = std::unique_ptr<GLContext>(new GLContext);
|
||||||
|
|
||||||
self.pixelFormat = [[NSOpenGLPixelFormat alloc] initWithCGLPixelFormatObj: context->pix];
|
self.pixelFormat = [[NSOpenGLPixelFormat alloc] initWithCGLPixelFormatObj: context->pix];
|
||||||
self.openGLContext = [[NSOpenGLContext alloc] initWithCGLContextObj: context->ctx];
|
self.openGLContext = [[NSOpenGLContext alloc] initWithCGLContextObj: context->ctx];
|
||||||
self.wantsBestResolutionOpenGLSurface = YES; // Opt-in for retina
|
self.wantsBestResolutionOpenGLSurface = YES; // Opt-in for retina
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -129,16 +206,16 @@ void NSAppWrapper::create_window(GLViewFunctionality const & f){
|
||||||
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||||
|
|
||||||
if(functionality.initialize_callback){
|
if(functionality.initialize_callback){
|
||||||
functionality.initialize_callback({*context});
|
functionality.initialize_callback({*context, nullptr, nullptr});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a display link capable of being used with all active displays
|
// Create a display link capable of being used with all active displays
|
||||||
linky = std::unique_ptr<CVDisplayLinky>(new CVDisplayLinky(*context));
|
linky = std::unique_ptr<CVDisplayLinky>(new CVDisplayLinky(*context));
|
||||||
linky->callback = [=]{
|
linky->callback = [=]{
|
||||||
// will be called in a different thread => need new autoreleasepool
|
// will be called in a different thread => need new autoreleasepool
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
[self drawView];
|
[self drawView];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
linky->start();
|
linky->start();
|
||||||
|
|
||||||
|
@ -167,7 +244,7 @@ void NSAppWrapper::create_window(GLViewFunctionality const & f){
|
||||||
NSRect viewRectPixels = [self convertRectToBacking:self.bounds];
|
NSRect viewRectPixels = [self convertRectToBacking:self.bounds];
|
||||||
|
|
||||||
if(functionality.resize_callback){
|
if(functionality.resize_callback){
|
||||||
functionality.resize_callback({*context}, viewRectPixels.size.width, viewRectPixels.size.height);
|
functionality.resize_callback({*context, nullptr, nullptr}, viewRectPixels.size.width, viewRectPixels.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
context->unlock();
|
context->unlock();
|
||||||
|
@ -197,19 +274,22 @@ void NSAppWrapper::create_window(GLViewFunctionality const & f){
|
||||||
// When resizing the view, -reshape is called automatically on the main
|
// When resizing the view, -reshape is called automatically on the main
|
||||||
// thread. Add a mutex around to avoid the threads accessing the context
|
// thread. Add a mutex around to avoid the threads accessing the context
|
||||||
// simultaneously when resizing
|
// simultaneously when resizing
|
||||||
context->lock();
|
context->lock();
|
||||||
|
|
||||||
NSRect viewRectPixels = [self convertRectToBacking:self.bounds];
|
NSRect viewRectPixels = [self convertRectToBacking:self.bounds];
|
||||||
|
auto& ctx = context->ctx;
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
if(functionality.draw_callback){
|
||||||
glViewport(0, 0, (int)viewRectPixels.size.width, (int)viewRectPixels.size.height);
|
functionality.draw_callback({*context, [viewRectPixels]{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glViewport(0, 0, (int)viewRectPixels.size.width, (int)viewRectPixels.size.height);
|
||||||
|
}, [&ctx]{
|
||||||
|
CGLFlushDrawable(ctx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if(functionality.draw_callback){
|
context->unlock();
|
||||||
functionality.draw_callback({*context});
|
|
||||||
}
|
|
||||||
|
|
||||||
CGLFlushDrawable(context->ctx);
|
|
||||||
context->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Reference in a new issue