Language

Good looking using Pliant UI

Styling overview

Is Pliant UI styling a good model ?
No.

Why didn't you designed a good styling model ?
Because it's too hard for me !

The ultimate goal of styling was to separate the code producing the content (semantic) from the code driving the rendering engine. Let's show how hard it can be through three examples.

First, let's imagine that we define a new 'important' semantic attribute, and that our document contains several kind of informations, let's say 'definition' 'demonstration' 'note'. If we decide to use different text colors for the different kind of informations, then we might expect the 'important' attribute to not only turn the text to bold, but also to make the text color more saturated. In other words, the color of the text marked with 'important' attribute depends on the tag ('definition' 'demonstration' or 'note') the 'important' attributes takes place in. So semantic content is not a flat set of markers, but rather nested, and the final rendering of some text depends on all the pile of tags it appears in, not only the innermost one.

Then, imagine a query that returns some informations about your company running orders. At semantic level, the result of the query it is a set of records (one record per order). So, it could be displayed as a table. Now, in order to get some good looking result, if the number of informations in each record is too large to be properly displayed on a single line, several fields will be displayed in a single cell, on several lines. It means reordering and grouping when translating from fields to cells. A mechanism such as providing the semantic as an HTML table with a class attribute for each row and each cell, then applying an HTML CSS is not be enough to do that.

Let's push to the limit with the third example: when we display a chart, the content should be sent as a table, and the styling machinery should turn the table to a nice looking chart, just like in a desktop spreadsheet.

I conclude that if the goal is to truly separate the semantic from the rendering, then the ultimate styling mechanism has to be handled on server side because it will have to do application specific computations and I don't want a language on client side.

So, the next question is: how powerful a styling mechanism should be provided on client side ?
My answer was: each widget rendering engine has a lot of parameters, so I need to provide an efficient mechanism to set all of them on server side and read all of them on client side. For the server it means that if some widget appears many times in the document with the same set of parameters, it should be possible to send them only onces, and on the client side it means that switching from a set of parameters to another one should be fast.

I've chosen to implement a Pliant UI style as the set of all rendering parameters for all tags. It satisfies both previously expressed constrains since, on server side a style needs to be defined only once, then using it just requires to provide the style identifier as opposed to all the rendering parameters it sets, and on client side, switching to another style just means changing the current style pointer.

The drawback is that Pliant styling system sucks from the consistency point of view as soon as the application defines new semantic tags. Each new semantic tag should add some rendering parameters to the UI style data structure, so that when switching from a style to another, the rendering parameters be properly defined both outside and inside the new semantic tag. In other words, a new semantic tag is a new widget so would need it's own set of rendering parameters in each Pliant style.
In order to properly cope with extra semantic tag notion, it might have been a better idea to have a style specifying the set of rendering parameters for just one widget, but then, some semantic tags such as 'note' would have been harder to implement because they need to change several widgets at once (standard paragraphs, headers and maybe more).
This is where HTML CSS is clearly a better solution from the semantic point of view, because the rendering parameters for a given tag can depend on the 'class' attribute (so the semantic) of one of it's parent tags. The drawback is that such a model require to precompute and store the set of rendering parameters for each tag in order to enable decent positioning and drawing speed, and it can be very computing and memory consuming if there are a lot of different sets of parameters in the end so that data cannot be efficiently shared. As an example, a table with a different background color for each cell.

As a summary, Pliant UI styling design policy is a bit: If you can't make it powerful, make it fast.
When explaining how it works in the two next paragraphs, you will see that two notions ('style set' and 'style mset') have been added on top of the main ('style use') model to bring extra flexibility.

Pliant UI styling machinery

- Some styling features are still buggy in Pliant release 101. Please upgrade to match the following documentation -

The widgets implemented in Pliant UI currently are:

   •   

para

   •   

header

   •   

title

   •   

link

   •   

button

   •   

input

   •   

select

   •   

table

   •   

focus

A set of rendering parameters is associated with each of them. The set of all rendering parameters for all widgets is called a style. Each style is identified by a string identifier. The default style is identified by empty string identifier.

