forked from pkulchenko/wxlua
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcalculator.wx.lua
More file actions
366 lines (324 loc) · 14.3 KB
/
calculator.wx.lua
File metadata and controls
366 lines (324 loc) · 14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
-------------------------------------------------------------------------=---
-- 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 = false
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 = false
-- 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 = tostring(num)
else
displayString = displayString..num
end
end
txtDisplay:SetLabel(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 = true
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"
local logNo = wx.wxLogNull() -- silence wxXmlResource error msg since we provide them
-- 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.wxFD_OPEN + wx.wxFD_FILE_MUST_EXIST)
if fileDialog:ShowModal() == wx.wxID_OK then
xrcFilename = fileDialog:GetPath()
else
return -- quit program
end
end
logNo:delete() -- turn error messages back on
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
local bitmap = wx.wxBitmap(xpmdata)
local 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.WXK_NUMPAD0, ID_0 },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD1, ID_1 },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD2, ID_2 },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD3, ID_3 },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD4, ID_4 },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD5, ID_5 },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD6, ID_6 },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD7, ID_7 },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD8, ID_8 },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD9, ID_9 },
{ wx.wxACCEL_NORMAL, string.byte('.'), ID_DECIMAL },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD_DECIMAL, ID_DECIMAL },
{ wx.wxACCEL_NORMAL, string.byte('='), ID_EQUALS },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD_ENTER, ID_EQUALS },
{ wx.wxACCEL_NORMAL, 13, ID_EQUALS },
{ wx.wxACCEL_NORMAL, string.byte('+'), ID_PLUS },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD_ADD, ID_PLUS },
{ wx.wxACCEL_NORMAL, string.byte('-'), ID_MINUS },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD_SUBTRACT, ID_MINUS },
{ wx.wxACCEL_NORMAL, string.byte('*'), ID_MULTIPLY },
{ wx.wxACCEL_NORMAL, wx.WXK_NUMPAD_MULTIPLY, ID_MULTIPLY },
{ wx.wxACCEL_NORMAL, string.byte('/'), ID_DIVIDE },
{ wx.wxACCEL_NORMAL, wx.WXK_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()