Skip to content

Instantly share code, notes, and snippets.

@2tvenom
Created September 23, 2024 14:40
Show Gist options
  • Save 2tvenom/160e7d4e7b8e63dd83133067094197b6 to your computer and use it in GitHub Desktop.
Save 2tvenom/160e7d4e7b8e63dd83133067094197b6 to your computer and use it in GitHub Desktop.
#![deny(unsafe_op_in_unsafe_fn)]
#![allow(clippy::incompatible_msrv)]
mod tut;
use std::cell::OnceCell;
use std::ffi::c_void;
use objc2::rc::{Id, Retained};
use objc2::encode::{Encode, RefEncode};
use objc2::runtime::{AnyObject, ProtocolObject};
use objc2::{declare_class, msg_send_id, ClassType, mutability, DeclaredClass, Encoding, msg_send};
use objc2_foundation::{NSObject, ns_string, NSString, NSRect, MainThreadMarker, NSObjectProtocol,
NSNotification, NSPoint, NSSize, NSInteger, NSArray, CGFloat, NSCoding};
use objc2_app_kit::{NSApplicationActivationPolicy, NSApplication, NSScrollView,
NSControlTextEditingDelegate, NSTableColumn, NSTableView, NSWindow,
NSWindowStyleMask, NSApplicationDelegate, NSBackingStoreType,
NSTableViewDataSource, NSTableViewDelegate, NSView, NSTextField, NSStackView,
NSUserInterfaceLayoutOrientation, NSLayoutAttribute, NSColor, NSTableRowView};
declare_class!(
struct TableViewSource;
unsafe impl ClassType for TableViewSource {
type Super = NSObject;
type Mutability = mutability::MainThreadOnly;
const NAME: &'static str = "TableViewSource";
}
impl DeclaredClass for TableViewSource {
// type Ivars = Ivars;
}
unsafe impl NSObjectProtocol for TableViewSource {}
unsafe impl NSControlTextEditingDelegate for TableViewSource {}
// unsafe impl NSCoding for TableViewSource {}
unsafe impl NSTableViewDelegate for TableViewSource {
#[method(tableView:heightOfRow:)]
unsafe fn table_view_height_of_row(&self, _: &NSTableView, _: NSInteger) -> CGFloat {
30.
}
#[method_id(tableView:rowViewForRow:)]
unsafe fn tableView_rowViewForRow(
&self,
table_view: &NSTableView,
row: NSInteger,
) -> Option<Retained<NSTableRowView>> {
println!("row view for {}", row);
None
}
#[method(tableView:didAddRowView:forRow:)]
unsafe fn table_view_did_add_row_view_for_row(
&self,
_: &NSTableView,
_: &NSTableRowView,
_: NSInteger,
) {
println!("tableView_didAddRowView:forRow:");
}
#[method(tableView:willDisplayCell:forTableColumn:row:)]
unsafe fn table_view_will_display_cell_for_table_column_row(
&self,
table_view: &NSTableView,
cell: &AnyObject,
table_column: Option<&NSTableColumn>,
row: NSInteger,
) {
println!("tableView_willDisplayCell:forTableColumn:row:");
}
#[method_id(tableView:viewForTableColumn:row:)]
unsafe fn tableView_viewForTableColumn_row(
&self,
_: &NSTableView,
_: Option<&NSTableColumn>,
_: NSInteger,
) -> Option<Retained<NSView>> {
println!("tableView_forTableColumn:row:");
// None
let mtm = MainThreadMarker::from(self);
let view = unsafe {
NSView::initWithFrame(
mtm.alloc(),
NSRect::new(NSPoint::new(0.0, 0.0), NSSize::new(40.0, 40.0)),
)
};
unsafe {
view.setWantsLayer(true);
#[repr(transparent)]
struct CGColorRef(*mut c_void);
unsafe impl Encode for CGColorRef {
const ENCODING: Encoding = Encoding::Pointer(&Encoding::Struct("CGColor", &[]));
}
let background = NSColor::redColor() ;
let background: CGColorRef = msg_send![&background, CGColor];
// CALayer
let layer: Id<NSObject> = msg_send_id![&view, layer];
let _: () = msg_send![&layer, setBorderWidth: 2.0 as CGFloat];
let _: () = msg_send![&layer, setBorderColor: background];
}
let label = unsafe {
let l = NSTextField::init(mtm.alloc());
l.setSelectable(false);
l.setWantsLayer(true);
l.setTranslatesAutoresizingMaskIntoConstraints(false);
l.setStringValue(ns_string!("dummy"));
l.setTextColor(Some(NSColor::redColor().as_ref()));
l
};
let views = [
Id::into_super(Id::into_super(label))
];
let stack = unsafe{
let s = NSStackView::stackViewWithViews(&NSArray::from_id_slice(&views),mtm);
s.setOrientation(NSUserInterfaceLayoutOrientation::Vertical);
s.setAlignment(NSLayoutAttribute::CenterX);
s.setSpacing(8.0);
s.setTranslatesAutoresizingMaskIntoConstraints(false);
s
};
unsafe {
view.addSubview(&stack);
}
Some(view)
}
}
);
declare_class!(
struct TableDataSource;
unsafe impl ClassType for TableDataSource {
type Super = NSObject;
type Mutability = mutability::MainThreadOnly;
const NAME: &'static str = "TableDataSource";
}
impl DeclaredClass for TableDataSource {
// type Ivars = Ivars;
}
unsafe impl NSObjectProtocol for TableDataSource {}
unsafe impl NSTableViewDataSource for TableDataSource {
#[method(numberOfRowsInTableView:)]
unsafe fn number_of_rows_in_table_view(&self, _: &NSTableView) -> NSInteger {
2
}
}
);
#[derive(Debug)]
#[allow(unused)]
struct Ivars {
window: OnceCell<Retained<NSWindow>>,
}
declare_class!(
struct AppDelegate;
unsafe impl ClassType for AppDelegate {
type Super = NSObject;
type Mutability = mutability::MainThreadOnly;
const NAME: &'static str = "AppDelegate";
}
impl DeclaredClass for AppDelegate {
type Ivars = Ivars;
}
unsafe impl NSObjectProtocol for AppDelegate {}
unsafe impl NSApplicationDelegate for AppDelegate {
#[method(applicationDidFinishLaunching:)]
fn application_did_finish_launching(&self, _notification: &NSNotification) {
let mtm = MainThreadMarker::from(self);
// create the app window
self.new_window(mtm)
}
#[method(applicationWillTerminate:)]
fn will_terminate(&self, _notification: &NSNotification) {
println!("It's a hell of a start, it could be made into a monster\nIf we all pull together as a team");
}
#[method(applicationShouldTerminateAfterLastWindowClosed:)]
fn application_should_terminate_after_last_window_closed(&self, _: &NSApplication)->bool {
true
}
}
);
impl TableDataSource {
fn new(mtm: MainThreadMarker) -> Retained<Self> {
let this = mtm.alloc();
unsafe { msg_send_id![this, init] }
}
}
impl TableViewSource {
fn new(mtm: MainThreadMarker) -> Retained<Self> {
let this = mtm.alloc();
unsafe { msg_send_id![this, init] }
}
}
impl AppDelegate {
fn new(mtm: MainThreadMarker) -> Retained<Self> {
let this = mtm.alloc();
let this = this.set_ivars(Ivars {
window: OnceCell::default(),
});
unsafe { msg_send_id![super(this), init] }
}
fn new_window(&self, mtm: MainThreadMarker) {
let this = mtm.alloc();
let window = {
let content_rect = NSRect::new(NSPoint::new(0., 0.), NSSize::new(768., 768.));
let style = NSWindowStyleMask::Closable
| NSWindowStyleMask::Resizable
| NSWindowStyleMask::Titled
| NSWindowStyleMask::Miniaturizable
| NSWindowStyleMask::UnifiedTitleAndToolbar
| NSWindowStyleMask::UnifiedTitleAndToolbar
;
let backing_store_type = NSBackingStoreType::NSBackingStoreBuffered;
let flag = false;
unsafe {
NSWindow::initWithContentRect_styleMask_backing_defer(
this,
content_rect,
style,
backing_store_type,
flag,
)
}
};
// window.makeKeyAndOrderFront(None);
unsafe {
window.orderFrontRegardless();
}
window.setTitle(&NSString::from_str("Rust NSTableView Example"));
window.center();
let column = {
unsafe {
let c = NSTableColumn::initWithIdentifier(mtm.alloc(), ns_string!("dummy"));
// c.setWidth(300.);
c.setTitle(ns_string!("dummy"));
c
}
};
let column1 = {
unsafe {
let c = NSTableColumn::init(mtm.alloc());
// c.setWidth(300.);
c.setTitle(ns_string!("dummy1"));
c
}
};
// Set up the data source and delegate
// let data_source = Box::new(TableDataSource::new());
// let delegate = Box::new(TableDataSource::new());
let ts = TableDataSource::new(mtm);
let ts_obj = ProtocolObject::from_ref(&*ts);
let tv = TableViewSource::new(mtm);
let tv_obj = ProtocolObject::from_ref(&*tv);
let table = {
let content_rect = NSRect::new(NSPoint::new(0., 0.), NSSize::new(100., 100.));
unsafe {
let t = NSTableView::initWithFrame(mtm.alloc(), content_rect);
t.addTableColumn(&column);
t.addTableColumn(&column1);
t.setDataSource(Some(ts_obj));
t.setDelegate(Some(tv_obj));
t
}
};
let sc = {
// let content_rect = NSRect::new(NSPoint::new(0., 0.), NSSize::new(100., 100.));
unsafe {
let scroll_view = NSScrollView::new(mtm);
scroll_view.setDocumentView(Some(&table));
scroll_view
}
};
// unsafe {
window.setContentView(Some(&sc));
// }
self.ivars().window.set(window).expect("error set window");
}
}
fn main() {
let mtm: MainThreadMarker = MainThreadMarker::new().unwrap();
let app = NSApplication::sharedApplication(mtm);
app.setActivationPolicy(NSApplicationActivationPolicy::Regular);
// configure the application delegate
let delegate = AppDelegate::new(mtm);
let object = ProtocolObject::from_ref(&*delegate);
app.setDelegate(Some(object));
// run the app
unsafe {
app.run();
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment