PageRenderTime 33ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/html/examples/tutorial/example3_9.lua

https://gitlab.com/willemmali-c/iup
Lua | 584 lines | 468 code | 105 blank | 11 comment | 43 complexity | 936c9397b3bd3d5c7155972b3365605a MD5 | raw file
  1. require("iuplua")
  2. require("iupluaimglib")
  3. --********************************** Utilities *****************************************
  4. function str_find(str, str_to_find, casesensitive, start)
  5. if (not casesensitive) then
  6. return str_find(string.lower(str), string.lower(str_to_find), true, start)
  7. end
  8. return string.find(str, str_to_find, start, true)
  9. end
  10. function str_filetitle(filename)
  11. local filename = string.gsub(filename, "\\", "/")
  12. filename = string.reverse(filename)
  13. final = string.find(filename, '/')
  14. filename = string.sub(filename, 1, final-1)
  15. filename = string.reverse(filename)
  16. return filename
  17. end
  18. function read_file(filename)
  19. local ifile = io.open(filename, "r")
  20. if (not ifile) then
  21. iup.Message("Error", "Can't open file: " .. filename)
  22. return nil
  23. end
  24. local str = ifile:read("*a")
  25. if (not str) then
  26. iup.Message("Error", "Fail when reading from file: " .. filename)
  27. return nil
  28. end
  29. ifile:close()
  30. return str
  31. end
  32. function write_file(filename, str)
  33. local ifile = io.open(filename, "w")
  34. if (not ifile) then
  35. iup.Message("Error", "Can't open file: " .. filename)
  36. return false
  37. end
  38. if (not ifile:write(str)) then
  39. iup.Message("Error", "Fail when writing to file: " .. filename)
  40. end
  41. ifile:close()
  42. return true
  43. end
  44. function new_file(ih)
  45. local dlg = iup.GetDialog(ih)
  46. local multitext = dlg.multitext
  47. dlg.title = "Untitled - Simple Notepad"
  48. multitext.filename = nil
  49. multitext.dirty = nil
  50. multitext.value = ""
  51. end
  52. function open_file(ih, filename)
  53. local str = read_file(filename)
  54. if (str) then
  55. local dlg = iup.GetDialog(ih)
  56. local multitext = dlg.multitext
  57. local config = multitext.config
  58. dlg.title = str_filetitle(filename).." - Simple Notepad"
  59. multitext.filename = filename
  60. multitext.dirty = nil
  61. multitext.value = str
  62. config:RecentUpdate(filename)
  63. end
  64. end
  65. function save_file(multitext)
  66. if (write_file(multitext.filename, multitext.value)) then
  67. multitext.dirty = nil
  68. end
  69. end
  70. function saveas_file(multitext, filename)
  71. if (write_file(filename, multitext.value)) then
  72. local dlg = iup.GetDialog(multitext)
  73. local config = multitext.config
  74. dlg.title = str_filetitle(filename).." - Simple Notepad"
  75. multitext.filename = filename
  76. multitext.dirty = nil
  77. config:RecentUpdate(filename)
  78. end
  79. end
  80. function save_check(ih)
  81. local dlg = iup.GetDialog(ih)
  82. local multitext = dlg.multitext
  83. if (multitext.dirty) then
  84. local resp = iup.Alarm("Warning", "File not saved! Save it now?", "Yes", "No", "Cancel")
  85. if resp == 1 then -- save the changes and continue
  86. save_file(multitext)
  87. elseif resp == 3 then -- cancel
  88. return false
  89. else -- ignore the changes and continue
  90. end
  91. end
  92. return true
  93. end
  94. --********************************** Main (Part 1/2) *****************************************
  95. config = iup.config{}
  96. config.app_name = "simple_notepad"
  97. config:Load()
  98. lbl_statusbar = iup.label{title = "Lin 1, Col 1", expand = "HORIZONTAL", padding = "10x5"}
  99. multitext = iup.text{
  100. multiline = "YES",
  101. expand = "YES",
  102. config = config,
  103. dirty = nil,
  104. }
  105. font = config:GetVariable("MainWindow", "Font")
  106. if (font) then
  107. multitext.font = font
  108. end
  109. item_new = iup.item{title = "&New...\tCtrl+N", image = "IUP_FileNew"}
  110. item_open = iup.item{title = "&Open...\tCtrl+O", image = "IUP_FileOpen"}
  111. item_save = iup.item{title="&Save\tCtrl+S"}
  112. item_saveas = iup.item{title="Save &As...", image = "IUP_FileSave"}
  113. item_font = iup.item{title="&Font..."}
  114. item_about = iup.item{title="&About..."}
  115. item_find = iup.item{title="&Find...\tCtrl+F", image = "IUP_EditFind"}
  116. item_goto = iup.item{title="&Go To..."}
  117. item_copy = iup.item{title="&Copy\tCtrl+C", image = "IUP_EditCopy"}
  118. item_paste = iup.item{title="&Paste\tCtrl+V", image = "IUP_EditPaste"}
  119. item_cut = iup.item{title="Cu&t\tCtrl+X", image = "IUP_EditCut"}
  120. item_delete = iup.item{title="&Delete\tDel", image = "IUP_EditErase"}
  121. item_select_all = iup.item{title="Select &All\tCtrl+A"}
  122. item_revert = iup.item{title="&Revert"}
  123. item_exit = iup.item{title="E&xit"}
  124. --********************************** Callbacks *****************************************
  125. function multitext:dropfiles_cb(filename)
  126. if (save_check(self)) then
  127. open_file(self, filename)
  128. end
  129. end
  130. function multitext:valuechanged_cb()
  131. self.dirty = "YES"
  132. end
  133. function config:recent_cb()
  134. if (save_check(self)) then
  135. local filename = self.title
  136. open_file(self, filename)
  137. end
  138. end
  139. function multitext:caret_cb(lin, col)
  140. lbl_statusbar.title = "Lin "..lin..", Col "..col
  141. end
  142. function item_new:action()
  143. if save_check(self) then
  144. new_file(self)
  145. end
  146. end
  147. function item_open:action()
  148. if not save_check(self) then
  149. return
  150. end
  151. local filedlg = iup.filedlg{
  152. dialogtype = "OPEN",
  153. filter = "*.txt",
  154. filterinfo = "Text Files",
  155. parentdialog=iup.GetDialog(self)
  156. }
  157. filedlg:popup(iup.CENTERPARENT, iup.CENTERPARENT)
  158. if (tonumber(filedlg.status) ~= -1) then
  159. local filename = filedlg.value
  160. open_file(self, filename)
  161. end
  162. filedlg:destroy()
  163. end
  164. function item_saveas:action()
  165. local filedlg = iup.filedlg{
  166. dialogtype = "SAVE",
  167. filter = "*.txt",
  168. filterinfo = "Text Files",
  169. parentdialog = iup.GetDialog(self),
  170. file = multitext.filename,
  171. }
  172. filedlg:popup(iup.CENTERPARENT, iup.CENTERPARENT)
  173. if (tonumber(filedlg.status) ~= -1) then
  174. local filename = filedlg.value
  175. saveas_file(multitext, filename)
  176. end
  177. filedlg:destroy()
  178. end
  179. function item_save:action()
  180. if (not multitext.filename) then
  181. item_saveas:action()
  182. else
  183. save_file(multitext)
  184. end
  185. end
  186. function item_revert:action()
  187. open_file(self, multitext.filename)
  188. end
  189. function item_exit:action()
  190. if not save_check(self) then
  191. return iup.IGNORE -- to abort the CLOSE_CB callback
  192. end
  193. config:DialogClosed(iup.GetDialog(self), "MainWindow")
  194. config:Save()
  195. config:destroy()
  196. return iup.CLOSE
  197. end
  198. function item_goto:action()
  199. local line_count = multitext.linecount
  200. local lbl_goto = iup.label{title = "Line Number [1-"..line_count.."]:"}
  201. local txt_goto = iup.text{mask = iup.MASK_UINT, visiblecolumns = 20} --unsigned integer numbers only
  202. local bt_goto_ok = iup.button{title = "OK", text_linecount = 0, padding = "10x2"}
  203. bt_goto_ok.text_linecount = line_count
  204. function bt_goto_ok:action()
  205. local line_count = tonumber(self.text_linecount)
  206. local line = tonumber(txt_goto.value)
  207. if (line < 1 or line >= line_count) then
  208. iup.Message("Error", "Invalid line number.")
  209. return
  210. end
  211. goto_dlg.status = 1
  212. return iup.CLOSE
  213. end
  214. local bt_goto_cancel = iup.button{title = "Cancel", padding = "10x2"}
  215. function bt_goto_cancel:action()
  216. goto_dlg.status = 0
  217. return iup.CLOSE
  218. end
  219. local box = iup.vbox{
  220. lbl_goto,
  221. txt_goto,
  222. iup.hbox{
  223. iup.fill{},
  224. bt_goto_ok,
  225. bt_goto_cancel,
  226. normalizesize="HORIZONTAL",
  227. },
  228. margin = "10x10",
  229. gap = "5",
  230. }
  231. goto_dlg = iup.dialog{
  232. box,
  233. title = "Go To Line",
  234. dialogframe = "Yes",
  235. defaultenter = bt_goto_ok,
  236. defaultesc = bt_goto_cancel,
  237. parentdialog = iup.GetDialog(self)
  238. }
  239. goto_dlg:popup(iup.CENTERPARENT, iup.CENTERPARENT)
  240. if (tonumber(goto_dlg.status) == 1) then
  241. local line = txt_goto.value
  242. local pos = iup.TextConvertLinColToPos(multitext, line, 0)
  243. multitext.caretpos = pos
  244. multitext.scrolltopos = pos
  245. end
  246. goto_dlg:destroy()
  247. end
  248. function item_find:action()
  249. local find_dlg = self.find_dialog
  250. if (not find_dlg) then
  251. local find_txt = iup.text{visiblecolumns = "20"}
  252. local find_case = iup.toggle{title = "Case Sensitive"}
  253. local bt_find_next = iup.button{title = "Find Next", padding = "10x2"}
  254. local bt_find_close = iup.button{title = "Close", padding = "10x2"}
  255. function bt_find_next:action()
  256. local find_pos = tonumber(find_dlg.find_pos)
  257. local str_to_find = find_txt.value
  258. local casesensitive = (find_case.value == "ON")
  259. -- test again, because it can be called from the hot key
  260. if (not str_to_find or str_to_find:len()==0) then
  261. return
  262. end
  263. if (not find_pos) then
  264. find_pos = 1
  265. end
  266. local str = multitext.value
  267. local pos, end_pos = str_find(str, str_to_find, casesensitive, find_pos)
  268. if (not pos) then
  269. pos, end_pos = str_find(str, str_to_find, casesensitive, 1) -- try again from the start
  270. end
  271. if (pos) and (pos > 0) then
  272. pos = pos - 1
  273. find_dlg.find_pos = end_pos
  274. iup.SetFocus(multitext)
  275. multitext.selectionpos = pos..":"..end_pos
  276. local lin, col = iup.TextConvertPosToLinCol(multitext, pos)
  277. local pos = iup.TextConvertLinColToPos(multitext, lin, 0) -- position at col=0, just scroll lines
  278. multitext.scrolltopos = pos
  279. else
  280. find_dlg.find_pos = nil
  281. iup.Message("Warning", "Text not found.")
  282. end
  283. end
  284. function bt_find_close:action()
  285. iup.Hide(iup.GetDialog(self)) -- do not destroy, just hide
  286. end
  287. box = iup.vbox{
  288. iup.label{title = "Find What:"},
  289. find_txt,
  290. find_case,
  291. iup.hbox{
  292. iup.fill{},
  293. bt_find_next,
  294. bt_find_close,
  295. normalizesize="HORIZONTAL",
  296. },
  297. margin = "10x10",
  298. gap = "5",
  299. }
  300. find_dlg = iup.dialog{
  301. box,
  302. title = "Find",
  303. dialogframe = "Yes",
  304. defaultenter = bt_next,
  305. defaultesc = bt_close,
  306. parentdialog = iup.GetDialog(self)
  307. }
  308. -- Save the dialog to reuse it
  309. self.find_dialog = find_dlg -- from the main dialog */
  310. end
  311. -- centerparent first time, next time reuse the last position
  312. find_dlg:showxy(iup.CURRENT, iup.CURRENT)
  313. end
  314. function item_copy:action()
  315. local clipboard = iup.clipboard{text = multitext.selectedtext}
  316. clipboard:destroy()
  317. end
  318. function item_paste:action()
  319. local clipboard = iup.clipboard{}
  320. multitext.insert = clipboard.text
  321. clipboard:destroy()
  322. return iup.IGNORE -- avoid system processing for hot keys, to correctly parse line feed
  323. end
  324. function item_cut:action()
  325. local clipboard = iup.clipboard{text = multitext.selectedtext}
  326. multitext.selectedtext = ""
  327. clipboard:destroy()
  328. end
  329. function item_delete:action()
  330. multitext.selectedtext = ""
  331. end
  332. function item_select_all:action()
  333. iup.SetFocus(multitext)
  334. multitext.selection = "ALL"
  335. end
  336. function item_font:action()
  337. local font = multitext.font
  338. local fontdlg = iup.fontdlg{value = font, parentdialog=iup.GetDialog(self)}
  339. fontdlg:popup(iup.CENTERPARENT, iup.CENTERPARENT)
  340. if (tonumber(fontdlg.status) == 1) then
  341. multitext.font = fontdlg.value
  342. config:SetVariable("MainWindow", "Font", fontdlg.value)
  343. end
  344. fontdlg:destroy()
  345. end
  346. function item_about:action()
  347. iup.Message("About", " Simple Notepad\n\nAutors:\n Gustavo Lyrio\n Antonio Scuri")
  348. end
  349. --********************************** Main (Part 2/2) *****************************************
  350. recent_menu = iup.menu{}
  351. file_menu = iup.menu{
  352. item_new,
  353. item_open,
  354. item_save,
  355. item_saveas,
  356. item_revert,
  357. iup.separator{},
  358. iup.submenu{title="Recent &Files", recent_menu},
  359. item_exit
  360. }
  361. function file_menu:open_cb()
  362. if (multitext.dirty) then
  363. item_save.active = "YES"
  364. else
  365. item_save.active = "NO"
  366. end
  367. if (multitext.dirty and multitext.filename) then
  368. item_revert.active = "YES"
  369. else
  370. item_revert.active = "NO"
  371. end
  372. end
  373. edit_menu = iup.menu{
  374. item_cut,
  375. item_copy,
  376. item_paste,
  377. item_delete,
  378. iup.separator{},
  379. item_find,
  380. item_goto,
  381. iup.separator{},
  382. item_select_all
  383. }
  384. function edit_menu:open_cb()
  385. local clipboard = iup.clipboard{}
  386. if (not clipboard.textavailable) then
  387. item_paste.active = "NO"
  388. else
  389. item_paste.active = "YES"
  390. end
  391. if (not multitext.selectedtext) then
  392. item_cut.active = "NO"
  393. item_delete.active = "NO"
  394. item_copy.active = "NO"
  395. else
  396. item_cut.active = "YES"
  397. item_delete.active = "YES"
  398. item_copy.active = "YES"
  399. end
  400. clipboard:destroy()
  401. end
  402. format_menu = iup.menu{item_font}
  403. help_menu = iup.menu{item_about}
  404. sub_menu_file = iup.submenu{file_menu, title = "&File"}
  405. sub_menu_edit = iup.submenu{edit_menu, title = "&Edit"}
  406. sub_menu_format = iup.submenu{format_menu, title = "F&ormat"}
  407. sub_menu_help = iup.submenu{help_menu, title = "&Help"}
  408. menu = iup.menu{
  409. sub_menu_file,
  410. sub_menu_edit,
  411. sub_menu_format,
  412. sub_menu_help,
  413. }
  414. btn_new = iup.button{image = "IUP_FileNew", flat = "Yes", action = item_new.action, canfocus="No", tip = "New (Ctrl+N)"}
  415. btn_open = iup.button{image = "IUP_FileOpen", flat = "Yes", action = item_open.action, canfocus="No", tip = "Open (Ctrl+O)"}
  416. btn_save = iup.button{image = "IUP_FileSave", flat = "Yes", action = item_save.action, canfocus="No", tip = "Save (Ctrl+S)"}
  417. btn_find = iup.button{image = "IUP_EditFind", flat = "Yes", action = item_find.action, canfocus="No", tip = "Find (Ctrl+F)"}
  418. btn_cut = iup.button{image = "IUP_EditCut", flat = "Yes", action = item_cut.action, canfocus="No", tip = "Cut (Ctrl+X)"}
  419. btn_copy = iup.button{image = "IUP_EditCopy", flat = "Yes", action = item_copy.action, canfocus="No", tip = "Copy (Ctrl+C)"}
  420. btn_paste = iup.button{image = "IUP_EditPaste", flat = "Yes", action = item_paste.action, canfocus="No", tip = "Paste (Ctrl+V)"}
  421. toolbar_hb = iup.hbox{
  422. btn_new,
  423. btn_open,
  424. btn_save,
  425. iup.label{separator="VERTICAL"},
  426. btn_cut,
  427. btn_copy,
  428. btn_paste,
  429. iup.label{separator="VERTICAL"},
  430. btn_find,
  431. margin = "5x5",
  432. gap = 2,
  433. }
  434. vbox = iup.vbox{
  435. toolbar_hb,
  436. multitext,
  437. lbl_statusbar,
  438. }
  439. dlg = iup.dialog{
  440. vbox,
  441. title = "Simple Notepad",
  442. size = "HALFxHALF",
  443. menu = menu,
  444. close_cb = item_exit.action,
  445. multitext = multitext,
  446. dropfiles_cb = multitext.dropfiles_cb,
  447. }
  448. function dlg:k_any(c)
  449. if (c == iup.K_cN) then
  450. item_new:action()
  451. elseif (c == iup.K_cO) then
  452. item_open:action()
  453. elseif (c == iup.K_cS) then
  454. item_save:action()
  455. elseif (c == iup.K_cF) then
  456. item_find:action()
  457. elseif (c == iup.K_cG) then
  458. item_goto:action()
  459. end
  460. end
  461. config:RecentInit(recent_menu, 10)
  462. -- parent for pre-defined dialogs in closed functions (IupMessage)
  463. iup.SetGlobal("PARENTDIALOG", iup.SetHandleName(dlg))
  464. config:DialogShow(dlg, "MainWindow")
  465. -- initialize the current file
  466. new_file(dlg)
  467. -- open a file from the command line (allow file association in Windows)
  468. if (arg and arg[1]) then
  469. filename = arg[1]
  470. open_file(dlg, filename)
  471. end
  472. -- to be able to run this script inside another context
  473. if (iup.MainLoopLevel()==0) then
  474. iup.MainLoop()
  475. iup.Close()
  476. end