use crate::error::Result;
use crate::traits::{FromParams, ToParams};
use crate::tree::TreeRecord;
use crate::types::{
CoordPoint, CoordRect, ParameterCollection, coord_to_dxp_frac, dxp_frac_to_coord,
};
pub trait SchPrimitive: Sized {
const RECORD_ID: i32;
fn import_from_params(params: &ParameterCollection) -> Result<Self>;
fn export_to_params(&self) -> ParameterCollection;
fn owner_index(&self) -> i32;
fn location(&self) -> Option<CoordPoint> {
None
}
fn record_type_name(&self) -> &'static str;
fn get_property(&self, _name: &str) -> Option<String> {
None
}
fn calculate_bounds(&self) -> CoordRect;
}
#[derive(Debug, Clone)]
pub struct SchPrimitiveBase {
pub owner_index: i32,
pub is_not_accessible: bool,
pub owner_part_id: Option<i32>,
pub owner_part_display_mode: Option<i32>,
pub graphically_locked: bool,
}
impl Default for SchPrimitiveBase {
fn default() -> Self {
Self {
owner_index: -1, is_not_accessible: false,
owner_part_id: None, owner_part_display_mode: None,
graphically_locked: false,
}
}
}
impl SchPrimitiveBase {
pub fn import_from_params(params: &ParameterCollection) -> Self {
SchPrimitiveBase {
owner_index: params
.get("OWNERINDEX")
.map(|v| v.as_int_or(0))
.unwrap_or(0),
is_not_accessible: params
.get("ISNOTACCESIBLE")
.map(|v| v.as_bool_or(false))
.unwrap_or(false),
owner_part_id: params.get("OWNERPARTID").map(|v| v.as_int_or(0)),
owner_part_display_mode: params.get("OWNERPARTDISPLAYMODE").map(|v| v.as_int_or(0)),
graphically_locked: params
.get("GRAPHICALLYLOCKED")
.map(|v| v.as_bool_or(false))
.unwrap_or(false),
}
}
pub fn export_to_params(&self, params: &mut ParameterCollection) {
params.add_int("OWNERINDEX", self.owner_index);
params.add_bool("ISNOTACCESIBLE", self.is_not_accessible);
if let Some(part_id) = self.owner_part_id {
params.add_int("OWNERPARTID", part_id);
}
if let Some(display_mode) = self.owner_part_display_mode {
params.add_int("OWNERPARTDISPLAYMODE", display_mode);
}
params.add_bool("GRAPHICALLYLOCKED", self.graphically_locked);
}
pub fn owner_index(&self) -> i32 {
self.owner_index
}
pub fn set_owner_index(&mut self, index: i32) {
self.owner_index = index;
}
}
impl FromParams for SchPrimitiveBase {
fn from_params(params: &ParameterCollection) -> Result<Self> {
Ok(Self::import_from_params(params))
}
}
impl ToParams for SchPrimitiveBase {
fn append_to_params(&self, params: &mut ParameterCollection) {
self.export_to_params(params);
}
}
#[derive(Debug, Clone, Default)]
pub struct SchGraphicalBase {
pub base: SchPrimitiveBase,
pub location_x: i32,
pub location_y: i32,
pub color: i32,
pub area_color: i32,
}
impl SchGraphicalBase {
pub const COLOR_BLUE: i32 = 128; pub const COLOR_RED: i32 = 8388608; pub const COLOR_LIGHT_CYAN: i32 = 11599871;
pub fn new_graphical() -> Self {
Self {
base: SchPrimitiveBase {
owner_index: -1,
is_not_accessible: false,
owner_part_id: Some(-1),
owner_part_display_mode: None,
graphically_locked: false,
},
location_x: 0,
location_y: 0,
color: Self::COLOR_BLUE,
area_color: Self::COLOR_LIGHT_CYAN,
}
}
pub fn new_wire_or_text() -> Self {
Self {
base: SchPrimitiveBase {
owner_index: -1,
is_not_accessible: false,
owner_part_id: Some(-1),
owner_part_display_mode: None,
graphically_locked: false,
},
location_x: 0,
location_y: 0,
color: Self::COLOR_RED,
area_color: 0,
}
}
pub fn import_from_params(params: &ParameterCollection) -> Self {
let base = SchPrimitiveBase::import_from_params(params);
let loc_x = params
.get("LOCATION.X")
.map(|v| v.as_int_or(0))
.unwrap_or(0);
let loc_x_frac = params
.get("LOCATION.X_FRAC")
.map(|v| v.as_int_or(0))
.unwrap_or(0);
let loc_y = params
.get("LOCATION.Y")
.map(|v| v.as_int_or(0))
.unwrap_or(0);
let loc_y_frac = params
.get("LOCATION.Y_FRAC")
.map(|v| v.as_int_or(0))
.unwrap_or(0);
SchGraphicalBase {
base,
location_x: dxp_frac_to_coord(loc_x, loc_x_frac),
location_y: dxp_frac_to_coord(loc_y, loc_y_frac),
color: params.get("COLOR").map(|v| v.as_int_or(0)).unwrap_or(0),
area_color: params.get("AREACOLOR").map(|v| v.as_int_or(0)).unwrap_or(0),
}
}
pub fn export_to_params(&self, params: &mut ParameterCollection) {
self.base.export_to_params(params);
let (x, x_frac) = coord_to_dxp_frac(self.location_x);
let (y, y_frac) = coord_to_dxp_frac(self.location_y);
params.add_int("LOCATION.X", x);
params.add_int("LOCATION.X_FRAC", x_frac);
params.add_int("LOCATION.Y", y);
params.add_int("LOCATION.Y_FRAC", y_frac);
params.add_int("COLOR", self.color);
params.add_int("AREACOLOR", self.area_color);
}
pub fn owner_index(&self) -> i32 {
self.base.owner_index
}
pub fn set_owner_index(&mut self, index: i32) {
self.base.owner_index = index;
}
}
impl FromParams for SchGraphicalBase {
fn from_params(params: &ParameterCollection) -> Result<Self> {
Ok(Self::import_from_params(params))
}
}
impl ToParams for SchGraphicalBase {
fn append_to_params(&self, params: &mut ParameterCollection) {
self.export_to_params(params);
}
}
#[derive(Debug, Clone)]
pub enum SchRecord {
Component(super::SchComponent),
Pin(super::SchPin),
Symbol(super::SchSymbol),
Label(super::SchLabel),
Bezier(super::SchBezier),
Polyline(super::SchPolyline),
Polygon(super::SchPolygon),
Ellipse(super::SchEllipse),
Pie(super::SchPie),
EllipticalArc(super::SchEllipticalArc),
Arc(super::SchArc),
Line(super::SchLine),
Rectangle(super::SchRectangle),
PowerObject(super::SchPowerObject),
Port(super::SchPort),
NoErc(super::SchNoErc),
NetLabel(super::SchNetLabel),
Bus(super::SchBus),
Wire(super::SchWire),
TextFrame(super::SchTextFrame),
TextFrameVariant(super::SchTextFrameVariant),
Junction(super::SchJunction),
Image(super::SchImage),
SheetHeader(super::SchSheetHeader),
Designator(super::SchDesignator),
BusEntry(super::SchBusEntry),
Parameter(super::SchParameter),
WarningSign(super::SchWarningSign),
ImplementationList(super::SchImplementationList),
Implementation(super::SchImplementation),
MapDefinerList(super::SchMapDefinerList),
MapDefiner(super::SchMapDefiner),
ImplementationParameters(super::SchImplementationParameters),
Unknown {
record_id: i32,
params: ParameterCollection,
},
}
impl SchRecord {
pub fn from_params(params: &ParameterCollection) -> Result<Self> {
let record_id = params.get("RECORD").map(|v| v.as_int_or(-1)).unwrap_or(-1);
let record = match record_id {
1 => SchRecord::Component(super::SchComponent::import_from_params(params)?),
2 => SchRecord::Pin(super::SchPin::import_from_params(params)?),
3 => SchRecord::Symbol(super::SchSymbol::import_from_params(params)?),
4 => SchRecord::Label(super::SchLabel::import_from_params(params)?),
5 => SchRecord::Bezier(super::SchBezier::import_from_params(params)?),
6 => SchRecord::Polyline(super::SchPolyline::import_from_params(params)?),
7 => SchRecord::Polygon(super::SchPolygon::import_from_params(params)?),
8 => SchRecord::Ellipse(super::SchEllipse::import_from_params(params)?),
9 => SchRecord::Pie(super::SchPie::import_from_params(params)?),
11 => SchRecord::EllipticalArc(super::SchEllipticalArc::import_from_params(params)?),
12 => SchRecord::Arc(super::SchArc::import_from_params(params)?),
13 => SchRecord::Line(super::SchLine::import_from_params(params)?),
14 => SchRecord::Rectangle(super::SchRectangle::import_from_params(params)?),
17 => SchRecord::PowerObject(super::SchPowerObject::import_from_params(params)?),
18 => SchRecord::Port(super::SchPort::import_from_params(params)?),
22 => SchRecord::NoErc(super::SchNoErc::import_from_params(params)?),
25 => SchRecord::NetLabel(super::SchNetLabel::import_from_params(params)?),
26 => SchRecord::Bus(super::SchBus::import_from_params(params)?),
27 => SchRecord::Wire(super::SchWire::import_from_params(params)?),
28 => SchRecord::TextFrame(super::SchTextFrame::import_from_params(params)?),
29 => SchRecord::Junction(super::SchJunction::import_from_params(params)?),
30 => SchRecord::Image(super::SchImage::import_from_params(params)?),
31 => SchRecord::SheetHeader(super::SchSheetHeader::import_from_params(params)?),
34 => SchRecord::Designator(super::SchDesignator::import_from_params(params)?),
37 => SchRecord::BusEntry(super::SchBusEntry::import_from_params(params)?),
41 => SchRecord::Parameter(super::SchParameter::import_from_params(params)?),
43 => SchRecord::WarningSign(super::SchWarningSign::import_from_params(params)?),
44 => SchRecord::ImplementationList(super::SchImplementationList::import_from_params(
params,
)?),
45 => SchRecord::Implementation(super::SchImplementation::import_from_params(params)?),
46 => SchRecord::MapDefinerList(super::SchMapDefinerList::import_from_params(params)?),
47 => SchRecord::MapDefiner(super::SchMapDefiner::import_from_params(params)?),
48 => SchRecord::ImplementationParameters(
super::SchImplementationParameters::import_from_params(params)?,
),
209 => {
SchRecord::TextFrameVariant(super::SchTextFrameVariant::import_from_params(params)?)
}
_ => SchRecord::Unknown {
record_id,
params: params.clone(),
},
};
Ok(record)
}
pub fn record_id(&self) -> i32 {
match self {
SchRecord::Component(_) => 1,
SchRecord::Pin(_) => 2,
SchRecord::Symbol(_) => 3,
SchRecord::Label(_) => 4,
SchRecord::Bezier(_) => 5,
SchRecord::Polyline(_) => 6,
SchRecord::Polygon(_) => 7,
SchRecord::Ellipse(_) => 8,
SchRecord::Pie(_) => 9,
SchRecord::EllipticalArc(_) => 11,
SchRecord::Arc(_) => 12,
SchRecord::Line(_) => 13,
SchRecord::Rectangle(_) => 14,
SchRecord::PowerObject(_) => 17,
SchRecord::Port(_) => 18,
SchRecord::NoErc(_) => 22,
SchRecord::NetLabel(_) => 25,
SchRecord::Bus(_) => 26,
SchRecord::Wire(_) => 27,
SchRecord::TextFrame(_) => 28,
SchRecord::Junction(_) => 29,
SchRecord::Image(_) => 30,
SchRecord::SheetHeader(_) => 31,
SchRecord::Designator(_) => 34,
SchRecord::BusEntry(_) => 37,
SchRecord::Parameter(_) => 41,
SchRecord::WarningSign(_) => 43,
SchRecord::ImplementationList(_) => 44,
SchRecord::Implementation(_) => 45,
SchRecord::MapDefinerList(_) => 46,
SchRecord::MapDefiner(_) => 47,
SchRecord::ImplementationParameters(_) => 48,
SchRecord::TextFrameVariant(_) => 209,
SchRecord::Unknown { record_id, .. } => *record_id,
}
}
pub fn owner_index(&self) -> i32 {
match self {
SchRecord::Component(r) => r.owner_index(),
SchRecord::Pin(r) => r.owner_index(),
SchRecord::Symbol(r) => r.owner_index(),
SchRecord::Label(r) => r.owner_index(),
SchRecord::Bezier(r) => r.owner_index(),
SchRecord::Polyline(r) => r.owner_index(),
SchRecord::Polygon(r) => r.owner_index(),
SchRecord::Ellipse(r) => r.owner_index(),
SchRecord::Pie(r) => r.owner_index(),
SchRecord::EllipticalArc(r) => r.owner_index(),
SchRecord::Arc(r) => r.owner_index(),
SchRecord::Line(r) => r.owner_index(),
SchRecord::Rectangle(r) => r.owner_index(),
SchRecord::PowerObject(r) => r.owner_index(),
SchRecord::Port(r) => r.owner_index(),
SchRecord::NoErc(r) => r.owner_index(),
SchRecord::NetLabel(r) => r.owner_index(),
SchRecord::Bus(r) => r.owner_index(),
SchRecord::Wire(r) => r.owner_index(),
SchRecord::TextFrame(r) => r.owner_index(),
SchRecord::TextFrameVariant(r) => r.owner_index(),
SchRecord::Junction(r) => r.owner_index(),
SchRecord::Image(r) => r.owner_index(),
SchRecord::SheetHeader(r) => r.owner_index(),
SchRecord::Designator(r) => r.owner_index(),
SchRecord::BusEntry(r) => r.owner_index(),
SchRecord::Parameter(r) => r.owner_index(),
SchRecord::WarningSign(r) => r.owner_index(),
SchRecord::ImplementationList(r) => r.owner_index(),
SchRecord::Implementation(r) => r.owner_index(),
SchRecord::MapDefinerList(r) => r.owner_index(),
SchRecord::MapDefiner(r) => r.owner_index(),
SchRecord::ImplementationParameters(r) => r.owner_index(),
SchRecord::Unknown { params, .. } => params
.get("OWNERINDEX")
.map(|v| v.as_int_or(0))
.unwrap_or(0),
}
}
pub fn set_owner_index(&mut self, index: i32) {
match self {
SchRecord::Component(r) => r.graphical.base.set_owner_index(index),
SchRecord::Pin(r) => r.graphical.set_owner_index(index),
SchRecord::Symbol(r) => r.graphical.set_owner_index(index),
SchRecord::Label(r) => r.graphical.set_owner_index(index),
SchRecord::Bezier(r) => r.graphical.set_owner_index(index),
SchRecord::Polyline(r) => r.graphical.set_owner_index(index),
SchRecord::Polygon(r) => r.graphical.set_owner_index(index),
SchRecord::Ellipse(r) => r.graphical.set_owner_index(index),
SchRecord::Pie(r) => r.graphical.set_owner_index(index),
SchRecord::EllipticalArc(r) => r.graphical.set_owner_index(index),
SchRecord::Arc(r) => r.graphical.set_owner_index(index),
SchRecord::Line(r) => r.graphical.set_owner_index(index),
SchRecord::Rectangle(r) => r.graphical.set_owner_index(index),
SchRecord::PowerObject(r) => r.graphical.set_owner_index(index),
SchRecord::Port(r) => r.graphical.set_owner_index(index),
SchRecord::NoErc(r) => r.graphical.set_owner_index(index),
SchRecord::NetLabel(r) => r.label.graphical.set_owner_index(index),
SchRecord::Bus(r) => r.graphical.set_owner_index(index),
SchRecord::Wire(r) => r.graphical.set_owner_index(index),
SchRecord::TextFrame(r) => r.graphical.set_owner_index(index),
SchRecord::TextFrameVariant(r) => r.graphical.set_owner_index(index),
SchRecord::Junction(r) => r.graphical.set_owner_index(index),
SchRecord::Image(r) => r.graphical.set_owner_index(index),
SchRecord::SheetHeader(r) => r.base.set_owner_index(index),
SchRecord::Designator(r) => r.param.label.graphical.set_owner_index(index),
SchRecord::BusEntry(r) => r.graphical.set_owner_index(index),
SchRecord::Parameter(r) => r.label.graphical.set_owner_index(index),
SchRecord::WarningSign(r) => r.graphical.set_owner_index(index),
SchRecord::ImplementationList(r) => r.base.set_owner_index(index),
SchRecord::Implementation(r) => r.base.set_owner_index(index),
SchRecord::MapDefinerList(r) => r.base.set_owner_index(index),
SchRecord::MapDefiner(r) => r.base.set_owner_index(index),
SchRecord::ImplementationParameters(r) => r.base.set_owner_index(index),
SchRecord::Unknown { params, .. } => {
params.add_int("OWNERINDEX", index);
}
}
}
pub fn location(&self) -> Option<CoordPoint> {
match self {
SchRecord::Component(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Pin(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Symbol(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Label(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Bezier(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Polyline(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Polygon(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Ellipse(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Pie(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::EllipticalArc(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Arc(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Line(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Rectangle(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::PowerObject(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Port(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::NoErc(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::NetLabel(r) => Some(CoordPoint::from_raw(
r.label.graphical.location_x,
r.label.graphical.location_y,
)),
SchRecord::Bus(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Wire(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::TextFrame(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::TextFrameVariant(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Junction(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Image(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::SheetHeader(_) => None,
SchRecord::Designator(r) => Some(CoordPoint::from_raw(
r.param.label.graphical.location_x,
r.param.label.graphical.location_y,
)),
SchRecord::BusEntry(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::Parameter(r) => Some(CoordPoint::from_raw(
r.label.graphical.location_x,
r.label.graphical.location_y,
)),
SchRecord::WarningSign(r) => Some(CoordPoint::from_raw(
r.graphical.location_x,
r.graphical.location_y,
)),
SchRecord::ImplementationList(_) => None,
SchRecord::Implementation(_) => None,
SchRecord::MapDefinerList(_) => None,
SchRecord::MapDefiner(_) => None,
SchRecord::ImplementationParameters(_) => None,
SchRecord::Unknown { .. } => None,
}
}
pub fn record_type_name(&self) -> &'static str {
match self {
SchRecord::Component(_) => "Component",
SchRecord::Pin(_) => "Pin",
SchRecord::Symbol(_) => "Symbol",
SchRecord::Label(_) => "Label",
SchRecord::Bezier(_) => "Bezier",
SchRecord::Polyline(_) => "Polyline",
SchRecord::Polygon(_) => "Polygon",
SchRecord::Ellipse(_) => "Ellipse",
SchRecord::Pie(_) => "Pie",
SchRecord::EllipticalArc(_) => "EllipticalArc",
SchRecord::Arc(_) => "Arc",
SchRecord::Line(_) => "Line",
SchRecord::Rectangle(_) => "Rectangle",
SchRecord::PowerObject(_) => "PowerObject",
SchRecord::Port(_) => "Port",
SchRecord::NoErc(_) => "NoErc",
SchRecord::NetLabel(_) => "NetLabel",
SchRecord::Bus(_) => "Bus",
SchRecord::Wire(_) => "Wire",
SchRecord::TextFrame(_) => "TextFrame",
SchRecord::TextFrameVariant(_) => "TextFrameVariant",
SchRecord::Junction(_) => "Junction",
SchRecord::Image(_) => "Image",
SchRecord::SheetHeader(_) => "SheetHeader",
SchRecord::Designator(_) => "Designator",
SchRecord::BusEntry(_) => "BusEntry",
SchRecord::Parameter(_) => "Parameter",
SchRecord::WarningSign(_) => "WarningSign",
SchRecord::ImplementationList(_) => "ImplementationList",
SchRecord::Implementation(_) => "Implementation",
SchRecord::MapDefinerList(_) => "MapDefinerList",
SchRecord::MapDefiner(_) => "MapDefiner",
SchRecord::ImplementationParameters(_) => "ImplementationParameters",
SchRecord::Unknown { .. } => "Unknown",
}
}
pub fn get_property(&self, name: &str) -> Option<String> {
match self {
SchRecord::Component(r) => match name {
"LIBREFERENCE" => Some(r.lib_reference.clone()),
"COMPONENTDESCRIPTION" => Some(r.component_description.clone()),
"UNIQUEID" => Some(r.unique_id.clone()),
_ => None,
},
SchRecord::Pin(r) => match name {
"NAME" => Some(r.name.clone()),
"DESIGNATOR" => Some(r.designator.clone()),
"DESCRIPTION" => Some(r.description.clone()),
_ => None,
},
SchRecord::Label(r) => match name {
"TEXT" => Some(r.text.clone()),
_ => None,
},
SchRecord::PowerObject(r) => match name {
"TEXT" => Some(r.text.clone()),
_ => None,
},
SchRecord::Port(r) => match name {
"NAME" => Some(r.name.clone()),
_ => None,
},
SchRecord::NetLabel(r) => match name {
"TEXT" => Some(r.label.text.clone()),
_ => None,
},
SchRecord::TextFrame(r) => match name {
"TEXT" => Some(r.text.clone()),
_ => None,
},
SchRecord::TextFrameVariant(r) => match name {
"TEXT" => Some(r.text.clone()),
_ => None,
},
SchRecord::Parameter(r) => match name {
"NAME" => Some(r.name.clone()),
"TEXT" => Some(r.label.text.clone()),
_ => None,
},
SchRecord::Designator(r) => match name {
"NAME" => Some(r.param.name.clone()),
"TEXT" => Some(r.param.label.text.clone()),
_ => None,
},
SchRecord::WarningSign(r) => match name {
"NAME" => Some(r.name.clone()),
_ => None,
},
SchRecord::Implementation(r) => match name {
"MODELNAME" => Some(r.model_name.clone()),
"MODELTYPE" => Some(r.model_type.clone()),
_ => None,
},
_ => None,
}
}
}
impl TreeRecord for SchRecord {
fn owner_index(&self) -> i32 {
self.owner_index()
}
fn set_owner_index(&mut self, index: i32) {
self.set_owner_index(index)
}
}