MurgaLua Logo

murgaLua 0.6.6

Copyright (C) 2006-8 John Murga


User Guide & Reference




Version History

murgaLua 0.6.6

24th of March of 2008
Maintenance release ... Mostly upgrades and community driven fixes.

murgaLua 0.6.4

24th of February of 2008
The first FULL release for 2008 ... Special thanks to mikshaw and Tobi for their contributions.

murgaLua 0.6.0

20th of January of 2008
More of a maintenance release with several upgrades and bug-fixes.

murgaLua 0.5.5

30th of July of 2007
A consolidation of the 5.5 features plus some API changes and new features.

murgaLua 0.5.PREVIEW

30th of June of 2007
PREVIEW release that only went out to the forum users.

murgaLua 0.4.1

2nd of May of 2007
Patch release to tidy up the 0.4 release and provide MacOS support out of the box again.

murgaLua 0.4

2nd of April of 2007
Mainly a bugfix release although it contains a few interesting additions.
Coincides with the relocation of the web-site and the opening of a projects forum.

murgaLua 0.3

12th of January of 2007
The first public release since murgaLua 0.1.
Incorporates many separate improvements I have been able to make during the course of my travels.

murgaLua 0.2

Was created at a time when I was unable to update the documentation to reflect the changes.

murgaLua 0.1

24th of July 2006
Initial release

Introduction

Why do we need yet another platform ?

murgaLua was born from a frustration with the size and licensing of some of the development tools I have been using. I am a Java developer by trade, but for my personal projects I wanted something that was better to deploy, something that :

Now, there are many things on the market that fulfilled most of those criteria, however, there is nothing that fulfills all of them or that comes close in terms of size.

So I decided to see what I could do ...

And what did I do ?

The first step was to find a core language that was small, easy to learn, portable, and that had advanced features.