Defining a new style is two steps. First create if through copying an existing one:

style_copy "" "foo"

Then change some parameters through using several time 'style_set' function:

style_set "foo" "para/text/italic" true

Using the new style is achieved through:

style use "foo"
  text "Text will be in italic"

Well, that was the entry point. Let's now explain that it's not that simple.

A UI style defines all rendering parameters for all widgets. It is implemented as a data structure defined in /pliant/graphic/layout/style.pli, named LayoutStyle that provides a large set of parameters the various widgets (paragraph, title, button, etc) will use at positioning and drawing time.
The initial value for all parameters is defined in /pliant/graphic/layout/default_style.pli. See listing for it's exact content.
The parameters can be seen has three levels:

   •   

the widget (an example could be 'button')

   •   

the context (examples could be 'standard' or 'inactive')

   •   

the various positioning and rendering parameters (examples could be 'text/size' or 'box/padding/left')

As shown in the provided listing, that's a lot of parameters in facts, so that changing one thing, let's say the buttons text size 'thing', requires to change several values (text size for all possible contexts). Another example would be changing the table cell padding 'thing' which require changing the left, right, top and bottom padding parameters.
There might be a serious risk for applications to forget to change some parameters when they expect to change one 'thing'. If we add new contexts in the future, how will existing applications behave ?

So the grouping name notion has been introduced. A grouping name is referring to several styling parameters. You can see the predefined ones on the listing lines starting with '--'. It is also possible to define new names and associate them with several parameters through using 'style_define' instruction several times:

style_define "myid" "para/text/italic"

