Aztec® Programming Language
Version 1.1 Alpha 2

Copyright © 2010-2017, Aztec Development Group, All Rights Reserved

Download Aztec

Search        Contact Us

Let's do some living... after we die.

- Mick Jagger and Keith Richards

 

The Aztec Engine features a flexible UI Display system that provides UI services for the Aztec Class Framework. The UI Display system can operate in two different modes.

♦ When the Aztec Engine executes a script in the Virtual Machine, the UI Display system is available if the script opens up a window on the "local" display.

♦ An internal thread to thread messaging system is used to communicate between the Virtual Machine and the UI system.

♦ The Engine can run in a special "UI Display Server" mode. An Aztec script running remotely on the network/internet can connect to the UI Display Server and open windows on the "remote" Display.

♦ The client script seamlessly sends socket messages to the remote UI Server to control the UI and the Server sends socket messages back to the script for UI event processing.

It is very easy for an Aztec script to open one or more windows on a remote UI server.

On the "server" machine

♦ Run the Aztec Engine in special UI Display Server mode: aztec -display 1080

On the "client" machine

♦ The Aztec script creates a Display object and connects to the UI Display Server using Display.Connect()

♦ When a "top level" window is opened, such as a dialog or frame window, use the remote Display object in the Frame or Dialog constructor argument list

That is all there is to it. Once a top level window is opened up on a remote Display, the Aztec Engine system takes over and handles all the details of communicating between the Aztec script and the UI Display Server. All UI events generated in the UI Server are sent back to the client machine and are made available to the Aztec script via the standard event handling system. This UI technology works on local networks and across the internet.

The following diagram shows the high level communication between the Aztec Script and the local and remote UI Display Servers. A "Request" is a message sent from the Aztec VM to the UI Server to create a new window or to manage an existing window, based on the Aztec script making a UI Class Framework method call. An "Event" is created inside the UI Server based on user interaction with the UI, and it is sent back to the Aztec script for event processing.

Aztec Remote UI Communication

 

This ability for the script to run on one machine and display its UI on one or more other machines gives the script a lot of flexibility for interacting with the user. The Aztec Engine will be ported to Linux in the near future, and this technology can be very useful in that environment. For the Internet of Things and other environments where code may run without the benefit of a display screen, this feature allows an Aztec script to run in those environments, and then interact with the user by sending the UI to a central control computer, yet retaining control over the operation since the UI events get sent back to the client script for processing.

Most of the Aztec UI Display system components (class framework and server) are written in ANSI C++, including the Aztec UI Framework, Internal UI Event/Request Frameworks and Generic UI Framework. The Platform Specific UI Framework (shown in gray) is the only part of the UI system that requires code changes when porting the Aztec Engine to a new platform.

Example Chat Script Using Remote UI Display Services

A simple Chat program was created as an example to demonstrate the Aztec Remote UI capability. It is similar to the "MessageChat" script presented in the "Why - Event Handling" page. The UI looks and feels the same, but the underlying communication mechanism and data handling is completely different.

The MessageChat communication model has an Aztec Script running on each end of the "conversation", and the two scripts talk back and forth using Aztec remote messaging technology. For this Remote UI script, only one instance of an Aztec Script is executed. The script runs on the "client" machine, and the script connects to the remote UI Display Server over the network. The UI that appears on the server machine is generated and processed by the code running on the client machine. The script creates two almost identical chat dialogs. One gets displayed on the remote UI Display Server, and one gets displayed on the local display where the client script is executed. All processing of the data from both UIs gets done in the same client script.

The Aztec source code for this remote UI chat script is shown below.

#===================================================================================================
# Example Script: RemoteUIChat
# Demonstrates the use of Aztec remote UI technology to create a network chat program. This code
# runs only on the "client" and it displays a dialog on the client and on the server.
#===================================================================================================

