app
Altium - the Altium Bridge
Public Made by Adomby adom
Adom Bridge for Altium Designer: a resident DelphiScript agent gives the AI eval, the 1,100-command process launcher, all 8 EDA surfaces with screenshots, compile/ERC, DRC, OutJob outputs, native SchLib/PcbLib authoring with STEP 3D bodies, and dialog handling by PID.
main
John Lauer
0.2.0: the bridge is Rust end to end — all 112 verbs dispatch from altium-bridge.exe (spawn.kind exe); Python runtime n…
4fb2c47
1mo ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
//! Background proof capture. John's etiquette (2026-09-01): never park an Altium window
//! off-screen — a user reaching for Altium must find it where they left it. If it is minimized,
//! restore it INTO THE BACKGROUND (bottom of the z-order), capture, and hand the user's
//! foreground straight back (~0.6 s end to end). A capture under MIN_PROOF_WIDTH px is a
//! minimized-window sliver, not evidence — refused as proofUnavailable rather than returned.
use crate::{ab, instance};
use serde_json::{json, Value};
/// Anything narrower is a minimized-window sliver, not a screenshot.
pub const MIN_PROOF_WIDTH: i64 = 400;
fn is_minimized(rect: &Value) -> bool {
if !rect.is_object() {
return false;
}
let g = |k: &str| rect.get(k).and_then(|v| v.as_i64()).unwrap_or(0);
g("left") <= -30000 || g("top") <= -30000 || (g("width") < MIN_PROOF_WIDTH && g("height") < 200)
}
/// Restore a minimized window and push it BEHIND the user's windows, then hand the foreground
/// straight back. Returns what it had to do, so a caller can report honestly whether the user's
/// screen was touched.
pub fn make_capturable(hwnd: i64) -> Value {
let mut out = json!({"restored": false, "sentToBack": false, "foregroundReturned": false});
let before = ab::call("desktop_get_foreground", json!({}), &[], 8).get("hwnd").and_then(|h| h.as_i64());
let rect = instance::altium_windows()
.into_iter()
.find(|w| w.get("hwnd").and_then(|h| h.as_i64()) == Some(hwnd))
.map(|w| w.get("rect").cloned().unwrap_or(Value::Null))
.unwrap_or(Value::Null);
if is_minimized(&rect) {
ab::call("desktop_set_window_state", json!({"hwnd": hwnd, "state": "restore",
"reason": "restore a minimized Altium into the background for a proof capture"}), &[], 10);
out["restored"] = json!(true);
instance::invalidate_snapshot();
}
ab::call("desktop_set_window_state", json!({"hwnd": hwnd, "state": "bottom",
"reason": "keep Altium behind the user's windows"}), &[], 10);
out["sentToBack"] = json!(true);
let after = ab::call("desktop_get_foreground", json!({}), &[], 8).get("hwnd").and_then(|h| h.as_i64());
if let Some(b) = before {
if after != Some(b) {
ab::call("desktop_raise_window", json!({"hwnd": b,
"reason": "hand the user's window back after restoring Altium into the background"}), &[], 10);
out["foregroundReturned"] = json!(true);
}
out["userForeground"] = json!(b);
}
out
}
/// A capture of the selected Altium's main window, or Null — never a sliver-as-proof.
pub fn shot_of_main() -> Value {
let mw = match instance::main_window() {
Some(w) => w,
None => return Value::Null,
};
let hwnd = match mw.get("hwnd").and_then(|h| h.as_i64()) {
Some(h) => h,
None => return Value::Null,
};
let title = mw.get("title").cloned().unwrap_or(Value::Null);
let prepared = make_capturable(hwnd);
let r = ab::call("desktop_screenshot_base64", json!({"hwnd": hwnd}), &[], 20);
let image = r.get("image").or_else(|| r.get("base64")).and_then(|i| i.as_str()).map(str::to_string);
match image {
Some(img) => {
let w = r.get("width").and_then(|v| v.as_i64());
let h = r.get("height").and_then(|v| v.as_i64());
if let Some(wpx) = w {
if wpx < MIN_PROOF_WIDTH {
return json!({"title": title, "hwnd": hwnd, "proofUnavailable": true,
"reason": format!("the Altium window is minimized (captured {}x{}) — Windows does not render a minimized window, so there is no image to prove anything", wpx, h.unwrap_or(0)),
"prepared": prepared});
}
}
json!({"title": title, "hwnd": hwnd, "image": img, "width": w, "height": h, "prepared": prepared})
}
None => Value::Null,
}
}
/// Altium PAINTS its dialog text (no Static child, not in WM_GETTEXT) — the only way to READ a
/// dialog is to look at it. Attach a base64 PNG per dialog row.
pub fn attach_dialog_shots(dialogs: &mut [Value]) {
for d in dialogs.iter_mut() {
if let Some(hwnd) = d.get("hwnd").and_then(|h| h.as_i64()) {
let r = ab::call("desktop_screenshot_base64", json!({"hwnd": hwnd}), &[], 10);
if let Some(img) = r.get("image").or_else(|| r.get("base64")).and_then(|i| i.as_str()) {
d["shot"] = json!(img);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn minimized_detection() {
assert!(is_minimized(&json!({"left": -32000, "top": -32000, "width": 160, "height": 28})));
assert!(is_minimized(&json!({"left": 100, "top": 100, "width": 237, "height": 39})));
assert!(!is_minimized(&json!({"left": 0, "top": 0, "width": 1920, "height": 1080})));
assert!(!is_minimized(&Value::Null));
}
}