I settled on Lua (http://www.lua.org/), it is popular in the embedded and game development space and appeared to be easy to bind to.

The next step was finding bindings that where rich and small enough, I found that the Lua community had done most of that work for me :

When it came to my XML requirements I found nothing that really addressed my needs (in terms of size and speed), so I adapted some code I had seen for TinyXML and made it the foundation for my new binding, which I am still adding to right now.

GUI was the next problem, and it didn't seem easy to solve ... However, I stumbled across lua-fltk (http://lua-fltk.sourceforge.net/), and this proved to me that a tiny runtime for both Linux and Windows WAS possible with FLTK. Unfortunately the existing bindings where VERY basic and out of date and there was nothing I could use, as I wanted something that would work with new versions of FLTK and Lua and that I could improve ... So I hacked around and knocked up my own binding.

Having settled on FLTK I wondered if it may be possible to use it's basic GUI builder (FLUID) to generate my code, and much my to my surprise after less than an hour I had written a utility to convert it's generated code to my new murgaLua bindings.

My objective was complete.

So what's actually included ?

The murgaLua distribution includes all required binaries along with examples and all the source and documentation for my code and used libraries.

Basically everything you could need for developing with murgaLua.

This is what's in this archive :

If for any reason you want to rebuild murgaLua or port it to another platform you'll also need the following :
For your convenience I have mirrored the files at :

http://www.murga-projects.com/murgaLua/files/

A support forum and improved documentation will follow.

How do I install / deploy it

Well ... There isn't really any installing, just extract the archive and run the executable for your platform.

Under Windows I would recommend installing MSys (http://www.mingw.org/msys.shtml) or Cygwin (http://cygwin.com/) to get BASH, RXVT and all those nice UNIX things that Windows lacks.

Under Linux I'd recommend copying the murgaLua executable to "/usr/bin", this way you'll be able to add "#!/usr/bin/murgaLua" at the start of your scripts and CHMOD them so that they can run as normal UNIX scripts.

A walk through

Crash course in LUA

Lua is a lean programming language that combines simple procedural syntax with powerful constructs for handling data and extensible semantics. It is also dynamically typed, which releases you from the burden of declaring variables, and has advanced features like automatic memory management and garbage collection to make sure your programs still run well.

Another neat thing about Lua is that it provides meta-mechanisms for implementing features instead of bloating itself with too many features to remember. For example, Lua is not a object-oriented language, but it provided mechanisms for implementing classes and inheritance if its a feature that is important to you.

Tables deserve special mention, as they really are the foundation for data storage in Lua. You can write pseudo-classes with them, they can be arrays, they are FAST, they can be pretty much whatever you want and the syntax to manipulate them is pretty cool.

Anyway, an in-depth discussion on the syntax and usage of Lua is out of the scope of this document ... And people have explained it better than I could have. Have a look at the following links :

A nice overview from the always great Wikipedia :
http://en.wikipedia.org/wiki/Lua_programming_language

A cool tutorial from the DeveloperWorks web-site :
http://www-128.ibm.com/developerworks/library/l-lua.html?ca=drs-

An overview to the language by the people who created Lua :
http://www.lua.org/spe.html

The official manual :
http://www.lua.org/manual/5.1/

This is an online version of the first edition of the "Programming in Lua" book :
http://www.lua.org/pil/ (Or buy the new edition - http://www.inf.puc-rio.br/~roberto/pil2/)

Tables deserve a few tutorials of their own :
http://lua-users.org/wiki/TablesTutorial
http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=6036

Your first program

I guess your first program would have to be the ubiquitous "Hello World".

If you think it kinda sucks you may want to skip to the next tutorial :-)

If not, so open up a file in the directory you extracted this archive to (normally named "murgaLua").

And type the following :


fltk.fl_message("Hello Word")
print("Hello World")


Save the file as "helloWorld.lua", and then run at the prompt :

bin/murgaLua helloWorld.lua


REMEMBER - If you are running in Windows the slash ("/") goes the other way, so do "bin\murgaLua".

Anyway, you'll see a nice FLTK message box with "Hello World", and the same on the standard Lua console output.

Linux users may want to copy "murgaLua" to "/usr/bin", and put the following as the first line of the program :
#!/usr/bin/murgaLua


Not you can make the script executable (chmod), and run it like a standard Linux utility.

Something more serious

So that last example was kinda lame ... How about a nice window and some buttons ?

OK, create a file called "step1.lua" and type this code in :


window = fltk:Fl_Window(505, 145, "My first little app")

fltk:Fl_Button(5, 5, 310, 135, "My First Button")
fltk:Fl_Button(320, 65, 180, 35, "Load a picture")
fltk:Fl_Button(320, 105, 180, 35, "Quittin Time")

window:show()
Fl:run()


Now run the file like we did before ("bin/murgaLua step1.lua") ...

This is what you should see :

Step 1


Umm, OK ... We now have a basic UI.

It should be fairly obvious how we created the buttons : we looked up "Fl_Window", and "Fl_Button" in the FLTK reference and found the parameters we needed.

Then we worked how where and how big we wanted everything and put the calls together ...

There is a much better/faster way to do this ... But that's in the next tutorial :-)

Anyway, those controls don't do anything yet, so copy your file to "step2.lua" and make the changes below (marked in red) :


window = fltk:Fl_Window(505, 145, "My first little app")

-- Step one, we have to assign our button to a variable in order
-- to be able to do things with it ...
firstButton = fltk:Fl_Button(5, 5, 310, 135, "My First Button")
fltk:Fl_Button(320, 65, 180, 35, "Load a picture")
fltk:Fl_Button(320, 105, 180, 35, "Quittin Time")

-- Step two, add a slider and get it change another control
slider = fltk:Fl_Slider(320, 10, 180, 30, "Size Me")
slider:type(1)
slider:range(5, 55)
slider:step(1)
slider:value(firstButton:labelsize())

slider:callback(
function(slider)
firstButton:labelsize(slider:value())
firstButton:label("My size is " .. slider:value())
firstButton:redraw()
end)

window:show()
Fl:run()


If you made the changes correctly you should be able to run the file and see the following (try moving the slider) :

Step 2

So now we have added some behavior, as you see we had to assign our controls to variables in order to anything with them.

Still not very impressive ... Let's try to put some more complex behavior in there.

Copy your file to "step2.lua" and make these changes (marked in red again) :


window = fltk:Fl_Window(505, 145, "My first little app");

firstButton = fltk:Fl_Button(5, 5, 310, 135, "My First Button");
-- Step three, we name everything
loadImage = fltk:Fl_Button(320, 65, 180, 35, "Load a picture");
quitButton = fltk:Fl_Button(320, 105, 180, 35, "Quittin Time");

slider = fltk:Fl_Slider(320, 10, 180, 30, "Size Me");
slider:type(1)
slider:range(5, 55)
slider:step(1)
slider:value(firstButton:labelsize())

slider:callback(
function(slider)
firstButton:labelsize(slider:value())
firstButton:label("My size is " .. slider:value())
firstButton:redraw()
end)

-- Step four, add a callback that we can share.
function quit_callback(object)
if fltk.fl_ask("Are you sure ?") >= 1 then
window:hide()
end
end

-- Step five, assign the callback to two objects.
window:callback(quit_callback)

quitButton:callback(quit_callback)

-- Step six, create a callback function to play with pictures
function loadImage_callback(object)
-- Required before we can use some of the image APIs
fltk.fl_register_images()
-- Open a nice file chooser to pick an image.
fileName = fltk.fl_file_chooser("Choose a picture", "Image Files (*.{bmp,gif,jpg,png})", nil, nil)
-- Load and create an image object
image = Fl_Shared_Image.get(fileName)
-- Assign it to a control and make sure the UI portion is redrawn.
firstButton:image(image)
firstButton:redraw()
end

-- Step seven, assign the image load function to the "Load a picture" button
loadImage:callback(loadImage_callback)

window:show()
Fl:run()



Now when you run the program click on the "Load a picture" button and choose the "examples/littlePic.gif" file ... You should see this :

Step 3

OK, now this a little more like it, we created a little function to choose and load a picture and we displayed it in one of our controls.

We are also using two dialogs (asking a question, and choosing a file), and we hooked into the window so that we can ask the user if he really wants to exit.

Now lets see if we can make this whole UI design easier (on to FLUID) ...

Advanced techniques

Using FLUID to generate our UI

Although being able to use FLTK from within Lua is great it is a pain to have to learn all those widgets and work out the coordinates and sizes ...

Wouldn't it be nice if we could use the UI designer FLTK has to create our UI's ?

The problem is that FLTK is a C++ toolkit, and as a consequence C++ is what FLUID generates.

Enter "convertFluidToMurgaLua" ... My effort at a generic FLUID C++ to Lua converter :-)

