1use std::path::PathBuf;
2use std::str::FromStr;
3
4use crate::model::board::{ColorRgba, PolygonWithHolesNm, Vector2Nm};
5use crate::proto::kiapi::common::types as common_types;
6
7#[derive(Clone, Debug, Eq, PartialEq)]
8pub struct VersionInfo {
10 pub major: u32,
12 pub minor: u32,
14 pub patch: u32,
16 pub full_version: String,
18}
19
20#[derive(Clone, Copy, Debug, Eq, PartialEq)]
21pub enum EditorFrameType {
23 ProjectManager,
25 SchematicEditor,
27 PcbEditor,
29 SpiceSimulator,
31 SymbolEditor,
33 FootprintEditor,
35 DrawingSheetEditor,
37}
38
39impl EditorFrameType {
40 pub(crate) fn to_proto(self) -> i32 {
41 match self {
42 Self::ProjectManager => common_types::FrameType::FtProjectManager as i32,
43 Self::SchematicEditor => common_types::FrameType::FtSchematicEditor as i32,
44 Self::PcbEditor => common_types::FrameType::FtPcbEditor as i32,
45 Self::SpiceSimulator => common_types::FrameType::FtSpiceSimulator as i32,
46 Self::SymbolEditor => common_types::FrameType::FtSymbolEditor as i32,
47 Self::FootprintEditor => common_types::FrameType::FtFootprintEditor as i32,
48 Self::DrawingSheetEditor => common_types::FrameType::FtDrawingSheetEditor as i32,
49 }
50 }
51}
52
53impl std::fmt::Display for EditorFrameType {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 let value = match self {
56 Self::ProjectManager => "project-manager",
57 Self::SchematicEditor => "schematic",
58 Self::PcbEditor => "pcb",
59 Self::SpiceSimulator => "spice",
60 Self::SymbolEditor => "symbol",
61 Self::FootprintEditor => "footprint",
62 Self::DrawingSheetEditor => "drawing-sheet",
63 };
64 write!(f, "{value}")
65 }
66}
67
68impl FromStr for EditorFrameType {
69 type Err = String;
70
71 fn from_str(value: &str) -> Result<Self, Self::Err> {
72 match value {
73 "project-manager" => Ok(Self::ProjectManager),
74 "schematic" => Ok(Self::SchematicEditor),
75 "pcb" => Ok(Self::PcbEditor),
76 "spice" => Ok(Self::SpiceSimulator),
77 "symbol" => Ok(Self::SymbolEditor),
78 "footprint" => Ok(Self::FootprintEditor),
79 "drawing-sheet" => Ok(Self::DrawingSheetEditor),
80 _ => Err(format!(
81 "unknown frame `{value}`; expected one of: project-manager, schematic, pcb, spice, symbol, footprint, drawing-sheet"
82 )),
83 }
84 }
85}
86
87#[derive(Clone, Copy, Debug, Eq, PartialEq)]
88pub enum DocumentType {
90 Schematic,
92 Symbol,
94 Pcb,
96 Footprint,
98 DrawingSheet,
100 Project,
102}
103
104impl DocumentType {
105 pub(crate) fn to_proto(self) -> i32 {
106 match self {
107 Self::Schematic => common_types::DocumentType::DoctypeSchematic as i32,
108 Self::Symbol => common_types::DocumentType::DoctypeSymbol as i32,
109 Self::Pcb => common_types::DocumentType::DoctypePcb as i32,
110 Self::Footprint => common_types::DocumentType::DoctypeFootprint as i32,
111 Self::DrawingSheet => common_types::DocumentType::DoctypeDrawingSheet as i32,
112 Self::Project => common_types::DocumentType::DoctypeProject as i32,
113 }
114 }
115
116 pub(crate) fn from_proto(value: i32) -> Option<Self> {
117 let ty = common_types::DocumentType::try_from(value).ok()?;
118 match ty {
119 common_types::DocumentType::DoctypeSchematic => Some(Self::Schematic),
120 common_types::DocumentType::DoctypeSymbol => Some(Self::Symbol),
121 common_types::DocumentType::DoctypePcb => Some(Self::Pcb),
122 common_types::DocumentType::DoctypeFootprint => Some(Self::Footprint),
123 common_types::DocumentType::DoctypeDrawingSheet => Some(Self::DrawingSheet),
124 common_types::DocumentType::DoctypeProject => Some(Self::Project),
125 common_types::DocumentType::DoctypeUnknown => None,
126 }
127 }
128}
129
130impl std::fmt::Display for DocumentType {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 let value = match self {
133 Self::Schematic => "schematic",
134 Self::Symbol => "symbol",
135 Self::Pcb => "pcb",
136 Self::Footprint => "footprint",
137 Self::DrawingSheet => "drawing-sheet",
138 Self::Project => "project",
139 };
140
141 write!(f, "{value}")
142 }
143}
144
145impl FromStr for DocumentType {
146 type Err = String;
147
148 fn from_str(value: &str) -> Result<Self, Self::Err> {
149 match value {
150 "schematic" => Ok(Self::Schematic),
151 "symbol" => Ok(Self::Symbol),
152 "pcb" => Ok(Self::Pcb),
153 "footprint" => Ok(Self::Footprint),
154 "drawing-sheet" => Ok(Self::DrawingSheet),
155 "project" => Ok(Self::Project),
156 _ => Err(format!(
157 "unknown document type `{value}`; expected one of: schematic, symbol, pcb, footprint, drawing-sheet, project"
158 )),
159 }
160 }
161}
162
163#[derive(Clone, Debug, Eq, PartialEq)]
164pub struct ProjectInfo {
166 pub name: Option<String>,
168 pub path: Option<PathBuf>,
170}
171
172#[derive(Clone, Debug, Eq, PartialEq)]
173pub struct DocumentSpecifier {
175 pub document_type: DocumentType,
177 pub board_filename: Option<String>,
179 pub project: ProjectInfo,
181}
182
183#[derive(Clone, Debug, Eq, PartialEq)]
184pub struct SelectionTypeCount {
186 pub type_url: String,
188 pub count: usize,
190}
191
192#[derive(Clone, Debug, Eq, PartialEq)]
193pub struct SelectionSummary {
195 pub total_items: usize,
197 pub type_url_counts: Vec<SelectionTypeCount>,
199}
200
201#[derive(Clone, Debug, Eq, PartialEq)]
202pub struct SelectionItemDetail {
204 pub type_url: String,
206 pub detail: String,
208 pub raw_len: usize,
210}
211
212#[derive(Clone, Debug, Eq, PartialEq)]
213pub struct CommitSession {
215 pub id: String,
217}
218
219#[derive(Clone, Copy, Debug, Eq, PartialEq)]
220pub enum CommitAction {
222 Commit,
224 Drop,
226}
227
228#[derive(Clone, Copy, Debug, Eq, PartialEq)]
229pub enum RunActionStatus {
231 Ok,
233 Invalid,
235 FrameNotOpen,
237 Unknown(i32),
239}
240
241#[derive(Clone, Copy, Debug, Eq, PartialEq)]
242pub enum MapMergeMode {
244 Merge,
246 Replace,
248}
249
250impl std::fmt::Display for MapMergeMode {
251 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
252 match self {
253 Self::Merge => write!(f, "merge"),
254 Self::Replace => write!(f, "replace"),
255 }
256 }
257}
258
259impl FromStr for MapMergeMode {
260 type Err = String;
261
262 fn from_str(value: &str) -> Result<Self, Self::Err> {
263 match value {
264 "merge" => Ok(Self::Merge),
265 "replace" => Ok(Self::Replace),
266 _ => Err(format!(
267 "unknown merge mode `{value}`; expected `merge` or `replace`"
268 )),
269 }
270 }
271}
272
273impl std::fmt::Display for CommitAction {
274 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275 match self {
276 Self::Commit => write!(f, "commit"),
277 Self::Drop => write!(f, "drop"),
278 }
279 }
280}
281
282impl FromStr for CommitAction {
283 type Err = String;
284
285 fn from_str(value: &str) -> Result<Self, Self::Err> {
286 match value {
287 "commit" => Ok(Self::Commit),
288 "drop" => Ok(Self::Drop),
289 _ => Err(format!(
290 "unknown commit action `{value}`; expected `commit` or `drop`"
291 )),
292 }
293 }
294}
295
296#[derive(Clone, Debug, Eq, PartialEq)]
297pub struct TitleBlockInfo {
299 pub title: String,
301 pub date: String,
303 pub revision: String,
305 pub company: String,
307 pub comments: Vec<String>,
309}
310
311#[derive(Clone, Debug, Eq, PartialEq)]
312pub struct ItemBoundingBox {
313 pub item_id: String,
314 pub x_nm: i64,
315 pub y_nm: i64,
316 pub width_nm: i64,
317 pub height_nm: i64,
318}
319
320#[derive(Clone, Copy, Debug, Eq, PartialEq)]
321pub enum ItemHitTestResult {
322 Unknown,
323 NoHit,
324 Hit,
325}
326
327#[derive(Clone, Copy, Debug, Eq, PartialEq)]
328pub struct PcbObjectTypeCode {
329 pub code: i32,
330 pub name: &'static str,
331}
332
333#[derive(Clone, Copy, Debug, Eq, PartialEq)]
334pub enum TextHorizontalAlignment {
335 Unknown,
336 Left,
337 Center,
338 Right,
339 Indeterminate,
340}
341
342#[derive(Clone, Copy, Debug, Eq, PartialEq)]
343pub enum TextVerticalAlignment {
344 Unknown,
345 Top,
346 Center,
347 Bottom,
348 Indeterminate,
349}
350
351#[derive(Clone, Debug, PartialEq)]
352pub struct TextAttributesSpec {
353 pub font_name: Option<String>,
354 pub horizontal_alignment: TextHorizontalAlignment,
355 pub vertical_alignment: TextVerticalAlignment,
356 pub angle_degrees: Option<f64>,
357 pub line_spacing: Option<f64>,
358 pub stroke_width_nm: Option<i64>,
359 pub italic: bool,
360 pub bold: bool,
361 pub underlined: bool,
362 pub mirrored: bool,
363 pub multiline: bool,
364 pub keep_upright: bool,
365 pub size_nm: Option<Vector2Nm>,
366}
367
368impl Default for TextAttributesSpec {
369 fn default() -> Self {
370 Self {
371 font_name: None,
372 horizontal_alignment: TextHorizontalAlignment::Unknown,
373 vertical_alignment: TextVerticalAlignment::Unknown,
374 angle_degrees: None,
375 line_spacing: None,
376 stroke_width_nm: None,
377 italic: false,
378 bold: false,
379 underlined: false,
380 mirrored: false,
381 multiline: false,
382 keep_upright: false,
383 size_nm: None,
384 }
385 }
386}
387
388#[derive(Clone, Debug, PartialEq)]
389pub struct TextSpec {
390 pub text: String,
391 pub position_nm: Option<Vector2Nm>,
392 pub attributes: Option<TextAttributesSpec>,
393 pub hyperlink: Option<String>,
394}
395
396impl TextSpec {
397 pub fn plain(text: impl Into<String>) -> Self {
398 Self {
399 text: text.into(),
400 position_nm: None,
401 attributes: None,
402 hyperlink: None,
403 }
404 }
405}
406
407#[derive(Clone, Debug, Eq, PartialEq)]
408pub struct TextExtents {
409 pub x_nm: i64,
410 pub y_nm: i64,
411 pub width_nm: i64,
412 pub height_nm: i64,
413}
414
415#[derive(Clone, Debug, PartialEq)]
416pub struct TextBoxSpec {
417 pub text: String,
418 pub top_left_nm: Option<Vector2Nm>,
419 pub bottom_right_nm: Option<Vector2Nm>,
420 pub attributes: Option<TextAttributesSpec>,
421}
422
423#[derive(Clone, Debug, PartialEq)]
424pub enum TextObjectSpec {
425 Text(TextSpec),
426 TextBox(TextBoxSpec),
427}
428
429#[derive(Clone, Debug, PartialEq)]
430pub enum TextShapeGeometry {
431 Segment {
432 start_nm: Option<Vector2Nm>,
433 end_nm: Option<Vector2Nm>,
434 },
435 Rectangle {
436 top_left_nm: Option<Vector2Nm>,
437 bottom_right_nm: Option<Vector2Nm>,
438 corner_radius_nm: Option<i64>,
439 },
440 Arc {
441 start_nm: Option<Vector2Nm>,
442 mid_nm: Option<Vector2Nm>,
443 end_nm: Option<Vector2Nm>,
444 },
445 Circle {
446 center_nm: Option<Vector2Nm>,
447 radius_point_nm: Option<Vector2Nm>,
448 },
449 Polygon {
450 polygons: Vec<PolygonWithHolesNm>,
451 },
452 Bezier {
453 start_nm: Option<Vector2Nm>,
454 control1_nm: Option<Vector2Nm>,
455 control2_nm: Option<Vector2Nm>,
456 end_nm: Option<Vector2Nm>,
457 },
458 Unknown,
459}
460
461#[derive(Clone, Debug, PartialEq)]
462pub struct TextShape {
463 pub geometry: TextShapeGeometry,
464 pub stroke_width_nm: Option<i64>,
465 pub stroke_style: Option<i32>,
466 pub stroke_color: Option<ColorRgba>,
467 pub fill_type: Option<i32>,
468 pub fill_color: Option<ColorRgba>,
469}
470
471#[derive(Clone, Debug, PartialEq)]
472pub struct TextAsShapesEntry {
473 pub source: Option<TextObjectSpec>,
474 pub shapes: Vec<TextShape>,
475}
476
477impl std::fmt::Display for ItemHitTestResult {
478 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
479 let value = match self {
480 Self::Unknown => "unknown",
481 Self::NoHit => "no-hit",
482 Self::Hit => "hit",
483 };
484
485 write!(f, "{value}")
486 }
487}
488
489#[cfg(test)]
490mod tests {
491 use super::{CommitAction, EditorFrameType, MapMergeMode};
492 use std::str::FromStr;
493
494 #[test]
495 fn commit_action_parses_known_values() {
496 assert_eq!(CommitAction::from_str("commit"), Ok(CommitAction::Commit));
497 assert_eq!(CommitAction::from_str("drop"), Ok(CommitAction::Drop));
498 }
499
500 #[test]
501 fn commit_action_rejects_unknown_values() {
502 assert!(CommitAction::from_str("rollback").is_err());
503 }
504
505 #[test]
506 fn editor_frame_type_parses_known_values() {
507 assert_eq!(
508 EditorFrameType::from_str("pcb"),
509 Ok(EditorFrameType::PcbEditor)
510 );
511 assert_eq!(
512 EditorFrameType::from_str("project-manager"),
513 Ok(EditorFrameType::ProjectManager)
514 );
515 }
516
517 #[test]
518 fn editor_frame_type_rejects_unknown_values() {
519 assert!(EditorFrameType::from_str("layout").is_err());
520 }
521
522 #[test]
523 fn map_merge_mode_parses_known_values() {
524 assert_eq!(MapMergeMode::from_str("merge"), Ok(MapMergeMode::Merge));
525 assert_eq!(MapMergeMode::from_str("replace"), Ok(MapMergeMode::Replace));
526 }
527
528 #[test]
529 fn map_merge_mode_rejects_unknown_values() {
530 assert!(MapMergeMode::from_str("upsert").is_err());
531 }
532}