363 lines
14 KiB
Lua
363 lines
14 KiB
Lua
-------------------------------------------------------------------------=---
|
|
-- Name: Calculator.wx.lua
|
|
-- Purpose: Calculator wxLua sample
|
|
-- Author: J Winwood
|
|
-- Based on the wxWidgets sample by Marco Ghislanzoni
|
|
-- Created: March 2002
|
|
-- Updated January 2003 to use XML resources
|
|
-- Copyright: (c) 2002-2003 Lomtick Software. All rights reserved.
|
|
-- Licence: wxWidgets licence
|
|
-------------------------------------------------------------------------=---
|
|
|
|
-- Load the wxLua module, does nothing if running from wxLua, wxLuaFreeze, or wxLuaEdit
|
|
package.cpath = package.cpath..";./?.dll;./?.so;../lib/?.so;../lib/vc_dll/?.dll;../lib/bcc_dll/?.dll;../lib/mingw_dll/?.dll;"
|
|
require("wx")
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Global variables
|
|
dialog = nil -- the wxDialog main toplevel window
|
|
xmlResource = nil -- the XML resource handle
|
|
txtDisplay = nil -- statictext window for the display
|
|
clearDisplay = nil
|
|
lastNumber = 0 -- the last number pressed, 0 - 9
|
|
lastOperationId = nil -- the window id of last operation button pressed
|
|
|
|
local xpmdata =
|
|
{
|
|
"16 15 5 1",
|
|
" c None",
|
|
"a c Black",
|
|
"b c #FFFFFF",
|
|
"c c #808080",
|
|
"d c #9DBDCD",
|
|
" aaaaaaaaaaaa ",
|
|
" addddddddddac ",
|
|
" adaaaaaaaadac ",
|
|
" adabbbbbbadac ",
|
|
" adabbbbbbadac ",
|
|
" adaaaaaaaadac ",
|
|
" addddddddddac ",
|
|
" adaadaadaadac ",
|
|
" adaadaadaadac ",
|
|
" addddddddddac ",
|
|
" adaadaadaadac ",
|
|
" adaadaadaadac ",
|
|
" addddddddddac ",
|
|
" aaaaaaaaaaaac ",
|
|
" ccccccccccccc "
|
|
}
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- return the path part of the currently executing file
|
|
function GetExePath()
|
|
local function findLast(filePath) -- find index of last / or \ in string
|
|
local lastOffset = nil
|
|
local offset = nil
|
|
repeat
|
|
offset = string.find(filePath, "\\") or string.find(filePath, "/")
|
|
|
|
if offset then
|
|
lastOffset = (lastOffset or 0) + offset
|
|
filePath = string.sub(filePath, offset + 1)
|
|
end
|
|
until not offset
|
|
|
|
return lastOffset
|
|
end
|
|
|
|
local filePath = debug.getinfo(1, "S").source
|
|
|
|
if string.byte(filePath) == string.byte('@') then
|
|
local offset = findLast(filePath)
|
|
if offset ~= nil then
|
|
-- remove the @ at the front up to just before the path separator
|
|
filePath = string.sub(filePath, 2, offset - 1)
|
|
else
|
|
filePath = "."
|
|
end
|
|
else
|
|
filePath = wx.wxGetCwd()
|
|
end
|
|
|
|
return filePath
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Handle the clear button event
|
|
function OnClear(event)
|
|
txtDisplay:SetLabel("0")
|
|
lastNumber = 0
|
|
lastOperationId = ID_PLUS
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Handle all number button events
|
|
function OnNumber(event)
|
|
local numberId = event:GetId()
|
|
local displayString = txtDisplay:GetLabel()
|
|
|
|
if (displayString == "0") or (tonumber(displayString) == nil) or clearDisplay then
|
|
displayString = ""
|
|
end
|
|
clearDisplay = nil
|
|
|
|
-- Limit string length to 12 chars
|
|
if string.len(displayString) < 12 then
|
|
if numberId == ID_DECIMAL then
|
|
if not string.find(displayString, ".", 1, 1) then
|
|
-- If the first pressed char is "." then we want "0."
|
|
if string.len(displayString) == 0 then
|
|
displayString = displayString.."0."
|
|
else
|
|
displayString = displayString.."."
|
|
end
|
|
end
|
|
else
|
|
-- map button window ids to numeric values
|
|
local idTable = { [ID_0] = 0, [ID_1] = 1, [ID_2] = 2, [ID_3] = 3,
|
|
[ID_4] = 4, [ID_5] = 5, [ID_6] = 6, [ID_7] = 7,
|
|
[ID_8] = 8, [ID_9] = 9 }
|
|
|
|
local num = idTable[numberId]
|
|
|
|
-- If first character entered is 0 we reject it
|
|
if (num == 0) and (string.len(displayString) == 0) then
|
|
displayString = "0"
|
|
elseif displayString == "" then
|
|
displayString = num
|
|
else
|
|
displayString = displayString..num
|
|
end
|
|
end
|
|
|
|
txtDisplay:SetLabel(tostring(displayString))
|
|
end
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Calculate the operation
|
|
function DoOperation(a, b, operationId)
|
|
local result = a
|
|
if operationId == ID_PLUS then
|
|
result = b + a
|
|
elseif operationId == ID_MINUS then
|
|
result = b - a
|
|
elseif operationId == ID_MULTIPLY then
|
|
result = b * a
|
|
elseif operationId == ID_DIVIDE then
|
|
if a == 0 then
|
|
result = "Divide by zero error"
|
|
else
|
|
result = b / a
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Handle all operation button events
|
|
function OnOperator(event)
|
|
-- Get display content
|
|
local displayString = txtDisplay:GetLabel()
|
|
local currentNumber = tonumber(displayString)
|
|
|
|
-- if error message was shown, zero output and ignore operator
|
|
if ((currentNumber == nil) or (lastNumber == nil)) then
|
|
lastNumber = 0
|
|
return
|
|
end
|
|
|
|
-- Get the required lastOperationId
|
|
local operationId = event:GetId()
|
|
|
|
displayString = DoOperation(currentNumber, lastNumber, lastOperationId)
|
|
lastNumber = tonumber(displayString)
|
|
|
|
if (lastOperationId ~= ID_EQUALS) or (operationId == ID_EQUALS) then
|
|
txtDisplay:SetLabel(tostring(displayString))
|
|
end
|
|
clearDisplay = 1
|
|
lastOperationId = operationId
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Handle the quit button event
|
|
function OnQuit(event)
|
|
event:Skip()
|
|
wx.wxMessageBox("wxLua calculator sample based on the calc sample written by Marco Ghislanzoni.\n"..
|
|
wxlua.wxLUA_VERSION_STRING.." built with "..wx.wxVERSION_STRING,
|
|
"wxLua Calculator",
|
|
wx.wxOK + wx.wxICON_INFORMATION, dialog)
|
|
|
|
dialog:Show(false)
|
|
dialog:Destroy()
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- The main program as a function (makes it easy to exit on error)
|
|
function main()
|
|
-- xml style resources (if present)
|
|
xmlResource = wx.wxXmlResource()
|
|
xmlResource:InitAllHandlers()
|
|
local xrcFilename = GetExePath().."/calculator.xrc"
|
|
|
|
-- try to load the resource and ask for path to it if not found
|
|
while not xmlResource:Load(xrcFilename) do
|
|
-- must unload the file before we try again
|
|
xmlResource:Unload(xrcFilename)
|
|
|
|
wx.wxMessageBox("Error loading xrc resources, please choose the path to 'calculator.xrc'.",
|
|
"Calculator",
|
|
wx.wxOK + wx.wxICON_EXCLAMATION,
|
|
wx.NULL)
|
|
local fileDialog = wx.wxFileDialog(wx.NULL,
|
|
"Open 'calculator.xrc' resource file",
|
|
"",
|
|
"calculator.xrc",
|
|
"XRC files (*.xrc)|*.xrc|All files (*)|*",
|
|
wx.wxOPEN + wx.wxFILE_MUST_EXIST)
|
|
|
|
if fileDialog:ShowModal() == wx.wxID_OK then
|
|
xrcFilename = fileDialog:GetPath()
|
|
else
|
|
return -- quit program
|
|
end
|
|
end
|
|
|
|
dialog = wx.wxDialog()
|
|
if not xmlResource:LoadDialog(dialog, wx.NULL, "Calculator") then
|
|
wx.wxMessageBox("Error loading xrc resources!",
|
|
"Calculator",
|
|
wx.wxOK + wx.wxICON_EXCLAMATION,
|
|
wx.NULL)
|
|
return -- quit program
|
|
end
|
|
|
|
-- -----------------------------------------------------------------------
|
|
-- This is a little awkward, but it's how it's done in C++ too
|
|
bitmap = wx.wxBitmap(xpmdata)
|
|
icon = wx.wxIcon()
|
|
icon:CopyFromBitmap(bitmap)
|
|
dialog:SetIcon(icon)
|
|
bitmap:delete()
|
|
icon:delete()
|
|
|
|
bestSize = dialog:GetBestSize()
|
|
dialog:SetSize(bestSize:GetWidth()/2, bestSize:GetHeight())
|
|
dialog:SetSizeHints(bestSize:GetWidth()/2, bestSize:GetHeight())
|
|
|
|
-- initialize the txtDisplay and verify that it's ok
|
|
txtDisplay = dialog:FindWindow(xmlResource.GetXRCID("ID_TEXT"))
|
|
if not txtDisplay then
|
|
wx.wxMessageBox('Unable to find window "ID_TEXT" in the dialog',
|
|
"Calculator",
|
|
wx.wxOK + wx.wxICON_EXCLAMATION,
|
|
wx.NULL)
|
|
dialog:Destroy()
|
|
return
|
|
end
|
|
if not txtDisplay:DynamicCast("wxStaticText") then
|
|
wx.wxMessageBox('window "ID_TEXT" is not a "wxStaticText" or is not derived from it"',
|
|
"Calculator",
|
|
wx.wxOK + wx.wxICON_EXCLAMATION,
|
|
wx.NULL)
|
|
dialog:Destroy()
|
|
return
|
|
end
|
|
txtDisplay:SetLabel("0")
|
|
|
|
-- init global wxWindow ID values
|
|
ID_0 = xmlResource.GetXRCID("ID_0")
|
|
ID_1 = xmlResource.GetXRCID("ID_1")
|
|
ID_2 = xmlResource.GetXRCID("ID_2")
|
|
ID_3 = xmlResource.GetXRCID("ID_3")
|
|
ID_4 = xmlResource.GetXRCID("ID_4")
|
|
ID_5 = xmlResource.GetXRCID("ID_5")
|
|
ID_6 = xmlResource.GetXRCID("ID_6")
|
|
ID_7 = xmlResource.GetXRCID("ID_7")
|
|
ID_8 = xmlResource.GetXRCID("ID_8")
|
|
ID_9 = xmlResource.GetXRCID("ID_9")
|
|
ID_DECIMAL = xmlResource.GetXRCID("ID_DECIMAL")
|
|
ID_EQUALS = xmlResource.GetXRCID("ID_EQUALS")
|
|
ID_PLUS = xmlResource.GetXRCID("ID_PLUS")
|
|
ID_MINUS = xmlResource.GetXRCID("ID_MINUS")
|
|
ID_MULTIPLY = xmlResource.GetXRCID("ID_MULTIPLY")
|
|
ID_DIVIDE = xmlResource.GetXRCID("ID_DIVIDE")
|
|
ID_OFF = xmlResource.GetXRCID("ID_OFF")
|
|
ID_CLEAR = xmlResource.GetXRCID("ID_CLEAR")
|
|
|
|
lastOperationId = ID_PLUS
|
|
|
|
dialog:Connect(ID_0, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_1, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_2, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_3, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_4, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_5, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_6, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_7, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_8, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_9, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_DECIMAL, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnNumber)
|
|
dialog:Connect(ID_EQUALS, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnOperator)
|
|
dialog:Connect(ID_PLUS, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnOperator)
|
|
dialog:Connect(ID_MINUS, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnOperator)
|
|
dialog:Connect(ID_MULTIPLY, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnOperator)
|
|
dialog:Connect(ID_DIVIDE, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnOperator)
|
|
dialog:Connect(ID_OFF, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnQuit)
|
|
dialog:Connect(ID_CLEAR, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnClear)
|
|
|
|
dialog:Connect(wx.wxEVT_CLOSE_WINDOW, OnQuit)
|
|
|
|
accelTable = wx.wxAcceleratorTable({
|
|
{ wx.wxACCEL_NORMAL, string.byte('0'), ID_0 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('1'), ID_1 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('2'), ID_2 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('3'), ID_3 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('4'), ID_4 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('5'), ID_5 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('6'), ID_6 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('7'), ID_7 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('8'), ID_8 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('9'), ID_9 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD0, ID_0 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD1, ID_1 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD2, ID_2 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD3, ID_3 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD4, ID_4 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD5, ID_5 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD6, ID_6 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD7, ID_7 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD8, ID_8 },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD9, ID_9 },
|
|
{ wx.wxACCEL_NORMAL, string.byte('.'), ID_DECIMAL },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD_DECIMAL, ID_DECIMAL },
|
|
{ wx.wxACCEL_NORMAL, string.byte('='), ID_EQUALS },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD_ENTER, ID_EQUALS },
|
|
{ wx.wxACCEL_NORMAL, 13, ID_EQUALS },
|
|
{ wx.wxACCEL_NORMAL, string.byte('+'), ID_PLUS },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD_ADD, ID_PLUS },
|
|
{ wx.wxACCEL_NORMAL, string.byte('-'), ID_MINUS },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD_SUBTRACT, ID_MINUS },
|
|
{ wx.wxACCEL_NORMAL, string.byte('*'), ID_MULTIPLY },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD_MULTIPLY, ID_MULTIPLY },
|
|
{ wx.wxACCEL_NORMAL, string.byte('/'), ID_DIVIDE },
|
|
{ wx.wxACCEL_NORMAL, wx.VXK_NUMPAD_DIVIDE, ID_DIVIDE },
|
|
{ wx.wxACCEL_NORMAL, string.byte('C'), ID_CLEAR },
|
|
{ wx.wxACCEL_NORMAL, string.byte('c'), ID_CLEAR },
|
|
{ wx.wxACCEL_NORMAL, wx.WXK_ESCAPE, ID_OFF }
|
|
})
|
|
|
|
dialog:SetAcceleratorTable(accelTable)
|
|
dialog:Centre()
|
|
dialog:Show(true)
|
|
end
|
|
|
|
main()
|
|
|
|
-- Call wx.wxGetApp():MainLoop() last to start the wxWidgets event loop,
|
|
-- otherwise the wxLua program will exit immediately.
|
|
-- Does nothing if running from wxLua, wxLuaFreeze, or wxLuaEdit since the
|
|
-- MainLoop is already running or will be started by the C++ program.
|
|
wx.wxGetApp():MainLoop()
|