Initial commit — Dossier Rhino 8 Plugin
OpenStudio-Suite Architektur-Plugin fuer Rhino 8 (Mac): - Smart-Elemente: Wand, Decke, Dach (Pult/Sattel/Walm/Mansarde), Oeffnungen (Fenster/Tueren mit Rahmen + Sims + Glas + Fluegel), Treppen (gerade · L · Wendel mit Schrittmass-Validierung) - Live-Previews mit Step-Lines + Soll-Range-Clamping - Bidirektionale Selection-Sync zwischen Source-Linie und Volume - Geschoss-/Ebenen-Verwaltung mit OKFF-Persistenz - Layouts mit PDF-Export - Ausschnitte / Massstab / Override-Regeln - Petrol-Gruen Theme (Rapport-konform) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
/target
|
||||
/gen
|
||||
Generated
+4829
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "dossier-launcher"
|
||||
version = "0.1.0"
|
||||
description = "Dossier — Projekt-Launcher fuer Rhino"
|
||||
authors = ["Karim Gabriele Varano"]
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "dossier_launcher_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2", features = [] }
|
||||
tauri-plugin-dialog = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
directories = "5"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
opt-level = "s"
|
||||
strip = true
|
||||
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability fuer das Hauptfenster",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"dialog:default"
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,174 @@
|
||||
// Verhindert ein extra Konsolen-Fenster auf Windows im Release-Build.
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
// Statisches Modul-Manifest — in die Binary einkompiliert, sodass die App
|
||||
// keine externe Datei zur Laufzeit braucht. Wer Module aendert: modules.json
|
||||
// im launcher-Root bearbeiten, dann neu bauen.
|
||||
const MODULES_JSON: &str = include_str!("../../modules.json");
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
struct Project {
|
||||
name: String,
|
||||
path: String,
|
||||
modules: Vec<String>,
|
||||
#[serde(rename = "lastOpened")]
|
||||
last_opened: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
struct ProjectConfig {
|
||||
name: String,
|
||||
modules: Vec<String>,
|
||||
#[serde(rename = "dossierVersion")]
|
||||
dossier_version: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
struct Settings {
|
||||
// App-Name oder absoluter Pfad zur Rhino-App. `open -a` akzeptiert beides:
|
||||
// "Rhinoceros 8" -> sucht in /Applications
|
||||
// "/Applications/Rhino 8.app" oder ein Beta-Build irgendwo anders.
|
||||
#[serde(rename = "rhinoApp")]
|
||||
rhino_app: String,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
rhino_app: "Rhinoceros 8".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dossier_dir() -> PathBuf {
|
||||
// ~/Library/Application Support/Dossier auf macOS,
|
||||
// entsprechend Plattform-Pendants sonst.
|
||||
let dir = directories::ProjectDirs::from("ch", "gabrielevarano", "Dossier")
|
||||
.map(|p| p.data_dir().to_path_buf())
|
||||
.unwrap_or_else(|| PathBuf::from("."));
|
||||
fs::create_dir_all(&dir).ok();
|
||||
dir
|
||||
}
|
||||
|
||||
fn recent_path() -> PathBuf {
|
||||
dossier_dir().join("recent.json")
|
||||
}
|
||||
|
||||
fn settings_path() -> PathBuf {
|
||||
dossier_dir().join("settings.json")
|
||||
}
|
||||
|
||||
fn load_settings() -> Settings {
|
||||
let p = settings_path();
|
||||
if !p.exists() {
|
||||
return Settings::default();
|
||||
}
|
||||
fs::read_to_string(&p)
|
||||
.ok()
|
||||
.and_then(|raw| serde_json::from_str(&raw).ok())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn list_recent() -> Vec<Project> {
|
||||
let p = recent_path();
|
||||
if !p.exists() {
|
||||
return vec![];
|
||||
}
|
||||
let raw = fs::read_to_string(&p).unwrap_or_default();
|
||||
serde_json::from_str(&raw).unwrap_or_default()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn save_recent(projects: Vec<Project>) -> Result<(), String> {
|
||||
let p = recent_path();
|
||||
let raw = serde_json::to_string_pretty(&projects).map_err(|e| e.to_string())?;
|
||||
fs::write(&p, raw).map_err(|e| format!("recent.json schreiben: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn write_project_config(
|
||||
path3dm: String,
|
||||
name: String,
|
||||
modules: Vec<String>,
|
||||
) -> Result<(), String> {
|
||||
let p = Path::new(&path3dm);
|
||||
let dir = p
|
||||
.parent()
|
||||
.ok_or_else(|| format!("Kein gueltiger Ordner aus Pfad: {path3dm}"))?;
|
||||
let config_path = dir.join("dossier.project.json");
|
||||
let config = ProjectConfig {
|
||||
name,
|
||||
modules,
|
||||
dossier_version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
};
|
||||
let raw = serde_json::to_string_pretty(&config).map_err(|e| e.to_string())?;
|
||||
fs::write(&config_path, raw).map_err(|e| format!("project-config schreiben: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn read_project_config(path3dm: String) -> Result<Option<ProjectConfig>, String> {
|
||||
let p = Path::new(&path3dm);
|
||||
let dir = p.parent().ok_or_else(|| "Pfad ungueltig".to_string())?;
|
||||
let config_path = dir.join("dossier.project.json");
|
||||
if !config_path.exists() {
|
||||
return Ok(None);
|
||||
}
|
||||
let raw = fs::read_to_string(&config_path).map_err(|e| e.to_string())?;
|
||||
let cfg: ProjectConfig = serde_json::from_str(&raw).map_err(|e| e.to_string())?;
|
||||
Ok(Some(cfg))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn open_rhino(path3dm: String) -> Result<(), String> {
|
||||
// macOS: `open -a <app> <file>`. `<app>` kann ein App-Name (in /Applications
|
||||
// gesucht) oder ein absoluter Pfad zur .app sein. Aus den Settings — Default
|
||||
// "Rhinoceros 8", falls der User nichts angepasst hat.
|
||||
let settings = load_settings();
|
||||
Command::new("open")
|
||||
.args(["-a", &settings.rhino_app, &path3dm])
|
||||
.spawn()
|
||||
.map_err(|e| format!(
|
||||
"open-Befehl fehlgeschlagen ({}): {e}", settings.rhino_app
|
||||
))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn read_settings() -> Settings {
|
||||
load_settings()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn save_settings(settings: Settings) -> Result<(), String> {
|
||||
let raw = serde_json::to_string_pretty(&settings).map_err(|e| e.to_string())?;
|
||||
fs::write(settings_path(), raw).map_err(|e| format!("settings.json schreiben: {e}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn read_modules_manifest() -> Result<serde_json::Value, String> {
|
||||
serde_json::from_str(MODULES_JSON).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
list_recent,
|
||||
save_recent,
|
||||
write_project_config,
|
||||
read_project_config,
|
||||
open_rhino,
|
||||
read_modules_manifest,
|
||||
read_settings,
|
||||
save_settings
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("Fehler beim Starten der Tauri-App");
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Tauri 2 Konvention: main.rs ist nur Einstieg, Logik in lib.rs (fuer Mobile-
|
||||
// Unterstuetzung und damit `tauri::generate_context!` korrekt aufgeloest wird).
|
||||
fn main() {
|
||||
dossier_launcher_lib::run()
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Dossier",
|
||||
"version": "0.1.0",
|
||||
"identifier": "ch.gabrielevarano.dossier",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "(cd .. && npm run build) && npm run build",
|
||||
"devUrl": "http://127.0.0.1:5183",
|
||||
"frontendDist": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"label": "main",
|
||||
"title": "Dossier",
|
||||
"width": 920,
|
||||
"height": 640,
|
||||
"minWidth": 720,
|
||||
"minHeight": 480,
|
||||
"resizable": true,
|
||||
"fullscreen": false
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": ["app", "dmg"],
|
||||
"icon": ["icons/icon.png"],
|
||||
"copyright": "© 2026 Karim Gabriele Varano",
|
||||
"category": "DeveloperTool",
|
||||
"shortDescription": "Dossier Launcher",
|
||||
"longDescription": "Projekt-Launcher fuer das Dossier-Plugin in Rhino 8.",
|
||||
"resources": {
|
||||
"../../dist": "dist",
|
||||
"../../rhino": "rhino"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user