mirror of
https://github.com/duhanbalci/dreport.git
synced 2026-07-01 18:39:16 +00:00
repofactor
This commit is contained in:
@@ -247,11 +247,8 @@ pub struct ChartStyle {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ChartElement {
|
pub struct ChartElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub chart_type: ChartType,
|
pub chart_type: ChartType,
|
||||||
pub data_source: ArrayBinding,
|
pub data_source: ArrayBinding,
|
||||||
pub category_field: String,
|
pub category_field: String,
|
||||||
@@ -272,6 +269,138 @@ pub struct ChartElement {
|
|||||||
pub style: ChartStyle,
|
pub style: ChartStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Element Base (ortak alanlar) ---
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ElementBase {
|
||||||
|
pub id: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub condition: Option<Condition>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub position: PositionMode,
|
||||||
|
#[serde(default)]
|
||||||
|
pub size: SizeConstraint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElementBase {
|
||||||
|
/// Flow pozisyonlu, condition'sız, verilen size ile base oluştur
|
||||||
|
pub fn flow(id: String, size: SizeConstraint) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
condition: None,
|
||||||
|
position: PositionMode::Flow,
|
||||||
|
size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasBase {
|
||||||
|
fn base(&self) -> &ElementBase;
|
||||||
|
fn base_mut(&mut self) -> &mut ElementBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_has_base {
|
||||||
|
($($t:ty),+ $(,)?) => {
|
||||||
|
$(impl HasBase for $t {
|
||||||
|
fn base(&self) -> &ElementBase { &self.base }
|
||||||
|
fn base_mut(&mut self) -> &mut ElementBase { &mut self.base }
|
||||||
|
})+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_has_base!(
|
||||||
|
ContainerElement,
|
||||||
|
StaticTextElement,
|
||||||
|
TextElement,
|
||||||
|
LineElement,
|
||||||
|
ImageElement,
|
||||||
|
PageNumberElement,
|
||||||
|
BarcodeElement,
|
||||||
|
RepeatingTableElement,
|
||||||
|
PageBreakElement,
|
||||||
|
CurrentDateElement,
|
||||||
|
ShapeElement,
|
||||||
|
CheckboxElement,
|
||||||
|
CalculatedTextElement,
|
||||||
|
RichTextElement,
|
||||||
|
ChartElement,
|
||||||
|
);
|
||||||
|
|
||||||
|
pub trait ElementTypeStr {
|
||||||
|
fn type_str(&self) -> &'static str;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_type_str {
|
||||||
|
($($t:ty => $s:literal),+ $(,)?) => {
|
||||||
|
$(impl ElementTypeStr for $t {
|
||||||
|
fn type_str(&self) -> &'static str { $s }
|
||||||
|
})+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_type_str!(
|
||||||
|
ContainerElement => "container",
|
||||||
|
StaticTextElement => "static_text",
|
||||||
|
TextElement => "text",
|
||||||
|
LineElement => "line",
|
||||||
|
ImageElement => "image",
|
||||||
|
PageNumberElement => "page_number",
|
||||||
|
BarcodeElement => "barcode",
|
||||||
|
RepeatingTableElement => "repeating_table",
|
||||||
|
PageBreakElement => "page_break",
|
||||||
|
CurrentDateElement => "current_date",
|
||||||
|
ShapeElement => "shape",
|
||||||
|
CheckboxElement => "checkbox",
|
||||||
|
CalculatedTextElement => "calculated_text",
|
||||||
|
RichTextElement => "rich_text",
|
||||||
|
ChartElement => "chart",
|
||||||
|
);
|
||||||
|
|
||||||
|
pub trait HasTextStyle {
|
||||||
|
fn text_style(&self) -> &TextStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_has_text_style {
|
||||||
|
($($t:ty),+ $(,)?) => {
|
||||||
|
$(impl HasTextStyle for $t {
|
||||||
|
fn text_style(&self) -> &TextStyle { &self.style }
|
||||||
|
})+
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_has_text_style!(
|
||||||
|
StaticTextElement,
|
||||||
|
TextElement,
|
||||||
|
PageNumberElement,
|
||||||
|
CurrentDateElement,
|
||||||
|
CalculatedTextElement,
|
||||||
|
RichTextElement,
|
||||||
|
);
|
||||||
|
|
||||||
|
pub trait HasOptionalBinding {
|
||||||
|
fn binding(&self) -> Option<&ScalarBinding>;
|
||||||
|
fn static_value(&self) -> Option<&str>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasOptionalBinding for ImageElement {
|
||||||
|
fn binding(&self) -> Option<&ScalarBinding> {
|
||||||
|
self.binding.as_ref()
|
||||||
|
}
|
||||||
|
fn static_value(&self) -> Option<&str> {
|
||||||
|
self.src.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasOptionalBinding for BarcodeElement {
|
||||||
|
fn binding(&self) -> Option<&ScalarBinding> {
|
||||||
|
self.binding.as_ref()
|
||||||
|
}
|
||||||
|
fn static_value(&self) -> Option<&str> {
|
||||||
|
self.value.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- Element tipleri ---
|
// --- Element tipleri ---
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
@@ -316,91 +445,59 @@ pub enum TemplateElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TemplateElement {
|
impl TemplateElement {
|
||||||
pub fn id(&self) -> &str {
|
fn inner_base(&self) -> &ElementBase {
|
||||||
match self {
|
match self {
|
||||||
Self::Container(e) => &e.id,
|
Self::Container(e) => e.base(),
|
||||||
Self::StaticText(e) => &e.id,
|
Self::StaticText(e) => e.base(),
|
||||||
Self::Text(e) => &e.id,
|
Self::Text(e) => e.base(),
|
||||||
Self::Line(e) => &e.id,
|
Self::Line(e) => e.base(),
|
||||||
Self::RepeatingTable(e) => &e.id,
|
Self::RepeatingTable(e) => e.base(),
|
||||||
Self::Image(e) => &e.id,
|
Self::Image(e) => e.base(),
|
||||||
Self::PageNumber(e) => &e.id,
|
Self::PageNumber(e) => e.base(),
|
||||||
Self::Barcode(e) => &e.id,
|
Self::Barcode(e) => e.base(),
|
||||||
Self::PageBreak(e) => &e.id,
|
Self::PageBreak(e) => e.base(),
|
||||||
Self::CurrentDate(e) => &e.id,
|
Self::CurrentDate(e) => e.base(),
|
||||||
Self::Shape(e) => &e.id,
|
Self::Shape(e) => e.base(),
|
||||||
Self::Checkbox(e) => &e.id,
|
Self::Checkbox(e) => e.base(),
|
||||||
Self::CalculatedText(e) => &e.id,
|
Self::CalculatedText(e) => e.base(),
|
||||||
Self::RichText(e) => &e.id,
|
Self::RichText(e) => e.base(),
|
||||||
Self::Chart(e) => &e.id,
|
Self::Chart(e) => e.base(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> &str {
|
||||||
|
&self.inner_base().id
|
||||||
|
}
|
||||||
|
|
||||||
pub fn position(&self) -> &PositionMode {
|
pub fn position(&self) -> &PositionMode {
|
||||||
match self {
|
&self.inner_base().position
|
||||||
Self::Container(e) => &e.position,
|
|
||||||
Self::StaticText(e) => &e.position,
|
|
||||||
Self::Text(e) => &e.position,
|
|
||||||
Self::Line(e) => &e.position,
|
|
||||||
Self::RepeatingTable(e) => &e.position,
|
|
||||||
Self::Image(e) => &e.position,
|
|
||||||
Self::PageNumber(e) => &e.position,
|
|
||||||
Self::Barcode(e) => &e.position,
|
|
||||||
Self::PageBreak(_) => &PositionMode::Flow,
|
|
||||||
Self::CurrentDate(e) => &e.position,
|
|
||||||
Self::Shape(e) => &e.position,
|
|
||||||
Self::Checkbox(e) => &e.position,
|
|
||||||
Self::CalculatedText(e) => &e.position,
|
|
||||||
Self::RichText(e) => &e.position,
|
|
||||||
Self::Chart(e) => &e.position,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn condition(&self) -> Option<&Condition> {
|
pub fn condition(&self) -> Option<&Condition> {
|
||||||
match self {
|
self.inner_base().condition.as_ref()
|
||||||
Self::Container(e) => e.condition.as_ref(),
|
|
||||||
Self::StaticText(e) => e.condition.as_ref(),
|
|
||||||
Self::Text(e) => e.condition.as_ref(),
|
|
||||||
Self::Line(e) => e.condition.as_ref(),
|
|
||||||
Self::RepeatingTable(e) => e.condition.as_ref(),
|
|
||||||
Self::Image(e) => e.condition.as_ref(),
|
|
||||||
Self::PageNumber(e) => e.condition.as_ref(),
|
|
||||||
Self::Barcode(e) => e.condition.as_ref(),
|
|
||||||
Self::PageBreak(e) => e.condition.as_ref(),
|
|
||||||
Self::CurrentDate(e) => e.condition.as_ref(),
|
|
||||||
Self::Shape(e) => e.condition.as_ref(),
|
|
||||||
Self::Checkbox(e) => e.condition.as_ref(),
|
|
||||||
Self::CalculatedText(e) => e.condition.as_ref(),
|
|
||||||
Self::RichText(e) => e.condition.as_ref(),
|
|
||||||
Self::Chart(e) => e.condition.as_ref(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> &SizeConstraint {
|
pub fn size(&self) -> &SizeConstraint {
|
||||||
static DEFAULT_SIZE: SizeConstraint = SizeConstraint {
|
&self.inner_base().size
|
||||||
width: SizeValue::Auto,
|
}
|
||||||
height: SizeValue::Auto,
|
|
||||||
min_width: None,
|
pub fn type_str(&self) -> &'static str {
|
||||||
min_height: None,
|
|
||||||
max_width: None,
|
|
||||||
max_height: None,
|
|
||||||
};
|
|
||||||
match self {
|
match self {
|
||||||
Self::Container(e) => &e.size,
|
Self::Container(e) => e.type_str(),
|
||||||
Self::StaticText(e) => &e.size,
|
Self::StaticText(e) => e.type_str(),
|
||||||
Self::Text(e) => &e.size,
|
Self::Text(e) => e.type_str(),
|
||||||
Self::Line(e) => &e.size,
|
Self::Line(e) => e.type_str(),
|
||||||
Self::RepeatingTable(e) => &e.size,
|
Self::RepeatingTable(e) => e.type_str(),
|
||||||
Self::Image(e) => &e.size,
|
Self::Image(e) => e.type_str(),
|
||||||
Self::PageNumber(e) => &e.size,
|
Self::PageNumber(e) => e.type_str(),
|
||||||
Self::Barcode(e) => &e.size,
|
Self::Barcode(e) => e.type_str(),
|
||||||
Self::PageBreak(_) => &DEFAULT_SIZE,
|
Self::PageBreak(e) => e.type_str(),
|
||||||
Self::CurrentDate(e) => &e.size,
|
Self::CurrentDate(e) => e.type_str(),
|
||||||
Self::Shape(e) => &e.size,
|
Self::Shape(e) => e.type_str(),
|
||||||
Self::Checkbox(e) => &e.size,
|
Self::Checkbox(e) => e.type_str(),
|
||||||
Self::CalculatedText(e) => &e.size,
|
Self::CalculatedText(e) => e.type_str(),
|
||||||
Self::RichText(e) => &e.size,
|
Self::RichText(e) => e.type_str(),
|
||||||
Self::Chart(e) => &e.size,
|
Self::Chart(e) => e.type_str(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,11 +505,8 @@ impl TemplateElement {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RichTextElement {
|
pub struct RichTextElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub style: TextStyle, // varsayilan stil (span'lar override edebilir)
|
pub style: TextStyle, // varsayilan stil (span'lar override edebilir)
|
||||||
pub content: Vec<RichTextSpan>,
|
pub content: Vec<RichTextSpan>,
|
||||||
@@ -421,13 +515,8 @@ pub struct RichTextElement {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ContainerElement {
|
pub struct ContainerElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub position: PositionMode,
|
|
||||||
#[serde(default)]
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
#[serde(default = "default_column")]
|
#[serde(default = "default_column")]
|
||||||
pub direction: String,
|
pub direction: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -463,11 +552,8 @@ fn default_start() -> String {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct StaticTextElement {
|
pub struct StaticTextElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub style: TextStyle,
|
pub style: TextStyle,
|
||||||
pub content: String,
|
pub content: String,
|
||||||
}
|
}
|
||||||
@@ -475,11 +561,8 @@ pub struct StaticTextElement {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TextElement {
|
pub struct TextElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub style: TextStyle,
|
pub style: TextStyle,
|
||||||
pub content: Option<String>,
|
pub content: Option<String>,
|
||||||
pub binding: ScalarBinding,
|
pub binding: ScalarBinding,
|
||||||
@@ -488,22 +571,16 @@ pub struct TextElement {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct LineElement {
|
pub struct LineElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub style: LineStyle,
|
pub style: LineStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ImageElement {
|
pub struct ImageElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub src: Option<String>,
|
pub src: Option<String>,
|
||||||
pub binding: Option<ScalarBinding>,
|
pub binding: Option<ScalarBinding>,
|
||||||
pub style: ImageStyle,
|
pub style: ImageStyle,
|
||||||
@@ -512,11 +589,8 @@ pub struct ImageElement {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PageNumberElement {
|
pub struct PageNumberElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub style: TextStyle,
|
pub style: TextStyle,
|
||||||
pub format: Option<String>,
|
pub format: Option<String>,
|
||||||
}
|
}
|
||||||
@@ -524,11 +598,8 @@ pub struct PageNumberElement {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct BarcodeElement {
|
pub struct BarcodeElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub format: String, // qr, ean13, ean8, code128, code39
|
pub format: String, // qr, ean13, ean8, code128, code39
|
||||||
pub value: Option<String>,
|
pub value: Option<String>,
|
||||||
pub binding: Option<ScalarBinding>,
|
pub binding: Option<ScalarBinding>,
|
||||||
@@ -538,11 +609,8 @@ pub struct BarcodeElement {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RepeatingTableElement {
|
pub struct RepeatingTableElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub data_source: ArrayBinding,
|
pub data_source: ArrayBinding,
|
||||||
pub columns: Vec<TableColumn>,
|
pub columns: Vec<TableColumn>,
|
||||||
pub style: TableStyle,
|
pub style: TableStyle,
|
||||||
@@ -557,19 +625,15 @@ fn default_true() -> Option<bool> {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct PageBreakElement {
|
pub struct PageBreakElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CurrentDateElement {
|
pub struct CurrentDateElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub style: TextStyle,
|
pub style: TextStyle,
|
||||||
pub format: Option<String>,
|
pub format: Option<String>,
|
||||||
}
|
}
|
||||||
@@ -577,11 +641,8 @@ pub struct CurrentDateElement {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ShapeElement {
|
pub struct ShapeElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub shape_type: String, // rectangle, ellipse, rounded_rectangle
|
pub shape_type: String, // rectangle, ellipse, rounded_rectangle
|
||||||
pub style: ContainerStyle,
|
pub style: ContainerStyle,
|
||||||
}
|
}
|
||||||
@@ -598,11 +659,8 @@ pub struct CheckboxStyle {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CheckboxElement {
|
pub struct CheckboxElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub checked: Option<bool>, // statik değer
|
pub checked: Option<bool>, // statik değer
|
||||||
pub binding: Option<ScalarBinding>, // dinamik boolean binding
|
pub binding: Option<ScalarBinding>, // dinamik boolean binding
|
||||||
pub style: CheckboxStyle,
|
pub style: CheckboxStyle,
|
||||||
@@ -611,11 +669,8 @@ pub struct CheckboxElement {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CalculatedTextElement {
|
pub struct CalculatedTextElement {
|
||||||
pub id: String,
|
#[serde(flatten)]
|
||||||
#[serde(default)]
|
pub base: ElementBase,
|
||||||
pub condition: Option<Condition>,
|
|
||||||
pub position: PositionMode,
|
|
||||||
pub size: SizeConstraint,
|
|
||||||
pub style: TextStyle,
|
pub style: TextStyle,
|
||||||
pub expression: String,
|
pub expression: String,
|
||||||
pub format: Option<String>,
|
pub format: Option<String>,
|
||||||
|
|||||||
@@ -116,10 +116,19 @@ export interface BarcodeStyle {
|
|||||||
includeText?: boolean // barkod altına değer yazılsın mı (QR hariç)
|
includeText?: boolean // barkod altına değer yazılsın mı (QR hariç)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Condition (koşullu gösterim) ---
|
||||||
|
|
||||||
|
export interface Condition {
|
||||||
|
path: string
|
||||||
|
operator: string
|
||||||
|
value?: unknown
|
||||||
|
}
|
||||||
|
|
||||||
// --- Element tipleri ---
|
// --- Element tipleri ---
|
||||||
|
|
||||||
interface BaseElement {
|
interface BaseElement {
|
||||||
id: string
|
id: string
|
||||||
|
condition?: Condition
|
||||||
position: PositionMode
|
position: PositionMode
|
||||||
size: SizeConstraint
|
size: SizeConstraint
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 121 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 166 KiB |
@@ -2,6 +2,9 @@ use dreport_core::models::*;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
// Re-export HasOptionalBinding for convenience
|
||||||
|
pub use dreport_core::models::HasOptionalBinding;
|
||||||
|
|
||||||
/// Şu anki tarihi verilen format string'ine göre formatla.
|
/// Şu anki tarihi verilen format string'ine göre formatla.
|
||||||
/// Desteklenen tokenlar: YYYY, MM, DD, HH, mm, ss
|
/// Desteklenen tokenlar: YYYY, MM, DD, HH, mm, ss
|
||||||
/// WASM'da js_sys::Date, native'de SystemTime kullanır.
|
/// WASM'da js_sys::Date, native'de SystemTime kullanır.
|
||||||
@@ -226,6 +229,15 @@ fn json_values_eq(a: &Value, b: &Value) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Çözümle optional binding: binding varsa data'dan, yoksa static value'dan
|
||||||
|
fn resolve_optional_binding(el: &impl HasOptionalBinding, data: &Value) -> String {
|
||||||
|
if let Some(binding) = el.binding() {
|
||||||
|
value_to_string(resolve_path(data, &binding.path))
|
||||||
|
} else {
|
||||||
|
el.static_value().unwrap_or_default().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedData, format_config: &dreport_core::models::FormatConfig) {
|
fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedData, format_config: &dreport_core::models::FormatConfig) {
|
||||||
// Koşul kontrolü: condition varsa ve sağlanmıyorsa, hidden olarak işaretle ve çık
|
// Koşul kontrolü: condition varsa ve sağlanmıyorsa, hidden olarak işaretle ve çık
|
||||||
if let Some(condition) = el.condition() && !evaluate_condition(condition, data) {
|
if let Some(condition) = el.condition() && !evaluate_condition(condition, data) {
|
||||||
@@ -235,7 +247,7 @@ fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedDa
|
|||||||
|
|
||||||
match el {
|
match el {
|
||||||
TemplateElement::StaticText(e) => {
|
TemplateElement::StaticText(e) => {
|
||||||
resolved.texts.insert(e.id.clone(), e.content.clone());
|
resolved.texts.insert(e.base.id.clone(), e.content.clone());
|
||||||
}
|
}
|
||||||
TemplateElement::Text(e) => {
|
TemplateElement::Text(e) => {
|
||||||
let bound_value = value_to_string(resolve_path(data, &e.binding.path));
|
let bound_value = value_to_string(resolve_path(data, &e.binding.path));
|
||||||
@@ -243,7 +255,7 @@ fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedDa
|
|||||||
Some(prefix) if !prefix.is_empty() => format!("{}{}", prefix, bound_value),
|
Some(prefix) if !prefix.is_empty() => format!("{}{}", prefix, bound_value),
|
||||||
_ => bound_value,
|
_ => bound_value,
|
||||||
};
|
};
|
||||||
resolved.texts.insert(e.id.clone(), text);
|
resolved.texts.insert(e.base.id.clone(), text);
|
||||||
}
|
}
|
||||||
TemplateElement::PageNumber(e) => {
|
TemplateElement::PageNumber(e) => {
|
||||||
// Format string'i sakla — sayfa bölme sonrası gerçek değerlerle çözülecek
|
// Format string'i sakla — sayfa bölme sonrası gerçek değerlerle çözülecek
|
||||||
@@ -254,28 +266,18 @@ fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedDa
|
|||||||
.to_string();
|
.to_string();
|
||||||
resolved
|
resolved
|
||||||
.page_number_formats
|
.page_number_formats
|
||||||
.insert(e.id.clone(), fmt.clone());
|
.insert(e.base.id.clone(), fmt.clone());
|
||||||
// Placeholder koy (tek sayfalık fallback)
|
// Placeholder koy (tek sayfalık fallback)
|
||||||
resolved.texts.insert(
|
resolved.texts.insert(
|
||||||
e.id.clone(),
|
e.base.id.clone(),
|
||||||
fmt.replace("{current}", "1").replace("{total}", "1"),
|
fmt.replace("{current}", "1").replace("{total}", "1"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
TemplateElement::Barcode(e) => {
|
TemplateElement::Barcode(e) => {
|
||||||
let value = if let Some(binding) = &e.binding {
|
resolved.barcodes.insert(e.base.id.clone(), resolve_optional_binding(e, data));
|
||||||
value_to_string(resolve_path(data, &binding.path))
|
|
||||||
} else {
|
|
||||||
e.value.clone().unwrap_or_default()
|
|
||||||
};
|
|
||||||
resolved.barcodes.insert(e.id.clone(), value);
|
|
||||||
}
|
}
|
||||||
TemplateElement::Image(e) => {
|
TemplateElement::Image(e) => {
|
||||||
let src = if let Some(binding) = &e.binding {
|
resolved.images.insert(e.base.id.clone(), resolve_optional_binding(e, data));
|
||||||
value_to_string(resolve_path(data, &binding.path))
|
|
||||||
} else {
|
|
||||||
e.src.clone().unwrap_or_default()
|
|
||||||
};
|
|
||||||
resolved.images.insert(e.id.clone(), src);
|
|
||||||
}
|
}
|
||||||
TemplateElement::RepeatingTable(e) => {
|
TemplateElement::RepeatingTable(e) => {
|
||||||
let array = resolve_path(data, &e.data_source.path);
|
let array = resolve_path(data, &e.data_source.path);
|
||||||
@@ -302,7 +304,7 @@ fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedDa
|
|||||||
}
|
}
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
resolved.tables.insert(e.id.clone(), ResolvedTable { rows });
|
resolved.tables.insert(e.base.id.clone(), ResolvedTable { rows });
|
||||||
}
|
}
|
||||||
TemplateElement::Container(e) => {
|
TemplateElement::Container(e) => {
|
||||||
for child in &e.children {
|
for child in &e.children {
|
||||||
@@ -312,7 +314,7 @@ fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedDa
|
|||||||
TemplateElement::CurrentDate(e) => {
|
TemplateElement::CurrentDate(e) => {
|
||||||
let fmt = e.format.as_deref().unwrap_or("DD.MM.YYYY");
|
let fmt = e.format.as_deref().unwrap_or("DD.MM.YYYY");
|
||||||
let text = format_current_date(fmt);
|
let text = format_current_date(fmt);
|
||||||
resolved.texts.insert(e.id.clone(), text);
|
resolved.texts.insert(e.base.id.clone(), text);
|
||||||
}
|
}
|
||||||
TemplateElement::Checkbox(e) => {
|
TemplateElement::Checkbox(e) => {
|
||||||
let checked = if let Some(binding) = &e.binding {
|
let checked = if let Some(binding) = &e.binding {
|
||||||
@@ -327,7 +329,7 @@ fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedDa
|
|||||||
e.checked.unwrap_or(false)
|
e.checked.unwrap_or(false)
|
||||||
};
|
};
|
||||||
// Store as "true"/"false" string in texts map
|
// Store as "true"/"false" string in texts map
|
||||||
resolved.texts.insert(e.id.clone(), checked.to_string());
|
resolved.texts.insert(e.base.id.clone(), checked.to_string());
|
||||||
}
|
}
|
||||||
TemplateElement::CalculatedText(e) => {
|
TemplateElement::CalculatedText(e) => {
|
||||||
let result = crate::expr_eval::evaluate_expression(&e.expression, data);
|
let result = crate::expr_eval::evaluate_expression(&e.expression, data);
|
||||||
@@ -338,7 +340,7 @@ fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedDa
|
|||||||
} else {
|
} else {
|
||||||
formatted
|
formatted
|
||||||
};
|
};
|
||||||
resolved.texts.insert(e.id.clone(), text);
|
resolved.texts.insert(e.base.id.clone(), text);
|
||||||
}
|
}
|
||||||
TemplateElement::RichText(e) => {
|
TemplateElement::RichText(e) => {
|
||||||
let spans: Vec<ResolvedRichSpan> = e
|
let spans: Vec<ResolvedRichSpan> = e
|
||||||
@@ -371,7 +373,7 @@ fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedDa
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
resolved.rich_texts.insert(e.id.clone(), spans);
|
resolved.rich_texts.insert(e.base.id.clone(), spans);
|
||||||
}
|
}
|
||||||
TemplateElement::Chart(e) => {
|
TemplateElement::Chart(e) => {
|
||||||
let array = resolve_path(data, &e.data_source.path);
|
let array = resolve_path(data, &e.data_source.path);
|
||||||
@@ -389,7 +391,7 @@ fn resolve_element(el: &TemplateElement, data: &Value, resolved: &mut ResolvedDa
|
|||||||
group_mode: e.group_mode.clone(),
|
group_mode: e.group_mode.clone(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
resolved.charts.insert(e.id.clone(), chart_data);
|
resolved.charts.insert(e.base.id.clone(), chart_data);
|
||||||
}
|
}
|
||||||
TemplateElement::Line(_) => {}
|
TemplateElement::Line(_) => {}
|
||||||
TemplateElement::Shape(_) => {}
|
TemplateElement::Shape(_) => {}
|
||||||
@@ -542,10 +544,7 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
@@ -554,10 +553,7 @@ mod tests {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::Text(TextElement {
|
children: vec![TemplateElement::Text(TextElement {
|
||||||
id: "el_name".to_string(),
|
base: ElementBase::flow("el_name".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
style: TextStyle::default(),
|
style: TextStyle::default(),
|
||||||
content: None,
|
content: None,
|
||||||
binding: ScalarBinding {
|
binding: ScalarBinding {
|
||||||
@@ -593,10 +589,7 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
@@ -605,10 +598,7 @@ mod tests {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::Text(TextElement {
|
children: vec![TemplateElement::Text(TextElement {
|
||||||
id: "el_no".to_string(),
|
base: ElementBase::flow("el_no".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
style: TextStyle::default(),
|
style: TextStyle::default(),
|
||||||
content: Some("Fatura No: ".to_string()),
|
content: Some("Fatura No: ".to_string()),
|
||||||
binding: ScalarBinding {
|
binding: ScalarBinding {
|
||||||
@@ -641,10 +631,7 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
@@ -653,10 +640,7 @@ mod tests {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::StaticText(StaticTextElement {
|
children: vec![TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "title".to_string(),
|
base: ElementBase::flow("title".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
style: TextStyle::default(),
|
style: TextStyle::default(),
|
||||||
content: "FATURA".to_string(),
|
content: "FATURA".to_string(),
|
||||||
})],
|
})],
|
||||||
@@ -682,10 +666,7 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
@@ -694,10 +675,7 @@ mod tests {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::RepeatingTable(RepeatingTableElement {
|
children: vec![TemplateElement::RepeatingTable(RepeatingTableElement {
|
||||||
id: "tbl".to_string(),
|
base: ElementBase::flow("tbl".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
data_source: ArrayBinding {
|
data_source: ArrayBinding {
|
||||||
path: "kalemler".to_string(),
|
path: "kalemler".to_string(),
|
||||||
},
|
},
|
||||||
@@ -754,10 +732,7 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
@@ -766,10 +741,7 @@ mod tests {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::RepeatingTable(RepeatingTableElement {
|
children: vec![TemplateElement::RepeatingTable(RepeatingTableElement {
|
||||||
id: "tbl".to_string(),
|
base: ElementBase::flow("tbl".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
data_source: ArrayBinding {
|
data_source: ArrayBinding {
|
||||||
path: "items".to_string(),
|
path: "items".to_string(),
|
||||||
},
|
},
|
||||||
@@ -808,10 +780,7 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
@@ -820,10 +789,7 @@ mod tests {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::Text(TextElement {
|
children: vec![TemplateElement::Text(TextElement {
|
||||||
id: "el_missing".to_string(),
|
base: ElementBase::flow("el_missing".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
style: TextStyle::default(),
|
style: TextStyle::default(),
|
||||||
content: None,
|
content: None,
|
||||||
binding: ScalarBinding {
|
binding: ScalarBinding {
|
||||||
|
|||||||
@@ -223,6 +223,75 @@ pub struct ResolvedStyle {
|
|||||||
pub barcode_include_text: Option<bool>,
|
pub barcode_include_text: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- From<&XStyle> for ResolvedStyle ---
|
||||||
|
|
||||||
|
impl From<&dreport_core::models::TextStyle> for ResolvedStyle {
|
||||||
|
fn from(s: &dreport_core::models::TextStyle) -> Self {
|
||||||
|
Self {
|
||||||
|
font_size: s.font_size,
|
||||||
|
font_weight: s.font_weight.clone(),
|
||||||
|
font_style: s.font_style.clone(),
|
||||||
|
font_family: s.font_family.clone(),
|
||||||
|
color: s.color.clone(),
|
||||||
|
text_align: s.align.clone(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&dreport_core::models::ContainerStyle> for ResolvedStyle {
|
||||||
|
fn from(s: &dreport_core::models::ContainerStyle) -> Self {
|
||||||
|
Self {
|
||||||
|
background_color: s.background_color.clone(),
|
||||||
|
border_color: s.border_color.clone(),
|
||||||
|
border_width: s.border_width,
|
||||||
|
border_radius: s.border_radius,
|
||||||
|
border_style: s.border_style.clone(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&dreport_core::models::LineStyle> for ResolvedStyle {
|
||||||
|
fn from(s: &dreport_core::models::LineStyle) -> Self {
|
||||||
|
Self {
|
||||||
|
stroke_color: s.stroke_color.clone(),
|
||||||
|
stroke_width: s.stroke_width,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&dreport_core::models::ImageStyle> for ResolvedStyle {
|
||||||
|
fn from(s: &dreport_core::models::ImageStyle) -> Self {
|
||||||
|
Self {
|
||||||
|
object_fit: s.object_fit.clone(),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&dreport_core::models::BarcodeStyle> for ResolvedStyle {
|
||||||
|
fn from(s: &dreport_core::models::BarcodeStyle) -> Self {
|
||||||
|
Self {
|
||||||
|
barcode_color: s.color.clone(),
|
||||||
|
barcode_include_text: s.include_text,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&dreport_core::models::CheckboxStyle> for ResolvedStyle {
|
||||||
|
fn from(s: &dreport_core::models::CheckboxStyle) -> Self {
|
||||||
|
Self {
|
||||||
|
color: s.check_color.clone(),
|
||||||
|
border_color: s.border_color.clone(),
|
||||||
|
border_width: s.border_width,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Ana layout hesaplama fonksiyonu.
|
/// Ana layout hesaplama fonksiyonu.
|
||||||
/// Template + data + font verileri alır, her element için pozisyon döner.
|
/// Template + data + font verileri alır, her element için pozisyon döner.
|
||||||
pub fn compute_layout(
|
pub fn compute_layout(
|
||||||
|
|||||||
@@ -1603,17 +1603,14 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Auto,
|
width: SizeValue::Auto,
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -1628,17 +1625,14 @@ mod tests {
|
|||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![
|
children: vec![
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "title".to_string(),
|
base: ElementBase::flow("title".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(18.0),
|
font_size: Some(18.0),
|
||||||
font_weight: Some("bold".to_string()),
|
font_weight: Some("bold".to_string()),
|
||||||
@@ -1647,34 +1641,28 @@ mod tests {
|
|||||||
content: "FATURA".to_string(),
|
content: "FATURA".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::Line(LineElement {
|
TemplateElement::Line(LineElement {
|
||||||
id: "line1".to_string(),
|
base: ElementBase::flow("line1".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
style: LineStyle {
|
style: LineStyle {
|
||||||
stroke_color: Some("#000000".to_string()),
|
stroke_color: Some("#000000".to_string()),
|
||||||
stroke_width: Some(0.5),
|
stroke_width: Some(0.5),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
TemplateElement::Text(TextElement {
|
TemplateElement::Text(TextElement {
|
||||||
id: "firma".to_string(),
|
base: ElementBase::flow("firma".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(11.0),
|
font_size: Some(11.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ pub fn container_to_style(el: &ContainerElement, parent_direction: Option<&str>)
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Pozisyon moduna göre
|
// Pozisyon moduna göre
|
||||||
match &el.position {
|
match &el.base.position {
|
||||||
PositionMode::Absolute { x, y } => {
|
PositionMode::Absolute { x, y } => {
|
||||||
style.position = Position::Absolute;
|
style.position = Position::Absolute;
|
||||||
style.inset = Rect {
|
style.inset = Rect {
|
||||||
@@ -152,7 +152,7 @@ pub fn container_to_style(el: &ContainerElement, parent_direction: Option<&str>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Boyut
|
// Boyut
|
||||||
apply_size_to_style(&mut style, &el.size, parent_direction);
|
apply_size_to_style(&mut style, &el.base.size, parent_direction);
|
||||||
|
|
||||||
// Container border
|
// Container border
|
||||||
if let Some(bw) = el.style.border_width {
|
if let Some(bw) = el.style.border_width {
|
||||||
@@ -197,7 +197,7 @@ pub fn leaf_style(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use dreport_core::models::{ContainerStyle, Padding};
|
use dreport_core::models::{ContainerStyle, ElementBase, Padding};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mm_to_pt_conversion() {
|
fn test_mm_to_pt_conversion() {
|
||||||
@@ -327,10 +327,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_container_to_style_direction() {
|
fn test_container_to_style_direction() {
|
||||||
let el = ContainerElement {
|
let el = ContainerElement {
|
||||||
id: "test".to_string(),
|
base: ElementBase::flow("test".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "row".to_string(),
|
direction: "row".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -354,10 +351,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_container_to_style_absolute() {
|
fn test_container_to_style_absolute() {
|
||||||
let el = ContainerElement {
|
let el = ContainerElement {
|
||||||
|
base: ElementBase {
|
||||||
id: "test".to_string(),
|
id: "test".to_string(),
|
||||||
condition: None,
|
condition: None,
|
||||||
position: PositionMode::Absolute { x: 20.0, y: 30.0 },
|
position: PositionMode::Absolute { x: 20.0, y: 30.0 },
|
||||||
size: SizeConstraint::default(),
|
size: SizeConstraint::default(),
|
||||||
|
},
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ pub fn expand_table_cached(
|
|||||||
) -> ContainerElement {
|
) -> ContainerElement {
|
||||||
let rows = resolved
|
let rows = resolved
|
||||||
.tables
|
.tables
|
||||||
.get(&table.id)
|
.get(&table.base.id)
|
||||||
.map(|t| t.rows.as_slice())
|
.map(|t| t.rows.as_slice())
|
||||||
.unwrap_or(&[]);
|
.unwrap_or(&[]);
|
||||||
let key = table_cache_key(table, rows, available_width_mm);
|
let key = table_cache_key(table, rows, available_width_mm);
|
||||||
@@ -211,7 +211,7 @@ pub fn expand_table(
|
|||||||
measurer: &mut TextMeasurer,
|
measurer: &mut TextMeasurer,
|
||||||
available_width_mm: f64,
|
available_width_mm: f64,
|
||||||
) -> ContainerElement {
|
) -> ContainerElement {
|
||||||
let resolved_table = resolved.tables.get(&table.id);
|
let resolved_table = resolved.tables.get(&table.base.id);
|
||||||
let rows = resolved_table.map(|t| t.rows.as_slice()).unwrap_or(&[]);
|
let rows = resolved_table.map(|t| t.rows.as_slice()).unwrap_or(&[]);
|
||||||
|
|
||||||
// Auto sütunlar için içerik bazlı genişlik hesapla
|
// Auto sütunlar için içerik bazlı genişlik hesapla
|
||||||
@@ -232,17 +232,14 @@ pub fn expand_table(
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, col)| {
|
.map(|(i, col)| {
|
||||||
let text = TemplateElement::StaticText(StaticTextElement {
|
let text = TemplateElement::StaticText(StaticTextElement {
|
||||||
id: format!("{}_hdr_{}", table.id, i),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
format!("{}_hdr_{}", table.base.id, i),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint {
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
..Default::default()
|
||||||
min_height: None,
|
|
||||||
max_width: None,
|
|
||||||
max_height: None,
|
|
||||||
},
|
},
|
||||||
|
),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: table.style.header_font_size.or(table.style.font_size),
|
font_size: table.style.header_font_size.or(table.style.font_size),
|
||||||
font_weight: Some("bold".to_string()),
|
font_weight: Some("bold".to_string()),
|
||||||
@@ -254,25 +251,13 @@ pub fn expand_table(
|
|||||||
content: col.title.clone(),
|
content: col.title.clone(),
|
||||||
});
|
});
|
||||||
TemplateElement::Container(ContainerElement {
|
TemplateElement::Container(ContainerElement {
|
||||||
id: format!("{}_hdr_{}_wrap", table.id, i),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
format!("{}_hdr_{}_wrap", table.base.id, i),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint { width: effective_widths[i].clone(), ..Default::default() },
|
||||||
size: SizeConstraint {
|
),
|
||||||
width: effective_widths[i].clone(),
|
|
||||||
height: SizeValue::Auto,
|
|
||||||
min_width: None,
|
|
||||||
min_height: None,
|
|
||||||
max_width: None,
|
|
||||||
max_height: None,
|
|
||||||
},
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding {
|
padding: Padding { top: header_pad_v, right: header_pad_h, bottom: header_pad_v, left: header_pad_h },
|
||||||
top: header_pad_v,
|
|
||||||
right: header_pad_h,
|
|
||||||
bottom: header_pad_v,
|
|
||||||
left: header_pad_h,
|
|
||||||
},
|
|
||||||
align: "stretch".to_string(),
|
align: "stretch".to_string(),
|
||||||
justify: "start".to_string(),
|
justify: "start".to_string(),
|
||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
@@ -283,31 +268,16 @@ pub fn expand_table(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
children.push(TemplateElement::Container(ContainerElement {
|
children.push(TemplateElement::Container(ContainerElement {
|
||||||
id: format!("{}_header", table.id),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
format!("{}_header", table.base.id),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint { width: SizeValue::Fr { value: 1.0 }, ..Default::default() },
|
||||||
size: SizeConstraint {
|
),
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
|
||||||
height: SizeValue::Auto,
|
|
||||||
min_width: None,
|
|
||||||
min_height: None,
|
|
||||||
max_width: None,
|
|
||||||
max_height: None,
|
|
||||||
},
|
|
||||||
direction: "row".to_string(),
|
direction: "row".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding {
|
padding: Padding::default(),
|
||||||
top: 0.0,
|
|
||||||
right: 0.0,
|
|
||||||
bottom: 0.0,
|
|
||||||
left: 0.0,
|
|
||||||
},
|
|
||||||
align: "stretch".to_string(),
|
align: "stretch".to_string(),
|
||||||
justify: "start".to_string(),
|
justify: "start".to_string(),
|
||||||
style: ContainerStyle {
|
style: ContainerStyle { background_color: table.style.header_bg.clone(), ..Default::default() },
|
||||||
background_color: table.style.header_bg.clone(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
children: header_cells,
|
children: header_cells,
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
}));
|
}));
|
||||||
@@ -315,17 +285,10 @@ pub fn expand_table(
|
|||||||
// Header altına ayırıcı çizgi
|
// Header altına ayırıcı çizgi
|
||||||
if table.style.border_color.is_some() {
|
if table.style.border_color.is_some() {
|
||||||
children.push(TemplateElement::Line(LineElement {
|
children.push(TemplateElement::Line(LineElement {
|
||||||
id: format!("{}_header_line", table.id),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
format!("{}_header_line", table.base.id),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint { width: SizeValue::Fr { value: 1.0 }, ..Default::default() },
|
||||||
size: SizeConstraint {
|
),
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
|
||||||
height: SizeValue::Auto,
|
|
||||||
min_width: None,
|
|
||||||
min_height: None,
|
|
||||||
max_width: None,
|
|
||||||
max_height: None,
|
|
||||||
},
|
|
||||||
style: LineStyle {
|
style: LineStyle {
|
||||||
stroke_color: table.style.border_color.clone(),
|
stroke_color: table.style.border_color.clone(),
|
||||||
stroke_width: table.style.border_width,
|
stroke_width: table.style.border_width,
|
||||||
@@ -343,17 +306,10 @@ pub fn expand_table(
|
|||||||
let text_content = row_data.get(col_idx).cloned().unwrap_or_default();
|
let text_content = row_data.get(col_idx).cloned().unwrap_or_default();
|
||||||
|
|
||||||
let text = TemplateElement::StaticText(StaticTextElement {
|
let text = TemplateElement::StaticText(StaticTextElement {
|
||||||
id: format!("{}_r{}c{}", table.id, row_idx, col_idx),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
format!("{}_r{}c{}", table.base.id, row_idx, col_idx),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint { width: SizeValue::Fr { value: 1.0 }, ..Default::default() },
|
||||||
size: SizeConstraint {
|
),
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
|
||||||
height: SizeValue::Auto,
|
|
||||||
min_width: None,
|
|
||||||
min_height: None,
|
|
||||||
max_width: None,
|
|
||||||
max_height: None,
|
|
||||||
},
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: table.style.font_size,
|
font_size: table.style.font_size,
|
||||||
font_weight: None,
|
font_weight: None,
|
||||||
@@ -365,25 +321,13 @@ pub fn expand_table(
|
|||||||
content: text_content,
|
content: text_content,
|
||||||
});
|
});
|
||||||
TemplateElement::Container(ContainerElement {
|
TemplateElement::Container(ContainerElement {
|
||||||
id: format!("{}_r{}c{}_wrap", table.id, row_idx, col_idx),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
format!("{}_r{}c{}_wrap", table.base.id, row_idx, col_idx),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint { width: effective_widths[col_idx].clone(), ..Default::default() },
|
||||||
size: SizeConstraint {
|
),
|
||||||
width: effective_widths[col_idx].clone(),
|
|
||||||
height: SizeValue::Auto,
|
|
||||||
min_width: None,
|
|
||||||
min_height: None,
|
|
||||||
max_width: None,
|
|
||||||
max_height: None,
|
|
||||||
},
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding {
|
padding: Padding { top: cell_pad_v, right: cell_pad_h, bottom: cell_pad_v, left: cell_pad_h },
|
||||||
top: cell_pad_v,
|
|
||||||
right: cell_pad_h,
|
|
||||||
bottom: cell_pad_v,
|
|
||||||
left: cell_pad_h,
|
|
||||||
},
|
|
||||||
align: "stretch".to_string(),
|
align: "stretch".to_string(),
|
||||||
justify: "start".to_string(),
|
justify: "start".to_string(),
|
||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
@@ -401,31 +345,16 @@ pub fn expand_table(
|
|||||||
};
|
};
|
||||||
|
|
||||||
children.push(TemplateElement::Container(ContainerElement {
|
children.push(TemplateElement::Container(ContainerElement {
|
||||||
id: format!("{}_row_{}", table.id, row_idx),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
format!("{}_row_{}", table.base.id, row_idx),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint { width: SizeValue::Fr { value: 1.0 }, ..Default::default() },
|
||||||
size: SizeConstraint {
|
),
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
|
||||||
height: SizeValue::Auto,
|
|
||||||
min_width: None,
|
|
||||||
min_height: None,
|
|
||||||
max_width: None,
|
|
||||||
max_height: None,
|
|
||||||
},
|
|
||||||
direction: "row".to_string(),
|
direction: "row".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding {
|
padding: Padding::default(),
|
||||||
top: 0.0,
|
|
||||||
right: 0.0,
|
|
||||||
bottom: 0.0,
|
|
||||||
left: 0.0,
|
|
||||||
},
|
|
||||||
align: "stretch".to_string(),
|
align: "stretch".to_string(),
|
||||||
justify: "start".to_string(),
|
justify: "start".to_string(),
|
||||||
style: ContainerStyle {
|
style: ContainerStyle { background_color: bg, ..Default::default() },
|
||||||
background_color: bg,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
children: cells,
|
children: cells,
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
}));
|
}));
|
||||||
@@ -433,18 +362,15 @@ pub fn expand_table(
|
|||||||
|
|
||||||
// Wrapper container (column direction, tüm tablo)
|
// Wrapper container (column direction, tüm tablo)
|
||||||
ContainerElement {
|
ContainerElement {
|
||||||
id: table.id.clone(),
|
base: ElementBase {
|
||||||
|
id: table.base.id.clone(),
|
||||||
condition: None,
|
condition: None,
|
||||||
position: table.position.clone(),
|
position: table.base.position.clone(),
|
||||||
size: table.size.clone(),
|
size: table.base.size.clone(),
|
||||||
|
},
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding {
|
padding: Padding::default(),
|
||||||
top: 0.0,
|
|
||||||
right: 0.0,
|
|
||||||
bottom: 0.0,
|
|
||||||
left: 0.0,
|
|
||||||
},
|
|
||||||
align: "stretch".to_string(),
|
align: "stretch".to_string(),
|
||||||
justify: "start".to_string(),
|
justify: "start".to_string(),
|
||||||
style: ContainerStyle {
|
style: ContainerStyle {
|
||||||
@@ -478,14 +404,10 @@ mod tests {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
RepeatingTableElement {
|
RepeatingTableElement {
|
||||||
id: "tbl".to_string(),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
"tbl".to_string(),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint { width: SizeValue::Fr { value: 1.0 }, ..Default::default() },
|
||||||
size: SizeConstraint {
|
),
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
|
||||||
height: SizeValue::Auto,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
data_source: ArrayBinding {
|
data_source: ArrayBinding {
|
||||||
path: "items".to_string(),
|
path: "items".to_string(),
|
||||||
},
|
},
|
||||||
@@ -554,7 +476,7 @@ mod tests {
|
|||||||
let container = expand_table(&table, &resolved, &mut measurer, 180.0);
|
let container = expand_table(&table, &resolved, &mut measurer, 180.0);
|
||||||
|
|
||||||
// Wrapper container properties
|
// Wrapper container properties
|
||||||
assert_eq!(container.id, "tbl");
|
assert_eq!(container.base.id, "tbl");
|
||||||
assert_eq!(container.direction, "column");
|
assert_eq!(container.direction, "column");
|
||||||
|
|
||||||
// Children: header row + 2 data rows (no border_color so no separator line)
|
// Children: header row + 2 data rows (no border_color so no separator line)
|
||||||
@@ -563,7 +485,7 @@ mod tests {
|
|||||||
// First child is header row container
|
// First child is header row container
|
||||||
match &container.children[0] {
|
match &container.children[0] {
|
||||||
TemplateElement::Container(c) => {
|
TemplateElement::Container(c) => {
|
||||||
assert_eq!(c.id, "tbl_header");
|
assert_eq!(c.base.id, "tbl_header");
|
||||||
assert_eq!(c.direction, "row");
|
assert_eq!(c.direction, "row");
|
||||||
assert_eq!(c.children.len(), 2); // 2 columns
|
assert_eq!(c.children.len(), 2); // 2 columns
|
||||||
// Check header cell text (inside wrapper container)
|
// Check header cell text (inside wrapper container)
|
||||||
@@ -577,7 +499,7 @@ mod tests {
|
|||||||
for (row_idx, child) in container.children[1..].iter().enumerate() {
|
for (row_idx, child) in container.children[1..].iter().enumerate() {
|
||||||
match child {
|
match child {
|
||||||
TemplateElement::Container(c) => {
|
TemplateElement::Container(c) => {
|
||||||
assert_eq!(c.id, format!("tbl_row_{}", row_idx));
|
assert_eq!(c.base.id, format!("tbl_row_{}", row_idx));
|
||||||
assert_eq!(c.direction, "row");
|
assert_eq!(c.direction, "row");
|
||||||
assert_eq!(c.children.len(), 2);
|
assert_eq!(c.children.len(), 2);
|
||||||
}
|
}
|
||||||
@@ -666,7 +588,7 @@ mod tests {
|
|||||||
// Second child should be a Line
|
// Second child should be a Line
|
||||||
match &container.children[1] {
|
match &container.children[1] {
|
||||||
TemplateElement::Line(l) => {
|
TemplateElement::Line(l) => {
|
||||||
assert_eq!(l.id, "tbl_header_line");
|
assert_eq!(l.base.id, "tbl_header_line");
|
||||||
}
|
}
|
||||||
_ => panic!("Expected Line separator after header"),
|
_ => panic!("Expected Line separator after header"),
|
||||||
}
|
}
|
||||||
@@ -738,14 +660,10 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let table = RepeatingTableElement {
|
let table = RepeatingTableElement {
|
||||||
id: "tbl".to_string(),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
"tbl".to_string(),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint { width: SizeValue::Fr { value: 1.0 }, ..Default::default() },
|
||||||
size: SizeConstraint {
|
),
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
|
||||||
height: SizeValue::Auto,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
data_source: ArrayBinding {
|
data_source: ArrayBinding {
|
||||||
path: "items".to_string(),
|
path: "items".to_string(),
|
||||||
},
|
},
|
||||||
@@ -769,14 +687,14 @@ mod tests {
|
|||||||
match &container.children[0] {
|
match &container.children[0] {
|
||||||
TemplateElement::Container(c) => {
|
TemplateElement::Container(c) => {
|
||||||
let w0 = match &c.children[0] {
|
let w0 = match &c.children[0] {
|
||||||
TemplateElement::Container(wrap) => match &wrap.size.width {
|
TemplateElement::Container(wrap) => match &wrap.base.size.width {
|
||||||
SizeValue::Fixed { value } => *value,
|
SizeValue::Fixed { value } => *value,
|
||||||
_ => panic!("Expected Fixed width for auto column wrapper"),
|
_ => panic!("Expected Fixed width for auto column wrapper"),
|
||||||
},
|
},
|
||||||
_ => panic!("Expected Container wrapper"),
|
_ => panic!("Expected Container wrapper"),
|
||||||
};
|
};
|
||||||
let w1 = match &c.children[1] {
|
let w1 = match &c.children[1] {
|
||||||
TemplateElement::Container(wrap) => match &wrap.size.width {
|
TemplateElement::Container(wrap) => match &wrap.base.size.width {
|
||||||
SizeValue::Fixed { value } => *value,
|
SizeValue::Fixed { value } => *value,
|
||||||
_ => panic!("Expected Fixed width for auto column wrapper"),
|
_ => panic!("Expected Fixed width for auto column wrapper"),
|
||||||
},
|
},
|
||||||
@@ -811,7 +729,7 @@ mod tests {
|
|||||||
// Second call — same inputs — cache hit
|
// Second call — same inputs — cache hit
|
||||||
let result2 = expand_table_cached(&table, &resolved, &mut measurer, 180.0, &mut cache);
|
let result2 = expand_table_cached(&table, &resolved, &mut measurer, 180.0, &mut cache);
|
||||||
assert_eq!(cache.len(), 1); // no new entry
|
assert_eq!(cache.len(), 1); // no new entry
|
||||||
assert_eq!(result1.id, result2.id);
|
assert_eq!(result1.base.id, result2.base.id);
|
||||||
assert_eq!(result1.children.len(), result2.children.len());
|
assert_eq!(result1.children.len(), result2.children.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ fn collect_break_modes(root: &ContainerElement) -> HashMap<String, String> {
|
|||||||
|
|
||||||
fn collect_break_modes_recursive(el: &TemplateElement, modes: &mut HashMap<String, String>) {
|
fn collect_break_modes_recursive(el: &TemplateElement, modes: &mut HashMap<String, String>) {
|
||||||
if let TemplateElement::Container(c) = el {
|
if let TemplateElement::Container(c) = el {
|
||||||
modes.insert(c.id.clone(), c.break_inside.clone());
|
modes.insert(c.base.id.clone(), c.break_inside.clone());
|
||||||
for child in &c.children {
|
for child in &c.children {
|
||||||
collect_break_modes_recursive(child, modes);
|
collect_break_modes_recursive(child, modes);
|
||||||
}
|
}
|
||||||
@@ -208,7 +208,7 @@ fn collect_no_repeat_recursive(el: &TemplateElement, set: &mut std::collections:
|
|||||||
}
|
}
|
||||||
TemplateElement::RepeatingTable(t) => {
|
TemplateElement::RepeatingTable(t) => {
|
||||||
if t.repeat_header == Some(false) {
|
if t.repeat_header == Some(false) {
|
||||||
set.insert(t.id.clone());
|
set.insert(t.base.id.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -233,7 +233,7 @@ fn build_container(
|
|||||||
// Child'lar için kullanılabilir genişliği hesapla
|
// Child'lar için kullanılabilir genişliği hesapla
|
||||||
// Container'ın kendi padding ve border'ını çıkar
|
// Container'ın kendi padding ve border'ını çıkar
|
||||||
let border_w = el.style.border_width.unwrap_or(0.0);
|
let border_w = el.style.border_width.unwrap_or(0.0);
|
||||||
let container_own_width = match &el.size.width {
|
let container_own_width = match &el.base.size.width {
|
||||||
SizeValue::Fixed { value } => *value,
|
SizeValue::Fixed { value } => *value,
|
||||||
_ => page_width_mm, // Fr veya Auto ise parent'ın genişliğini kullan
|
_ => page_width_mm, // Fr veya Auto ise parent'ın genişliğini kullan
|
||||||
};
|
};
|
||||||
@@ -268,17 +268,10 @@ fn build_container(
|
|||||||
node_map.insert(
|
node_map.insert(
|
||||||
node,
|
node,
|
||||||
NodeInfo {
|
NodeInfo {
|
||||||
element_id: el.id.clone(),
|
element_id: el.base.id.clone(),
|
||||||
element_type: "container".to_string(),
|
element_type: el.type_str().to_string(),
|
||||||
content: None,
|
content: None,
|
||||||
style: ResolvedStyle {
|
style: (&el.style).into(),
|
||||||
background_color: el.style.background_color.clone(),
|
|
||||||
border_color: el.style.border_color.clone(),
|
|
||||||
border_width: el.style.border_width,
|
|
||||||
border_radius: el.style.border_radius,
|
|
||||||
border_style: el.style.border_style.clone(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
children_ids,
|
children_ids,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -309,88 +302,63 @@ fn build_element(
|
|||||||
page_width_mm,
|
page_width_mm,
|
||||||
table_cache,
|
table_cache,
|
||||||
),
|
),
|
||||||
TemplateElement::StaticText(e) => build_text_leaf(
|
TemplateElement::StaticText(e) => build_resolved_text_leaf(
|
||||||
|
&e.base,
|
||||||
|
e.type_str(),
|
||||||
|
&e.style,
|
||||||
taffy,
|
taffy,
|
||||||
node_map,
|
node_map,
|
||||||
&e.id,
|
resolved,
|
||||||
"static_text",
|
|
||||||
resolved
|
|
||||||
.texts
|
|
||||||
.get(&e.id)
|
|
||||||
.map(|s| s.as_str())
|
|
||||||
.unwrap_or(&e.content),
|
|
||||||
&e.style,
|
|
||||||
&e.size,
|
|
||||||
&e.position,
|
|
||||||
parent_direction,
|
parent_direction,
|
||||||
|
&e.content,
|
||||||
),
|
),
|
||||||
TemplateElement::Text(e) => {
|
TemplateElement::Text(e) => build_resolved_text_leaf(
|
||||||
let text = resolved.texts.get(&e.id).map(|s| s.as_str()).unwrap_or("");
|
&e.base,
|
||||||
build_text_leaf(
|
e.type_str(),
|
||||||
|
&e.style,
|
||||||
taffy,
|
taffy,
|
||||||
node_map,
|
node_map,
|
||||||
&e.id,
|
resolved,
|
||||||
"text",
|
|
||||||
text,
|
|
||||||
&e.style,
|
|
||||||
&e.size,
|
|
||||||
&e.position,
|
|
||||||
parent_direction,
|
parent_direction,
|
||||||
)
|
"",
|
||||||
}
|
),
|
||||||
TemplateElement::PageNumber(e) => {
|
TemplateElement::PageNumber(e) => build_resolved_text_leaf(
|
||||||
let text = resolved
|
&e.base,
|
||||||
.texts
|
e.type_str(),
|
||||||
.get(&e.id)
|
&e.style,
|
||||||
.map(|s| s.as_str())
|
|
||||||
.unwrap_or("1 / 1");
|
|
||||||
build_text_leaf(
|
|
||||||
taffy,
|
taffy,
|
||||||
node_map,
|
node_map,
|
||||||
&e.id,
|
resolved,
|
||||||
"page_number",
|
|
||||||
text,
|
|
||||||
&e.style,
|
|
||||||
&e.size,
|
|
||||||
&e.position,
|
|
||||||
parent_direction,
|
parent_direction,
|
||||||
)
|
"1 / 1",
|
||||||
}
|
),
|
||||||
TemplateElement::CurrentDate(e) => {
|
TemplateElement::CurrentDate(e) => build_resolved_text_leaf(
|
||||||
let text = resolved.texts.get(&e.id).map(|s| s.as_str()).unwrap_or("");
|
&e.base,
|
||||||
build_text_leaf(
|
e.type_str(),
|
||||||
|
&e.style,
|
||||||
taffy,
|
taffy,
|
||||||
node_map,
|
node_map,
|
||||||
&e.id,
|
resolved,
|
||||||
"current_date",
|
|
||||||
text,
|
|
||||||
&e.style,
|
|
||||||
&e.size,
|
|
||||||
&e.position,
|
|
||||||
parent_direction,
|
parent_direction,
|
||||||
)
|
"",
|
||||||
}
|
),
|
||||||
TemplateElement::CalculatedText(e) => {
|
TemplateElement::CalculatedText(e) => build_resolved_text_leaf(
|
||||||
let text = resolved.texts.get(&e.id).map(|s| s.as_str()).unwrap_or("");
|
&e.base,
|
||||||
build_text_leaf(
|
e.type_str(),
|
||||||
|
&e.style,
|
||||||
taffy,
|
taffy,
|
||||||
node_map,
|
node_map,
|
||||||
&e.id,
|
resolved,
|
||||||
"calculated_text",
|
|
||||||
text,
|
|
||||||
&e.style,
|
|
||||||
&e.size,
|
|
||||||
&e.position,
|
|
||||||
parent_direction,
|
parent_direction,
|
||||||
)
|
"",
|
||||||
}
|
),
|
||||||
TemplateElement::Line(e) => {
|
TemplateElement::Line(e) => {
|
||||||
let stroke_w = e.style.stroke_width.unwrap_or(0.5);
|
let stroke_w = e.style.stroke_width.unwrap_or(0.5);
|
||||||
let style = sizing::leaf_style(&e.size, &e.position, parent_direction);
|
let style = sizing::leaf_style(&e.base.size, &e.base.position, parent_direction);
|
||||||
|
|
||||||
// Line: genişlik parent'tan, yükseklik stroke width
|
// Line: genişlik parent'tan, yükseklik stroke width
|
||||||
let mut leaf_style = style;
|
let mut leaf_style = style;
|
||||||
if matches!(e.size.height, SizeValue::Auto) {
|
if matches!(e.base.size.height, SizeValue::Auto) {
|
||||||
leaf_style.size.height = Dimension::length(mm_to_pt(stroke_w));
|
leaf_style.size.height = Dimension::length(mm_to_pt(stroke_w));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,13 +366,13 @@ fn build_element(
|
|||||||
node_map.insert(
|
node_map.insert(
|
||||||
node,
|
node,
|
||||||
NodeInfo {
|
NodeInfo {
|
||||||
element_id: e.id.clone(),
|
element_id: e.base.id.clone(),
|
||||||
element_type: "line".to_string(),
|
element_type: e.type_str().to_string(),
|
||||||
content: Some(ResolvedContent::Line),
|
content: Some(ResolvedContent::Line),
|
||||||
style: ResolvedStyle {
|
style: {
|
||||||
stroke_color: e.style.stroke_color.clone(),
|
let mut s: ResolvedStyle = (&e.style).into();
|
||||||
stroke_width: Some(stroke_w),
|
s.stroke_width = Some(stroke_w);
|
||||||
..Default::default()
|
s
|
||||||
},
|
},
|
||||||
children_ids: vec![],
|
children_ids: vec![],
|
||||||
},
|
},
|
||||||
@@ -412,37 +380,34 @@ fn build_element(
|
|||||||
Ok(node)
|
Ok(node)
|
||||||
}
|
}
|
||||||
TemplateElement::Image(e) => {
|
TemplateElement::Image(e) => {
|
||||||
let style = sizing::leaf_style(&e.size, &e.position, parent_direction);
|
let style = sizing::leaf_style(&e.base.size, &e.base.position, parent_direction);
|
||||||
let src = resolved.images.get(&e.id).cloned().unwrap_or_default();
|
let src = resolved.images.get(&e.base.id).cloned().unwrap_or_default();
|
||||||
|
|
||||||
let node = taffy.new_leaf(style)?;
|
let node = taffy.new_leaf(style)?;
|
||||||
node_map.insert(
|
node_map.insert(
|
||||||
node,
|
node,
|
||||||
NodeInfo {
|
NodeInfo {
|
||||||
element_id: e.id.clone(),
|
element_id: e.base.id.clone(),
|
||||||
element_type: "image".to_string(),
|
element_type: e.type_str().to_string(),
|
||||||
content: Some(ResolvedContent::Image { src }),
|
content: Some(ResolvedContent::Image { src }),
|
||||||
style: ResolvedStyle {
|
style: (&e.style).into(),
|
||||||
object_fit: e.style.object_fit.clone(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
children_ids: vec![],
|
children_ids: vec![],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Ok(node)
|
Ok(node)
|
||||||
}
|
}
|
||||||
TemplateElement::Barcode(e) => {
|
TemplateElement::Barcode(e) => {
|
||||||
let mut style = sizing::leaf_style(&e.size, &e.position, parent_direction);
|
let mut style = sizing::leaf_style(&e.base.size, &e.base.position, parent_direction);
|
||||||
let value = resolved.barcodes.get(&e.id).cloned().unwrap_or_default();
|
let value = resolved.barcodes.get(&e.base.id).cloned().unwrap_or_default();
|
||||||
|
|
||||||
// Barcode leaf'e minimum boyut ver (MeasureFunc yok, Auto=0 olur)
|
// Barcode leaf'e minimum boyut ver (MeasureFunc yok, Auto=0 olur)
|
||||||
let is_qr = e.format == "qr";
|
let is_qr = e.format == "qr";
|
||||||
let default_h = if is_qr { 20.0 } else { 15.0 }; // mm
|
let default_h = if is_qr { 20.0 } else { 15.0 }; // mm
|
||||||
let default_w = if is_qr { 20.0 } else { 40.0 }; // mm
|
let default_w = if is_qr { 20.0 } else { 40.0 }; // mm
|
||||||
if matches!(e.size.height, SizeValue::Auto) {
|
if matches!(e.base.size.height, SizeValue::Auto) {
|
||||||
style.min_size.height = Dimension::length(mm_to_pt(default_h));
|
style.min_size.height = Dimension::length(mm_to_pt(default_h));
|
||||||
}
|
}
|
||||||
if matches!(e.size.width, SizeValue::Auto) {
|
if matches!(e.base.size.width, SizeValue::Auto) {
|
||||||
style.min_size.width = Dimension::length(mm_to_pt(default_w));
|
style.min_size.width = Dimension::length(mm_to_pt(default_w));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,17 +415,13 @@ fn build_element(
|
|||||||
node_map.insert(
|
node_map.insert(
|
||||||
node,
|
node,
|
||||||
NodeInfo {
|
NodeInfo {
|
||||||
element_id: e.id.clone(),
|
element_id: e.base.id.clone(),
|
||||||
element_type: "barcode".to_string(),
|
element_type: e.type_str().to_string(),
|
||||||
content: Some(ResolvedContent::Barcode {
|
content: Some(ResolvedContent::Barcode {
|
||||||
format: e.format.clone(),
|
format: e.format.clone(),
|
||||||
value,
|
value,
|
||||||
}),
|
}),
|
||||||
style: ResolvedStyle {
|
style: (&e.style).into(),
|
||||||
barcode_color: e.style.color.clone(),
|
|
||||||
barcode_include_text: e.style.include_text,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
children_ids: vec![],
|
children_ids: vec![],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -497,23 +458,17 @@ fn build_element(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
TemplateElement::Shape(e) => {
|
TemplateElement::Shape(e) => {
|
||||||
let style = sizing::leaf_style(&e.size, &e.position, parent_direction);
|
let style = sizing::leaf_style(&e.base.size, &e.base.position, parent_direction);
|
||||||
let node = taffy.new_leaf(style)?;
|
let node = taffy.new_leaf(style)?;
|
||||||
node_map.insert(
|
node_map.insert(
|
||||||
node,
|
node,
|
||||||
NodeInfo {
|
NodeInfo {
|
||||||
element_id: e.id.clone(),
|
element_id: e.base.id.clone(),
|
||||||
element_type: "shape".to_string(),
|
element_type: e.type_str().to_string(),
|
||||||
content: Some(ResolvedContent::Shape {
|
content: Some(ResolvedContent::Shape {
|
||||||
shape_type: e.shape_type.clone(),
|
shape_type: e.shape_type.clone(),
|
||||||
}),
|
}),
|
||||||
style: ResolvedStyle {
|
style: (&e.style).into(),
|
||||||
background_color: e.style.background_color.clone(),
|
|
||||||
border_color: e.style.border_color.clone(),
|
|
||||||
border_width: e.style.border_width,
|
|
||||||
border_radius: e.style.border_radius,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
children_ids: vec![],
|
children_ids: vec![],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -522,19 +477,19 @@ fn build_element(
|
|||||||
TemplateElement::Checkbox(e) => {
|
TemplateElement::Checkbox(e) => {
|
||||||
let checked_str = resolved
|
let checked_str = resolved
|
||||||
.texts
|
.texts
|
||||||
.get(&e.id)
|
.get(&e.base.id)
|
||||||
.map(|s| s.as_str())
|
.map(|s| s.as_str())
|
||||||
.unwrap_or("false");
|
.unwrap_or("false");
|
||||||
let checked = checked_str == "true";
|
let checked = checked_str == "true";
|
||||||
let box_size_mm = e.style.size.unwrap_or(4.0);
|
let box_size_mm = e.style.size.unwrap_or(4.0);
|
||||||
let style = sizing::leaf_style(&e.size, &e.position, parent_direction);
|
let style = sizing::leaf_style(&e.base.size, &e.base.position, parent_direction);
|
||||||
|
|
||||||
// Auto size → square based on style.size
|
// Auto size → square based on style.size
|
||||||
let mut leaf_style = style;
|
let mut leaf_style = style;
|
||||||
if matches!(e.size.width, SizeValue::Auto) {
|
if matches!(e.base.size.width, SizeValue::Auto) {
|
||||||
leaf_style.size.width = Dimension::length(mm_to_pt(box_size_mm));
|
leaf_style.size.width = Dimension::length(mm_to_pt(box_size_mm));
|
||||||
}
|
}
|
||||||
if matches!(e.size.height, SizeValue::Auto) {
|
if matches!(e.base.size.height, SizeValue::Auto) {
|
||||||
leaf_style.size.height = Dimension::length(mm_to_pt(box_size_mm));
|
leaf_style.size.height = Dimension::length(mm_to_pt(box_size_mm));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,22 +497,17 @@ fn build_element(
|
|||||||
node_map.insert(
|
node_map.insert(
|
||||||
node,
|
node,
|
||||||
NodeInfo {
|
NodeInfo {
|
||||||
element_id: e.id.clone(),
|
element_id: e.base.id.clone(),
|
||||||
element_type: "checkbox".to_string(),
|
element_type: e.type_str().to_string(),
|
||||||
content: Some(ResolvedContent::Checkbox { checked }),
|
content: Some(ResolvedContent::Checkbox { checked }),
|
||||||
style: ResolvedStyle {
|
style: (&e.style).into(),
|
||||||
color: e.style.check_color.clone(),
|
|
||||||
border_color: e.style.border_color.clone(),
|
|
||||||
border_width: e.style.border_width,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
children_ids: vec![],
|
children_ids: vec![],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Ok(node)
|
Ok(node)
|
||||||
}
|
}
|
||||||
TemplateElement::RichText(e) => {
|
TemplateElement::RichText(e) => {
|
||||||
let spans = resolved.rich_texts.get(&e.id).cloned().unwrap_or_default();
|
let spans = resolved.rich_texts.get(&e.base.id).cloned().unwrap_or_default();
|
||||||
let rich_span_measures: Vec<crate::text_measure::RichSpanMeasure> = spans
|
let rich_span_measures: Vec<crate::text_measure::RichSpanMeasure> = spans
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| crate::text_measure::RichSpanMeasure {
|
.map(|s| crate::text_measure::RichSpanMeasure {
|
||||||
@@ -573,7 +523,7 @@ fn build_element(
|
|||||||
.map(|s| s.font_size_pt)
|
.map(|s| s.font_size_pt)
|
||||||
.fold(11.0f32, f32::max);
|
.fold(11.0f32, f32::max);
|
||||||
|
|
||||||
let style = sizing::leaf_style(&e.size, &e.position, parent_direction);
|
let style = sizing::leaf_style(&e.base.size, &e.base.position, parent_direction);
|
||||||
|
|
||||||
let context = MeasureContext {
|
let context = MeasureContext {
|
||||||
text: String::new(),
|
text: String::new(),
|
||||||
@@ -600,39 +550,32 @@ fn build_element(
|
|||||||
node_map.insert(
|
node_map.insert(
|
||||||
node,
|
node,
|
||||||
NodeInfo {
|
NodeInfo {
|
||||||
element_id: e.id.clone(),
|
element_id: e.base.id.clone(),
|
||||||
element_type: "rich_text".to_string(),
|
element_type: e.type_str().to_string(),
|
||||||
content: Some(ResolvedContent::RichText {
|
content: Some(ResolvedContent::RichText {
|
||||||
spans: resolved_spans,
|
spans: resolved_spans,
|
||||||
}),
|
}),
|
||||||
style: ResolvedStyle {
|
style: (&e.style).into(),
|
||||||
font_size: e.style.font_size,
|
|
||||||
font_weight: e.style.font_weight.clone(),
|
|
||||||
font_family: e.style.font_family.clone(),
|
|
||||||
color: e.style.color.clone(),
|
|
||||||
text_align: e.style.align.clone(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
children_ids: vec![],
|
children_ids: vec![],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
Ok(node)
|
Ok(node)
|
||||||
}
|
}
|
||||||
TemplateElement::Chart(e) => {
|
TemplateElement::Chart(e) => {
|
||||||
let mut style = sizing::leaf_style(&e.size, &e.position, parent_direction);
|
let mut style = sizing::leaf_style(&e.base.size, &e.base.position, parent_direction);
|
||||||
// Default minimum boyut — Auto ise chart cok kucuk olmasin
|
// Default minimum boyut — Auto ise chart cok kucuk olmasin
|
||||||
if matches!(e.size.width, SizeValue::Auto) {
|
if matches!(e.base.size.width, SizeValue::Auto) {
|
||||||
style.min_size.width = Dimension::length(mm_to_pt(80.0));
|
style.min_size.width = Dimension::length(mm_to_pt(80.0));
|
||||||
}
|
}
|
||||||
if matches!(e.size.height, SizeValue::Auto) {
|
if matches!(e.base.size.height, SizeValue::Auto) {
|
||||||
style.min_size.height = Dimension::length(mm_to_pt(60.0));
|
style.min_size.height = Dimension::length(mm_to_pt(60.0));
|
||||||
}
|
}
|
||||||
let node = taffy.new_leaf(style)?;
|
let node = taffy.new_leaf(style)?;
|
||||||
node_map.insert(
|
node_map.insert(
|
||||||
node,
|
node,
|
||||||
NodeInfo {
|
NodeInfo {
|
||||||
element_id: e.id.clone(),
|
element_id: e.base.id.clone(),
|
||||||
element_type: "chart".to_string(),
|
element_type: e.type_str().to_string(),
|
||||||
content: None, // SVG collect_layout'ta uretilecek
|
content: None, // SVG collect_layout'ta uretilecek
|
||||||
style: ResolvedStyle::default(),
|
style: ResolvedStyle::default(),
|
||||||
children_ids: vec![],
|
children_ids: vec![],
|
||||||
@@ -653,8 +596,8 @@ fn build_element(
|
|||||||
node_map.insert(
|
node_map.insert(
|
||||||
node,
|
node,
|
||||||
NodeInfo {
|
NodeInfo {
|
||||||
element_id: e.id.clone(),
|
element_id: e.base.id.clone(),
|
||||||
element_type: "page_break".to_string(),
|
element_type: e.type_str().to_string(),
|
||||||
content: None,
|
content: None,
|
||||||
style: ResolvedStyle::default(),
|
style: ResolvedStyle::default(),
|
||||||
children_ids: vec![],
|
children_ids: vec![],
|
||||||
@@ -669,7 +612,7 @@ fn build_element(
|
|||||||
fn register_expanded_texts(el: &TemplateElement, resolved: &mut ResolvedData) {
|
fn register_expanded_texts(el: &TemplateElement, resolved: &mut ResolvedData) {
|
||||||
match el {
|
match el {
|
||||||
TemplateElement::StaticText(e) => {
|
TemplateElement::StaticText(e) => {
|
||||||
resolved.texts.insert(e.id.clone(), e.content.clone());
|
resolved.texts.insert(e.base.id.clone(), e.content.clone());
|
||||||
}
|
}
|
||||||
TemplateElement::Container(e) => {
|
TemplateElement::Container(e) => {
|
||||||
for child in &e.children {
|
for child in &e.children {
|
||||||
@@ -680,6 +623,35 @@ fn register_expanded_texts(el: &TemplateElement, resolved: &mut ResolvedData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generic text leaf builder — HasTextStyle trait ile text-benzeri elementleri tek yerde build eder
|
||||||
|
fn build_resolved_text_leaf(
|
||||||
|
el_base: &ElementBase,
|
||||||
|
el_type_str: &str,
|
||||||
|
text_style: &TextStyle,
|
||||||
|
taffy: &mut TaffyTree<MeasureContext>,
|
||||||
|
node_map: &mut HashMap<NodeId, NodeInfo>,
|
||||||
|
resolved: &ResolvedData,
|
||||||
|
parent_direction: Option<&str>,
|
||||||
|
fallback_text: &str,
|
||||||
|
) -> Result<NodeId, LayoutError> {
|
||||||
|
let text = resolved
|
||||||
|
.texts
|
||||||
|
.get(&el_base.id)
|
||||||
|
.map(|s| s.as_str())
|
||||||
|
.unwrap_or(fallback_text);
|
||||||
|
build_text_leaf(
|
||||||
|
taffy,
|
||||||
|
node_map,
|
||||||
|
&el_base.id,
|
||||||
|
el_type_str,
|
||||||
|
text,
|
||||||
|
text_style,
|
||||||
|
&el_base.size,
|
||||||
|
&el_base.position,
|
||||||
|
parent_direction,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Text leaf node oluştur (static_text, text, page_number için ortak)
|
/// Text leaf node oluştur (static_text, text, page_number için ortak)
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_text_leaf(
|
fn build_text_leaf(
|
||||||
@@ -714,15 +686,7 @@ fn build_text_leaf(
|
|||||||
content: Some(ResolvedContent::Text {
|
content: Some(ResolvedContent::Text {
|
||||||
value: text.to_string(),
|
value: text.to_string(),
|
||||||
}),
|
}),
|
||||||
style: ResolvedStyle {
|
style: text_style.into(),
|
||||||
font_size: text_style.font_size,
|
|
||||||
font_weight: text_style.font_weight.clone(),
|
|
||||||
font_style: text_style.font_style.clone(),
|
|
||||||
font_family: text_style.font_family.clone(),
|
|
||||||
color: text_style.color.clone(),
|
|
||||||
text_align: text_style.align.clone(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
children_ids: vec![],
|
children_ids: vec![],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -902,17 +866,14 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Auto,
|
width: SizeValue::Auto,
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -927,17 +888,14 @@ mod tests {
|
|||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![
|
children: vec![
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "title".to_string(),
|
base: ElementBase::flow("title".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(18.0),
|
font_size: Some(18.0),
|
||||||
font_weight: Some("bold".to_string()),
|
font_weight: Some("bold".to_string()),
|
||||||
@@ -946,34 +904,28 @@ mod tests {
|
|||||||
content: "FATURA".to_string(),
|
content: "FATURA".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::Line(LineElement {
|
TemplateElement::Line(LineElement {
|
||||||
id: "line1".to_string(),
|
base: ElementBase::flow("line1".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
style: LineStyle {
|
style: LineStyle {
|
||||||
stroke_color: Some("#000000".to_string()),
|
stroke_color: Some("#000000".to_string()),
|
||||||
stroke_width: Some(0.5),
|
stroke_width: Some(0.5),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "body".to_string(),
|
base: ElementBase::flow("body".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(11.0),
|
font_size: Some(11.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1051,17 +1003,14 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Auto,
|
width: SizeValue::Auto,
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -1075,17 +1024,14 @@ mod tests {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::Container(ContainerElement {
|
children: vec![TemplateElement::Container(ContainerElement {
|
||||||
id: "row".to_string(),
|
base: ElementBase::flow("row".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
direction: "row".to_string(),
|
direction: "row".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -1100,17 +1046,14 @@ mod tests {
|
|||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![
|
children: vec![
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "left".to_string(),
|
base: ElementBase::flow("left".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(11.0),
|
font_size: Some(11.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1118,17 +1061,14 @@ mod tests {
|
|||||||
content: "Sol".to_string(),
|
content: "Sol".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "right".to_string(),
|
base: ElementBase::flow("right".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(11.0),
|
font_size: Some(11.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1184,17 +1124,14 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Auto,
|
width: SizeValue::Auto,
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
min_width: None,
|
min_width: None,
|
||||||
min_height: None,
|
min_height: None,
|
||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
}),
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -1208,6 +1145,7 @@ mod tests {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::StaticText(StaticTextElement {
|
children: vec![TemplateElement::StaticText(StaticTextElement {
|
||||||
|
base: ElementBase {
|
||||||
id: "abs_text".to_string(),
|
id: "abs_text".to_string(),
|
||||||
condition: None,
|
condition: None,
|
||||||
position: PositionMode::Absolute { x: 50.0, y: 80.0 },
|
position: PositionMode::Absolute { x: 50.0, y: 80.0 },
|
||||||
@@ -1219,6 +1157,7 @@ mod tests {
|
|||||||
max_width: None,
|
max_width: None,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(14.0),
|
font_size: Some(14.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1276,10 +1215,7 @@ mod tests {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -1295,10 +1231,7 @@ mod tests {
|
|||||||
children: vec![
|
children: vec![
|
||||||
// Header row
|
// Header row
|
||||||
TemplateElement::Container(ContainerElement {
|
TemplateElement::Container(ContainerElement {
|
||||||
id: "c_header".to_string(),
|
base: ElementBase::flow("c_header".to_string(), sz_fr_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_fr_auto.clone(),
|
|
||||||
direction: "row".to_string(),
|
direction: "row".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: p0.clone(),
|
padding: p0.clone(),
|
||||||
@@ -1309,10 +1242,7 @@ mod tests {
|
|||||||
children: vec![
|
children: vec![
|
||||||
// Sol: firma bilgileri
|
// Sol: firma bilgileri
|
||||||
TemplateElement::Container(ContainerElement {
|
TemplateElement::Container(ContainerElement {
|
||||||
id: "c_firma".to_string(),
|
base: ElementBase::flow("c_firma".to_string(), sz_fr_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_fr_auto.clone(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 1.0,
|
gap: 1.0,
|
||||||
padding: p0.clone(),
|
padding: p0.clone(),
|
||||||
@@ -1322,10 +1252,7 @@ mod tests {
|
|||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![
|
children: vec![
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_firma_unvan".to_string(),
|
base: ElementBase::flow("el_firma_unvan".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(14.0),
|
font_size: Some(14.0),
|
||||||
font_weight: Some("bold".to_string()),
|
font_weight: Some("bold".to_string()),
|
||||||
@@ -1334,10 +1261,7 @@ mod tests {
|
|||||||
content: "Teknova Yazılım ve Danışmanlık A.Ş.".to_string(),
|
content: "Teknova Yazılım ve Danışmanlık A.Ş.".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_firma_adres".to_string(),
|
base: ElementBase::flow("el_firma_adres".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(9.0),
|
font_size: Some(9.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1346,10 +1270,7 @@ mod tests {
|
|||||||
.to_string(),
|
.to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_firma_il".to_string(),
|
base: ElementBase::flow("el_firma_il".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(9.0),
|
font_size: Some(9.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1357,10 +1278,7 @@ mod tests {
|
|||||||
content: "Istanbul".to_string(),
|
content: "Istanbul".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_firma_tel".to_string(),
|
base: ElementBase::flow("el_firma_tel".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(9.0),
|
font_size: Some(9.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1368,10 +1286,7 @@ mod tests {
|
|||||||
content: "Tel: +90 212 555 0042".to_string(),
|
content: "Tel: +90 212 555 0042".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_firma_vd".to_string(),
|
base: ElementBase::flow("el_firma_vd".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(9.0),
|
font_size: Some(9.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1379,10 +1294,7 @@ mod tests {
|
|||||||
content: "VD: Levent VD".to_string(),
|
content: "VD: Levent VD".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_firma_vn".to_string(),
|
base: ElementBase::flow("el_firma_vn".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(9.0),
|
font_size: Some(9.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1393,10 +1305,7 @@ mod tests {
|
|||||||
}),
|
}),
|
||||||
// Sağ: fatura başlığı
|
// Sağ: fatura başlığı
|
||||||
TemplateElement::Container(ContainerElement {
|
TemplateElement::Container(ContainerElement {
|
||||||
id: "c_fatura_baslik".to_string(),
|
base: ElementBase::flow("c_fatura_baslik".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 2.0,
|
gap: 2.0,
|
||||||
padding: p0.clone(),
|
padding: p0.clone(),
|
||||||
@@ -1406,10 +1315,7 @@ mod tests {
|
|||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![
|
children: vec![
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_fatura_baslik".to_string(),
|
base: ElementBase::flow("el_fatura_baslik".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(18.0),
|
font_size: Some(18.0),
|
||||||
font_weight: Some("bold".to_string()),
|
font_weight: Some("bold".to_string()),
|
||||||
@@ -1418,10 +1324,7 @@ mod tests {
|
|||||||
content: "FATURA".to_string(),
|
content: "FATURA".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_fatura_no".to_string(),
|
base: ElementBase::flow("el_fatura_no".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(10.0),
|
font_size: Some(10.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1429,10 +1332,7 @@ mod tests {
|
|||||||
content: "No: FTR-2026-001547".to_string(),
|
content: "No: FTR-2026-001547".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_fatura_tarih".to_string(),
|
base: ElementBase::flow("el_fatura_tarih".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(10.0),
|
font_size: Some(10.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -1440,10 +1340,7 @@ mod tests {
|
|||||||
content: "Tarih: 2026-03-29".to_string(),
|
content: "Tarih: 2026-03-29".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "el_fatura_vade".to_string(),
|
base: ElementBase::flow("el_fatura_vade".to_string(), sz_auto.clone()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: sz_auto.clone(),
|
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(10.0),
|
font_size: Some(10.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|||||||
@@ -27,12 +27,9 @@ fn base_template() -> Template {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
condition: None,
|
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
top: 15.0,
|
top: 15.0,
|
||||||
right: 15.0,
|
right: 15.0,
|
||||||
@@ -57,14 +54,11 @@ fn test_1_2_text_wrapping_layout_height() {
|
|||||||
// Dar bir container'da uzun metin → yükseklik tek satırdan fazla olmalı
|
// Dar bir container'da uzun metin → yükseklik tek satırdan fazla olmalı
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "long_text".to_string(),
|
base: ElementBase::flow("long_text".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fixed { value: 40.0 }, // 40mm genişlik — kısa
|
width: SizeValue::Fixed { value: 40.0 }, // 40mm genişlik — kısa
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(12.0),
|
font_size: Some(12.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -94,14 +88,11 @@ fn test_1_2_text_wrapping_pdf_renders() {
|
|||||||
// PDF render sırasında text wrapping çalışmalı — crash olmamalı
|
// PDF render sırasında text wrapping çalışmalı — crash olmamalı
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "wrap_pdf".to_string(),
|
base: ElementBase::flow("wrap_pdf".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fixed { value: 50.0 },
|
width: SizeValue::Fixed { value: 50.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(11.0),
|
font_size: Some(11.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -125,14 +116,11 @@ fn test_1_2_text_wrapping_pdf_renders() {
|
|||||||
fn test_1_3_image_object_fit_in_layout() {
|
fn test_1_3_image_object_fit_in_layout() {
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::Image(ImageElement {
|
tpl.root.children.push(TemplateElement::Image(ImageElement {
|
||||||
id: "img_contain".to_string(),
|
base: ElementBase::flow("img_contain".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fixed { value: 40.0 },
|
width: SizeValue::Fixed { value: 40.0 },
|
||||||
height: SizeValue::Fixed { value: 30.0 },
|
height: SizeValue::Fixed { value: 30.0 },
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
src: Some("data:image/png;base64,iVBORw0KGgo=".to_string()),
|
src: Some("data:image/png;base64,iVBORw0KGgo=".to_string()),
|
||||||
binding: None,
|
binding: None,
|
||||||
style: ImageStyle {
|
style: ImageStyle {
|
||||||
@@ -167,14 +155,11 @@ fn test_1_4_italic_font_in_pdf() {
|
|||||||
tpl.root
|
tpl.root
|
||||||
.children
|
.children
|
||||||
.push(TemplateElement::StaticText(StaticTextElement {
|
.push(TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "italic_text".to_string(),
|
base: ElementBase::flow("italic_text".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(12.0),
|
font_size: Some(12.0),
|
||||||
font_style: Some("italic".to_string()),
|
font_style: Some("italic".to_string()),
|
||||||
@@ -205,14 +190,11 @@ fn test_1_4_bold_italic_font_in_pdf() {
|
|||||||
tpl.root
|
tpl.root
|
||||||
.children
|
.children
|
||||||
.push(TemplateElement::StaticText(StaticTextElement {
|
.push(TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "bold_italic".to_string(),
|
base: ElementBase::flow("bold_italic".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(14.0),
|
font_size: Some(14.0),
|
||||||
font_weight: Some("bold".to_string()),
|
font_weight: Some("bold".to_string()),
|
||||||
@@ -239,14 +221,11 @@ fn test_2_1_repeat_header_false_no_repeat_on_second_page() {
|
|||||||
tpl.root
|
tpl.root
|
||||||
.children
|
.children
|
||||||
.push(TemplateElement::RepeatingTable(RepeatingTableElement {
|
.push(TemplateElement::RepeatingTable(RepeatingTableElement {
|
||||||
id: "tbl_no_repeat".to_string(),
|
base: ElementBase::flow("tbl_no_repeat".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
data_source: ArrayBinding {
|
data_source: ArrayBinding {
|
||||||
path: "items".to_string(),
|
path: "items".to_string(),
|
||||||
},
|
},
|
||||||
@@ -305,14 +284,11 @@ fn test_2_1_repeat_header_true_repeats_on_second_page() {
|
|||||||
tpl.root
|
tpl.root
|
||||||
.children
|
.children
|
||||||
.push(TemplateElement::RepeatingTable(RepeatingTableElement {
|
.push(TemplateElement::RepeatingTable(RepeatingTableElement {
|
||||||
id: "tbl_repeat".to_string(),
|
base: ElementBase::flow("tbl_repeat".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
data_source: ArrayBinding {
|
data_source: ArrayBinding {
|
||||||
path: "items".to_string(),
|
path: "items".to_string(),
|
||||||
},
|
},
|
||||||
@@ -389,14 +365,11 @@ fn test_2_2_table_column_format_currency() {
|
|||||||
tpl.root
|
tpl.root
|
||||||
.children
|
.children
|
||||||
.push(TemplateElement::RepeatingTable(RepeatingTableElement {
|
.push(TemplateElement::RepeatingTable(RepeatingTableElement {
|
||||||
id: "tbl_fmt".to_string(),
|
base: ElementBase::flow("tbl_fmt".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
data_source: ArrayBinding {
|
data_source: ArrayBinding {
|
||||||
path: "items".to_string(),
|
path: "items".to_string(),
|
||||||
},
|
},
|
||||||
@@ -459,14 +432,11 @@ fn test_2_2_table_column_format_currency() {
|
|||||||
fn test_2_3_rounded_rectangle_renders() {
|
fn test_2_3_rounded_rectangle_renders() {
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::Shape(ShapeElement {
|
tpl.root.children.push(TemplateElement::Shape(ShapeElement {
|
||||||
id: "rounded_shape".to_string(),
|
base: ElementBase::flow("rounded_shape".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fixed { value: 50.0 },
|
width: SizeValue::Fixed { value: 50.0 },
|
||||||
height: SizeValue::Fixed { value: 30.0 },
|
height: SizeValue::Fixed { value: 30.0 },
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
shape_type: "rounded_rectangle".to_string(),
|
shape_type: "rounded_rectangle".to_string(),
|
||||||
style: ContainerStyle {
|
style: ContainerStyle {
|
||||||
background_color: Some("#3b82f6".to_string()),
|
background_color: Some("#3b82f6".to_string()),
|
||||||
@@ -505,14 +475,11 @@ fn test_2_3_container_border_radius_renders() {
|
|||||||
tpl.root
|
tpl.root
|
||||||
.children
|
.children
|
||||||
.push(TemplateElement::StaticText(StaticTextElement {
|
.push(TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "text_in_rounded".to_string(),
|
base: ElementBase::flow("text_in_rounded".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(12.0),
|
font_size: Some(12.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -604,14 +571,11 @@ fn test_2_7_format_config_in_template() {
|
|||||||
fn test_ellipse_shape_renders() {
|
fn test_ellipse_shape_renders() {
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::Shape(ShapeElement {
|
tpl.root.children.push(TemplateElement::Shape(ShapeElement {
|
||||||
id: "ellipse".to_string(),
|
base: ElementBase::flow("ellipse".to_string(), SizeConstraint {
|
||||||
position: PositionMode::Flow,
|
|
||||||
condition: None,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fixed { value: 40.0 },
|
width: SizeValue::Fixed { value: 40.0 },
|
||||||
height: SizeValue::Fixed { value: 20.0 },
|
height: SizeValue::Fixed { value: 20.0 },
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
shape_type: "ellipse".to_string(),
|
shape_type: "ellipse".to_string(),
|
||||||
style: ContainerStyle {
|
style: ContainerStyle {
|
||||||
background_color: Some("#ff6600".to_string()),
|
background_color: Some("#ff6600".to_string()),
|
||||||
@@ -635,14 +599,12 @@ fn test_ellipse_shape_renders() {
|
|||||||
fn test_7_1_condition_gt_hides_element() {
|
fn test_7_1_condition_gt_hides_element() {
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "always_visible".to_string(),
|
base: ElementBase::flow("always_visible".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
||||||
content: "Visible".to_string(),
|
content: "Visible".to_string(),
|
||||||
}));
|
}));
|
||||||
tpl.root.children.push(TemplateElement::Text(TextElement {
|
tpl.root.children.push(TemplateElement::Text(TextElement {
|
||||||
|
base: ElementBase {
|
||||||
id: "conditional_text".to_string(),
|
id: "conditional_text".to_string(),
|
||||||
condition: Some(Condition {
|
condition: Some(Condition {
|
||||||
path: "toplamlar.iskonto".to_string(),
|
path: "toplamlar.iskonto".to_string(),
|
||||||
@@ -651,6 +613,7 @@ fn test_7_1_condition_gt_hides_element() {
|
|||||||
}),
|
}),
|
||||||
position: PositionMode::Flow,
|
position: PositionMode::Flow,
|
||||||
size: SizeConstraint::default(),
|
size: SizeConstraint::default(),
|
||||||
|
},
|
||||||
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
||||||
content: None,
|
content: None,
|
||||||
binding: ScalarBinding { path: "toplamlar.iskonto".to_string() },
|
binding: ScalarBinding { path: "toplamlar.iskonto".to_string() },
|
||||||
@@ -676,6 +639,7 @@ fn test_7_1_condition_gt_hides_element() {
|
|||||||
fn test_7_1_condition_gt_shows_element() {
|
fn test_7_1_condition_gt_shows_element() {
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::Text(TextElement {
|
tpl.root.children.push(TemplateElement::Text(TextElement {
|
||||||
|
base: ElementBase {
|
||||||
id: "conditional_text".to_string(),
|
id: "conditional_text".to_string(),
|
||||||
condition: Some(Condition {
|
condition: Some(Condition {
|
||||||
path: "toplamlar.iskonto".to_string(),
|
path: "toplamlar.iskonto".to_string(),
|
||||||
@@ -684,6 +648,7 @@ fn test_7_1_condition_gt_shows_element() {
|
|||||||
}),
|
}),
|
||||||
position: PositionMode::Flow,
|
position: PositionMode::Flow,
|
||||||
size: SizeConstraint::default(),
|
size: SizeConstraint::default(),
|
||||||
|
},
|
||||||
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
||||||
content: None,
|
content: None,
|
||||||
binding: ScalarBinding { path: "toplamlar.iskonto".to_string() },
|
binding: ScalarBinding { path: "toplamlar.iskonto".to_string() },
|
||||||
@@ -705,6 +670,7 @@ fn test_7_1_condition_gt_shows_element() {
|
|||||||
fn test_7_1_condition_eq_operator() {
|
fn test_7_1_condition_eq_operator() {
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
||||||
|
base: ElementBase {
|
||||||
id: "status_text".to_string(),
|
id: "status_text".to_string(),
|
||||||
condition: Some(Condition {
|
condition: Some(Condition {
|
||||||
path: "durum".to_string(),
|
path: "durum".to_string(),
|
||||||
@@ -713,6 +679,7 @@ fn test_7_1_condition_eq_operator() {
|
|||||||
}),
|
}),
|
||||||
position: PositionMode::Flow,
|
position: PositionMode::Flow,
|
||||||
size: SizeConstraint::default(),
|
size: SizeConstraint::default(),
|
||||||
|
},
|
||||||
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
||||||
content: "Aktif".to_string(),
|
content: "Aktif".to_string(),
|
||||||
}));
|
}));
|
||||||
@@ -732,6 +699,7 @@ fn test_7_1_condition_eq_operator() {
|
|||||||
fn test_7_1_condition_empty_not_empty() {
|
fn test_7_1_condition_empty_not_empty() {
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
tpl.root.children.push(TemplateElement::StaticText(StaticTextElement {
|
||||||
|
base: ElementBase {
|
||||||
id: "show_if_exists".to_string(),
|
id: "show_if_exists".to_string(),
|
||||||
condition: Some(Condition {
|
condition: Some(Condition {
|
||||||
path: "note".to_string(),
|
path: "note".to_string(),
|
||||||
@@ -740,6 +708,7 @@ fn test_7_1_condition_empty_not_empty() {
|
|||||||
}),
|
}),
|
||||||
position: PositionMode::Flow,
|
position: PositionMode::Flow,
|
||||||
size: SizeConstraint::default(),
|
size: SizeConstraint::default(),
|
||||||
|
},
|
||||||
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
||||||
content: "Has note".to_string(),
|
content: "Has note".to_string(),
|
||||||
}));
|
}));
|
||||||
@@ -763,6 +732,7 @@ fn test_7_1_condition_empty_not_empty() {
|
|||||||
fn test_7_1_condition_on_container_hides_children() {
|
fn test_7_1_condition_on_container_hides_children() {
|
||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.root.children.push(TemplateElement::Container(ContainerElement {
|
tpl.root.children.push(TemplateElement::Container(ContainerElement {
|
||||||
|
base: ElementBase {
|
||||||
id: "cond_container".to_string(),
|
id: "cond_container".to_string(),
|
||||||
condition: Some(Condition {
|
condition: Some(Condition {
|
||||||
path: "show".to_string(),
|
path: "show".to_string(),
|
||||||
@@ -771,6 +741,7 @@ fn test_7_1_condition_on_container_hides_children() {
|
|||||||
}),
|
}),
|
||||||
position: PositionMode::Flow,
|
position: PositionMode::Flow,
|
||||||
size: SizeConstraint::default(),
|
size: SizeConstraint::default(),
|
||||||
|
},
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
@@ -779,10 +750,7 @@ fn test_7_1_condition_on_container_hides_children() {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::StaticText(StaticTextElement {
|
children: vec![TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "child_text".to_string(),
|
base: ElementBase::flow("child_text".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
style: TextStyle { font_size: Some(10.0), ..Default::default() },
|
||||||
content: "Child".to_string(),
|
content: "Child".to_string(),
|
||||||
})],
|
})],
|
||||||
@@ -854,10 +822,7 @@ fn test_7_5_effective_format_config_priority() {
|
|||||||
header: None,
|
header: None,
|
||||||
footer: None,
|
footer: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
@@ -889,10 +854,7 @@ fn test_7_5_effective_format_config_locale_fallback() {
|
|||||||
header: None,
|
header: None,
|
||||||
footer: None,
|
footer: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding::default(),
|
padding: Padding::default(),
|
||||||
@@ -915,14 +877,11 @@ fn test_7_5_locale_affects_table_currency_format() {
|
|||||||
let mut tpl = base_template();
|
let mut tpl = base_template();
|
||||||
tpl.locale = Some("en-US".to_string());
|
tpl.locale = Some("en-US".to_string());
|
||||||
tpl.root.children.push(TemplateElement::RepeatingTable(RepeatingTableElement {
|
tpl.root.children.push(TemplateElement::RepeatingTable(RepeatingTableElement {
|
||||||
id: "tbl_locale".to_string(),
|
base: ElementBase::flow("tbl_locale".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
data_source: ArrayBinding { path: "items".to_string() },
|
data_source: ArrayBinding { path: "items".to_string() },
|
||||||
columns: vec![
|
columns: vec![
|
||||||
TableColumn {
|
TableColumn {
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ fn simple_template() -> Template {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -37,14 +34,14 @@ fn simple_template() -> Template {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::StaticText(StaticTextElement {
|
children: vec![TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "title".to_string(),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
"title".to_string(),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint {
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(14.0),
|
font_size: Some(14.0),
|
||||||
font_weight: Some("bold".to_string()),
|
font_weight: Some("bold".to_string()),
|
||||||
@@ -166,10 +163,7 @@ fn test_compute_layout_with_data_binding() {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -183,14 +177,14 @@ fn test_compute_layout_with_data_binding() {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::Text(TextElement {
|
children: vec![TemplateElement::Text(TextElement {
|
||||||
id: "bound_text".to_string(),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
"bound_text".to_string(),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint {
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(12.0),
|
font_size: Some(12.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -235,10 +229,7 @@ fn test_compute_layout_multiple_children_ordering() {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -253,14 +244,14 @@ fn test_compute_layout_multiple_children_ordering() {
|
|||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![
|
children: vec![
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "first".to_string(),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
"first".to_string(),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint {
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(12.0),
|
font_size: Some(12.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -268,14 +259,14 @@ fn test_compute_layout_multiple_children_ordering() {
|
|||||||
content: "First".to_string(),
|
content: "First".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "second".to_string(),
|
base: ElementBase::flow(
|
||||||
condition: None,
|
"second".to_string(),
|
||||||
position: PositionMode::Flow,
|
SizeConstraint {
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(12.0),
|
font_size: Some(12.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ fn simple_template() -> Template {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -40,14 +37,11 @@ fn simple_template() -> Template {
|
|||||||
style: ContainerStyle::default(),
|
style: ContainerStyle::default(),
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::StaticText(StaticTextElement {
|
children: vec![TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "title".to_string(),
|
base: ElementBase::flow("title".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(18.0),
|
font_size: Some(18.0),
|
||||||
font_weight: Some("bold".to_string()),
|
font_weight: Some("bold".to_string()),
|
||||||
@@ -94,10 +88,7 @@ fn test_render_pdf_with_multiple_elements() {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -112,14 +103,11 @@ fn test_render_pdf_with_multiple_elements() {
|
|||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![
|
children: vec![
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "header".to_string(),
|
base: ElementBase::flow("header".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(16.0),
|
font_size: Some(16.0),
|
||||||
font_weight: Some("bold".to_string()),
|
font_weight: Some("bold".to_string()),
|
||||||
@@ -128,28 +116,22 @@ fn test_render_pdf_with_multiple_elements() {
|
|||||||
content: "FATURA".to_string(),
|
content: "FATURA".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::Line(LineElement {
|
TemplateElement::Line(LineElement {
|
||||||
id: "sep".to_string(),
|
base: ElementBase::flow("sep".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: LineStyle {
|
style: LineStyle {
|
||||||
stroke_color: Some("#000000".to_string()),
|
stroke_color: Some("#000000".to_string()),
|
||||||
stroke_width: Some(0.5),
|
stroke_width: Some(0.5),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "body".to_string(),
|
base: ElementBase::flow("body".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(11.0),
|
font_size: Some(11.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -192,10 +174,7 @@ fn test_render_pdf_with_container_styles() {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -214,14 +193,11 @@ fn test_render_pdf_with_container_styles() {
|
|||||||
},
|
},
|
||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![TemplateElement::StaticText(StaticTextElement {
|
children: vec![TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "text".to_string(),
|
base: ElementBase::flow("text".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(12.0),
|
font_size: Some(12.0),
|
||||||
color: Some("#ff0000".to_string()),
|
color: Some("#ff0000".to_string()),
|
||||||
@@ -257,10 +233,7 @@ fn test_page_break_produces_multiple_pages() {
|
|||||||
format_config: None,
|
format_config: None,
|
||||||
locale: None,
|
locale: None,
|
||||||
root: ContainerElement {
|
root: ContainerElement {
|
||||||
id: "root".to_string(),
|
base: ElementBase::flow("root".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint::default(),
|
|
||||||
direction: "column".to_string(),
|
direction: "column".to_string(),
|
||||||
gap: 5.0,
|
gap: 5.0,
|
||||||
padding: Padding {
|
padding: Padding {
|
||||||
@@ -275,14 +248,11 @@ fn test_page_break_produces_multiple_pages() {
|
|||||||
break_inside: "auto".to_string(),
|
break_inside: "auto".to_string(),
|
||||||
children: vec![
|
children: vec![
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "t1".to_string(),
|
base: ElementBase::flow("t1".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(18.0),
|
font_size: Some(18.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -290,18 +260,14 @@ fn test_page_break_produces_multiple_pages() {
|
|||||||
content: "Page 1 content".to_string(),
|
content: "Page 1 content".to_string(),
|
||||||
}),
|
}),
|
||||||
TemplateElement::PageBreak(PageBreakElement {
|
TemplateElement::PageBreak(PageBreakElement {
|
||||||
id: "pb1".to_string(),
|
base: ElementBase::flow("pb1".to_string(), SizeConstraint::default()),
|
||||||
condition: None,
|
|
||||||
}),
|
}),
|
||||||
TemplateElement::StaticText(StaticTextElement {
|
TemplateElement::StaticText(StaticTextElement {
|
||||||
id: "t2".to_string(),
|
base: ElementBase::flow("t2".to_string(), SizeConstraint {
|
||||||
condition: None,
|
|
||||||
position: PositionMode::Flow,
|
|
||||||
size: SizeConstraint {
|
|
||||||
width: SizeValue::Fr { value: 1.0 },
|
width: SizeValue::Fr { value: 1.0 },
|
||||||
height: SizeValue::Auto,
|
height: SizeValue::Auto,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}),
|
||||||
style: TextStyle {
|
style: TextStyle {
|
||||||
font_size: Some(18.0),
|
font_size: Some(18.0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|||||||
Reference in New Issue
Block a user