wxLua is a Lua scripting language wrapper around the wxWidgets cross-platform C++ GUI library. It consists of two IDE type editors that can edit, debug, and run Lua programs (wxLua and wxLuaEdit), an executable for running standalone wxLua scripts (wxLuaFreeze), a Lua module that may be loaded using require("wx") when using the standard Lua executable, and a library for extending C++ programs with a fast, small, fully embeddable scripting language.

Lua is a small scripting language written in ANSI C that can load and run interpreted scripts as either files or strings. The Lua language is fast, dynamic, and easy to learn. Lua contains a limited number of data types, mainly numbers, booleans, strings, functions, tables, and userdata. Perhaps the most powerful feature of the Lua language is that tables can be used as either numerically indexed arrays or associative arrays that can cross-reference any variable type to any other variable type.

wxLua adds to this small and elegant language the power of the C++ wxWidgets cross-platform GUI library. This includes the ability to create complex user interface dialogs, file and image manipulation, drawing, networking, displaying HTML, and printing to name a few. You can use as much or as little of wxWidgets as you like and C++ developers can trim down the size the bindings by turning off preprocessor directives.

Additionally, wxLua adds a library for manipulating the bits of integer numbers using a back-ported bit32 library from Lua 5.2.

References:

wxLua website - http://wxlua.sourceforge.net
wxLua Sourceforge page - http://sourceforge.net/projects/wxlua
Lua website - http://www.lua.org
wxWidgets website - http://www.wxwidgets.org
Mailing list - wxlua-users@lists.sourceforge.net

Table of Contents

  1. Version Information
  2. Requirements
  3. Brief Introduction to Lua
  4. Bit Library
  5. Programming in wxLua
    5.1 Naming, location, and usage of the wxWidgets objects declared in the C++ header files in the wx Lua table
  6. wxLua Samples and How to Run Them
    6.1 How to Run the Samples
    6.2 Provided Samples
  7. wxLua Applications
    7.1 wxLua
    7.2 wxLuaEdit
    7.3 wxLuaFreeze
    7.4 Lua Module using require()
  8. wxLua Utils
    8.1 bin2c.lua
  9. wxLua Sourcecode Modules
  10. wxLua C++ Programming Guide
    10.1 Data stored in Lua's LUA_REGISTRYINDEX table
    10.2 Functions to Create a wxLuaState
    10.3 Using a wxLuaState

1 - Version Information

2 - Requirements

Lua programmers can use the binary packages of wxLua and everything that's needed is contained within it. C++ programmers or users on platforms that we don't provide binaries for will need a development library of wxWidgets; typically the source code that you have compiled on your system. More information about compiling wxLua is contained in the wxLua install.html file.

3 - Brief Introduction to Lua

