Lucid Community User Manual
inxware-Lucid - 2.1.8
Understanding the ‘Hello World’ Application
Starting an Application from Scratch
Understanding Event-Based Programming
“For”, “While”, and “Do” loops (Iteration)
Step 3: Running Your Application
Re-Connecting Lines to Different Ports
(Optional): Take a look inside the new function block
Adding Subsystems to Your Library (LucidPro)
Creating an Empty Subsystem Block
Understanding the Debugger Workspace
Lucid is a no-code software platform that is used to develop and deploy software for devices, servers and workstations. Lucid is the IDE (integrated development Environment) for the inxware runtime environment. The runtime environment is event driven and ensures your applications run reliably, and quickly on any type of computing device.
This free community version of Lucid for Windows PCs can be downloaded from Git Hub. The community version of Lucid is free for life and fully functional for building non-commercial IoT, Desktop UI and cloud services. This manual is an introduction to Lucid and inxware and covers the basics only. More advanced features of Lucid and inxware such as state machine models that can be used in Lucid and other external tools such as systems integration tools and a complete function block library manual are not included here.
On first install Lucid will automatically load the example “Hello World” application to help you understand how things work while running on your desktop environment. It can also be opened from the Help->Tutoria menu. An overview of how this simple app works is used for the introduction in this manual.
Lucid is made up of an interface with different parts doing different jobs. The different parts are annotated and described below. (Fig.1)
Figure 1: Annotated Lucid Window
The workspace is where you build your project by linking components from the component library (See next) to form applications. Drawing links in the workspace defines when functions are triggered by external events or results of other functions in the application. Links also define what data sources are used by functions.
The drop-down menu where you find the different components arranged by the category of functionality. You can drag components from here into the workspace any time you need to add a new function in your application. You can preview more information for components in the library by left-clicking on the chosen component to show the properties and manual page available for the component.
The static properties and parameters are displayed and edited in this side panel for the currently selected function block. The section headed “instance properties” is where you will find the parameters available to configure each instance of a library component.
The example below shows the editable constant string parameter for the constant string library component, however, some components have multiple parameters and some have none at all.
Figure 2: Properties list for a string constant component
A more detailed manual for how to use the component is provided in the lower area of the sidebar. The read-only properties indicate the function block component type and summary of its function.
There is a Remarks section where you can note the purpose of the instance of the component in your application.
This contains the description of all of the ports and parameters of a component. This shows how they work, what they can be connected to, and what they will do.
When you run a program this is where any success or error messages will show up describing what went wrong.
This is the window that your GUI and widgets will appear in. This is essentially a preview of any app or program that you're building. You can interact with the widgets by clicking or holding down the left mouse button on the boxes and it will do whatever you programmed it to do.
When you first run Lucid after installation the “Hello World” test app should be automatically loaded. Otherwise, you can open a copy of it using the Help->Tutorial Apps menu at the top and open hello_world->hello_world.lpj
You can run this project by pressing the Play button (or Transfer->Send All Data to target). You should see a new “eRT” window appear (fig.4): If this does not appear check that you have your computer selected as the target device:
The “Hello World” program provides us with a demonstration of a few key elements of Event-based programming and data flow. The quickest way to understand the workings of this application is to run the program, select all of the lines that you want to monitor (click all of them for now while we’re understanding how it works) and switch on the debugger. Use the “Bug” button or Debug->Start to switch to debug mode, then select Debug->Select All Monitors. You should see something like this… (Fig.5)
Figure 5: Example “Hello World!” script with debugger
Now (if necessary) move the eRT window so that both the Lucid workspace and eRT are visible and click the text box in the eRT window and hold the mouse down. You should see the line connected to the “mouse down” port flash orange and the line connected to the “update” input port turn orange, in addition to the red-backed text by the data input change to “How are you?”.
What you have just seen is the grey GUI “Text UI” element asserting click and mouse-down events, which have triggered the data “Mux” function block to select between two constant string values. The “Mux” block simply selects data presented to the red data input ports and presents this on the red data output port and finally asserts an event out of the output event port that new data is presented. The connections to the GUI “Text UI” element notifies the GUI element to update with new data and cause it to display it.
Another feature of the Hello World script is the bracket symbol. This element combines two events and performs the event “OR” operation. “OR”ing events simply means that an output event is asserted when either of the input events occurs. There are other methods of combining events that are more selective, which will be discussed later. You may now be asking why there is seemingly only one event connection made to the “OR” element. There are two connections, but the second is an initialised event, which is a special global event that occurs when an application first starts. You can initialise ports by right-clicking on a port and selecting “Initialise”. You can try uninitialising the port in the same way, leaving the port unconnected. To see what happens with this change stop the debugger ( ) and re-run the application ( )... - Now the text box is initially empty when the App starts, but clicking the box will cause it to update as before. This tells us that unconnected inputs to an “OR” element don’t prevent events from the other inputs from passing through unaffected.
The installer also includes a few other sample applications that can be found from the Help->Tutorial App menu. Many of these examples rely on your Desktop’s user interface to interactively demonstrate how applications work, however, there is no need for an application to support any GUI features as inxware apps are often deployed as embedded software or cloud servers.
Users first testing Lucid will likely build a Hello World application that renders a UI to your PC screen. When developing such applications from scratch Lucid provides a GUI layout tool called LGB (Lucid GUI Builder) to help developers lay out graphical function blocks that may be part of the application.
After adding UI components to an application, Lucid will load LGB automatically to prompt the user to place any UI widgets in the desired layout. LGB can also be loaded at any time later to change the UI layout and theme by right-clicking on any GUI component in the workspace and selecting the Edit Layout option.
Figure 3: LGB window
Figure 4: eRT window
To create an App in Lucid a new project can be created and edited with the following stages and contexts:
● Project Creation - simply give your app a name and optional other information in Lucid.
● Application Development - selecting library “Components” and connecting these in the Lucid workspace.
● GUI Layout (Optional) - Layout widgets and import artwork.
● Debugging (Optional - but we’re all human!) using Lucid to view application operations.
● Deployment to test target and upload to Appland(Optional).
Rather than giving a detailed step-by-step set of instructions here, we will refer to the UI features of the tools. Lucid can launch applications to run in a desktop version of eRT, but can also launch additional “plug-in” tools such as LGB, the GUI layout editing tool. Reference to the Lucid tool’s features is covered in the following section and LGB is described in more detail later in this document. A suggested exercise to familiarise yourself with Lucid and LGB is to reproduce the “Hello World” Application.
This can be achieved with the following steps:
a. File->New Project:
i. Enter a project name and any other optional information you wish to include in the dialogue box.
b. View new empty project window.
a. Drag the following components from the “Components” window to the new application window
b. User Interface->Graphics->Widgets->string display
c. Data Utilities->Selector-Mux2->string
d. Data Utilities->Constant->string (x2)
e. Event->Combiners/Flow->Event OR->OR2
a. Left click-down on a port to connect.
b. Drag to the desired other port and release only when above the target port.
c. Lines will be drawn between the two ports. Black lines represent event paths and red lines represent string data.
d. illegal connection attempts will be rejected. e.g. connecting two outputs together or two lines to a single input.
e. Lines that represent events or data “travelling” from right to left are displayed as dotted lines to help differentiate lines.
a. The GUI widget and event “OR” components require initial events.
b. Right-click on an event port and select “Initialise” from the pop-up menu.
c. The port will change to a grey colour.
a. Double-click on a Constant function block in the application workspace to open a properties dialogue box.
b. Enter appropriate text in the “String Constant” text box.
c. press OK to close, and repeat for the other string constant function Block.
a. File->Save or the file save button.
b. Lucid will detect if a GUI element is present and open LGB (the GUI layout plug-in) to deal with it.
c. In LGB stretch the text block (see example) wider enough for the text you entered previously.
a. Press the run button in Lucid.
b. eRT will start up and show your application (after showing a pop-up progress bar).
c. If any errors are reported at this stage check that your LGB was run and the project saved after any edits in LGB. LGB can be started anytime by right-clicking on the GUI function block and selecting “Edit Layout” from the pop-up menu.
d. If your application starts but does not behave as you expect, switch on the debugger and try to identify what events are occurring and what data values are present.
Tutorials not included in the “Hello World!” example
We will first see how to move components around in the editing window. Move the cursor over a component. Note that the cursor changes from an arrow to a hand to confirm when it is over a
component. [Left-click]->Drag when over a component. Note that the position of the component is dragged with the cursor.
Move the cursor over a port Note that the cursor changes into a crosshair to confirm it is over a port. Left-click on the output port and drag to another port of the correct data
Type. Whilst over the target port release the left button. Note that inputs can only be connected to outputs and vice-versa. Also, more than one connection cannot be made to a single input.
It is often required that processes are started at application load time, requiring an initial event to be asserted by the system and connected to components required to run on startup. A convenient way to specify a start event that is asserted at start-up is by configuring the port itself to be asserted at start-up. This is achieved as follows:
[Input port]->{Right Click}->initialise.
Note that the ’initialise’ label becomes ticked in each case.
To move around your workspace is easy, use the scroll wheel to zoom in and out and to move around the page move your mouse so that it is not over a component or a line and [Right-click]->drag
The “Hello World” example demonstrated how events can originate from components and subsequently cause data to be processed in components and cause things to happen in others. Lucid’s “Event-based” graphical programming environment gives a developer great flexibility in producing desirable system behaviour that is difficult to produce in conventional “procedural” languages. This additional freedom does, however, require a little discipline as it is very easy to create concurrent processing constructs when a sequential approach is simpler and easier to produce in Lucid. As with all programming languages, there is a relatively small set of “Pattern” constructs that emerge as the most effective way to tackle common problems and Lucid is no exception. As a first step, we will look at some standard programming constructs from procedural programming and how these are represented in Lucid.
Conditional branching in event-based programming is perhaps the most different element from conventional branching because blocks of sequential instructions don’t exist in Lucid. Instead, control flow is defined by which output events are asserted by function blocks. Lucid contains a library of data-specific operators that test values and assert events on different output ports accordingly. These operations such as “is equal”, “is greater than”, and “is true” are however used far less than in procedural programming because nearly all Lucid function blocks contain function-specific logic that produces the relevant condition-specific events.
In any case, the following example illustrates a simple conditional branch depending on an integer value. (fig.6)
Figure 6: Example of a conditional branch using the “greater than or equal to” component
This example moves the Patch GUI object 1 pixel to the right for the first 30 clicks and then hides the widget. The equivalent object-oriented code pseudo (ignoring framework code) is:
int counter=0; /* Counter value */
GUIWidget widget; /* Widget object */
/* Function called when widget object is clicked */
Mouse_click_callback() {
counter = counter + 1;
if (counter >= 30) then
widget.hide();
Else
widget.move_x_position(counter);
endif
}
To illustrate why Lucid applications rarely require the low-level programming in the previous example the following alternative implementation using a more versatile counter function block is provided.
Figure 7: Example of a conditional branch using a versatile counter
Figure 8: Instance properties of the versatile counter in Figure 7
Fig.8 shows the configuration of the parameters that allow us to change the maximum threshold at which the “ovf” (overflow) event is asserted in Fig.7. This provides the same conditional branch as Fig.6.
There are no specific loop components currently provided in Lucid because loops are naturally expressed by looped event paths in Lucid. Loop break conditions are also naturally expressed by the outcomes of processes in the loop where continuation or exist is dependent on success or failure of functions or expressions.
The snippet below shows how a file can be read one line at a time and stored in an array for random access:
Figure 9: Iterative file reading loop
Let’s look at this line by line:
Lucid represents variables as data-type lines. Lines represent data mappings from component to component. Data lines can be connected to one data output port only and many input ports to share data with other components. Lucid also allows data to be labelled or “tagged” so that data that is used in many places within a workspace can be distributed without causing line clutter, this is done using the right-click menu. The scope of tags is the same as lines: i.e. these can be used within the workspace or “subsystem” and cannot be referenced outside of this scope. Subsystems are simply a way of condensing chains of components into one to provide structure to your applications - we will look into these in more detail later.
The four primitive data types are supported in the public version of Lucid:
● Boolean values
● Integer (32-bit signed integers)
● Real (23-bit IEEE floating point values)
● String - char arrays with a maximum length of 2048 bytes.
Figure 10: Example of a 4-input multiplexer
Data can be distributed simply by connecting output ports to multiple input ports as required. To combine data from multiple sources into a single data input port (“sink”). Combining data is a process of selecting between sources. The “Hello World” example at the beginning of this document already illustrated the use of the MUX (multiplexer) component to select between data sources depending on which is the last input event asserted. Typically changes in data are accompanied by an event being asserted, so events and data typically travel in similar pathways so that data consumers are notified when to read new data.
Figure 11: An example that shows how a string value can be dynamically created and applied to multiple GUI widgets
The overall structure of the diagram is again a loop using a counter to create an index value at each iteration. The counter value presented at the “cnt” port is converted from an integer to a string and concatenated into the static prefix text to form label text for the widgets. The string manipulation components used here are a little more verbose than needed to help illustrate the principle of the persistence model of data paths.
Notice here that the converter and “Cat” components are connected sequentially for both data and event paths. The blue “cnt” data line, however, forks and bypasses these elements, joining the event sequence again at the “Demux”. The counter value is the same at the time the converter is triggered and the time the Demux is triggered because there is only one event flowing through the sequence of components in one iteration and hence the data remains stable during each iteration. The next iteration is triggered only when the event asserted on a dotted line connected to the counter’s “inc” port is asserted. At this point, all the previous iteration data has been consumed.
When feeding back events to form iteration loops it is usually advisable to make sure the event that causes the next iteration to start can only be asserted when all inner processing has been completed. A variation of the previous diagram (Figure 11) shows a case where a race condition could be introduced. The brown area shows how the tighter event loop can run faster than the larger area of functions that should be complete before continuing to iterate and produce non-synchronous data to subsequent functions.
Figure 12: Dynamic widget creation with race conditions
In this version of the diagram the value of “cnt” is liable to change from the point it is converted to a string and the point it is used as the Demux index value.
Developers should not use assumptions about what sequence events are asserted unless the sequence is explicit in the diagram. For example, if the event feedback loop was taken from the output of the “CAT” function block it might be assumed that the “Demux” function block would beat the counter and read the counter value before it changed because there are more steps required to write the data. This however shouldn’t be assumed because the run-time engine may, for example, execute instructions in parallel on separate processors.
GUIs are created when components from the “User Interface” Component menu are used in your application. Items from the “Graphics” or “View Port” sub-menu relate to graphical elements in an application and any active components in your application can be edited using LGB to accurately arrange your layout and integrate artwork.
Note: This mini tutorial requires you to be familiar with the basic use of Lucid tools as
described above.
Create a new application and drag a string display component into your workspace:
[Lucid tools: Component Library] ‘ User Interface->Graphics->Text
You may notice the create port is flashing pink, this is to remind you that the component must be connected so that it can be initialised at some point. For our application we want this to initialise it straight away so we can right-click in the create port and select “Initialise”. We also want the function block to be visible so we need to do the same with the “show” port. It should look like (Fig.13)
Figure 13: Text UI component with initialised create and show ports
Now if you save your project, Lucid tools will identify there is a GUI object and open the LGB plug-in (Fig.3) for you (If this doesn’t happen, you probably haven’t connected the create port).
LGB is the GUI helper tool responsible for the aesthetics of your application's GUI. It allows you to change the colour, transparency, position, size and/or associated graphics files independently of the functional behaviour.
The connection between widgets represented in Lucid tools (as Components) and LGB (as screen elements) is established by the use of “tag” names defined in the Properties List for each widget. A default tag name is generated for each GUI Widget. It is recommended that you rename these to something meaningful as this will help you keep track as you edit and move widgets.
LGB layouts can be viewed at any time by right-clicking the UI component and selecting “Edit Layout”. It is possible to group widgets into layouts and to view multiple layouts independently in LGB, but this is not a concern for now.
The easiest way to test your application is to run it on your desktop machine. Lucid tools are usually installed with a version of eRT, the Lucid runtime which is launched when Lucid tools or LGB’s play or debug operations are used.
Lucid tools can communicate with already running versions of eRT on the desktop or remote IP-connected devices, however for now we will make sure the desktop version is selected as the run target by checking “My computer” is selected as the Run target: .
To run your app simply click the button, and eRT should be started for you and the default GUI, an empty grey text box, should be displayed in a new eRT window. You may see the (Fig.14) for a few seconds indicating progress, then your app running in eRT.
Figure 14: Device asset and application download progress
Figure 15: eRT with a blank widget
OK! But a bit boring looking! If you like, add some constant text to the data port (don’t forget to initialise the update port!) and change the colour, position, size etc. in LGB. Further use of the play button will use the same eRT window if it is already open. You can also use the button in LGB to update eRT with only files that have changed. This saves time when your applications have a lot of graphic files to transfer, but won’t make much difference with this simple application.
Groups of Components can be selected by dragging a rectangle around the group or holding the control key down while adding individual Components with left clicks. Groups of Components can be moved together, including connections or cut and pasted as described later in this section. Group selection is also used to hide selected Components in a sub-system, creating a new Component.
Each Component may have a set of configuration parameters declared in the component’s description file. Lucid displays these along with user manual information by left-clicking the Component. Parameters can be numbers, string or Boolean flag types and are pre-checked for range and format as specified by the component.
Move the cursor over a connecting-line segment (away from any corner in the
Line) and the cursor will change into a resizing cursor indicating the line can be moved
orthogonally to its direction. While over the line segment, left-click and drag with the mouse.
A new ‘corner’ appears in the line, whose position is dragged by the mouse. While over the line segment, right-click. You should see (Fig.16)
Figure 16: Line path editor menu
Deletes the connection.
Renders the line straight
Adds a corner (although this is done automatically by left-clicking/dragging on a line segment).
Recalculates a likely-to-be convenient path from port to port, via horizontal/vertical segments.
Replaces the line with an implicit connection between two ports which share a pair of tags.
The options available for ports depend on their type and the type of Component they are associated with. Sub-system ports can be removed and renamed, however, ports belonging to library components only allow editing of the lines connected to them. To view the options for a port: Move the cursor over a port The cursor changes into a crosshair While over the port, left-click and drag with the mouse. A connecting line stretches between the port and the present cursor position. While over the port, right-click with the mouse. A pull-down menu will appear, containing the option to tag a port. This allows lines to be replaced with text-tags. This is useful if a port output is used in many parts of the diagram or when the connection must pass a long distance in the diagram and clarity of its path is lost.
Connections to ports can be moved from one set of input/output ports to another. To do this drag the connection starting at the port where it will be detached and drag it to the new port (which must be of the same kind).
Now that we have some data on the project, it is worthwhile examining the Project metadata window in the bottom left (shown in Fig.1). This is populated with data that reflects the current project workspace and resource files associated with the App.
Firstly, expand the data tree fully by clicking the ‘+’ symbols on the tree. The categories on the tree are as follows:
This contains the name of the current project and a tree identifying subsystems
that may be part of the project. Sub-systems can be opened directly from the tree
view by double-clicking on the navigated branch.
This contains a list of layouts for the project. Layouts are what LGB deals with:
they are used to define the position of layouts on the screen. LGB can be launched
directly from the navigated branch.
This lists the image files (in LucidFree these must be of type ‘PNG’) that exist in the project. double-clicking files in this branch should open an image editor.
This lists text files that have been added to the project. Text files are stored by Lucid, and sent to the target when the user requests this, but are otherwise not processed by Lucid.
Lists any resources that the application needs at runtime. This typically includes an
icon graphics file in .png format named icon128x128.png which is the icon for the app
displayed in Lucid and the eRT application navigator environment.
Contains Metadata such as version information and the display name for the application. This data can be edited in a dialogue box created when double-clicking in this area. The dialogue box includes an import feature for importing the application icon into the resources area with the correct naming format.
‘Encapsulation’ of groups of Components into a single Component allows Lucid software to be easily structured into manageable units that can be re-used and duplicated. The encapsulation process creates a new workspace for the encapsulated components, which can be edited in the same way as the root workspace.
The easiest form of encapsulation is a top-down process where an existing set of Components can be subsumed into a single Component and the existing connections that travel into the new composite Component cause the automatic creation of a set of ports for the Components, forming the interface to use the composite Component.
Figure 17: The selector tool being used
Click and drag a rectangle around a group of components. (Fig.17)
Use the encapsulation button to start creating the sub-system. The dialogue box (Fig.18) will be displayed to allow you to name the sub-system and optionally provide labels for the ports and a menu heading should the subsystem be saved as a library component.
Figure 18: Encapsulation dialogue box
Simply press OK on the Encapsulate dialogue box and the components will be contained in a new sub-system (Fig.19). At this point you can right-click on each port and re-label them now the sub-system is in an informative context.
Figure 19: Top-level view of a structured sub-system
Your sub-system is now created, but you may want to make labelling changes. Now you can see your new composite component from an internal perspective by right-clicking on the clock and clicking “view component” (Fig.20). The pink “x-port” blocks represent the ports of the subsystem seen from the external perspective.
Figure 20: Inside view of a sub-system
Any sub-system in a workspace can be added to the Component menu for reuse in other projects. To do this right-click a subsystem and select “Add to Library” from the pop-up menu.
When applications are developed in a “top-down” approach it can be convenient to create subsystems and add ports before implementing any internal Components.
This is achieved by dragging “Components->Software Structure->Function Blocks->New Component” into your workspace.
Ports can be added by right-clicking on the new Component’s body and selecting “Add Port”. Ports can also be added internally by dragging the appropriate port type from the component chooser under “Software Structure->Function Blocks->*ports”.
Applications running locally on your workstation or networked devices can be debugged using the same debugging process. Lucid debugging helps you see what is happening inside your application as it runs. Data values can be displayed as an overlay on the data connections, and the occurrence of events is identified with colour changes of lines and optional counter and timing information overlays.
The debugger also supports breakpoints so that eRT will pause when user-defined events occur. eRT can then be stepped through events one at a time or unpaused to continue running. The debugger has a small overhead on the target CPU as information is sent via TCP, but this rarely slows down the operation of your application and the same Application code is executed as in the normal case.
Start the debugging tool by clicking the button. If eRT is already running and your application has already been transferred then the application will not be resent. If eRT is not running Lucid tools will start it, transfer the application, start it and enable debugging.
After a short period, the debugger should be active and some of the other debugging buttons will become active and the debugger toolbar should look like Fig.21
Figure 21: Debug toolbar when running
The square button is the stop button, which deactivates the debugger but leaves the application to continue running without interruption.
The two vertical lines are for pausing the runtime, leaving the debugger enabled, to inspect any variables. The application may also pause when a breakpoint event is asserted. In pause mode, the stepped line button is enabled, which allows the user to step through application execution one event at a time. The continue button is also enabled in pause, which exits pause mode and allows the application to continue in debug mode. The circular button is to enable outputting of logged data for use with trace tools such as time-doctor.
Fig.5 shows debugging enabled for the Hello World application. The first thing to notice is that some lines are displayed normally and others are purple. The purple lines are those that have been selected to be monitored. Left-clicking a line will toggle it between monitored and unmonitored. The Debug menu allows all lines to be set or reset in the current view and also allows monitor select mode to be enabled before a debugging session starts.
The colour of the monitored event lines is the next most significant feature to be familiar with. Orange indicates the last event that was asserted and pink indicates events that were asserted in a user-definable time period. This period can be adjusted in the Debug->Options menu pop-up box. Accompanying each monitored line is also a small blue text box that indicates how
many times the event has been asserted during the debug session. It is also possible to display relative and absolute time by enabling these features in us from the Debug->Options pop-up box.
Importing image files and assigning these to widgets is achieved in LGB by double-clicking the dummy image, (or [Rt-Click]->Properties) to show the properties dialog box (Fig.22).
Figure 22: LGB image-properties dialogue
Click the [Import a File] button
Then find an image from your favourite images repository or look in your home directory under ./inx-tools/resources/ directory where a few useful icon files have been installed with the Lucid tools.
The LGB window should now show your image, resizing the frame to fit the image.
The next time you run your app the new image will be displayed.
The same image cannot be imported more than once, however, the same image can be assigned to multiple widgets by selecting it from the pulldown menu of imported images.
The background colour of the LGB workspace can be changed from black to grey (e.g. if you have a lot of black widgets):
Tools->Options->Native View-background
This toggles the colour of the display background between black and grey.
The widget labels can also be hidden by unselecting Display Widget Labels:
Tools->Options->Display Widget Labels
The slider bars on the right-hand side of the LGB workspace allow the z-order of the widget to be viewed with a 3D perspective and/or the higher-level widgets hidden to reveal lower-level widgets for easier editing.
z-clipping aids working on lower layers of widgets when they are obscured.
This feature allows the developer an alternative method of separating overlapping widgets by visualising the widgets with a 3D perspective related to their z-position.
Dragging the edge or corners of the widget resizes it. Dragging the interior moves it. The cursor should change icons accordingly to prompt you to what will happen on a drag operation.
An image widget initially takes its size from the image it represents. Resizing the image can be done after loading the first image.
A text widget can be moved and/or resized, Image widgets just moved, by opening its ‘Properties’ dialog, via a double left-click, or by:
Right-click->Properties
Any field for which all the widgets share a given value will be populated with that value. In this case, all the edge and width values are the same for each widget.
Any field for which the widgets do not all share a given value will be populated with ‘---‘. For example, all the widgets have a different image file, so the ‘image file’ field will have a ‘---‘ field.
If such a field is edited with a non ‘---‘ value, all widgets will be updated to that value. In this case, if the image file drop-down were to be set to ‘jack-hearts.png’, all the widgets would be updated (upon OK) to show that image.
For any field with a ‘---‘ value, all widgets will not have that attribute updated.
Z-ordering allows you to control which widgets appear above other widgets. A widget at a higher z-level will be drawn in front of another lower z-value widget if they overlap.
LGB has the following controls to allow you to statically manage z-ordered widgets:
This control is found on the right-hand side tool area in LGB.
Slide the z-clip control up / down
The upper widgets progressively disappear as the slider is moved down, and vice-versa.
There are ‘notches’ on the slider corresponding to the z-levels where widgets are.
This control is also found on the right-hand side tool area in LGB. To try this, leave the z-clip control at max z.
Slide the z-lean control up / down.
The widgets move progressively into pseudo-3D positions, and back again.
Z-order values are normally defined absolutely, but from time to time you may want to tidy these up and remove gaps.
Tools->Z-Ordering->Renumber (Consecutively) renumbers all z-levels starting
from 0.
Tools->Z-Ordering->Renumber (keeping any gaps) renumbers all z-levels starting from 0 and compresses any gap in the ordering of more than 1 down to a gap of 1.
Eg: Z values of:
2,3,4, 11,12, 20, 30,31
would be renumbered to:
0,1,2, 4,5, 7, 9,10.
LGB allows the user to control which items are selected, and define a ‘master’ widget for the selection. The significance of the ‘master’ selection will be described later.
To begin a multiple selection you start by selecting a widget you want to be the master:
Ctrl & left-click any widget
Note that it gains a border with solid red rectangles on the corners. These solid red handles indicate that it is the ‘master’ selection.
Now you can select further widgets by Ctrl-left-click several further (as yet unselected) widgets; note which widget was clicked after the master.
Note that selections after the first (master) gain a border with hollow red rectangles on the corners. The hollowness of these red handles indicates that they are ‘non-master’ selections.
Left-click on space, and drag a marquee around a selection of widgets ensuring that at least one widget is only partially within the box, release the left mouse button to the lower-right of the start point
Note that widgets completely within the box get selected. It is not easy to define any other widget as the master after selection though widgets can be individually toggled using the Ctrl_Left-click.
LGB allows the user to align widget edges in a left-right and up/down sense.
Note that the slave selections are aligned with the master.
To demonstrate this try the following:
Select several widgets, noting which is the master.
Click Tools->Alignment
Experiment with these options.
You can also use the shortcut buttons that are enabled when a group of widgets is selected.
LGB allows the user to set the size of a given widget or widgets to be the same as a user-nominated ‘master’ widget.
Tools->Resize
LGB can be used standalone, without Lucid tools, to “skin” the application’s look and feel. LGB can be started (in Windows) using
[Windows ‘Start’]->All Programs->inx->inxware GUI Builder {Left Click}
and in Debian Linux:
[Linux ‘Applications’]->Programming->inxware GUI Builder {Left Click}
You can then open projects using File->Open Project and find the project directory.
Figure 23: LGB tool with the layout manager open
To open the Layout menu click [file->layout manager] the Layout manager shows the layouts for the project, grouped by ‘tabbed-window’ into their respective widget groups.
We can open the layout for the project as follows:
[Layout Manager: Open ALL Active Layouts Then Dismiss] {Left Click}
The dialogue is dismissed.
You can also start LGB with the project by right-clicking the “Text Out” block and selecting “Edit Layout”.
A further option is to select a layout from the Project->[Your app name]->GUI menu. The project window identifies all layouts used in the project. In our case, there is only one layout called
“DEFAULT_LAYOUT_FOR_WIDGET_GROUP_default” (!). The use of multiple layouts is an advanced feature not covered in this manual.
Widget groups are collections of widgets that correspond to each other in a GUI context. These may be a set of widgets that together form a new widget, such as a menu box or an animation, or an entire screen of elements.
Widget groups can be created in Lucid tools using the Widget-Group Manager found on each widget’s properties or from LGB’s file menu. When a widget is introduced in Lucid tools it is assigned to the default widget group but can be changed in the widget’s properties. Widgets cannot be moved between widget groups in LGB.
LGB provides a default layout screen for each widget group, however, more than one layout can be associated with a widget group to provide alternative layouts for the same GUI functions.
New Layouts can be created and associated with widget groups in LGB’s File->Layout Manager dialogue box. Multiple layouts can be useful for targeting multiple screen types, testing multiple ideas and supporting multiple user preferences. Lucid supports only one active layout for each target build, hence dynamic GUI profile changing is not supported in the Lucid version of inxware. The active layout is selected in LGB’s Layout Manager dialog box.
The widget group manager is quite rarely needed, however, its features are described in more detail in the following section.
The Widget group manager can be accessed directly from GUI widget Components in Lucid tool’s workspace and LGB’s File->Layout Manager->Manage Widget Groups.
Figure 24: Widget-group Manager dialogue
This dialogue box (Fig.24) shows each widget group and identifies how many widgets are assigned to it in Lucid tools.
The Layout manager is accessible only from LGB using:
File->Layout Manager
Figure 25: LGB Layout Manager
The layout manager lists each Widget group as tabs, each tab showing a list of layouts available. Only one layout in each list can be selected as active and this layout is selected as the live layout when your app is deployed. Layouts can be created, copied and removed using the appropriate buttons
Figure 26: LLM Prompt option
The LLM prompting can be accessed through the “Tools” option in the toolbar.
Figure 27: LLM Prompt window
This can be used to create state machines using an LLM to generate it by describing the required functionality. Then, when the processing has concluded, the actual state machine can be generated into the project by pressing the “Process” button.
Figure 28: LLM Prompt has been successfully processed
Figure 29: State machine created using the mermaid diagram generated by the LLM
The state blocks will be placed into the open project selected in the tools currently.
The prompt is of the form:
“traffic light system”
Replace the traffic light with the particular state machine. You do not need a special prompt for generation.
Assert | The action of sending an event on a function blocks output trigger |
Components. | A collection of operations on data that are fired by input triggers, read data on "input data ports", write data to "output data ports", and assert "output triggers" |
Concatenated. | One piece of data is added at the end of another. |
Data Port. | A port that is responsible for sending or receiving data (as opposed to events) |
Port. | A connector on a Component. A port can be an input or an output. |
Trigger. | An event port. A trigger may be an input port or an output port. |
Data types | |
Boolean. | Has 2 values, True or False, 1 or 0 respectively |
Integer. | Numerical data, stores any whole number using binary. |
Real. | Numerical data, stores any number, including fractions and decimals. |
String. | Text data will be stored as text that will be displayed. They can hold any sequence of letters, digits, punctuation, and other valid characters. |
Some devices (Targets) have different capabilities from others. This means some components are only available for some targets. Profiles for different target types are provided with the tools set and checks are made at load time to ensure compatibility. This document does not contain target-specific information and refers only to the standard + GUI profile. Supplements for other profiles can be downloaded from www.inx-systems.com
© 20010-2023 inx Limited. All rights reserved.
The information in this document is subject to change without notice and does not represent a commitment on any part of inx Ltd. While the information contained herein is assumed to be accurate, inx Ltd assumes no responsibility for any errors or omissions.
In no event shall inx Ltd, its employees, its contractors, or the authors of this document be liable for special, direct, indirect, or consequential damage, losses, costs, charges, claims, demands, claims for lost profits, fees, or expenses of any nature or kind.
All product names are trademarks or registered trademarks of their respective owners.
inxware-community license - 2024