Formatting and Styling BasicsNytril lets you put text and data into a document quickly and easily. Once you have done that, you'll want to add some formatting and style. Please take a few minutes to read the sections below to learn the basics of revisions and formatting to prevent common misunderstandings. Formatters are the way to turn data into visible content. Use them to place your data into a paragraph, table, document or even a popup tip. Formatters retain a link to the data so you and your users can easily find the source for any part of a document with a simple control-click. RevisionsA revision is a set of expressions (each one ending with a semicolon) that are enclosed in curly braces {...}. Each expression in the revision can either be an element or a property. •An element is a number, string or some other value like a date. It can be a variable holding a value or function call that returns a value. •A property is a field: value pair that gives a formatter styling information. It can also be used to specify content for some formatters. Elements are added to a revision in order of appearance. If an element is an array, then the array itself is not added to the revision. Instead, all the values in the array are added to the revision in order, without changing the array. Properties, on the other hand, have no order and can be specified at any place in the revision. Regardless of where they are placed, they effect the entire revision. For instance the TextWeight:Bold property makes all the text bold, regardless of whether it is placed at the beginning, middle or end of the revision. The entire revision {...} is treated as a single object that can be used to 'operate' on a formatter. When a formatter is 'revised' in this way, a separate object is created that represents the revised formatter. Neither the formatter nor the revision are changed by this operation. This means that revisions can be built from other revisions without causing side effects. A revised formatter can, in turn, be revised further to achieve the desired style structure. This is same idea as cascading style sheets in web programming and styles in word processors. In the example below, the Paragraph is revised to contain one property and two elements. ExamplePar = Paragraph { TextHeight: 8pt; "First element. "; "Second element. ";};These revisions can be combined with other revisions. The next example shows another revision being applied to the previous one, to give it more content and change its color. RevisedPar = ExamplePar { TextColor: Colors.Red; "Third element. ";};If a new revision has a property that is the same as a property from a previous revision (in this case TextColor), then the latter overrides the former. In the next example, the red paragraph from the previous example is revised with a blue color. Again, this does not change the previous paragraph, but instead makes a new object with the revised properties. This allows you to reuse existing styles, while making surgical changes as needed. BluePar = RevisedPar { TextColor: Colors.Blue;};
Computed ContentIf you are used to working with markup languages, it is easy to forget that the content in Nytril is not static. In Nytril, no content is actually added until the statements creating the content are executed at runtime. This execution occurs when you refresh the document (by pressing F5). As you look at the examples, keep in mind that each of them is a function that executes line by line, just like a normal computer program. If you want to see this in action, simply set a breakpoint on a line by clicking just to the left of the line numbers in your code. When you refresh the document, the program will stop at the breakpoint, and you will be able to step through the logic of your code. The code below shows a more complex set of functions that use an if statement to make a decision about what content to include depending on the value of a number. This topic is covered more detain in the Tutorial. namespace TestOutput { TestNumber(number) = Span { "The number is "; number; if (number > 9) ", which is quite large. "; else ". "; }; UseContent = Block { // Call the function declared above TestNumber(5); TestNumber(15); };}Content FlowIn general there are two ways that content can flow in a document. •Vertical or 'block'In vertical flow, the children are allowed to take up the entire horizontal space between margins, and flow downward to the bottom of the page. If the bottom of the page is reached, a new page is created, and the content will continue to flow. ParagraphTable•Horizontal or 'span'In horizontal flow, the child elements become runs of rectangular 'characters' like text, icons, frames, canvases and images. These characters are aligned horizontally, end-to-end on a line, and vertically on the baseline of the text. When the line is too long, a new line is created. When the paragraph runs out of room on a page, a new page is created and the process continues.
Content fills horizontally î—ˆ until the end of the line is reached and a new line is created. The Basic FormattersNow that you understand a little about the two kinds of flow, let's take a look at a few of the workhorses. In most documents, almost all of the formatting work will be handled by the formatters below. There is a comprehensive list of formatters at the end. SpanA Span is a collection of elements with its own text-formatting properties. A Span never exists in a document by itself and will always be placed inside a Paragraph either explicitly or implicitly. If you want to changed the formatting of some text in a paragraph without changeing the text around it, put it in a Span. ExampleSpan = Span { "Here is a span of text with "; Span { TextColor: Colors.Red; "a red"; }; "span inside. ";};ParagraphA Paragraph can be thought of as a block that has flowing Spans within. It also has extra properties such as tab stops, indenting, justification and borders. A Paragraph will take up the available horizontal space inside the margins of whatever space it happens to be inside, and will flow left-to-right and downward. There are no 'levels' in a Paragraph. If there are inner Spans, they simply become a differently formatted sections of text inside the Paragraph. ComplexPar = Paragraph { ParAlignment: Justify; LeftIndent: 8pt; RevisedPar; "Plain text"; Span { "Inline span with custom formatting"; TextHeight: 120%; Underline; };};BlockA Block is a collection of Paragraphs and Tables (and other Blocks) that flow downward in a document. A Block is a convenient way of gathering vertically oriented content together and assigning common properties to the elements. If a child element of a block is not already a Paragraph or Table, it will be 'promoted' the be a Paragraph and it will appear on a new line. If a Block contains another Block, it simply means that the outer Block will add the content of the inner Block to itself. In other words, no nesting 'levels' are created inside a block. In this way, pre-formed Paragraphs and Blocks can be stitched together and reused in a different contexts.
The nature of the outer formatter determines how its inner elements are interpreted. Keep in mind that each formatter can only allow certain formatters to be its children. For example, if we try to add a complex formatter like a Table to a Paragraph, there would be no clear way for the table to "flow" with the other text in the paragraph horizontally. A table needs to take up the entire horizontal extent of its parent, so a table must be placed in a block. ExampleBlock = Block { TextHeight: 12pt; // All the text, in all the elements, will be 12pt ComplexPar; Paragraph { "Inline paragraph"; TextHeight: 10pt; // Override the TextHeight setting above }; Span {"Converts to a separate paragraph"}; "This string becomes a paragraph"; 5 + 3; // Computes the value 8 and becomes a paragraph;};DocumentA Document is a Block with many additional properties such as paper size, headers, footers, gutter, etc. The example below shows a Document with custom margins. Notice that the Header and Footer are not Elements of the Document, but are expressed as Properties. Just as in a Block, the content of the document itself is expressed as separate Elements of the Revision that operates on the document. ExampleDoc = Document(new(0.5", 1", 0.5", 0.75")) { Header: MarginBlock { "Title"; }; Footer: MarginBlock { Paragraph { ParAlignment: Center; "Page "; DocFields.PageNumber; }; }; "Here is the content"; ExampleBlock;};Formatters by categoryBelow is a comprehensive list of the formatters and the container rules. It is critical to understand that each formatter has a very specific set of characteristics the serve a particular formatting need. The important thing is that these formatters can be mixed and matched to generate documents of great complexity. CommonSpanA collection of text runs inside a paragraph. Children may include: [Span, object]. DropCapA span with an enlarged dropped letter. Children may include: [Span, object]. ListSpanA Span containing enumerated items. Children may include: [Span, object]. ParagraphA paragraph contains zero or more spans that wrap inside the left and right margins. Children may include: [Span, object].
BlockA container that holds Paragraphs and Tables. Children may include: [Block, Table, ListBlock, Paragraph, Span, object]. It will convert its child elements to Paragraph if they are not already of that type. ListBlockA Block containing enumerated items with a marker to the left. Children may include: [Paragraph, Span, object]. It will convert its child elements to Paragraph if they are not already of that type. ListItemAn item inside a ListBlock. Children may include: [Block, Table, ListBlock, Paragraph, Span, object]. It will convert its child elements to Paragraph if they are not already of that type. TextBlockA Block with fixed-width formatting. Children may include: [Paragraph, Span, object]. It will convert its child elements to Paragraph if they are not already of that type. FrameA rectangular Block containing Paragraphs and Tables that fits in a Span. Children may include: [Block, Table, ListBlock, Paragraph, Span, object]. It will convert its child elements to Paragraph if they are not already of that type. TablesTableA container for Rows and Columns. Children may include: [Row]. It will convert its child elements to Row if they are not already of that type. RowA horizontal container of Cells. Children may include: [Cell]. It will convert its child elements to Cell if they are not already of that type. CellA cell inside a Row. Children may include: [Block, Table, ListBlock, Paragraph, Span, object]. It will convert its child elements to Paragraph if they are not already of that type. MathFractionA canvas that draws a horizontal/diagonal line between its children. Children may include: [Block, Table, ListBlock, Paragraph, Span, object]. It will convert its child elements to Paragraph if they are not already of that type. NaryDraws an operator with optional superscript, subscript and body elements. Children may include: [Block, Table, ListBlock, Paragraph, Span, object]. It will convert its child elements to Paragraph if they are not already of that type. RadicalDraws a square-root shape around is elements. Children may include: [Block, Table, ListBlock, Paragraph, Span, object]. AlignBlockA Block containing alignment markers. Children may include: [Paragraph]. It will convert its child elements to
Paragraph if they are not already of that type. MatrixBoxA canvas that contains Rows and vertically aligns the columns. Children may include: [Row]. It will convert its child elements to Row if they are not already of that type. ChartChartA chart containing one or more ChartSeries. Children may include: [ChartSeries]. ChartSeriesA data series that displays in a Chart. Children may include: [DataPoint, double]. ChartAxisDefines a Chart axis. Children may include: [double]. ChartLegendDefines a chart legend. Children may include: [Paragraph]. DrawingTreeBoxDraws a tree structure with its Root elements. QRBoxA QR code. FitBoxRezize and rescale an image to fit into a specific rectangle. CanvasA rectangular container that holds elements with arbitrary position. Children may include: [Block]. HBoxA canvas with a Direction of Horizontal. Children may include: [Block]. VBoxA canvas with a Direction of Vertical. Children may include: [Block]. ShapeShapeA container for ShapePaths. Children may include: [object, ClosedPath, OpenPath]. ClosedPathA closed path. Children may include: [LineTo, QuadTo, CurveTo, ArcTo]. OpenPathAn open shape containing elements (e.g. LineTo, QuadTo, CurveTo and ArcTo). Children may include: [LineTo, QuadTo, CurveTo, ArcTo]. LineToA line segment.
QuadToA quadratic curve segment. CurveToA bezier segment. ArcToAn elliptic arc segment. DocumentDocumentA complete document that contains sections. Children may include: [Block, Table, ListBlock, Paragraph, Span, object, MarginBlock, SectionContinuous, SectionNextPage, SectionOddPage, SectionEvenPage]. It will convert its child elements to Paragraph if they are not already of that type. SectionNextPageCreates a new section with a page break. Children may include: [MarginBlock]. SectionOddPageCreates a new section starting on the next odd page. Children may include: [MarginBlock]. SectionEvenPageCreates a new section starting on the next even page. Children may include: [MarginBlock]. SectionContinuousCreates a new section on the same page. CiteA citation span that contains Reference facts. Children may include: [DocReference]. It will convert its child elements to DocReference if they are not already of that type. FigureAdd a figure or table to the document. Children may include: [Block, Table, ListBlock, Paragraph, Span, object]. DocumentIndexAn index block for the document. DocumentEndnotesAn endnote listing Block.