convert SCAD to Cordial menu, Apple Event handler, status feedback
This commit is contained in:
parent
5e5ab706b2
commit
ef64a9996f
|
|
@ -41,5 +41,10 @@ else
|
||||||
echo "no icon svg or rsvg-convert not found, skipping icon"
|
echo "no icon svg or rsvg-convert not found, skipping icon"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
LSREGISTER="/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister"
|
||||||
|
if [ -x "${LSREGISTER}" ]; then
|
||||||
|
"${LSREGISTER}" -f "${BUNDLE}"
|
||||||
|
echo "registered file types with LaunchServices"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "done: ${BUNDLE}"
|
echo "done: ${BUNDLE}"
|
||||||
echo "to register file types, run: open ${BUNDLE}"
|
|
||||||
|
|
|
||||||
|
|
@ -31,4 +31,5 @@ muda = "0.17"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
objc2 = "0.6"
|
objc2 = "0.6"
|
||||||
objc2-foundation = { version = "0.3", features = ["NSAppleEventDescriptor", "NSAppleEventManager", "NSString"] }
|
objc2-foundation = { version = "0.3", features = ["NSAppleEventDescriptor", "NSAppleEventManager", "NSString", "NSURL", "NSArray"] }
|
||||||
|
objc2-app-kit = { version = "0.3", features = ["NSApplication", "NSRunningApplication"] }
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ pub enum Message {
|
||||||
RenderPlots,
|
RenderPlots,
|
||||||
RenderAll,
|
RenderAll,
|
||||||
DecomposeMesh,
|
DecomposeMesh,
|
||||||
|
ConvertToCordial,
|
||||||
Tick,
|
Tick,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,14 +334,16 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::DecomposeMesh => self.decompose_mesh(),
|
Message::DecomposeMesh => self.decompose_mesh(),
|
||||||
|
Message::ConvertToCordial => self.convert_to_cordial(),
|
||||||
Message::Tick => {
|
Message::Tick => {
|
||||||
if !self.menu_ready {
|
if !self.menu_ready {
|
||||||
setup_native_menu();
|
setup_native_menu();
|
||||||
self.menu_ready = true;
|
self.menu_ready = true;
|
||||||
}
|
}
|
||||||
self.poll_menu_events();
|
self.poll_menu_events();
|
||||||
if let Ok(mut q) = open_queue().lock() {
|
if let Ok(mut queue) = open_queue().try_lock() {
|
||||||
for path in q.drain(..) {
|
if let Some(path) = queue.pop() {
|
||||||
|
drop(queue);
|
||||||
self.open_path(&path);
|
self.open_path(&path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -400,6 +403,7 @@ impl App {
|
||||||
"export_scad" => Some(Message::ExportMesh(MeshFormat::Scad)),
|
"export_scad" => Some(Message::ExportMesh(MeshFormat::Scad)),
|
||||||
"undo" => Some(Message::Undo),
|
"undo" => Some(Message::Undo),
|
||||||
"redo" => Some(Message::Redo),
|
"redo" => Some(Message::Redo),
|
||||||
|
"convert_cordial" => Some(Message::ConvertToCordial),
|
||||||
"decompose" => Some(Message::DecomposeMesh),
|
"decompose" => Some(Message::DecomposeMesh),
|
||||||
"render_objects" => Some(Message::RenderObjects),
|
"render_objects" => Some(Message::RenderObjects),
|
||||||
"render_plots" => Some(Message::RenderPlots),
|
"render_plots" => Some(Message::RenderPlots),
|
||||||
|
|
@ -633,6 +637,46 @@ impl App {
|
||||||
self.status = Some("decomposed mesh to Cordial".into());
|
self.status = Some("decomposed mesh to Cordial".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn convert_to_cordial(&mut self) {
|
||||||
|
if self.mode != InputMode::Scad {
|
||||||
|
self.status = Some("already in Cordial mode".into());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let src = self.source.text();
|
||||||
|
let src = src.trim();
|
||||||
|
|
||||||
|
use cord_parse::lexer::Lexer;
|
||||||
|
use cord_parse::parser::Parser;
|
||||||
|
use cord_sdf::lower::lower_program;
|
||||||
|
|
||||||
|
let tokens = match Lexer::new(src).tokenize() {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(e) => { self.status = Some(format!("parse error: {e}")); return; }
|
||||||
|
};
|
||||||
|
let program = match Parser::new(tokens).parse_program() {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => { self.status = Some(format!("parse error: {e}")); return; }
|
||||||
|
};
|
||||||
|
let mut sdf = match lower_program(&program) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => { self.status = Some(format!("lower error: {e}")); return; }
|
||||||
|
};
|
||||||
|
cord_sdf::simplify(&mut sdf);
|
||||||
|
let cordial = cord_sdf::sdf_to_cordial(&sdf);
|
||||||
|
|
||||||
|
self.source = text_editor::Content::with_text(&cordial);
|
||||||
|
self.undo_stack.push(cordial);
|
||||||
|
if self.undo_stack.len() > UNDO_LIMIT {
|
||||||
|
self.undo_stack.remove(0);
|
||||||
|
}
|
||||||
|
self.redo_stack.clear();
|
||||||
|
self.dirty = true;
|
||||||
|
self.mode = InputMode::Expr;
|
||||||
|
self.reparse();
|
||||||
|
self.update_markdown();
|
||||||
|
self.status = Some("converted SCAD to Cordial".into());
|
||||||
|
}
|
||||||
|
|
||||||
fn open_dialog(&mut self) {
|
fn open_dialog(&mut self) {
|
||||||
let path = rfd::FileDialog::new()
|
let path = rfd::FileDialog::new()
|
||||||
.add_filter("All Supported", &["crd", "cord", "zcd", "scad", "stl", "obj", "3mf", "step", "stp"])
|
.add_filter("All Supported", &["crd", "cord", "zcd", "scad", "stl", "obj", "3mf", "step", "stp"])
|
||||||
|
|
@ -2201,6 +2245,7 @@ fn setup_native_menu() {
|
||||||
&MenuItem::with_id("export_step", "Export STEP\u{2026}", true, None),
|
&MenuItem::with_id("export_step", "Export STEP\u{2026}", true, None),
|
||||||
&MenuItem::with_id("export_scad", "Export OpenSCAD\u{2026}", true, None),
|
&MenuItem::with_id("export_scad", "Export OpenSCAD\u{2026}", true, None),
|
||||||
&PredefinedMenuItem::separator(),
|
&PredefinedMenuItem::separator(),
|
||||||
|
&MenuItem::with_id("convert_cordial", "Convert SCAD to Cordial", true, m(cmd_shift, Code::KeyC)),
|
||||||
&MenuItem::with_id("decompose", "Decompose Mesh to Cordial", true, m(cmd_shift, Code::KeyD)),
|
&MenuItem::with_id("decompose", "Decompose Mesh to Cordial", true, m(cmd_shift, Code::KeyD)),
|
||||||
]).unwrap();
|
]).unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ mod apple_events {
|
||||||
use objc2::runtime::{AnyObject, NSObject};
|
use objc2::runtime::{AnyObject, NSObject};
|
||||||
use objc2::{define_class, msg_send, sel, AnyThread};
|
use objc2::{define_class, msg_send, sel, AnyThread};
|
||||||
|
|
||||||
// kCoreEventClass = 'aevt', kAEOpenDocuments = 'odoc', keyDirectObject = '----'
|
|
||||||
const KAEVT: u32 = u32::from_be_bytes(*b"aevt");
|
const KAEVT: u32 = u32::from_be_bytes(*b"aevt");
|
||||||
const KODOC: u32 = u32::from_be_bytes(*b"odoc");
|
const KODOC: u32 = u32::from_be_bytes(*b"odoc");
|
||||||
const KEY_DIRECT_OBJECT: u32 = u32::from_be_bytes(*b"----");
|
const KEY_DIRECT_OBJECT: u32 = u32::from_be_bytes(*b"----");
|
||||||
|
|
@ -132,7 +131,6 @@ mod apple_events {
|
||||||
andEventID: KODOC
|
andEventID: KODOC
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// Leak the handler so it lives for the process lifetime
|
|
||||||
std::mem::forget(handler);
|
std::mem::forget(handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// SPE Press-Contact Jig
|
||||||
|
spe_length = 31.0;
|
||||||
|
spe_width = 12.0;
|
||||||
|
spe_thick = 0.35;
|
||||||
|
strip_count = 3;
|
||||||
|
strip_y = [3.1, 6.05, 9.0];
|
||||||
|
strip_length = 18.0;
|
||||||
|
wire_dia = 0.65;
|
||||||
|
wall = 1.8;
|
||||||
|
floor_t = 1.2;
|
||||||
|
rim = 1.5;
|
||||||
|
tol = 0.15;
|
||||||
|
nest = 0.8;
|
||||||
|
lid_coverage = strip_length - 1.0;
|
||||||
|
tray_inner_l = spe_length + 2*tol;
|
||||||
|
tray_inner_w = spe_width + 2*tol;
|
||||||
|
tray_outer_l = tray_inner_l + 2*wall;
|
||||||
|
tray_outer_w = tray_inner_w + 2*wall;
|
||||||
|
lid_inner_l = lid_coverage + 2*tol;
|
||||||
|
lid_outer_l = lid_inner_l + 2*wall;
|
||||||
|
lid_outer_w = tray_outer_w;
|
||||||
|
blade_w = 1.2;
|
||||||
|
blade_drop = rim + 0.3;
|
||||||
|
|
||||||
|
module bottom() {
|
||||||
|
difference() {
|
||||||
|
cube([tray_outer_l, tray_outer_w, floor_t + rim]);
|
||||||
|
translate([wall, wall, floor_t])
|
||||||
|
cube([tray_inner_l + wall + 1, tray_inner_w, rim + 0.1]);
|
||||||
|
for (i = [0:strip_count-1]) {
|
||||||
|
wy = wall + tol + strip_y[i];
|
||||||
|
translate([-0.1, wy - (wire_dia + tol)/2, floor_t])
|
||||||
|
cube([wall + 0.2, wire_dia + tol, rim + 0.1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module top() {
|
||||||
|
lip_inset = tol;
|
||||||
|
difference() {
|
||||||
|
cube([lid_outer_l, lid_outer_w, floor_t]);
|
||||||
|
for (i = [0:strip_count-1]) {
|
||||||
|
wy = wall + tol + strip_y[i];
|
||||||
|
translate([-0.1, wy - (wire_dia + tol)/2, -0.1])
|
||||||
|
cube([wall + 0.2, wire_dia + tol, floor_t + 0.2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
translate([wall + lip_inset, wall + lip_inset, -nest])
|
||||||
|
difference() {
|
||||||
|
cube([lid_inner_l - 2*lip_inset, tray_inner_w - 2*lip_inset, nest]);
|
||||||
|
translate([tol, tol, -0.1])
|
||||||
|
cube([lid_inner_l - 2*lip_inset - 2*tol, tray_inner_w - 2*lip_inset - 2*tol, nest + 0.2]);
|
||||||
|
}
|
||||||
|
for (i = [0:strip_count-1]) {
|
||||||
|
wy = wall + tol + strip_y[i];
|
||||||
|
translate([wall, wy - blade_w/2, -blade_drop])
|
||||||
|
cube([lid_inner_l, blade_w, blade_drop]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bottom();
|
||||||
|
translate([tray_outer_l + 8, 0, blade_drop])
|
||||||
|
top();
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 8.0 MiB After Width: | Height: | Size: 9.7 MiB |
Loading…
Reference in New Issue