2using System.Collections.Generic;
4using System.Reflection;
6using System.Threading.Tasks;
35 public const string Namespace =
"http://waher.se/Schema/Layout2D.xsd";
42 private static Dictionary<string, ILayoutElement> elementTypes =
new Dictionary<string, ILayoutElement>();
43 private static bool initialized =
false;
45 private readonly Dictionary<string, ILayoutElement> elementsById =
new Dictionary<string, ILayoutElement>();
46 private readonly Dictionary<string, object> attachments =
new Dictionary<string, object>(StringComparer.CurrentCultureIgnoreCase);
59 this.session = Session;
61 if (!(Attachments is
null))
63 foreach (KeyValuePair<string, object> P
in Attachments)
64 this.attachments[P.Key] = P.Value;
68 internal async Task<ILayoutElement> CreateElement(XmlElement Xml,
ILayoutElement Parent)
70 string Key = Xml.NamespaceURI +
"#" + Xml.LocalName;
79 if (Id.
Ok && !
string.IsNullOrEmpty(Id.
Result))
80 this.AddElementId(Id.
Result, Result);
90 public static Task<Layout2DDocument>
FromFile(
string FileName, params KeyValuePair<string, object>[] Attachments)
92 return FromFile(FileName,
true, Attachments);
101 public static Task<Layout2DDocument>
FromFile(
string FileName,
bool Preprocess, params KeyValuePair<string, object>[] Attachments)
113 public static async Task<Layout2DDocument>
FromFile(
string FileName,
bool Preprocess,
Variables Session, params KeyValuePair<string, object>[] Attachments)
116 return await
FromXml(Xml, Preprocess, Session, Attachments);
125 public static Task<Layout2DDocument>
FromStream(Stream Input, Encoding DefaultEncoding, params KeyValuePair<string, object>[] Attachments)
127 return FromStream(Input, DefaultEncoding,
true, Attachments);
137 public static Task<Layout2DDocument>
FromStream(Stream Input, Encoding DefaultEncoding,
bool Preprocess, params KeyValuePair<string, object>[] Attachments)
150 public static Task<Layout2DDocument>
FromStream(Stream Input, Encoding DefaultEncoding,
bool Preprocess,
Variables Session, params KeyValuePair<string, object>[] Attachments)
152 long c = Input.Length - Input.Position;
153 if (c >
int.MaxValue)
154 throw new OutOfMemoryException(
"Input too large");
157 byte[] Bin =
new byte[c2];
158 Input.ReadAll(Bin, 0, c2);
162 return FromXml(Xml, Preprocess, Session, Attachments);
170 public static Task<Layout2DDocument>
FromXml(
string Xml, params KeyValuePair<string, object>[] Attachments)
172 return FromXml(Xml,
true, Attachments);
181 public static Task<Layout2DDocument>
FromXml(
string Xml,
bool Preprocess, params KeyValuePair<string, object>[] Attachments)
193 public static async Task<Layout2DDocument>
FromXml(
string Xml,
bool Preprocess,
Variables Session, params KeyValuePair<string, object>[] Attachments)
198 XmlDocument Doc =
new XmlDocument();
204 catch (XmlException ex)
209 return await
FromXml(Doc, Session, Attachments);
217 public static Task<Layout2DDocument>
FromXml(XmlDocument Xml, params KeyValuePair<string, object>[] Attachments)
228 public static Task<Layout2DDocument>
FromXml(XmlDocument Xml,
Variables Session, params KeyValuePair<string, object>[] Attachments)
230 return FromXml(Xml.DocumentElement, Session, Attachments);
238 public static Task<Layout2DDocument>
FromXml(XmlElement Xml, params KeyValuePair<string, object>[] Attachments)
249 public static async Task<Layout2DDocument>
FromXml(XmlElement Xml,
Variables Session, params KeyValuePair<string, object>[] Attachments)
251 if (Xml.LocalName != LocalName || Xml.NamespaceURI != Namespace)
252 throw new ArgumentException(
"XML does not represent a 2D layout document.", nameof(Xml));
259 Dictionary<string, ILayoutElement> TypesPerKey =
new Dictionary<string, ILayoutElement>();
262 foreach (Type T
in LayoutElementTypes)
264 TypeInfo TI = T.GetTypeInfo();
265 if (TI.IsAbstract || TI.IsInterface || TI.IsGenericTypeDefinition)
271 string Key = E.Namespace +
"#" + E.
LocalName;
273 if (TypesPerKey.ContainsKey(Key))
274 Log.
Error(
"Layout element type already defined: " + Key);
276 TypesPerKey[Key] = E;
284 elementTypes = TypesPerKey;
287 Types.OnInvalidated += (Sender, e) => initialized =
false;
292 Result.root = await Result.CreateElement(Xml,
null);
302 this.root?.Dispose();
304 foreach (
object Attachment
in this.attachments.Values)
306 if (Attachment is IDisposable Disposable)
307 Disposable.Dispose();
335 Width = Settings.
Width;
340 SKSurface Surface = SKSurface.Create(
new SKImageInfo(Width, Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul));
344 SKCanvas Canvas = Surface.
Canvas;
345 State =
new DrawingState(Canvas, Settings, this.session);
352 while (!(this.root is
null))
365 throw new InvalidOperationException(
"Layout positions not well defined. Dimensions diverge:\r\n\r\n" + ShortestBranch);
378 if (!(this.root is
null))
380 Width = (int)this.root.
Right - (
int)this.root.Left + 1;
381 Height = (int)this.root.
Bottom - (
int)this.root.Top - 1;
384 Surface = SKSurface.Create(
new SKImageInfo(Width, Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul));
386 throw new InvalidOperationException(
"Unable to render layout.");
388 Canvas = Surface.Canvas;
389 State.Canvas = Canvas;
394 if (!(this.root is
null) && this.root.
Left.HasValue &&
this.root.Top.HasValue)
395 State.
Canvas.Translate(-this.root.
Left.Value, -
this.root.Top.Value);
399 if (!(this.root is
null))
401 if (this.root.
Width.HasValue &&
this.root.Height.HasValue)
403 float Width2 = this.root.Width.Value + 1;
404 float Height2 = this.root.Height.Value + 1;
405 float ScaleX = Width / Width2;
406 float ScaleY = Height / Height2;
410 State.
Canvas.Translate(0, (Height - Height2 * ScaleX) / 2);
411 State.
Canvas.Scale(ScaleX);
413 else if (ScaleY < ScaleX)
415 State.
Canvas.Translate((Width - Width2 * ScaleY) / 2, 0);
416 State.
Canvas.Scale(ScaleY);
420 if (this.root.
Left.HasValue &&
this.root.Top.HasValue)
421 State.
Canvas.Translate(-this.root.
Left.Value, -
this.root.Top.Value);
426 if (!(this.root is
null))
427 await this.root.
Draw(State);
429 return new KeyValuePair<SKImage, Map[]>(Surface.Snapshot(), Maps);
527 return this.attachments.TryGetValue(ContentId, out Content);
537 if (this.attachments.TryGetValue(ContentId, out
object Obj))
539 this.attachments.Remove(ContentId);
541 if (Obj is IDisposable Disposable)
542 Disposable.Dispose();
561 ContentId = Guid.NewGuid().ToString();
563 while (this.attachments.ContainsKey(ContentId));
565 this.attachments[ContentId] = Content;
578 this.attachments[ContentId] = Content;
588 this.elementsById[Id] = Element;
599 return this.elementsById.TryGetValue(Id, out Element);
607 this.elementsById.Clear();
619 ImageSize = RenderedImageSize.ResizeImage
622 if (this.root is Model.Backgrounds.Layout2D
Layout2D)
631 float w = Result.
Width;
633 Result.Width = (int)(w + 0.5f);
641 Result.Height = (int)(h + 0.5f);
646 if (BackgroundId.
Ok &&
652 Result.BackgroundColor = Color.
Result;
666 KeyValuePair<string, object>[] Attachments =
new KeyValuePair<string, object>[this.attachments.Count];
669 foreach (KeyValuePair<string, object> P
in this.attachments)
670 Attachments[i++] = P;
674 root = this.root.
Copy(
null),
708 StringBuilder Output =
new StringBuilder();
710 return Output.ToString();
718 public void ExportState(StringBuilder Output, XmlWriterSettings Settings)
720 using (XmlWriter w = XmlWriter.Create(Output, Settings))
733 Output.WriteStartElement(
"Layout2DState",
"http://waher.se/Schema/Layout2DState.xsd");
735 Output.WriteEndElement();
Helps with parsing of commong data types.
static string GetString(byte[] Data, Encoding DefaultEncoding)
Gets a string from its binary representation, taking any Byte Order Mark (BOM) into account.
Static class managing loading of resources stored as embedded resources or in content files.
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
Helps with common XML-related tasks.
static XmlException AnnotateException(XmlException ex)
Creates a new XML Exception object, with reference to the source XML file, for information.
static XmlWriterSettings WriterSettings(bool Indent, bool OmitXmlDeclaration)
Gets an XML writer settings object.
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
Event raised when the layout model has been Drawing internally.
Event raised when the layout model has been updated internally.
Syntax-related layout exception
Contains a 2D layout document.
UpdatedEventHandler OnUpdated
Event raised when the internal state of the layout has been updated.
const string LocalName
Layout2D
Layout2DDocument Copy(Variables Session)
Makes a copy of the layout document.
static Task< Layout2DDocument > FromStream(Stream Input, Encoding DefaultEncoding, params KeyValuePair< string, object >[] Attachments)
Loads a 2D layout document from a stream.
void ClearElementIds()
Clears registered elements with IDs.
bool Dynamic
If the layout is dynamic (i.e. contains script).
void RaiseUpdated(ILayoutElement Element)
Raises the OnUpdated event.
static Task< Layout2DDocument > FromStream(Stream Input, Encoding DefaultEncoding, bool Preprocess, Variables Session, params KeyValuePair< string, object >[] Attachments)
Loads a 2D layout document from a stream.
static Task< Layout2DDocument > FromFile(string FileName, bool Preprocess, params KeyValuePair< string, object >[] Attachments)
Loads a 2D layout document from a file.
void RaiseMeasuringDimensions(DrawingState State)
Raises the OnMeasuringDimensions event.
DrawingEventHandler OnMeasuringPositions
Event raised when the layout positions are being measured. Event is eaised once after dimensions have...
void ExportState(StringBuilder Output, XmlWriterSettings Settings)
Exports the internal state of the layout.
void AddElementId(string Id, ILayoutElement Element)
Adds an element with an ID
string ExportState()
Exports the internal state of the layout.
void ExportState(XmlWriter Output)
Exports the internal state of the layout.
static Task< Layout2DDocument > FromXml(string Xml, bool Preprocess, params KeyValuePair< string, object >[] Attachments)
Parses a 2D layout document from its XML definition.
static Task< Layout2DDocument > FromXml(XmlDocument Xml, params KeyValuePair< string, object >[] Attachments)
Parses a 2D layout document from its XML definition.
static async Task< Layout2DDocument > FromXml(XmlElement Xml, Variables Session, params KeyValuePair< string, object >[] Attachments)
Parses a 2D layout document from its XML definition.
bool TryGetElement(string Id, out ILayoutElement Element)
Tries to get a layout element, given an ID reference
string AddContent(object Content)
Adds content to the layout.
async Task< KeyValuePair< SKImage, Map[]> > Render(RenderSettings Settings)
Renders the layout to an image
static readonly string SchemaResourceName
Schema resource name.
static Task< Layout2DDocument > FromXml(XmlDocument Xml, Variables Session, params KeyValuePair< string, object >[] Attachments)
Parses a 2D layout document from its XML definition.
DrawingEventHandler OnMeasuringDimensions
Event raised when the layout dimensions are being measured. Event can be raised multiple times during...
void AddContent(string ContentId, object Content)
Adds content to the layout.
bool DisposeContent(string ContentId)
Disposes of attached content, given its ID.
const string Namespace
http://waher.se/Schema/Layout2D.xsd
static Task< Layout2DDocument > FromFile(string FileName, params KeyValuePair< string, object >[] Attachments)
Loads a 2D layout document from a file.
static Task< Layout2DDocument > FromXml(string Xml, params KeyValuePair< string, object >[] Attachments)
Parses a 2D layout document from its XML definition.
static async Task< Layout2DDocument > FromXml(string Xml, bool Preprocess, Variables Session, params KeyValuePair< string, object >[] Attachments)
Parses a 2D layout document from its XML definition.
bool TryGetContent(string ContentId, out object Content)
Tries to get content from attached content.
static Task< Layout2DDocument > FromStream(Stream Input, Encoding DefaultEncoding, bool Preprocess, params KeyValuePair< string, object >[] Attachments)
Loads a 2D layout document from a stream.
void Dispose()
IDisposable.Dispose
void RaiseMeasuringPositions(DrawingState State)
Raises the OnMeasuringPositions event.
string ExportState(XmlWriterSettings Settings)
Exports the internal state of the layout.
async Task< RenderSettings > GetRenderSettings(Variables Session)
Creates a render settings object.
static Task< Layout2DDocument > FromXml(XmlElement Xml, params KeyValuePair< string, object >[] Attachments)
Parses a 2D layout document from its XML definition.
static async Task< Layout2DDocument > FromFile(string FileName, bool Preprocess, Variables Session, params KeyValuePair< string, object >[] Attachments)
Loads a 2D layout document from a file.
Contains information about an actionable area in a generated image.
Manages an attribute value or expression.
bool Defined
If the attribute is defined.
static async Task< EvaluationResult< T > > TryEvaluate(Attribute< T > Attribute, Variables Session)
Tries to evaluate the attribute value.
Result of asynchronous evaluation.
T Result
Evaluated result, if successful.
bool Ok
If evaluation was successful.
Root node for two-dimensional layouts
StringAttribute BackgroundColorAttribute
Background Color
ColorAttribute ColorAttribute
Color
SKCanvas Canvas
Current drawing canvas.
void Dispose()
IDisposable.Dispose
void CalcDrawingSize(Length L, ref float Size, bool Horizontal, ILayoutElement Element)
Converts a defined length to drawing size.
string GetShortestRelativeMeasurementStateXml()
Gets the shortest subtree State XML of an element with relative measurements.
void ClearRelativeMeasurement(bool LogRelativeElements)
Clears information about first relative measurement.
bool MeasureRelative
If layout contains relative sizes and dimensions should be recalculated.
LengthAttribute WidthAttribute
Width
LengthAttribute HeightAttribute
Height
SKColor BackgroundColor
Background color
int Height
Height of image
RenderedImageSize ImageSize
Offset along X-axis.
Static class that dynamically manages types and interfaces available in the runtime environment.
static object Instantiate(Type Type, params object[] Arguments)
Returns an instance of the type Type . If one needs to be created, it is. If the constructor requires...
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
Class managing a script expression.
static Task< string > TransformAsync(string s, string StartDelimiter, string StopDelimiter, Variables Variables)
Transforms a string by executing embedded script.
Base interface for all layout elements.
float? Bottom
Bottom coordinate of bounding box, after measurement.
float? Width
Width of element
Task RegisterIDs(Variables Session)
Registers any IDs defined with the encapsulating document.
ILayoutElement Copy(ILayoutElement Parent)
Creates a copy of the layout element.
float? Right
Right coordinate of bounding box, after measurement.
Task Draw(DrawingState State)
Draws layout entities.
Task MeasureDimensions(DrawingState State)
Measures layout entities and defines unassigned properties, related to dimensions....
string LocalName
Local name of type of element.
Task FromXml(XmlElement Input)
Populates the element (including children) with information from its XML definition.
float? Left
Left coordinate of bounding box, after measurement.
ILayoutElement Create(Layout2DDocument Document, ILayoutElement Parent)
Creates a new instance of the layout element.
string ExportState()
Exports the internal state of the layout.
void MeasurePositions(DrawingState State)
Measures layout entities and defines unassigned properties, related to positions.
StringAttribute IdAttribute
ID Attribute
delegate void DrawingEventHandler(object Sender, DrawingEventArgs e)
Delegate for Drawing event handlers.
delegate void UpdatedEventHandler(object Sender, UpdatedEventArgs e)
Delegate for Updated event handlers.
RenderedImageSize
Affects the size of the rendered image.