The samples provided in this document cannot be run in the interpreter. They need to take place within the framework of a graphical Pliant application as introduced in 'a first graphic mode application'.
The two following sample provide the same: move cursor to the next line within existing paragraph:
A paragraph is introduced with 'para':
The default is to have some empty space at the top and bottom of a paragraph. If you want to remove them, just use 'stick' option:
Para accepts two other options, 'cursor' and 'edit' that we will see later.
Title and headers are also paragraphs, with different looking:
Also 'title' and 'header' accept a shorter writing if the content of the title or header is a single string:
title "The main title of the document"
Usage is rather trivial:
These attributes provide entry level styling. See 'Good looking using Pliant UI' article for doing the same, and more, using 'style' instruction.
Pliant tables are mostly moddled on HTML:
As stated in the introduction to Pliant UI, a Pliant UI application displays it's content in up to four windows. The content of each window can be provided, and later changed using 'window' instruction:
The size of the side windows will be automatically adjusted according to their content size, within the limit of roughly 1/4 of the screen area. So, be wise when you send content to side windows in order to keep as screen space as possible for your main window.
A section is a way to identify some part of the document rendered on client side, most of the time in order to be abble to later change it:
Then you can change the content of the section with:
There are four other keywords enabling to extend the section content:
Another way to change the content of a section is to execute again the code that created it. A section that can be recreated through rexecuting at any time must be created with 'dynamic' attribute:
section "time" dynamic
Then recreation is ordered using 'section_replay' instruction:
Real applications mostly either use 'section', then 'section_overwrite' in a button code, or 'section dynamic', then 'section_replay' in a button code. See bellow in this document for an example.
I found many applications to contain:
then, in various places of the code:
so that in the end, I created a 'help' instruction that does it all at once. The next code sample produces exactly the same as the previous one:
help "Do this, do that, or it failed because ..."
Let's start with an input field:
ovar Float s_value := undefined
If the default value is the right one, we can use more compact writing:
input "What is your name ? " (ovar Str name)
A help message can be automatically displayed in the "help" section when the mouse pointer is over the input field:
input "Value: " s_value help "Expected range is 1 to 1000."
The focus can also be set to the input field at time the field is created:
input "Value: " s_value focus true
More details about focus handling will be provided in 'High interactivity applications using Pliant UI' article.
We also have select boxes:
select "Source unit: " (ovar Str s_unit)
And finally, the button control:
When using Pliant UI, a link is just a button with different looking:
'button' and 'link' instructions accept many options:
If the button contains a help option, a help instruction will overwrite the help section with the provided text each time the mouse passes over the button, and will clear the area when the mouse goes away:
button "Exit" help "Use this button to leave the myapp application"
'key' option enables to bind the button to a keyword shortcut. It is highly recommanded the shortcut to be ATL plus a letter:
button "Exit" key "alt x"
'stretch' option is a styling option that instructs the client drawing engine to extend the button horizontal size as much as possible. It is mostly used in the left window to get buttons that have all the same size.
button "Exit" stretch
'active' option defauts to true and tells if the button is usable in the current state of the software:
ovar Bool saved <- false
'selected' option defaults to false and is used to change the color of the button when it is intended to work as a check box:
ovar Str mode
'layout' is the last option and it is used to ask the UI client to send informations about the screen layout (each window size) to the server just before the button clic instruction. It will be used by some very specific application to adjust the content sent to the client according to the effective size of the screen:
button "Info" layout
- explain why we use 'ovar' instead of 'var' -
As explained in the introduction, Pliant UI client uses the URLs and history notion it picked from the web terrific idea.
If we load a module containing the following code, or name the module '/myorg/url_demonstration.ui' to enable automatic loading on request:
then any client request to '/myorg/url_demonstration3/foo' will start a session of the demonstration applet on the server with subpath = "3/foo"
The application can use 'url_jump' to force the client to close the current session, then switch to another URL so open a new session, maybe on a different server:
button "test me"
It can also use 'url_call' to ask the browser to push the current URL to it's history, then issue 'url_jump':
button "A submenu"
and finaly use 'url_return' to ask the browser to pull the URL from the history.
With 'url_call' and 'url_return' we have a very convienient way to enter and leave a complex application submenus. 'url_jump' that we introduced first is in fact the non standard behaviour, as opposed to 'url_call', and you will use it only in very specific circonstances.
It is very important to understand that the Pliant UI session notion is tightly bound to the URL notion: each time the URL is changed through issuing 'url_jump', 'url_call' or 'url_return', the current session on the server is closed and a new one is open. It might seem strange at first if you use 'url_call' to provide access to submenus in your large application.
Let's image your application is a search engine (See /pliant/appli/file.ui for a real example). As a result of pressing 'search' button, the main window get's filled with search result, full of links to the various documents. Now, if you clic on one of the links, the application will issue 'url_call' to start the application dedicated to viewing this kind of document. When terminated, the user will press 'Exit' button and the document viewer will issue 'url_return' bringing back to the search engine application. The problem is that you expect not to get back an empty content, but again the result of your previous search, so that you can select another link if the first one you followed prooved not to be the right one, but it hurts the close connection between URLs and sessions. Your initial search session has been closed, so it's internal state is lost. We could work around through saying that 'url_call' does not close the current session, but keep it open and suspended until 'url_return' brings the user back to it, but then we would get servers full of suspended sessions, so that servers would have to timeout close them anyway.
Now, in some situation, you would like the keyword -> value setting to cross the URL boundary so that you can use it within your all complex application, even if it is spitted in several URLs..
url_set cross "pattern" pattern
But be warned about the potencial security related issue: the value can be changed or retreived by any application that knows the key. It is not site bounded like web cookies.
Threading is a very powefull mechanism the server can use to track some event, and change content on the client accordingly.
'flush' is used to force the server to client communication channel cache to be flushed. 'flush' can be used in an UI thread, or just to display a message on the client while some long computation is appening on the server:
The 'sync' instruction is more rarely used. Not only does it flushes the cache, but it also waits for the client to have processed it. It will be used in situations like this:
var Sem sem
Now, the big problem with threading is that Pliant standard variables are low level, so are not thread safe. As a result, you have to protect access to some of them with semaphores:
ovar Sem sem
If you had written your thread with the simpler:
then your application would be unreliable because 'mode' string variable might have an inconsistent value (since mode := "emergency" is executing at the exact same time) leading to a server crash even if the probability of such a situation is low. The semaphore prevents both actions to append at the same time.
In order to make things a little bit easier, 'critical' instruction is provided that grants that the current thread is the only one currently running in this session, so that no semaphore is required:
ovar Str mode
All buttons code are always executed with the critical section single semaphore reserved, so that in facts, you need to use 'critical' only in the 'ui_thread' code. Be warned, that while one of your threads is executing code in a critical section, others in the same session cannot, and events from the user are not processed either, so it can be wise to use several small critical sections instead of a single big one if execution time can be long.