So far it's worked with all the UI's I've created, so lets take a look at how to create UI's in FLUID for Lua.

Run the FLUID executable that you'll find in "bin", and you should see something like this :

The FLUID UI

Note : It is all too easy to "loose" the widget bin, in this case go to the "Edit / Show Widget Bin" menu or hit CTRL-B.

Anyway, the FLTK distribution contains a tutorial on how to use FLUID, but in order to use it for LUA code generation you'll be better off following these simple instructions. Lets go through it step-by-step ...

Creating the Window

  1. First of all start FLUID (duh!)
  2. Click the "Function" button in the "Widget Bin".
  3. Just press OK in the "Function/Method Properties" dialog that appears.
  4. Now click the "Window" button in the "Widget Bin".
  5. Double click inside the new window that was created.
  6. Type "My first window" as the "Label:" for the new window.
    (You may want to re-size the created window so you can see the title).

The FLUID UI 2

And now it's time to :

Put some stuff on the window :

  1. Lets start by making sure we have clicked back on the window we created.
  2. Click the "Return Button" button in the "Widget Bin", enter a caption of "A return button", press ENTER, and resize according the the screen shot.
  3. Click the "Check Browser" button in the "Widget Bin", enter a caption of "Some Choices", press ENTER, and and resize to allow room for the input field.
  4. Now click the "Input" button in the "Widget Bin" and press ENTER,.
  5. Place the input button between the "Check Browser" and the "Return Button" so that things look like the do in the screen shot.
  6. Try double clicking on the input field, you'll see that the "Properties" dialog comes up, you can lose it again by pressing ENTER.

The FLUID UI 3

Create the files

OK, now you can save your design and generate the C++ :

Now we have C++ code we can generate LUA from it, go to the command line and try the following (if you saved to the "examples" directory) :


$ ../bin/Windows/murgaLua.exe ../tools/convertFluidToMurgaLua.lua MyApp.cxx > MyApp.lua
$ ../bin/Windows/murgaLua.exe MyApp.lua


The first command creates a LUA file from the C++ file.

So after running the second line you should see something like this (depending on your design) :

Our program

The contents of "MyApp.lua" should be something like this :


do local object = fltk:Fl_Double_Window(166, 165, "My App");
window = object;
fltk:Fl_Return_Button(5, 130, 155, 30, "A return button");
fltk:Fl_Check_Browser(5, 5, 155, 70, "Some choices");
fltk:Fl_Input(5, 95, 155, 30);
end
window:show();
Fl:run()


