
| Lesson
1 Lesson 2 Lesson 3 Lesson 4 Lesson 5 Lesson 6 Lesson 7 Lesson 8 Lesson 9 Lesson 10 Lesson 11 Lesson 12 Lesson 13 Lesson 14 Lesson 15 Lesson 16 Lesson 17 Lesson 18 Lesson 19 |
Lesson 19 Window and User InterfaceThe Window package has several functions for creating window and controls. The wrapping of Windows system functions by zeGraph is straitforward: it simply send Windows callback message and parameters to the Lua call back function of yours. A Window callback function has the form of WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) In which the first argument is the Window's handle, the second is the message ID, and the third and the fourth are parameters whose contents vary depending on the message. In some cases, parameter contents of wParam and lParam are stored in their lower-order and higher-order bytes. The Lua callback function that you supply should deal with eight parameters with the first being the message as string, the second as the Window's handle, the third to fifth as the wParam and its lower- and higher-order bytes, and the sixth to eigth as lParam and its lower- and higher-order bytes. The following Window's ID are send back as string: WM_CREATE: "CREATE" WM_COMMAND: "COMMAND" WM_SIZE: "SIZE" WM_PAINT: "PAINT" WM_KEYUP: "KEYUP" WM_KEYDOWN: "KEYDOW" WM_LBUTTONUP: "LBUTTONUP" WM_LBUTTONDOWN: "LBUTTONDOWN" WM_LBUTTONDBLCLK: "LBUTTONDBLCLK" WM_MOUSEMOVE: "MOUSEMOVE" WM_RBUTTONUP: "RBUTTONUP" WM_RBUTTONDOWN: "RBUTTONDOWN" WM_RBUTTONDBLCLK: "RBUTTONDBLCLK" WM_TIMER: "TIMER" The first time you use the window function, you may wonder when you get what message; and which parameters or bytes contain the code of the key you pressed or the mouse's position moving over the clieant area of the window created by you. To find out these information, you can simply write a callback function to print all the parameters:
require("register")
callback = function(message, hwnd, wparm, lwparm, hwparm, lparm, llparm, hlparm)
print(message, hwnd, wparm, lwparm, hwparm, lparm, llparm, hlparm)
end
win = zeWindow.create("callback", 200, 200)
Any window created zeGraph, including the main window, can not be resized by dragging its corner. But you can achieve resizing through the callback function. ZeGraph's main purpose of wrapping Windows sytem functions is to create simple user interface. Not having to deal with window resizing simplifies laying out controls in the main window. For advanced window programming by Lua, you should use wxLua or Lua-FLTK; and advanced window should resume to C or C++ for good performance. Controls in the main Window should be create only once. Because the user cannot resize the window, the best way is to create controls is in handling the WM_SIZE message. You may attemp to do that in the WM_CREATE message loop. It will not work. In addition to commonly used control buttons, you can also create a pop menu for the main window. Let's see how to do these thing:
require("register")
callback = function(message, hwnd, wparm, lwparm, hwparm, lparm, llparm, hlparm)
if (message == "RBUTTONUP") then
zeWindow.showmenu(llparm, hlparm)
elseif (message == "CREATE") then
hmain = hwnd;
elseif (message == "SIZE") then
zeWindow.button(hmain, 50, 50, 70, 30, "OK")
zeWindow.combobox(hmain, 200, 50, 80, 400, "Item1", "Item2",
"Item3", "Item4", "Item5")
zeWindow.menu("menu1", "menu2", "menu3", "menu4", "menu5")
end
end
zeWindow.create("callback", 400, 300)
Creating a message window or a dialog windows for choosing color or file does not require the main window and the callback function:
require("register")
zeWindow.message("Hi! this if for testing the message box.\nThe is the second line.")
require("register")
print(zeWindow.choosecolor())
--[[A output:
0 64 128
]]
Now let's see how to do animation. The ring of Sauron in the Lord of Ring has magical powers. So does zeGraph. In just a few lines of code, you can create a ring that looks real enough to fool a hobbit. And yet you can rotate and animate the ring by creating a window. Watch this.
require("register")
render, scene, root, node, light, material
= zeGrf.new("render", "scene", "node", "node", "light", "material")
render:set{color = {0, 0, 0, 1}}
render:add(scene)
scene:perspective()
scene:set{node = root}
root:add(light, material, node)
light:set{position = {100, 500, 100}, ambient = {0.3, 0.3, 0.3, 1}}
material:set{ambient = {0.24725, 0.2245, 0.0645, 1, 0},
diffuse = {0.34615, 0.3143, 0.0903, 1, 0},
specular = {0.797357, 0.723991, 0.208006, 1, 0},
shininess = {83.2, 0}}
--Create the ring
arr = zeUtl.new("double")
R = 100; r = 15
for k = 0, 350, 10 do
shape, xyz, nor = zeGrf.new("polygon", "vertex", "vertex")
shape:set{vertex = xyz, vertex_normal = nor, type = "quadstrip"}
node:add(shape)
zeMake.toroid(arr, R, r, k, 10, 32)
xyz:add(arr)
arr:shift(3)
nor:add(arr)
end
node:set{color = {1, 1, 1, 1}}
--Define the callback function before creating the window and define
hwnd = 0
rotx = -60
roty = 0
key = 0
deg = 2
tm = 30
node:rotatex(rotx)
callback = function(message, hwnd, wparm, lwparm, hwparm, lparm, llparm, hlparm)
if (message == "PAINT") then
-- Window asks to repaint it.
if (hwnd > 0) then
render:towindow(hwnd, 1)
end
elseif (message == "KEYUP") then
-- Key up.
if (wparm >= 37 and wparm <= 40) then
if (wparm == 37) then
-- left arrow
roty = roty - deg
elseif (wparm == 38) then
-- up arrow
rotx = rotx - deg
elseif (wparm == 39) then
-- right arrow
roty = roty + deg
elseif (wparm == 40) then
-- down arrow
rotx = rotx + deg
end
key = wparm
node:rotatex(rotx)
node:rotatey(roty)
render:towindow(hwnd, 1)
end
elseif (message == "LBUTTONDBLCLK") then
--Double click left mouse
zeWindow.timer(tm)
if (tm > 0) then
tm = 0
else
tm = 30
end
elseif (message == "TIMER") then
-- Timer. Animate scene.
if (key == 37) then
roty = roty - deg
elseif (key == 38) then
rotx = rotx - deg
elseif (key == 39) then
roty = roty + deg
elseif (key == 40) then
rotx = rotx + deg
end
node:rotatex(rotx)
node:rotatey(roty)
render:towindow(hwnd, 1)
elseif (message == "CREATE") then
-- Window created. Save its handle.
hwnd = wparm
end
end
zeWindow.create("callback", 512, 512)
You rotate the ring using the four arrow keys. Double clicking the left mouse button will trigger the timer, which will animate (rotating) the ring. Another double click will kill the timer and stop the animation. |