The lua source code, the C code to turn lua code into application and the makefile (linux and Windows/mingw) @end itemize
The windows version can be compiled using MINGW environment, which is completely based on free software.
"Porting" the demo application from Linux to Windows required no changes to the code, and only minimal changes to the makefile.
2. Getting started
- Download the mnooxxx_tar.bz package from luaforge.net. http://www.luaforge.net/frs/?group_id=156
- Unpack with bzip2 -dc mnooxxx_tar.bz2 | tar -xvf -
- On windows, remove the .so file from the lib folder
- Windows (from a cmd prompt)
| lua50/bin/win32/lua50.exe mnoo_fltk_test.lua
|
- Linux
| lua50/bin/Linux24/lua50 mnoo_fltk_test.lua
|
3. Using mnoofltk using standard lua executable (via loadlib)
"mnoofltk" can be loaded through the standard "lua" interpreter, provided that loadlib support has been compiled in. This is mostly useful for development.
On Windows it is essential that the mnoofltk library has been compiled against the correct luaXX.dll. The download includes the standard lua 5.0.2 binary, provided by the luabinaries project.
In order to find the libraries, lua must be started from a path that contains
- The folder mnoo_current and its contents
- The folder lib including the correct library.
For example, the following program is run with
| -- ########################################################################################
-- # mnoofltk_simple: Test/demo program for mnoo_fltk
-- ########################################################################################
-- ########################################################################################
-- # Load library
-- ########################################################################################
local mnoofltk=require("mnoo_current/mnoofltk.lua")
-- set scheme (optional)
mnoofltk.fltk:scheme{name="plastic"}
-- ########################################################################################
-- # Create window and handle close event
-- ########################################################################################
local run=true
local w=mnoofltk.window:new{
x=100, y=100,
w=100, h=40,
callback=function(arg)
if arg.eventType=="close" then
if mnoofltk.fltk:ask{text="do you want to quit?"} > 0 then
run=false
end
end
end,
data=0
}
-- ########################################################################################
-- # Create a button and callback function
-- ########################################################################################
w:button{
label="a button",
x=0, y=0,
w=100, h=40,
callback=function() mnoofltk.fltk:message{text="Hello World"} end,
data=0
}
-- ########################################################################################
-- # Show the window and run the main loop
-- ########################################################################################
w:show{}
while run do
mnoofltk.fltk:wait{time=999}
end
|
This is the result:
4. mnoofltk concepts
4.1 Inheritance
Both FLTK and mnoofltk follow the object oriented approach, and make heavy use of inheritance.
As a consequence, functionality that is common to a whole class of widgets are implemented in a common class, and available in all classes, that are directly or indirectly derived from "class widget".
For example, the functionality to get position and size of a widget (my_w:getx{}, my_w:gety{}, my_w:getw{}, my_w:geth{}) are defined in class widget, and available for buttons, windows etc.
The picture is taken from the FLTK manual and shows the dependency between some of the classes:
4.2 Main loop
Usually, a GUI-driven application gives the control back to the GUI library, once it has started up.
The GUI library responds to user actions by notifying the application through callbacks.
When an application callback function is finished, it returns control back to the GUI library.
In mnoofltk, the "easy" way to achieve this is to call
after everything is started up. It will run forever, or until the last window is destroyed.
A second approach, that gives the program more control, is
| while true do
mnoofltk.fltk.wait{time=0.1}
(...)
end
|
The wait function will return after no more than 100 ms, OR FOR ANY FLTK EVENT (such as mouse move, expect that the code in (...) gets executed a lot!)
4.3 Callbacks
The standard approach to callback functions in mnoofltk is as follows:
Every widget with callback functionality expects a callback function and an arbitrary (non-nil) data argument in its constructor.
When mnoofltk executes the callback function, there is one argument "arg" of type "table".
arg.data contains the given data element (which may be a table, to pass arbitrary amounts of information to the callback).
The other entries in "arg" depend on the widget. For example, checkbuttons and entries return a "value" field.
Note that unlike in fltk, the widget itself is not passed to the callback. A possible workaround is
| local my_button
my_button=my_window:button{x=... callback=function() my_button:do_something{} end}
|
Often, there is one callback function for each widget.
When the size of your application grows, it may be a good idea to use only one callback function for many widgets, and identify the purpose of the call through the "data" tag.
4.4 Relationship between parent / child widgets
One significant difference between FLTK and mnoofltk is the creation of widgets:
In mnoofltk, the only constructor for a widget without a parent is mnoofltk.window:new{...}.
All other widgets are created explicitly "into" a parent widget, for example
| local my_button=my_window:button{...}
|
In other words, all constructors except window are found in class "group", which is the "smallest common denominator" of all container widgets.
5. Class reference
Both mnoofltk library and the manual are work in progress. Chances are, that the manual is not 100 % up-to-date.
In case something does not work, please read the library generator top level file: mnoofltk/build_mnoofltk.lua
It contains a complete list of all library functions, and the use of named arguments makes it almost "human-readable"...
5.1 class mnoofltk.fltk
5.1.1 FLTK mainloop
5.1.1.1 mnoofltk.fltk:wait{time=num}
Runs the FLTK main loop, and returns after x seconds or earlier (for example when the mouse is moved).
5.1.1.2 mnoofltk.fltk.run{}
Runs FLTK main loop, and returns only when all windows are closed. Use wait{} for more control over the application.
5.1.2 Drawing functions
Unless stated otherwise, the following functions may only be used in a redraw callback (canvas). Clipping is automatically enabled.
5.1.2.1 mnoofltk.fltk.begin_line{}
Starts a line
5.1.2.2 mnoofltk.fltk.end_line{}
Ends a line
5.1.2.3 mnoofltk.fltk.vertex{x=num, y=num}
Places a vertex, between begin_line{} and end_line{}
5.1.2.4 mnoofltk.fltk.rgb_color{red=num, green=num, blue=num} returns color
num=0..255
Returns a color (lua type is number) according to the given RGB values. Can be used anytime (not limited to redraw callback).
5.1.2.5 mnoofltk.fltk.set_color{color=color}
Sets the given color (use rgb_color to create one)
5.1.2.6 mnoofltk.fltk.rect{x=num, y=num, w=num, h=num}
Draws and fills a rectangle with the given color.
5.1.3 Common dialogs
5.1.3.1 mnoofltk.fltk.message{text=string}
5.1.3.2 mnoofltk.fltk.ask{text=string}
5.1.4 Other
5.1.4.1 scheme
Default scheme
mnoofltk.fltk:scheme{scheme='plastic'} result in:
5.2 class mnoofltk.widget
Many classes (buttons etc) are derived from the widget class, but a widget as such cannot be instantiated.
5.2.1 widget:getx{}, widget:gety{}, widget:geth{}, widget:getw{}
Returns position (top left corner), width, height of a widget.
Note: getw{} and geth{} may give not the expected result, if a window hasn't actually been shown and drawn yet.
5.2.2 widget.color{color=color}
Change the color of a widget.
5.2.3 widget:label{label=string}
Change the label of a widget or title of a window.
5.2.4 widget:redraw{}
Flags a widget for redraw. This is only needed in special cases (when the content of a canvas should be redrawn, or when child widgets have been removed).
5.2.5 widget:delete{}
Destroys a widget. The lua variable may not be used anymore (SEGFAULT!). Use with caution.
5.3 class mnoofltk.button
Derived from widget class (inherits all functionality).
5.3.1 Creating button object
Button objects are created using the group:button{x=num, y=num, w=num, h=num, callback=fun, data=any, label=string} constructor (the button becomes then a child of the given group).
Callback is triggered, when the button is clicked. Its argument is a table {data=data}.
5.4 class mnoofltk.checkbutton
Derived from widget class (inherits all functionality).
5.4.1 Creating checkbutton object
Checkbutton objects are created using the group:checkbutton{x=num, y=num, w=num, h=num, callback=fun, data=any, label=string} constructor, and the new checkbutton becomes then a child of the given group.
5.4.2 Callback
Callback is triggered, when the button is clicked. Its argument is a table {data=data, value=num} value either 0 or 1.
5.4.3 checkbutton:set_value{value=num}
Sets (value=1) or clears (value=0) the checkbutton.
5.4.4 checkbutton:get_value{} returns num
Returns 0 or 1, depending on the state of the button.
5.5 checkbutton class mnoofltk.checkbutton
Derived from widget class (inherits all functionality).
5.5.1 Creating menubutton object
Menubutton objects are created using the group:menubutton{x=num, y=num, w=num, h=num, label=string} constructor, and the new menubutton becomes then a child of the given group.
5.5.2 checkbutton:add{label=string, callback=fun, data=any}
Adds a new entry to the button. Each entry may have its own callback function.
5.5.3 Callback
Callback is triggered, when an entry is selected. Its argument is a table {data=data}.
5.6 class input
Derived from widget class (inherits all functionality).
5.6.1 Creating input object
Input objects are created using the group:input{x=num, y=num, w=num, h=num, callback=fun, data=any, label=string} constructor, and the new input becomes then a child of the given group.
5.6.2 Callback
Callback is triggered, when the input is changed and loses focus (curiously, both RETURN and TAB do not always work, but clicking with the mouse somewhere into the window will). The callback argument is a table {data=data, value=string}.
5.6.3 input:set_value{value=string}
Sets the widget content.
5.6.4 input:get_value{} returns string
Returns the widget content.
5.7 class choice
A drop-down list that shows "choices". The last choice selected remains visible.
The FLTK choice is a quite complicated widget, and has a lot of built-in functionality (for example, entries with an existing name are overwritten).
Every entry has an index, and the first element appears at index 1.
5.7.1 Creating choice object
Choice objects are created using the group:choice{x=num, y=num, w=num, h=num, callback=fun, data=any, label=string} constructor, and the new choice becomes then a child of the given group.
A newly created choice object shows a blank entry, but it is not recommended to rely on this functionality (once a value has been selected, there is no way to set it back to blank but to remove and rebuild the whole widget). Therefore it is recommended to use choice:set_index{index=1} once an entry has been added.
5.7.2 Callback
Callback is triggered, when the choice is changed by the user. The callback argument is a table {data=data, value=string, index=num}.
5.7.3 choice:get_index{} returns num
Returns the currently selected index.
5.7.4 choice:set_index{index=num}
Choose the entry that matches the index.
5.7.5 choice:add{text=string} returns num
Adds a new entry. All entries must be different, otherwise results are undefined. Returns the index of the added entry, beginning with 1.
Entries that contain slashes will be grouped into submenus.
5.7.6 choice:clear{}
Deletes all entries.
5.8 group class
Resize, remove, clear, plus the constructors for all widgets. Todo...
5.9 tabs class
Notebook-style widget that allows to put several pages into one window. Todo...
5.10 canvas class
Blank area that allows arbitrary drawing. Has two separate callbacks for redraw and events (mouse click / move, keyboard events etc). Todo...
5.10.1 Callback
The canvas has two separate callbacks for redraw and events (mouse click / move, keyboard events etc).
5.11 window class
5.11.1 constructor
| w=mnoofltk.window:new{x=100, y=100, w=640, h=480, callback=function() end, data=0}
|
show, hide, size_range, label, delete. Todo...
6. Shipping a finished application
It requires only a screenful of code to pack the lua interpreter and required lua files into a single executable.
Here is an example (standalone_demo/main.c) (plus the Makefile).
All involved lua files are first converted into bytecode using luac (in the right order!), and then packed into a C header file (generated.h) via bin2c.
Each lua file that is compiled into the executable needs to write its return value into the _LOADED global table under its filename (and one has to be careful to always write out the .lua extension in require() statements.
In order to meet the dependencies, the makefile must include all lua files in the correct order (hint: lua allows to overwrite the system "require" function, this can be used to print a log of require() statements, when the application is run from source).
7. Extending the library
mnoofltk only covers a small subset of FLTK widgets. If an unsupported widget is needed, it may be straightforward to add it to mnoofltk/build_mnoofltk.lua in the source and rebuild the library using make.
When callbacks are involved, it is necessary to derive a class from the FLTK class - there are plenty of examples in mnoofltk/widgets.
Bear in mind: Functions from parent classes are automatically inherited. But often, a class overloads a given function - for example Fl_Window::label(...). In such a case, the window class must reimplement the function (using the overloaded flag in the library builder). Otherwise, the library would call for example Fl_Widget::label(..) on an Fl_Window, and that's probably not the intention (it won't SEGFAULT, because a window is a widget, but it just won't work).
The library is rebuilt using "make". Set CFLAGS and LFLAGS accordingly (setenv).
8. Not Bugs
Any mnoofltk object is a reference to the FLTK object. When FLTK destroys a container widget, it also destroys all children, and afterwards the reference in lua is invalid. Using an invalid reference results in a segfault.
Since correct code does not access widgets after they were destroyed, this is not really a problem. But one should be aware of the issue - mnoofltk is not foolproof.
9. Bugs
Currently it is not allowed to destroy a widget from its own callback. Such a case appears, when widgets are created dynamically on the data. A widget changes the data, triggers a redraw, the redraw deletes the window contents and ... BANG!
Solution:
- Create all widgets that are data dependent in containers (usually a scroll).
- When the content changes, use parent:remove{widget=my_scroll}. This does NOT actually delete the scroll or its children!
- Perform the delete{} after the callback has completed. A good time to delete{} the old scroll is when the next callback occurs.
10. Contact
11. License
The source files included in the distribution and this document are in the public domain and may be used freely. No warranty is given or implied.
The package includes parts (for example FLTK binaries, and lua executables), that are licensed under different terms.
Please refer to the documentation of the respective libraries.
Table of Contents
This document was generated
by markus nentwig on February, 19 2006
using texi2html