The next thing is to put some logic ... Make the UI do something.

For example we could :

  1. Name the objects so that can manipulate them (as seen in previous examples).
  2. Add some values to the controls.
  3. Maybe add some callback logic so that we can see things happen.

After about 5 minutes things would look like this :


do local object = fltk:Fl_Double_Window(166, 165, "My App");
window = object;
fltk:Fl_Return_Button(5, 130, 155, 30, "A return button");
-- Step one, name the objects
myOptions = fltk:Fl_Check_Browser(5, 5, 155, 70, "Some choices");
myField = fltk:Fl_Input(5, 95, 155, 30);

-- Step two, add some values to the check browser ...
myOptions:add("Shower and shave")
myOptions:add("Breakfast")
myOptions:add("Watch TV")
myOptions:add("Go to work")
myOptions:add("Call the plumber")

-- Step tree, put in some code to react to a value-change
myField:callback(
function(myField)
fltk.fl_message("Changed the value to \"" .. myField:value() .. "\"")
end)
end
window:show();
Fl:run();


This is a simple example, and hopefully took just a few minutes to complete.

Once you have the code above you should see the following when running it.

Our program

Now on to something more complicated.

Let's build a tiny network chat application

This is a tutorial I haven't had time to write yet ... However, the code was so easy that it didn't take long.

You'll have to run two instances of this program, one as a server (first), and then one as a client.

Here is the code :


#!/usr/bin/murgaLua

-- Define the constants
host = "127.0.0.1"
port = 6969

-- Ask what mode we want to run in
if fltk.fl_choice("Are you a client or a server (start the server first)",
"Client", "Server", nil) >= 1
then
server = assert(socket.bind("*", port))
serverMode = "server"
fltk.fl_message("Chat window will appear when a connection is received\n" ..
"Listening on PORT : " .. port .. "...")
print ("Listening on PORT '" .. port .. "', please connect with a client.")
io.flush()
client = server:accept()
else
client = assert(socket.connect(host, port))
serverMode = "client"
end

-- If you are going to use a callback it has to be defined before it's used.
function quit_callback(w)
if fltk.fl_choice("Are you sure you want to EXIT ?", "No", "Yes", nil) >= 1 then
window:hide()
os.exit()
end
end

window = fltk:Fl_Window(295, 132, "Tiny Chat " .. serverMode)
window:callback(quit_callback)

messageInput = fltk:Fl_Input(5, 80, 285, 25);
messageOutput = fltk:Fl_Browser(5, 5, 285, 70);
quitButton = fltk:Fl_Button(230, 105, 60, 25, "Quit");
sendButton = fltk:Fl_Return_Button(5, 105, 70, 25, "Send");

quitButton:callback(quit_callback)

sendButton:callback(
function(sendButton)
messageOutput:add("Sent : " .. messageInput:value())
messageOutput:bottomline(messageOutput:size())
assert(client:send(messageInput:value() .. "\n"))

messageInput:value("")

end
)

window:show()

-- client:setoption("tcp-nodelay", true)
client:settimeout(0.10)

while 1 do

line, err = client:receive('*l')

if (line)
then
messageOutput:add("Recv : " .. line)
messageOutput:bottomline(messageOutput:size())
end

Fl:check()
Fl:wait(1)

end


The eagled eyed who've looked at the FLTK docs will have noticed that there is a "Timeout" mechanism that seems better suited to this kinda thing ... However, I that is part of the 5% of FLTK that I haven't ported yet, so you'll have to wait until the next release to use it ;-).

Anyway, here is what the app above looks like :

tinyChat

Things to watch out for

I have implemented most of the FLTK API, except for the GL functions and an ever decreasing set of methods.