# The "Main" class is derived from 'Thread'. System automatically creates it and invokes Run().
public class Main from<Thread>
{
public method Main()
{
}

#----------------------------------------------------------------------------
# This is the main Run method for the Script. The Aztec system automatically
# invokes this method in order to start execution of the Script. It builds
# and displays the main UI for the script and then immediately goes into an
# event waiting mode, never to return.
#----------------------------------------------------------------------------
public virtual method Run()
{
data<bool> Success = false
data<int> RemotePort
data<string> ErrorMessage
data<string> RemoteAddress

# Get the remote address and port from the command line (1st and 2nd "arg").
RemoteAddress = Script().GetArg(1)
RemotePort = Script().GetArg(2).Int()

# Create the Display object and try to connect to it.
if ( RemoteAddress.Len() > 0 )
{
RemoteDisplay = new<Display>
Success = RemoteDisplay.Connect(RemoteAddress,RemotePort)
}

# Create two separate chat objects - one for local and one for remote - and go into Event Mode.
if ( Success )
{
# Successfully connected to remote display, so create both chat windows.
LocalChatDialog = new<ChatDialog(self,GetDisplay(),true)>
RemoteChatDialog = new<ChatDialog(self,RemoteDisplay,false)>
}
else
{
# Not able to connect to remote display. Create local chat window, disable most controls, and display message.
if ( RemoteAddress.Len() > 0 )
ErrorMessage = "Unable to connect to remote display and port (" + RemoteAddress + "/" + RemotePort.Str() + ")."
else
ErrorMessage = "Remote display and port must be specified on command line (-arg)."

LocalChatDialog = new<ChatDialog(self,GetDisplay(),true,false,ErrorMessage)>
}

# Whether successful or error, at least one window gets displayed, so go into VM event mode.
EventMode()
}

#------------------------------------------------------------------------
# Method to be called from either of the ChatDialog objects when the
# Send button is pressed. We massage the message text and send it out to
# both of the ChatDialog objects to be embedded within the conversation.
# Depending on who sends it and which dialog we're sending it to, we
# prepend the message with text to indicate the source of the message.
#------------------------------------------------------------------------
method ProcessMessage(string Message,bool SourceIsLocal)
{
data<string> LocalSource = "Local: "
data<string> RemoteSource = "Remote: "
data<string> MassagedMessage

# Create the message for the local ChatDialog object and send it to it.
if ( SourceIsLocal )
MassagedMessage = LocalSource + Message
else
MassagedMessage = RemoteSource + Message

LocalChatDialog.UpdateConversation(MassagedMessage)

# Create the message for the remote ChatDialog object and send it to it.
if ( SourceIsLocal )
MassagedMessage = RemoteSource + Message
else
MassagedMessage = LocalSource + Message

if ( RemoteChatDialog != null )
{
RemoteChatDialog.UpdateConversation(MassagedMessage)
if ( SourceIsLocal )
{
RemoteChatDialog.UpdateAlertText("New message received")
}
}

# Update the Alert text box to tell the recipient there's a new message.
if ( !SourceIsLocal )
{
LocalChatDialog.UpdateAlertText("New message received")
}
}

#----------------------------------------------------------------------
# Method to be called from within the script to shut down the program.
# Close both frames (local and remote), though not necessary.
#----------------------------------------------------------------------
method ShutdownScript(string Message)
{
LocalChatDialog.CloseFrame()

if ( RemoteChatDialog != null )
{
RemoteChatDialog.CloseFrame()
RemoteChatDialog = null
}

Script().WriteLog(Message)
exit
}

#--------------------------------------------------------------------------
# Function to be called when remote dialog was closed. We close the remote
# dialog and then disable some of the local dialog.
#--------------------------------------------------------------------------
method ShutdownRemote(string Message)
{
# Disable messaging controls in local dialog, close remote dialog and close remote connection.
LocalChatDialog.DisableMessageInput(Message)
if ( RemoteChatDialog != null )
{
RemoteChatDialog.CloseFrame()
RemoteChatDialog = null

if ( RemoteDisplay != null )
{
RemoteDisplay.Close()
}
}
}

# Data items for the 'Main' Class - 'private' by default.
data<Display> RemoteDisplay
data<ChatDialog> LocalChatDialog
data<ChatDialog> RemoteChatDialog
}

