1use crate::render_attributes::RenderAttributes;
2use crate::styled_text::StyledText;
3use serde::{Deserialize, Deserializer, Serialize};
4
5#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "kebab-case")]
7pub enum Fragment {
8 Whole,
9 ContinuedFromPrev,
10 ContinuedToNext,
11 ContinuedFromPrevAndToNext,
12}
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
15pub struct LineRange(pub u32, pub u32);
16
17#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
18pub struct PaginationScope {
19 #[serde(default, skip_serializing_if = "Option::is_none")]
20 pub first_page_number: Option<u32>,
21 pub title_page_count: Option<u32>,
22 pub body_start_page: Option<u32>,
23}
24
25#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
26pub struct PageBreakFixtureSourceRefs {
27 pub fountain: Option<String>,
28 pub fdx: Option<String>,
29 pub pdf: Option<String>,
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
33pub struct NormalizedElement {
34 pub element_id: String,
35 pub kind: String,
36 pub text: String,
37 #[serde(default, skip_serializing_if = "Option::is_none")]
38 pub inline_text: Option<StyledText>,
39 #[serde(default, skip_serializing_if = "RenderAttributes::is_default")]
40 pub render_attributes: RenderAttributes,
41 pub fragment: Option<Fragment>,
42 pub block_kind: Option<String>,
43 pub block_id: Option<String>,
44 pub dual_dialogue_group: Option<String>,
45 pub dual_dialogue_side: Option<u8>,
46}
47
48impl<'de> Deserialize<'de> for NormalizedElement {
49 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
50 where
51 D: Deserializer<'de>,
52 {
53 #[derive(Deserialize)]
54 struct NormalizedElementRepr {
55 element_id: String,
56 kind: String,
57 text: String,
58 #[serde(default)]
59 inline_text: Option<StyledText>,
60 #[serde(default)]
61 render_attributes: Option<RenderAttributes>,
62 fragment: Option<Fragment>,
63 #[serde(default)]
64 centered: bool,
65 #[serde(default)]
66 starts_new_page: bool,
67 #[serde(default)]
68 scene_number: Option<String>,
69 block_kind: Option<String>,
70 block_id: Option<String>,
71 dual_dialogue_group: Option<String>,
72 dual_dialogue_side: Option<u8>,
73 }
74
75 let repr = NormalizedElementRepr::deserialize(deserializer)?;
76 let render_attributes = repr.render_attributes.unwrap_or(RenderAttributes {
77 centered: repr.centered,
78 starts_new_page: repr.starts_new_page,
79 scene_number: repr.scene_number,
80 ..RenderAttributes::default()
81 });
82
83 Ok(Self {
84 element_id: repr.element_id,
85 kind: repr.kind,
86 text: repr.text,
87 inline_text: repr.inline_text,
88 render_attributes,
89 fragment: repr.fragment,
90 block_kind: repr.block_kind,
91 block_id: repr.block_id,
92 dual_dialogue_group: repr.dual_dialogue_group,
93 dual_dialogue_side: repr.dual_dialogue_side,
94 })
95 }
96}
97
98#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
99pub struct NormalizedScreenplay {
100 pub screenplay: String,
101 pub starting_page_number: Option<u32>,
102 pub elements: Vec<NormalizedElement>,
103}
104
105#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
106pub struct PageItem {
107 pub element_id: String,
108 pub kind: String,
109 #[serde(default, skip_serializing_if = "Option::is_none")]
110 pub text_preview: Option<String>,
111 pub fragment: Fragment,
112 pub line_range: Option<LineRange>,
113 pub block_id: Option<String>,
114 pub dual_dialogue_group: Option<String>,
115 pub dual_dialogue_side: Option<u8>,
116}
117
118#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
119pub struct PageBreakFixturePage {
120 pub number: u32,
121 pub items: Vec<PageItem>,
122}
123
124#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
125pub struct PageBreakFixture {
126 pub screenplay: String,
127 pub style_profile: String,
128 pub source: PageBreakFixtureSourceRefs,
129 pub scope: PaginationScope,
130 pub pages: Vec<PageBreakFixturePage>,
131}