Although there are about 130 methods on my list they represent an insignificant portion of the FLTK API (apart from timeout functions, which I'd like to support in a future release).

For more info on what's available in FLTK look here.

Reference

XML functionality

saveToXml( fileName, variableName )

Usage:


local table_1 = {firstVar=1; secondVar=2; thirdVar="abc"}
local myVar = "This is a string"
local table_2 = {myVar, "Test String", true, table_1}

local myTable = {firstKey="simpleItem"; secondKey=table_2}

murgaLua.saveToXml("foo.xml", myTable)


As we see in the example we have defined a series of data structures and wrapped a table around them ...

And the function allows you to save all this data to a human readable XML file.

loadFromXml( fileName )

Usage:


local loadedTable = murgaLua.loadFromXml("foo.xml")


Returns a table will all the data just like we saved it before.

importXmlFile( fileName )

Usage:


local xmlTable = murgaLua.importXmlFile("test.xml")

print( "Root Element Name : " .. xmlTable[1].name )


Loads and parses any valid XML file (see xmlImport.lua test).

importXmlString( fileName )

Usage:


local xmlTable = murgaLua.importXmlString("<test height=2>text</test>")

print( "Element Name     : " .. xmlTable[1].name )
print( "Element contents : " .. xmlTable[1][1])
print( "Attribute Name   : " .. next(xmlTable[1].attr))
print( "Attribute Value  : " .. xmlTable[1].attr[next(xmlTable[1].attr)])


Loads and parses any valid XML file (see xmlImport.lua test).

exportXml( xmlTable, fileHandle )

Usage:


diskfile = io.open("test.xml", "w")
murgaLua.exportXml(xmlTable, diskfile)
diskfile:close()


Saves the structure created by importXml* ... This has to be better documented (see xmlImport.lua test).

exportXml( xmlTable, fileHandle )

Usage:


diskfile = io.open("test.xml", "w")
murgaLua.exportXml(xmlTable, diskfile)
diskfile:close()


Saves the structure created by importXml* ... This has to be better documented (see xmlImport.lua test).

findXmlNode( xmlTable, pathToNode )

Usage:


subStruct = murgaLua.findXmlNode(xmlTable, "/example/subStruct")


Allows you to search for the part of the XML table that you are interested in (see xmlImport.lua test).

findNextXmlNode( xmlTable, pathToNode )

Usage:


subStruct = murgaLua.findXmlNode(xmlTable, "/example/subStruct")
repeatingNode = murgaLua.findNextXmlNode(subStruct, "repeatingNode")


Allows you to get nodes that repeat inside an XML structure (see xmlImport.lua test).

Utility functions

These functions are included to ease debugging and make filtering tables a little easier.

getHostOsName()

Usage:


murgaLua.getHostOsName()


Returns the OS murgaLua was build for, currently one of "linux", "windows" or "macos".

sleep(miliseconds)

Usage:


murgaLua.sleep(1000)


Sleeps for the specified number of miliseconds without taxing the system.

newIoString()

Usage:


function write_squares_table(file)
  for i = 1,10 do
    file:write(i, " ", i*i, "\n")
  end
end

-- write to file:

diskfile = io.open("squares", "w")
write_squares_table(diskfile)
diskfile:close()

-- write to string:

stringfile = murgaLua.newIoString()
write_squares_table(stringfile)
print(stringfile:getstring())


Creates a new iostring - need to document more (see xmlImport.lua test).

createFltkTimer()

Usage:


timer = murgaLua.createFltkTimer()
timer:callback(sleep_callback)


Allows you to do neat timing tricks on FLTK (needs more documentaion), (see timerTest).

printDebug( table, indentLevel )

Usage:


murgaLua.printDebug(myTable)


Will navigate the whole table and print ALL of it's contents, which can be pretty useful for debug purposes.

filterTable( path )

Usage:


copyTable = murgaLua.filterTable (myTable, function)


Returns a table containing the data for which the function returns "true" :


myTable =
{
bob = { age = 22, sex = "male", surname = "Smith" },
tracy = { age = 25, sex = "female", surname = "Smith" },
john = { age = 32, sex = "male", surname = "Murga" },
}

copyTable = murgaLua.filterTable (myTable, function (myValue) return myValue.surname == "Smith" end)
murgaLua.printDebug(myTable)


The output of which would be :


[tracy] => table
(
[surname] => Smith
[age] => 25
[sex] => female
)
[bob] => table
(
[surname] => Smith
[age] => 22
[sex] => male
)

Courtesy of our other new function printDebug (see murgaLuaLib.lua example).

Networking and Database APIs

Need to work on this

Test programs can be found here.

Here are the links to the included documentation :

The modified source for these two Lua bindings is included in the murgaLua distribution.

Copas and LuaFileSystem

Need to work on this

Copas documentation is here.
LuaFileSystem documentation is here.

Other interesting stuff

Nothing here yet.