setfenv(1, require'winapi') --functions require'winapi.monitor' require'winapi.cursor' --standard controls require'winapi.windowclass' require'winapi.menuclass' require'winapi.buttonclass' require'winapi.toolbarclass' require'winapi.groupboxclass' require'winapi.checkboxclass' require'winapi.radiobuttonclass' require'winapi.editclass' require'winapi.tabcontrolclass' require'winapi.listboxclass' require'winapi.comboboxclass' require'winapi.labelclass' require'winapi.listviewclass' --panels require'winapi.bitmappanel' local have_wgl = pcall(require, 'winapi.wglpanel') local have_cairo = pcall(require, 'winapi.cairopanel') --get the monitor where the mouse is right now. ------------------------------ local mon = MonitorFromPoint(GetCursorPos(), MONITOR_DEFAULTTONEAREST) local moninfo = GetMonitorInfo(mon) --create the main window ----------------------------------------------------- local w, h = 550, 550 local win = Window{ x = (moninfo.work_rect.w - w) / 2, --center the window on the monitor y = (moninfo.work_rect.h - h) / 2, w = w, h = h, title = (' '):rep(50)..' ┬┴┬┴┤ Lua Rulez ├┬┴┬┴', autoquit = true, --quit the app when the window is closed } --create and show an about box ----------------------------------------------- local function about_box() local w, h = 300, 200 local aboutwin = Window{ x = win.x + (win.w - w) / 2, --center the window on its parent y = win.y + (win.h - h) / 2, w = 300, h = 200, title = 'About winapi', maximizable = false, minimizable = false, resizeable = false, owner = win, --don't show it in taskbar tool_window = true, } local w, h = 100, 24 local okbtn = Button{ x = (aboutwin.client_w - w) / 2, y = aboutwin.client_h * 5/6 - h, w = w, h = h, parent = aboutwin, default = true, --respond to pressing Enter } local lb = Label{ x = 0, y = 40, w = aboutwin.client_w, h = aboutwin.client_h, parent = aboutwin, align = 'center', text = 'Windows API Binding Demo', } --make it modal function okbtn:on_click() aboutwin:close() end function aboutwin:on_close() win:enable() end aboutwin.__wantallkeys = true --give us the ESC key! function okbtn:on_key_down(vk) if vk == VK_ESCAPE then aboutwin:close() end end win:disable() okbtn:focus() end --create menus for the main menu bar ----------------------------------------- local filemenu = Menu{ items = { {text = '&Close', on_click = function() win:close() end}, }, } local aboutmenu = Menu{ items = { {text = '&About', on_click = about_box}, }, } --create the main menu bar --------------------------------------------------- local menubar = MenuBar() menubar.items:add{text = '&File', submenu = filemenu} menubar.items:add{text = '&About', submenu = aboutmenu} win.menu = menubar --create a toolbar ----------------------------------------------------------- require'winapi.showcase' local toolbar = Toolbar{ parent = win, image_list = ImageList{w = 16, h = 16, masked = true, colors = '32bit'}, items = { --NOTE: using `iBitmap` instead of `i` because `i` counts from 1 {iBitmap = STD_FILENEW, text = 'New'}, {iBitmap = STD_FILEOPEN, text = 'Open'}, {iBitmap = STD_FILESAVE, text = 'Save'}, }, } toolbar:load_images(IDB_STD_SMALL_COLOR) --create a group box --------------------------------------------------------- local groupbox1 = GroupBox{ parent = win, x = 20, y = 180, w = 100, h = 170, text = 'Group 1', } local groupbox2 = GroupBox{ parent = win, x = 140, y = 180, w = 100, h = 170, text = 'Group 2', } --create radio buttons ------------------------------------------------------- for i = 1, 5 do RadioButton{ parent = groupbox1, x = 20, y = 10 + i * 22, w = 60, text = 'Option &'..i, checked = i == 2, } end --create check boxes --------------------------------------------------------- for i = 1, 5 do CheckBox{ parent = groupbox2, x = 20, y = 10 + i * 22, w = 60, text = 'Option &'..i, checked = i == 3 or i == 5, } end --create a tab control ------------------------------------------------------- local tabs = TabControl{ parent = win, x = 380, y = 70, w = 100, h = 100, anc = 'ltr', items = { {text = 'Tab1',}, {text = 'Tab2',}, }, } local tablabel = Label{ parent = tabs, x = 10, y = 30, w = 50, h = 50, anc = 'ltr', } tablabel.name = 'label' tabs.name = 'tabs' win.name = '!win' function tabs:on_tab_change() tablabel.text = 'Selected tab: '..tostring(self.selected_index) end tabs:on_tab_change() --create a bitmap panel ------------------------------------------------------ local bmppanel = BitmapPanel{w = 100, h = 100, x = 20, y = 70, parent = win} function bmppanel:on_bitmap_paint(bmp) local p = self.cursor_pos local pixels = ffi.cast('uint8_t*', bmp.data) for y = 0, bmp.h - 1 do for x = 0, bmp.w - 1 do pixels[y * bmp.stride + x * 4 + 0] = x + p.x - 100 pixels[y * bmp.stride + x * 4 + 1] = y + p.y - 100 pixels[y * bmp.stride + x * 4 + 2] = x + p.x - 100 end end end function bmppanel:on_mouse_move(x, y) self:invalidate() end --create a cairo panel ------------------------------------------------------- if have_cairo then local cairo = require'cairo' local cairopanel = CairoPanel{w = 100, h = 100, x = 140, y = 70, parent = win} local r = 0 function cairopanel:on_cairo_paint(cr) cr:rgba(0,0,0,1) cr:paint() cr:identity_matrix() cr:translate(self.w/2, self.h/2) r = r + .02 cr:rotate(r) cr:translate(-self.w/2, -self.h/2) cr:scale(0.4, 0.4) cr:rgba(0,0.7,0,1) cr:line_width(40.96) cr:move_to(76.8, 84.48) cr:rel_line_to(51.2, -51.2) cr:rel_line_to(51.2, 51.2) cr:line_join'miter' cr:stroke() cr:move_to(76.8, 161.28) cr:rel_line_to(51.2, -51.2) cr:rel_line_to(51.2, 51.2) cr:line_join'bevel' cr:stroke() cr:move_to(76.8, 238.08) cr:rel_line_to(51.2, -51.2) cr:rel_line_to(51.2, 51.2) cr:line_join'round' cr:stroke() end win:settimer(1/30, function() cairopanel:invalidate() end) end --create a wglpanel ---------------------------------------------------------- if have_wgl then local wglpanel = WGLPanel{w = 100, h = 100, x = 260, y = 70, parent = win} local function cube(w, r) gl.glPushMatrix() gl.glTranslated(0,0,-3) gl.glScaled(w, w, 1) gl.glRotated(r,1,r,1) gl.glTranslated(0,0,2) local function face(c) gl.glBegin(gl.GL_QUADS) gl.glColor4d(c,0,0,.5) gl.glVertex3d(-1, -1, -1) gl.glColor4d(0,c,0,.5) gl.glVertex3d(1, -1, -1) gl.glColor4d(0,0,c,.5) gl.glVertex3d(1, 1, -1) gl.glColor4d(c,0,c,.5) gl.glVertex3d(-1, 1, -1) gl.glEnd() end gl.glTranslated(0,0,-2) face(1) gl.glTranslated(0,0,2) face(1) gl.glTranslated(0,0,-2) gl.glRotated(-90,0,1,0) face(1) gl.glTranslated(0,0,2) face(1) gl.glRotated(-90,1,0,0) gl.glTranslated(0,2,0) face(1) gl.glTranslated(0,0,2) face(1) gl.glPopMatrix() end function wglpanel:on_set_viewport() local w, h = self.w, self.h gl.glViewport(0, 0, w, h) gl.glMatrixMode(gl.GL_PROJECTION) gl.glLoadIdentity() gl.glFrustum(-1, 1, -1, 1, 1, 100) --so fov is 90 deg gl.glScaled(1, w/h, 1) end local r = 0 function wglpanel:on_render() gl.glClearColor(0, 0, 0, 1) gl.glClear(bit.bor(gl.GL_COLOR_BUFFER_BIT, gl.GL_DEPTH_BUFFER_BIT)) gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_SRC_ALPHA) gl.glDisable(gl.GL_DEPTH_TEST) gl.glDisable(gl.GL_CULL_FACE) gl.glDisable(gl.GL_LIGHTING) gl.glMatrixMode(gl.GL_MODELVIEW) gl.glLoadIdentity() gl.glTranslated(0,0,-1) r = r + 2 cube(2, r) end win:settimer(1/30, function() wglpanel:invalidate() end) end --create some buttons -------------------------------------------------------- local closebtn = Button{ x = win.client_w - 130, y = win.client_h - 40, w = 100, text = '&Close', parent = win, anc = 'rb', } function closebtn:on_click() win:close() end win.min_cw = win.client_w win.min_ch = win.client_h --create a list box ---------------------------------------------------------- local lb = ListBox{parent = win, x = 260, y = 187, h = 160, hextent = 100} for i = 1,100 do lb.items:add('ListBox item '..i) end --create an edit box --------------------------------------------------------- local edit = Edit{parent = win, x = 380, y = 187, cue = 'Edit me'} --create a combo box --------------------------------------------------------- local combo = ComboBox{ parent = win, x = 380, y = 220, type = 'dropdownlist', items = { {text = 'First item'}, {text = 'Second item'}, }, selected_index = 2, } for i = 1, 10 do combo.items:add{text = 'Item '..i} end --create some labels --------------------------------------------------------- local lb1 = Label{parent = win, x = 20, y = 50, text = 'BitmapPanel'} local lb2 = Label{parent = win, x = 140, y = 50, text = 'CairoPanel'} local lb3 = Label{parent = win, x = 260, y = 50, text = 'WGLPanel'} --create an accelerator ------------------------------------------------------ win.accelerators:add{ hotkey = 'escape', --VK_ESCAPE handler = function() win:close() end, } --create some list views ----------------------------------------------------- local rlv = ReportListView{ parent = win, x = 20, y = 360, w = 220, h = 100, columns = {'name', 'address'}, items = { {text = 'Louis Armstrong', subitems = {'Basin Street'}}, {text = 'Django Reinhardt', subitems = {'Beyond The Sea'}}, }, } --start the message loop ----------------------------------------------------- os.exit(MessageLoop())