This short primer is meant to give you a good enough feeling for Lua that you should be able to understand the sample programs and begin to write your own. It assumes that you have a cursory understanding of general programming techniques. You should, in any case, read the Lua documentation at www.lua.org.

        do
            -- create a new local scope
            local a = 2
        end
        local a, b, c = 1, 2, 3 -- can assign multiple values
        a = 1; b = 2; c = 3     -- use ; for multiple lines of code on single line
        a, b, c = 1, 2, 3       -- this works too

        if (a == 1) and ((b <= 2) or (c ~= 3)) then
            print(a+b/c)
        elseif a == 2 then      -- no parentheses necessary
            print(a)
        else
            print(b)
        end
        case = {}
        case[1] = function() print("Hello #1") end -- anonymous function
        case[2] = function() print("Hello #2") end
        ...
        if case[value] then
            case[value]()
        else
            print("Unknown case value")
        end
        function Check5(val) -- returns nil if val ~= 5
            if val == 5 then
                return true
            end
        end

        local a = 1
        while a < 10 do
            print(a)
            if Check5(a) then break end
            a = a + 1 -- no increment operator
        end
        local a = 0
        while a < 10 do while true do
            a = a + 1 -- no increment operator
            if Check5 (a) then
                break -- break in the inner while loop to "continue" in the outer loop
            else
                print(a)
            end

            break end -- break out of inner while loop
        end
        local a = 10
        repeat
            local temp = a * 2
            print(temp, type(temp))
            a = a - 1 -- no decrement operator
        until a < 0
        local a = "hello"
        for a = 1, 10 --[[, increment]] do -- optional increment value, default increment is 1
            local temp = a * 2
            print(temp)
        end

        print(a) -- a == "hello" since loop counter variable is local to the loop
        -- Print the keys in table t that have the given values.
        function PrintKeys(t, values, cmp_case)
            -- use nested functions for repetitive code or to simplify code
            local function cmp_values(a, b)
                if cmp_case then -- can use upvalue variables
                return a == b
                else
                    return string.lower(a) == string.lower(b)
                end
            end
            local function find_key(t, val)
                for k,v in pairs(t) do
                    if cmp_values(val, v) then return k end
                end
            end
            for i = 1, #values do
                print(find_key(t, values[i]), values[i])
            end
        end

        data = {a1 = "a2", b1 = "b2", c1 = "c2"}

        -- prints "a1 a2", "b1 b2", "nil C2"
        PrintKeys(data, {"a2", "b2", "C2"}, true)
        -- Varargs example demonstrating the different ways to handle them.
        function Varargs(...)
            local args = {...}
            print(select("#", ...), #{...}, #args, args[2], unpack({...}, 2, 2))
            return args, unpack(args) -- same as return ...
        end

        -- prints "4 4 4 20 20" and "table: 0183B820 10 30 5"
        vals, val1, _, val3 = Varargs(10, 20, 30, 40)
        print(vals, val1, val3, select("#", Varargs(10, 20, 30, 40)))

4 - Bit Library

wxLua automatically loads a library for manipulating the bits of an integer number and puts it into the global bit32 table. This is because wxWidgets often uses enumeration flags to control the behavior of functions and for compactly storing status information. You can easily "or" bits by adding them together and this is the preferred method, for example 0x02 + 0x04 = 0x06 or bitwise 0110. If the bits you're trying to "or" are not powers of 2 (perhaps one is a bit mask) this fails, 0x01 + 0x03 = 0x04 or bitwise 0100 (oops) instead of the desired 0011.

wxLua uses a bitlib library backported from Lua 5.2 and since the code for it is very small, it's embedded into the wxLua sourcecode.

All function arguments should be integers. The number of bits available for logical operations depends on the data type used to represent Lua numbers; this is typically 8-byte IEEE floats, which give 53 bits (the size of the mantissa).

The logical operations start with "b" for "bit" to avoid clashing with reserved words; although "xor" isn't a reserved word, it is consistent.

bit32.rshift(x, disp) - returns x shifted logically right disp places or left if negative
bit32.band(...) - returns the bitwise and of the input values
bit32.bnot(x) - returns the one's complement of x
bit32.bor(...) - returns the bitwise or of the input values
bit32.btest(ยทยทยท) - returns true if the and of the input values is not 0
bit32.bxor(...) - returns the bitwise exclusive or of the input values
bit32.extract(n, field [, width]) - returns the number of bits set in n for the given 0-31 starting field to optionally field+width-1
bit32.replace(n, v, field [, width]) - returns n with the bits in field to optionally field+width-1 replaced by the value v
bit32.lrotate(x, disp) - returns x rotated disp bits to the left
bit32.lshift(x, disp) - returns x shifted left disp places or right if negative
bit32.rrotate(x, disp) - returns x rotated disp bits to the right
bit32.rshift(x, disp) - returns x shifted right disp places or left if negative

5 - Programming in wxLua

Programming in wxLua means that you're writing programs in the Lua language using an additional table of functions, objects, numbers, strings, and "classes" in the namespace table wx from wxWidgets. Additional wxWidgets libraries are added as their own bindings and placed in their own "namespace" table, but for the examples below the wx table is used.

wxLua creates five Lua tables for the binding functions and objects. These are in addition to the standard Lua tables; coroutine, debug, io, math, os, package, string, table. Note that the wxaui and wxstc libraries have been separated into their own tables since they are fairly specialized libraries.

bit32 - A backport of the Lua 5.2 bit32 library for manipulating integer bits added to Lua 5.1.
wxlua - Special functions for introspecting wxLua or
generic functions that wxLua provides that are independent of wxWidgets.
wx - wxWidgets functions, classes, defines, enums, strings,
events, and objects are placed here.
wxaui - The wxWidgets Advanced User Interface library.
wxstc - The wxStyledTextCtrl wrapper around the Scintilla text editor.

The semantics for accessing wxWidgets elements in wxLua tries to map closely to the underlying C++ notation so that the official C++ documentation may be used as a reference, http://www.wxwidgets.org/docs. The most common cases where wxLua deviates from C++ are for functions with values passed by reference that will be changed; wxLua will typically return multiple values instead. Please see the wxluaref.html document that lists all the wxWidgets objects wrapped by wxLua and take note of the functions that are marked %override since you will need to use them as described in that document. You should also look at the binding.html file, even if you do not plan to write your own bindings, to get a better understanding of the wxluaref.html file.

Strings : wxLua does not typically use the wxString class for strings, rather it uses Lua strings. This means that all wxWidgets functions that take a wxString parameter take either a wxString userdata or preferrably a Lua string (Lua variables that are of type(var) == "string"). Functions that return wxStrings convert the value into a Lua string for convenience. The conversion from the Lua ANSI C 8-bit char* string to a wxString (which may be a Unicode wchar* string) is done internally.

wxArrayString and wxSortedArrayString : Function parameters that take a "const wxArrayString& arr" or "wxArrayString arr" will accept either a wxArrayString userdata or a Lua table that has numeric indexes and string values and convert it into a wxArrayString for the function call. If the function call is "wxArrayString& arr" or "wxArrayString* arr" you must provide a wxArrayString userdata since the C++ function will most likely modify the wxArrayString that's passed to it.

wxArrayInt : Function parameters that take a "const wxArrayInt& arr" or "wxArrayInt arr" will accept either a wxArrayInt userdata or a Lua table that has numeric indexes and numeric values and convert it into a wxArrayInt for the function call. If the function call is "wxArrayInt& arr" or "wxArrayInt* arr" you must provide a wxArrayInt userdata since the C++ function will most likely modify the wxArrayInt that's passed to it.

Coroutines : wxLua works with coroutines with one important caveat.
NEVER connect an event handler function callback from within a coroutine

  1. There is no way for wxLua to detect that a coroutine is closed until the garbage collector runs which is usually too late and the program crashes.
  2. The callback function will probably only be called when the coroutine is yielded and Lua throws an error for this condition.
  3. The one exception to this rule is if the whole wxLua program is run in a coroutine that never yields, which doesn't make typically make sense.

5.1 - Naming, location, and usage of the wxWidgets objects declared in the C++ header files in the wx Lua table

6 - wxLua Samples and How to Run Them

There are a number of sample programs in the wxLua/samples directory. These programs demonstrate how to write simple programs and try to show how to use some of the many classes of wxWidgets. They are a good resource to learn how to write your own more complicated programs.

We welcome any enhancements or additional samples that might be generally useful to the wxLua community. Please understand that any code you contribute has to be maintained and easily understood, so the code must be simple and clear.

If something in wxLua seems to not work as expected it is best to try to duplicate your error in the simplest possible way in one of the samples and ask on the wxlua-users@lists.sourceforge.net mailing list.

Why are the samples named sample.wx.lua? To allow them to be colorized correctly in syntax highlighting editors, yet denote to people that they are for wxLua and must be run using a wxLua executable or the wxLua module.

6.1 - How to Run the Samples

The examples below are for MS Windows .exe executables, but the same applies for Linux or OSX, just remove the .exe extension from the executable. See also wxLua Applications for more information about these programs. - On the command line run wxlua.exe sample.wx.lua - On the command line run wxluafreeze.exe sample.wx.lua - Open the Lua program in wxlua.exe and choose the menu item 'Run'. - Open the Lua program in wxluaedit.exe and select the menu item 'wxLua->Run' or press the toolbar 'play' button to run it. - Use wxLua as a Lua module using the function require("wx"), run lua.exe sample.wx.lua - In order to use wxLua as a module, the Lua code must have require("wx") to load the wxLua bindings in the beginning and wx.wxGetApp():MainLoop() at the end to run the wxWidgets event loop. - To be sure - From the command line you can create wxFrames or wxDialogs and populate them, but nothing will happen when you call Show() on them since the wxEventLoop is not running. - For example, run this code in the Lua console: - require("wx") - f = wx.wxFrame(wx.NULL, -1, "Title") - f:Show() - Note that the wxFrame is not shown or if it is you won't be able to use it... - wx.wxGetApp():MainLoop() - The wxFrame is now shown and you can interact with it nomally, but the Lua console prompt is hung in the MainLoop() function while wxWidgets processes events. When you close the wxFrame or the last top-level window, the MainLoop() exits and control is returned to the Lua console. - You can now create new wxFrames or wxDialogs, but you always have to call wx.wxGetApp():MainLoop() in order to use them.

-   You may need to adjust the `package.cpath`{.lua} variable to have it
    point to the correct location of the wx.so or wx.dll shared library
    for `require("wx")`{.lua} to load.

6.2 - Provided Samples

7 - wxLua Applications

The applications that wxLua provides are in the wxLua/apps directory. These are C++ programs that are compiled against the wxWidgets library and the wxWidgets wxStyledTextCtrl library.

8 - wxLua Utils

Utility programs for wxLua are located in the wxLua/util directory.

9 - wxLua Sourcecode Modules

wxLua is broken up into "modules" that are compiled into libraries so that you can choose to link to some or all of them. The directory structure of the modules dir is such that you need only add the #include path to wxLua/modules in your compiler settings and then in the code always write #include "modulename/optionalsubname/filename.h".

10 - wxLua C++ Programming Guide

The documentation for the wxLua library is in the header files and descriptions are given for each function, enum, etc. Please read through them to get a feel for what functions wxLua provides. Below is a brief synopsis of wxLua for C++ programmers.

Lua uses char strings while wxWidgets uses the wxString class which uses the wxChar data type. Depending on whether you have compiled wxWidgets in Unicode mode or not, wxChar can be either wchar or char. Therefore, wxLua uses the functions "wxString lua2wx(const char str)"* and "const wxCharBuffer wx2lua(const wxString& str)" to translate between the two. Note that wxCharBuffer can be used as a const char* string directly without any casting.

The core of wxLua is based upon a ref counted wxLuaState class derived from the wxWidget's wxObject class. The wxLuaState class contains as a member of its ref data the 'C' lua_State struct which is the heart of Lua. Since the class is ref counted, it should be passed as const wxLuaState& and can be used in much the same way as a wxBitmap, wxPen, or any of the other wxObject derived classes that make use of its ref counting mechanism. What this means for wxLua is that instead of keeping pointers to the lua_State you have instances of the wxLuaState, there is a slight overhead for this, but it is minimal. When the lua_State is closed, all the wxLuaStates sharing the ref data can check their ref data to see if the lua_State is NULL and segfaults from dangling pointers are avoided. The reason why this is a good idea is that wxWidgets has delayed wxWindow deletion and things can get out of order. Care must be taken for pushed event handlers from Lua because if the lua_State is closed, but the window hasn't been deleted just yet... It's best to have a way to check and the wxLuaState wraps this all up.

When the wxLuaState is Ok() the wxLuaState has its ref data and the lua_State is created. If it's not Ok() then most wxLuaState functions will assert in debug mode, so it's always best to compile in debug mode until you're sure things are working properly.

The wxLuaState contains all of the Lua 'C' functions, such as lua_gettop(lua_State* L), but as member functions named lua_GetTop() which use the internal lua_State and check for its validity before use. The functions are capitalized to make them easier to find in an editor. If you want the greatest performance just use wxLuaState::GetLuaState() and directly manipulate the returned pointer to the lua_State.

It is instructive to follow the creation of the wxLuaState by looking at bool wxLuaState::Create(wxEvtHandler handler, wxWindowID id) inwxLua/modules/wxlua/src/wxlstate.cpp*.

  1. The lua_State is created using lua_open() and then the standard Lua libraries are loaded, base, table, string, math, and so on using luaL_openlibs(L) as well as luaopen_bit(L) to open the bit32 library we use.
  2. The function wxLuaState::Create(L, wxLUASTATE_USESTATE) is called to finish setting up the lua_State.
    1. The wxObject::m_refData is created as a new wxLuaStateRefData(). This ref data class contains a pointer to the lua_State struct and to a shared wxLuaStateData class that is also created. If a Lua program running in this wxLuaState creates coroutines, each will have their own wxLuaStateRefData and associated lua_State, but they will all share the same wxLuaStateData class.
    2. The C lua_State is added to a hash table to allow looking up the owner wxLuaStateRefData when Lua calls the C wxLua binding functions with the lua_State as the only parameter. A new wxLuaState with the wxLuaStateRefData set using wxObject::SetRefData(), which does not "ref" the data, but simply sets it, is used since we do not want an extra "ref". The same wxLuaState is pushed into the LUA_REGISTRYINDEX table as a lightuserdata using the &wxlua_lreg_wxluastate_key as a secondary means to find the wxLuaState "owner" of the lua_State which will be used for coroutines since there is no way to determine when a coroutine (new lua_State) is created and then silently destroyed.
    3. The tables and values that wxLua uses to store information about the bindings or track its state are pushed into the LUA_REGISTYINDEX. Information about these items can be found in the next section.
    4. We register a print() function for Lua to get the output of Lua print() statements to send messages as wxLuaEvents, see wxEVT_LUA_PRINT.
  3. The bindings are registered by calling wxLuaState::RegisterBindings().
    • Each binding that is loaded are derived wxLuaBinding classes whose member data variables point to structs in each binding. A single static instance of each binding class are installed into a wxList when the wxLuaBinding_XXX_init() functions are called. The reason behind the need for running the init function from the binding libraries is to stop certain compilers from throwing out the whole binding library, which happens even if the binding was added to the list from within the library.
    1. Each binding has wxLuaBinding::RegisterBinding(...) called for it.
      • luaI_openlib(L, "binding_namespace", fake luaL_Reg, 0) ; is called to have Lua create the tables that we will install the bindings into. This allows wxLua to look like a standard Lua library even though it works a little differently.
        • LUA_REGISTRYINDEX["_LOADED"][binding_namespace] = table
        • LUA_GLOBALSINDEX[binding_namespace] = table
        • LUA_GLOBALSINDEX["package"]["loaded"][binding_namespace] = table
      • wxLuaBinding::DoRegisterBinding(...) is called to actually push the bindings into the "binding_namespace" table we've created in Lua.
  4. At the end of creation a wxLuaEvent is sent with the wxEVT_LUA_CREATION event type.

10.1 - Data stored in Lua's LUA_REGISTRYINDEX table

wxLua stores its bookkeeping data in the Lua's LUA_REGISTRYINDEX table that the wxLuaState creates and uses. The keys are const char* strings with its address pushed as a light userdata. Pushing the string itself requires that it be hashed and it was found to take a considerable amount of the total time of a function call. A list of all of the tables is at the top of the wxlstate.h header file.

10.2 - Functions to Create a wxLuaState

10.3 - Using a wxLuaState