This commit is contained in:
@@ -44,7 +44,8 @@ public partial class DesignerViewModel : ObservableObject
|
||||
|
||||
public IReadOnlyList<string> Units { get; } = ["mm", "cm", "pt", "in"];
|
||||
public IReadOnlyList<PlaceholderType> PlaceholderTypes { get; } = Enum.GetValues<PlaceholderType>();
|
||||
public IReadOnlyList<string> ElementTypes { get; } = ["TEXT", "TEXTBOX", "FLOWBOX", "IMG", "TABLE", "CHART"];
|
||||
public IReadOnlyList<string> ElementTypes { get; } =
|
||||
["TEXT", "TEXTBOX", "FLOWBOX", "DRAWBOX", "FLOWDRAWBOX", "IMG", "TABLE", "CHART"];
|
||||
public ObservableCollection<DesignerPlaceholder> Placeholders { get; } =
|
||||
[
|
||||
new("Datum", PlaceholderType.Date, true, DateTime.Today.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)),
|
||||
@@ -117,14 +118,16 @@ public partial class DesignerViewModel : ObservableObject
|
||||
issues.Add(new(ValidationSeverity.Error, $"Platzhalter „{used}“ ist nicht deklariert."));
|
||||
foreach (var path in layouts.SelectMany(x => x.Elements).Select(x => x switch { BackgroundElement b => b.Path, ImageElement i => i.Path, _ => null }).Where(x => x is not null))
|
||||
if (!Assets.ContainsKey(path!)) issues.Add(new(ValidationSeverity.Error, $"Asset „{path}“ fehlt."));
|
||||
var firstFlows = layout.Elements.OfType<FlowBoxElement>().ToList();
|
||||
var firstFlows = layout.Elements.Where(x => x is FlowBoxElement or FlowDrawBoxElement).ToList();
|
||||
if (firstFlows.Count > 1)
|
||||
issues.Add(new(ValidationSeverity.Error, "Ein Layout darf höchstens eine FLOWBOX enthalten."));
|
||||
if (continuationLayout is not null)
|
||||
{
|
||||
var continuationFlows = continuationLayout.Elements.OfType<FlowBoxElement>().ToList();
|
||||
var continuationFlows = continuationLayout.Elements.Where(x => x is FlowBoxElement or FlowDrawBoxElement).ToList();
|
||||
if (firstFlows.Count != 1 || continuationFlows.Count != 1)
|
||||
issues.Add(new(ValidationSeverity.Error, "Haupt- und Folgeseite müssen jeweils genau eine FLOWBOX enthalten."));
|
||||
issues.Add(new(ValidationSeverity.Error, "Haupt- und Folgeseite müssen jeweils genau ein fließendes Element enthalten."));
|
||||
else if (firstFlows[0].GetType() != continuationFlows[0].GetType())
|
||||
issues.Add(new(ValidationSeverity.Error, "Haupt- und Folgeseite müssen denselben fließenden Elementtyp verwenden."));
|
||||
else if (firstFlows[0].X != continuationFlows[0].X || firstFlows[0].Y != continuationFlows[0].Y
|
||||
|| firstFlows[0].Width != continuationFlows[0].Width || firstFlows[0].Height != continuationFlows[0].Height)
|
||||
issues.Add(new(ValidationSeverity.Error, "Die FLOWBOX muss auf Haupt- und Folgeseiten dieselbe Position und Größe haben."));
|
||||
@@ -269,6 +272,8 @@ public partial class DesignerViewModel : ObservableObject
|
||||
"TEXT" => $"TEXT {NewX} {NewY} {QuoteIfLiteral(NewContent)}{attrs}",
|
||||
"TEXTBOX" => $"TEXTBOX {NewX} {NewY} {NewWidth} {NewHeight} {QuoteIfLiteral(NewContent)}{attrs}",
|
||||
"FLOWBOX" => $"FLOWBOX {NewX} {NewY} {NewWidth} {NewHeight} {QuoteIfLiteral(NewContent)}{attrs}",
|
||||
"DRAWBOX" => $"DRAWBOX {NewX} {NewY} {NewWidth} {NewHeight} {NewContent}{attrs}",
|
||||
"FLOWDRAWBOX" => $"FLOWDRAWBOX {NewX} {NewY} {NewWidth} {NewHeight} {NewContent}{attrs}",
|
||||
"IMG" => $"IMG {NewContent} {NewX} {NewY} {NewWidth} {NewHeight} scale={NormalizedImageScale()}%",
|
||||
"TABLE" => $"TABLE {NewX} {NewY} {NewWidth} {NewHeight} {NewContent}{attrs}",
|
||||
"CHART" => $"CHART {NewX} {NewY} {NewWidth} {NewHeight} {NewContent}{attrs}",
|
||||
@@ -353,6 +358,10 @@ public partial class DesignerViewModel : ObservableObject
|
||||
+ $"{Content(box.Content, box.Placeholder, box.Format)}{Attributes(box.Attributes)}",
|
||||
FlowBoxElement box => $"FLOWBOX {x} {y} {FormatNumber(width)} {FormatNumber(height)} "
|
||||
+ $"{Content(box.Content, box.Placeholder, box.Format)}{Attributes(box.Attributes)}",
|
||||
DrawBoxElement box => $"DRAWBOX {x} {y} {FormatNumber(width)} {FormatNumber(height)} "
|
||||
+ $"${box.Placeholder}{Attributes(box.Attributes)}",
|
||||
FlowDrawBoxElement box => $"FLOWDRAWBOX {x} {y} {FormatNumber(width)} {FormatNumber(height)} "
|
||||
+ $"${box.Placeholder}{Attributes(box.Attributes)}",
|
||||
TableElement table => $"TABLE {x} {y} {FormatNumber(width)} {FormatNumber(height)} "
|
||||
+ $"${table.Placeholder}{Attributes(table.Attributes)}",
|
||||
ChartElement chart => $"CHART {x} {y} {FormatNumber(width)} {FormatNumber(height)} "
|
||||
@@ -525,11 +534,13 @@ public partial class DesignerPlaceholder : ObservableObject
|
||||
PlaceholderType.Image => new ImageValue([], "image/png"),
|
||||
PlaceholderType.Table => ParseTable(Sample),
|
||||
PlaceholderType.Chart => ParseChart(Sample),
|
||||
PlaceholderType.Drawing => SampleDrawing(),
|
||||
_ => new TextValue(Sample),
|
||||
};
|
||||
public static string SampleFor(PlaceholderType type) => type switch
|
||||
{ PlaceholderType.Date => DateTime.Today.ToString("yyyy-MM-dd"), PlaceholderType.Number => "42,5",
|
||||
PlaceholderType.Table => "Datum;Grund|01.09.;Krank", PlaceholderType.Chart => "Sep:2;Okt:3;Nov:1", _ => "Beispielwert" };
|
||||
PlaceholderType.Table => "Datum;Grund|01.09.;Krank", PlaceholderType.Chart => "Sep:2;Okt:3;Nov:1",
|
||||
PlaceholderType.Drawing => "Externe Zeichenbefehle", _ => "Beispielwert" };
|
||||
private static TableValue ParseTable(string value)
|
||||
{
|
||||
var lines = value.Split('|', StringSplitOptions.RemoveEmptyEntries);
|
||||
@@ -538,6 +549,10 @@ public partial class DesignerPlaceholder : ObservableObject
|
||||
}
|
||||
private static ChartValue ParseChart(string value) => new([new("Werte", value.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select((x, i) => { var parts = x.Split(':', 2); return new ChartPoint(parts[0], parts.Length == 2 && decimal.TryParse(parts[1], CultureInfo.InvariantCulture, out var y) ? y : i + 1); }).ToList())]);
|
||||
private static DrawingValue SampleDrawing() => new DrawingValue(
|
||||
[new DrawRectangle(0, 0, 80, 24, "#2563EB", 0.8f, "#EFF6FF"),
|
||||
new DrawString(4, 4, "Dynamischer Inhalt", 10, "#1E3A8A", Bold: true),
|
||||
new MoveTo(4, 19), new LineTo(76, 19, "#93C5FD", 0.6f)], 24);
|
||||
}
|
||||
|
||||
internal sealed class DesignerDataProvider(IReadOnlyDictionary<string, PlaceholderValue> values) : ITemplateDataProvider
|
||||
|
||||
@@ -192,7 +192,8 @@ public sealed class LayoutOverlayEditor : Control
|
||||
{
|
||||
if (element is BackgroundElement) continue;
|
||||
var keyword = element switch
|
||||
{ ImageElement => "IMG", TextElement => "TEXT", TextBoxElement => "TEXTBOX",
|
||||
{ ImageElement => "IMG", TextElement => "TEXT", TextBoxElement => "TEXTBOX", FlowBoxElement => "FLOWBOX",
|
||||
DrawBoxElement => "DRAWBOX", FlowDrawBoxElement => "FLOWDRAWBOX",
|
||||
TableElement => "TABLE", ChartElement => "CHART", _ => "?" };
|
||||
var (width, height, resizable) = element switch
|
||||
{
|
||||
|
||||
@@ -196,6 +196,8 @@
|
||||
TextWrapping="Wrap" Opacity="0.65" FontSize="11"/>
|
||||
<TextBlock Text="FLOWBOX verteilt Text automatisch über beliebig viele Seiten. TEXTBOX bleibt ein fester Bereich."
|
||||
TextWrapping="Wrap" Foreground="#166534" FontSize="12"/>
|
||||
<TextBlock Text="DRAWBOX und FLOWDRAWBOX nehmen deklarative Zeichenbefehle (Text, Linien, Rechtecke, Bilder) aus einer externen App entgegen."
|
||||
TextWrapping="Wrap" Foreground="#166534" FontSize="12"/>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
Reference in New Issue
Block a user