This example means that 'myid' name now refers to all parameters it already referred to (none if it's a new keyword as in this example) plus all the ones 'para/text/italic' refers to (a single one since 'para/text/italic' is the name of a real styling parameters, not a grouping name).

Then, the '*' sign can be used to automatically generate grouping names (only one '*' sign can be used). As an example, the following code would change the ground color of buttons in all contexts at once:

style_set "" "button/*/box/r2/color" (color rgb 192 64 64)

Now, that we have fully explained how to cleanly define styles, let's explain how to dirtily modify styling in the middle of an application using several parameters in a 'style' instruction. Yes, it should not be done, but that's real life.

style set "table/padding" 3 set table "table/ground/color" (color rgb 255 192 192)
  table
    ...

Basically, the current style is modified on the fly while executing the underlying bloc.
Using both 'use' and 'set' in the same 'style' instruction is also possible to use a slightly modified version of the style.

Please don't mistake 'style_set' function which is used to modify a style declaration with 'style set' control which is used to temporary modify the current style while rendering the bloc.

Box styling

Pliant UI 'style' instruction applies to all the subtree, so it is not convenient if what we want to style is just the box around some content:

style use "mybox"
  table
    row
      cell
        text "My content is disturbed because using 'mybox' styling parameters"

So, 'mark' and 'recall' options have been added (starting from release 103):

style mark "anid" use "mybox"
  table
    row
      cell
        style recall "anid"
          text "My undisturbed content"

'mark' will save the current style pointer under the specified name, and 'recall' will pick it back.


Advanced styling

We have seen the clean grouping name notion. Let's introduce the dirty shared parameters notion.

We will start through refining the semantic of 'style set' instruction we introduced at the beginning of the styling machinery presentation. If we write:

style_set "foo" "para/text/italic" true

we not only change some parameters in the 'foo' style, but also change parameters sharing.
Basically, what will append is that a new boolean value will be created, and all the parameters grouped under 'para/text/italic' name (this is name grouping) will now share the same new value (this is parameters sharing).
For advanced programmers, let's say that each parameter is not a value, but a link to a value, and when we call 'style_set' function, it creates a new object with the specified value, then connects all the links of the parameters grouped under the provided name to the new object.

Let explain the effect of parameters sharing with a few examples:

style_define "highlight" "para/text/bold"
style_define "highlight" "para/text/italic"
style_set "" "highlight" false
...
style set "highlight" true
  text "Hello"

Since 'highlight' has been defined as a grouping name, the 'Hello' word will be displayed bold and italic.

Now, if keep the same beginning, but change the end with:

style set "para/text/bold" true
  text "Hello"

Then the 'Hello' word will be bold only.

Now the trick is using 'mset' instead of 'set':

style mset "para/text/bold" true
  text "Hello"

And the result is a bold and italic word.

As opposed to 'set', 'mset' does not change the parameters links, but rather overwrites the parameters values. Since the instruction 'style_set "" "highlight" false' linked both 'para/text/bold' and 'para/text/italic' parameters to the same value, overwriting  the value of one of them with 'mset' changes both parameters at once. 'mset' stands for multiple set.

Another important thing to specify about parameters sharing is that 'style_copy' creates a new style with all parameters shared with the source one. Using 'style_set' will later link some of the parameters to different values.

Shared parameters notion seems hard to use and inconsistent. What is it useful for ?
It's just faster, so helps the UI client to compute document elements positions faster if the document is very long. I've changed implementation between release 101 and release 102 to make using parameters sharing notion completely optional. Entry level programmers can just ignore it.

As a summary:

   •   

'style use' is very fast and consistent.

   •   

'style mset' is fast but hard to use and inconsistent.

   •   

'style set' is slow but consistent.

Coffee time, then I will explain the semantic of various styling parameters.

Meaning of various styling parameters

Let me remind you that the list of all available styling parameters is not included in this document, because it's too long, but available as a separate document.

First of all, many widgets, such as 'button' or 'para' or 'table/cell' are using a set of parameters to define a surrounding box. Drawing the box is implemented in /pliant/graphic/layout/helper/draw.pli.
We have 'padding/left' 'padding/top' 'padding/right' and 'padding/bottom' that add some space (specified in millimeters) around the content.
Then, we have a very important 'mode' parameter that defines what we draw:

0

draw nothing.

1

draw 'r1' rectangle.

2

draw 'r1' and 'r2' rectangles. If 'r2' color is undefined, then 'r2' will define a hole in the 'r1' rectangle.

The rectangle coordinates 'left' 'top' 'right' and 'bottom' are specified in the millimeters, and go the opposite side of padding, so start (zero value) from the padded area of the box and grow (positive value) to the center of the box. Then 'round' enables to get rounded corners (also expressed in millimeters), and 'angles' enables to discard angles rounding in some of the corners. 1 for the top left corner, 2 for the top right one, 4 for the bottom left, and 8 for the bottom right corner. Of course, several corners rounding can be discarded through adding these values.

For the 'button' and 'link' widget, 'spacing' means the space between the label and the keyboard key combination associated with the button (when the key is not part of the label, so is displayed at the right of the label).

For 'para' 'title' and 'header' widgets, 'spacing' means line spacing. 1 means standard line as specified in the font definition.

For 'table' widget, 'box' parameters define the padding and the table external border (or ground), whereas 'cell' and 'header' ones define them for individual cells (depending if they have the 'header' flag set or not).

For all widgets, 'css' specifies the value to add to the HTML tag as the 'class' attribute.
How to translate UI style to HTML CSS is explained in the document about the HTTP proxy.

Images

The following module has to be included in order to access images related UI instructions:

module "/pliant/graphic/ui/server/image.pli"

Let's assume that the application created an image, maybe through:

var Link:ImagePrototype img :> new ImagePixmap
img setup (image_prototype -10 -10 10 10 256 256 color_gamut:"rgb") ""
for (var Int y) 0 255
  for (var Int x) 0 255
    var ColorRGB888 c := color rgb x y 0
    img write x y 1 addressof:c

Then, transferring the image to the UI client is done through:

image_define "img1" img

and finally, inserting the image in the middle of the current paragraph, just if it was a single character, is done through:

image_inline "img1"

We use two instructions, one for transferring and one for using, so that the same image can be reused at several places in the page content without transferring it several time. The identifier, here 'img1' can be freely selected and is used only to identify the image on the UI.
As far as size and alignment are concerned, the size of the image on the UI client depends only on the dimensions, here 20 by 20 millimeters (20 = 10 - (-10) ), not the number of pixels the image contains (here 256 by 256).
The alignment will be the text baseline will be aligned with the image vertical 0 position, so here with the middle of the image.

'image_define' can be provided extra options.
As an example:

image_define "img1" img "jpeg quality 0.9"

instructs the server to send the image to the UI client as an JPEG compressed image (consumes less bandwidth if the image is a photo) with JPEG quality set to 0.9 (quality is in the 0 to 1 range).
'pack4' could be used instead of 'jpeg' to request to use Pliant PACK4 encoding (an advanced two dimensions run length compression).

As opposed to most other UI instructions, 'image_define' server side instruction does not translate to sending a single PML encoded instruction to the UI client. Instead it sends 'image_define' first in order to define the prototype of the new image (dimensions, number of pixels, pixel encoding), then it sends either 'image_write_raw' or 'image_write_pack4' or 'image_write_jpeg' to send pixels.

Very often, people just want to pick an image from a file, and display it.
Instead of having to define an image object, then load it, then transfer it, then insert it, a single shortcut command is provided:

image_inline_file "bug" "/pliant/welcome/image/bug.jpeg"

The size of the image depends on the image resolution in the file. The alignment will be on zero point, which for most on disk file formats means top left corner. If different alignment is expected, an extra parameter shall be provided to image_inline_file:

image_inline_file "bug" "/pliant/welcome/image/bug.jpeg" "center 0.5 0.5"

'center' will force the zero point in the image, 0 0 means top left, 0 1 means bottom left, 0.5 0.5 means center, etc.

Lastly, 'image_copy' can be used to copy an area of an image to another image, or a different area in the same image:

image_copy "img1" 200 200 300 300 "img2" 120 130

means, copy a 100 by 100 area of 'img1' starting at (top left corner) point 200 200 to the 100 by 100 area in 'img2' starting at (top left corner) point 120 130.

Drawing

The following module has to be included in order to access vector drawing UI instructions:

module "/pliant/graphic/ui/server/draw.pli"

Here is just a tiny vector drawing sample:

draw -10 -10 10 10
  fill color (color rgb 255 0 0)
    curve
      angle -10 -10
      point 2 -2 tg_in 0 -1 auto_out
      point -2 2 in 5 0 out -10 0
    curve
      through 0 -1
      through 1 0
      through 0 1
      through -1 0

'draw' is used to introduce some vector drawing. A vector drawing is considered by the positioning engine as a single characters, just like an image. Provided parameters are borders coordinates in millimeters.

'fill' draws an outline. An outline is made of one or several curves. Pliant curves can use either Pliant native formula, or Bezier, or Conics. See literature and 'pos' method in /pliant/math/curve.pli for extra details. Also, at the moment, only Pliant native curve formula and even-odd filling rule are mapped from Pliant vector drawing layer to Pliant UI.

'curve' is used to define a single curve. Each point of the curve is defined through either 'angle' or 'through' or 'point' instruction.
'angle' means that the point has no imposed in and out tangents. 'through' means that the point will have auto computed in and out tangents in order to provide smooth path through the specified position.
Lastly, 'point' is a more general version that enables to provide explicit in and out tangents. There are three ways to define each tangent:

   •   

'in' or 'out' means that both direction and length of the tangent is provided (a longer tangent means that the curve will remain close to the tangent for a longer time)

   •   

'tg_in' or 'tg_out' means that the direction of the tangent is provided through a vector, but it's length will be computed automatically.

   •   

'auto_in' or 'auto_out' means that both tangent direction and length are to be computed automatically.

It should now be clear that:

angle 10 20

is a shortcut of

point 10 20 tg_in 0 0 tg_out 0 0

and

through 10 20

is a shortcut of

point 10 20 auto_in auto_out

Only filling is supported at the moment. No text and no image is supported, so it's mostly unusable.
Pliant vector drawing library is very mature, but the glue code to enable using it in an UI based application is both incomplete and unsatisfying. Will have to be reworked.
When done, I'll document with greater details.