#-----------------------------------------------------------------------------------------------
# The "ChatDialog" class is responsible for creating a chat window, displaying it (either
# locally or on a remote computer), and then processing events. The program will create two
# separate instances of this class - one for the local client and one for the remote UI.
#-----------------------------------------------------------------------------------------------
public class ChatDialog
{
#--------------------------------------------------------------------------------------
# Constructor for the Main class. Receives the target Display object. The caller is
# responsible for creating the Display object, and in the case of the remote UI,
# connecting to the remote Display Server.
#--------------------------------------------------------------------------------------
public method ChatDialog(Main MainThread, Display Target, bool IsLocal, bool RemoteConnectionSuccessful = true,
string ErrorMessage = "")
{
MainScriptThread = MainThread
TargetDisplay = Target
IsClosed = false
IsLocalDialog = IsLocal

# Build and display the chat dialog.
BuildChatDialog(RemoteConnectionSuccessful,ErrorMessage)
}

# This method is used to create the Chat Dialog for local and remote windows.
method BuildChatDialog(bool RemoteConnectionSuccessful, string ErrorMessage)
{
data<bool> ReadOnly = true
data<string> FrameTitle

if ( IsLocalDialog )
FrameTitle = "Local UI Chat Dialog"
else
FrameTitle = "Remote UI Chat Dialog"

# Create main window and the controls for the run-time options. Add Close and Resize handlers.
MainFrame = new<Frame(TargetDisplay,0,0,FrameWidth,FrameHeight,FrameTitle,true)>
MainFrame.AddWindowCloseHandler(MainFrameCloseHandler,null)
MainFrame.AddWindowResizeHandler(MainFrameResizeHandler,null)

# Create the "Conversation" box and associated text box (read-only). Use arbitrary size.
ConversationBox = new<GroupBox(MainFrame,TopBoxPosX,TopBoxPosY,10,10," Conversation ")>
ConversationEditor = new<Editor(ConversationBox,1,1,10,10,ReadOnly)>

# Create the "Message" box and associated text box (arbitrary size) and "Send" button (disable at startup).
MessageBox = new<GroupBox(MainFrame,TopBoxPosX,TopBoxPosY,10,10," Outgoing Message ")>
MessageEditor = new<Editor(MessageBox,1,1,10,10)>
MessageEditor.AddTextChangedHandler(MessageUpdateHandler,null)

SendButton = new<PushButton(MessageBox,1,1,ButtonWidth,ButtonHeight,"Send",null)>
SendButton.AddButtonClickHandler(SendHandler,null)
SendButton.Disable()

# Finally create the "Alert" text and the "Exit" button and attach the appropriate event handler.
AlertText = new<Text(MainFrame,1,1,10,10,"")>
ExitButton = new<PushButton(MainFrame,1,1,ButtonWidth,ButtonHeight,"Close",null)>
ExitButton.AddButtonClickHandler(ExitHandler,null)

#----------------------------------------------------------------------------
# If there was an error connecting to remote display, display error message
# on local window and gray out the messaging controls.
#----------------------------------------------------------------------------
if ( !RemoteConnectionSuccessful )
{
DisableMessageInput(ErrorMessage)
}

#--------------------------------------------------------------------
# Display the dialog and and all controls below it. Works the same
# way for the local and the remote UI. The UI framework handles all
# of the details.
#--------------------------------------------------------------------
SetUISizesAndPositions()
MainFrame.Show()
}

# Method to disable messaging controls in Local when error in Remote.
method DisableMessageInput(string ErrorMessage)
{
AlertText.SetWindowText(ErrorMessage)
MessageBox.Disable()
ConversationBox.Disable()
}

#--------------------------------------------------------------------------------------
# Takes a massaged message from the Main object and adds it to the Conversation
# editor control. This will be slightly different based on the source of the message
# and which ChatDialog is receiving it.
#--------------------------------------------------------------------------------------
method UpdateConversation(string Message)
{
# Simply add the string to the conversation editor control.
ConversationEditor.AddLine(Message)
}

#--------------------------------------------------------------------------------------
# Sends a message to the "other" chat dialog. We send it to the Main Script object and
# let it handle the details. It massages it based on who sent it, and then it gets
# sent back out to both ChatDialog objects to be embedded in the Conversation editor.
# Finally, we clear out the Message editor control within this dialog.
#--------------------------------------------------------------------------------------
method unique SendHandler(ButtonClickEvent ButtonEvent1,Base ExtraRef1)
{
data<string> Message

# Extract the message and send it to the main object for processing.
Message = MessageEditor.WindowText()
MainScriptThread.ProcessMessage(Message,IsLocalDialog)

# Clear the text in the Message editor control and disable Send button.
MessageEditor.SetWindowText("")
SendButton.Disable()
}

#-----------------------------------------------------------------------
# Event handler to get control when the Message field has been updated.
# We simply turn on the Send button. We will also clear out Alert text.
#-----------------------------------------------------------------------
method unique MessageUpdateHandler(TextChangedEvent ChangedEvent1,Base ExtraRef1)
{
SendButton.Enable()
UpdateAlertText("")
}

# Updates the "Alert" text box near the bottom of the window.
method UpdateAlertText(string AlertMessage)
{
AlertText.SetWindowText(AlertMessage)
}

# Event handler to get control when the Chat Dialog is closed.
method unique MainFrameCloseHandler(WindowCloseEvent CloseEvent1,Base ExtraRef1)
{
ShutdownChatDialog()
}


# Event handler to get control when the Chat Dialog is resized.
method unique MainFrameResizeHandler(WindowResizeEvent CloseEvent1,Base ExtraRef1)
{
# Resize and/or reposition all of the controls in the window.
SetUISizesAndPositions()
}

# Event handler to get control when the Chat Dialog is closed via the 'Close' button.
method unique ExitHandler(ButtonClickEvent ButtonEvent1,Base ExtraRef1)
{
ShutdownChatDialog()
}

#---------------------------------------------------------------------------------
# This method calls the associated shut down method from the Main Script Thread.
# if we're the Local dialog. If we're the remote dialog, then we'll hide ourself
# and then tell the Local dialog to disable messaging controls.
#---------------------------------------------------------------------------------
method ShutdownChatDialog()
{
data<string> Message

if ( IsLocalDialog )
{
Message = "Shutting down chat script - cancelled from local chat dialog."
MainScriptThread.ShutdownScript(Message)
}
else
{
Message = "Disabled chat communication - cancelled from remote chat dialog."
MainScriptThread.ShutdownRemote(Message)
}

}

method CloseFrame()
{
if ( !IsClosed )
{
MainFrame.Close()
IsClosed = true
}
}

#-----------------------------------------------------------------------
# Dynamically sets the position and size of the controls in the frame.
# Invoked when first shown and as a resize handler.
#-----------------------------------------------------------------------
method SetUISizesAndPositions()
{
data<int> ButtonX
data<int> ButtonY
data<int> BoxWidth
data<int> BoxHeight
data<int> FrameWidth
data<int> FrameHeight
data<int> TestFrameWidth
data<int> TestFrameHeight

data<int> const InnerGapX = 5
data<int> const InnerGapY = 5
data<int> const OuterGapX = 10
data<int> const OuterGapY = 10
data<int> const ButtonGapX = 10
data<int> const ButtonGapY = 7
data<int> const MinFrameWidth = 250
data<int> const MinFrameHeight = 250
data<int> const TextToButtonAdjustY = 3

#------------------------------------------------------------------------------
# First, determine width and height of frame to use for sizing other controls.
# We will only let the entire thing get so small, and will fix the dimension
# at the min value, regardless of actual size of the window.
#------------------------------------------------------------------------------
TestFrameWidth = MainFrame.Width()
TestFrameHeight = MainFrame.Height()

# Determine if we use the actual width or the min width for our "virtual frame".
if ( TestFrameWidth > MinFrameWidth )
FrameWidth = TestFrameWidth
else
FrameWidth = MinFrameWidth

# Determine if we use the actual height or the min height for our "virtual frame".
if ( TestFrameHeight > MinFrameHeight )
FrameHeight = TestFrameHeight
else
FrameHeight = MinFrameHeight

#----------------------------------------------------------------------------------------------
# Now we know the size that we're going to work with, so lay out the controls appropriately.
# Some will be moved (most controls and all buttons) and some will be resized. The group boxes
# and the Editor controls will grow in both directions as necessary.
#----------------------------------------------------------------------------------------------

# First, determine the width and height of the two group boxes. They will have same height.
BoxWidth = FrameWidth - (2 * OuterGapX)
BoxHeight = (FrameHeight - ((2 * ButtonGapY) + ButtonHeight + OuterGapY + TopBoxPosY)) / 2

# Do the top box first and its internal editor control.
ConversationBox.SetPos(TopBoxPosX,TopBoxPosY)
ConversationBox.SetSize(BoxWidth,BoxHeight)
ConversationEditor.SetSize(ConversationBox.Width(),ConversationBox.Height())

# Do the bottom box next, its internal editor control and the Send button.
MessageBox.SetPos(TopBoxPosX,TopBoxPosY + BoxHeight + OuterGapY)
MessageBox.SetSize(BoxWidth,BoxHeight)
MessageEditor.SetSize(MessageBox.Width(),MessageBox.Height() - (ButtonHeight + (ButtonGapY *2)))
SendButton.SetPos(1,MessageEditor.Height() + ButtonGapY + 1)

# Finally, modify the position of the Alert text (and size) and the Exit button.
ButtonX = FrameWidth - OuterGapX - ButtonWidth
ButtonY = TopBoxPosY + (BoxHeight * 2) + OuterGapY + ButtonGapY
AlertText.SetPos(OuterGapX,ButtonY + TextToButtonAdjustY)
AlertText.SetSize(ButtonX - (OuterGapX + ButtonGapX),ControlHeight)
ExitButton.SetPos(ButtonX,ButtonY)
}

# Data items for the 'ChatDialog' Class - 'private' by default.
data<Main> MainScriptThread
data<Display> TargetDisplay

data<Frame> MainFrame
data<GroupBox> ConversationBox
data<GroupBox> MessageBox
data<Editor> ConversationEditor
data<Editor> MessageEditor
data<Text> AlertText
data<Button> SendButton
data<Button> ExitButton

data<bool> IsClosed
data<bool> IsLocalDialog

data<int> const FrameWidth = 600
data<int> const FrameHeight = 500
data<int> const TopBoxPosX = 10
data<int> const TopBoxPosY = 15
data<int> const ButtonWidth = 75
data<int> const ButtonHeight = 25
data<int> const ControlHeight = 25
}

 

Page UpPage DownCopyright © 2010-2017
Aztec Development Group
All Rights Reserved

Download Aztec