DialogClass — модуль для работы с диалогами с стиле ООП

Здесь обсуждается всё, что касается макросов.
User avatar
Smitis
Posts: 1676
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 22 times
Been thanked: 52 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by Smitis »

Latest post of the previous page:

Приводимый выше пример макроса ReName выявил некоторую несовместимость с новой версией модуля.
Вот совместимая
  1. --[=[ ----------------------------------------------------------------------------------------------
  2. Макрос для переименования текущего файла - раздельно имя и расширение
  3. Служит также для демонстрации использования DiaologClass
  4. v.1.02 (C) Smitis, 2014-2015
  5. --]=] ----------------------------------------------------------------------------------------------
  6.  
  7. local TestAddItem = 6 -- тест: способ добавления элементов диалога
  8. local TestRename = 0 -- тест: 1 - не делать реального переименования
  9. local dialog = require 'DialogClass'
  10. --local dialog = require 'DerivedDialogClass' -- тест для примера наследования
  11.  
  12. ----------------------------------------------------------------------------------------------------
  13.  
  14. local RENAME_ID = "C6A21A86-96AC-44FF-9046-CAF14EE76CD2"
  15. local RENAME_GUID = win.Uuid(RENAME_ID)
  16.  
  17. local MOVE_ID = "431A2F37-AC01-4ECD-BB6F-8CDE584E5A03" -- стандартный диалог RENAME/MOVE
  18. local TMPPANEL_ID = "B77C964B-E31E-4D4C-8FE5-D6B0C6853E7C"
  19.  
  20. local F = far.Flags
  21.  
  22. local cfg = {}
  23.  
  24. cfg.HotKeyRename = "" -- хоткей для макроса ReName
  25. cfg.HotKeyMove = "ShiftF6" -- хоткей для вызова стандартной функции переименования
  26. cfg.HotKeySwitch = "ShiftF6" -- хоткей макроса переключения диалогов
  27. cfg.FileNameHistory = "Rename" -- имя истории имён, в оригинальном диалоге используется "Copy"
  28. cfg.FileExtHistory = "RenameExt" -- имя истории расширений
  29. cfg.KillDupExt = true -- заменять повторяющиеся расширения на простые (типа .jpg.jpg на .jpg)
  30. cfg.DialogWidth = 76 -- ширина диалога
  31. cfg.FileNameRTrim = " ." -- символы, отбрасывамые от имени справа
  32. cfg.FileNameLTrim = " " -- символы, отбрасывамые от имени слева
  33. cfg.FileExtRTrim = " ." -- символы, отбрасывамые от расширения справа
  34. cfg.FileExtLTrim = " ." -- символы, отбрасывамые от расширения слева
  35. cfg.MoveHist = true -- вести историю в вызываемом стандартном диалоге
  36. cfg.FileNameChanged = false -- снимать состояние Unchanged для имени файла
  37. cfg.FileExtChanged = false -- снимать состояние Unchanged для расширения
  38.  
  39. ----------------------------------------------------------------------------------------------------
  40. -- Локализация
  41. ----------------------------------------------------------------------------------------------------
  42. local langs = { english = {}, russian = {} }
  43.  
  44. langs.english.Title           = 'Rename'
  45. langs.english.FileNamePrompt  = 'Change name "%s" to:'
  46. langs.english.FileExtPrompt   = 'Change extension "%s" to:'
  47. langs.english.OkButton        = 'Rename'
  48. langs.english.CancelButton    = 'Cancel'
  49.  
  50. langs.russian.Title           = 'Переименование'
  51. langs.russian.FileNamePrompt  = 'Изменить имя "%s" на:'
  52. langs.russian.FileExtPrompt   = 'Изменить расширение "%s" на:'
  53. langs.russian.OkButton        = 'Переименовать'
  54. langs.russian.CancelButton    = 'Отменить'
  55.  
  56. ----------------------------------------------------------------------------------------------------
  57.  
  58. local function ReName_DlgProc(hDlg,Msg,Param1,Param2,D,DI)
  59.     if Msg==F.DN_INITDIALOG then
  60.         DI.FileName:Unchanged(not cfg.FileNameChanged)
  61.         if APanel.Folder then
  62.             DI.FileExt:Enable(false)
  63.         else
  64.             DI.FileExt:Unchanged(not cfg.FileExtChanged)
  65.         end
  66.     end
  67. end
  68.  
  69. ----------------------------------------------------------------------------------------------------
  70.  
  71. local function ReName()
  72.     local lang = langs[win.GetEnv("FARLANG"):lower()] or langs.english
  73.     local DW,DH = cfg.DialogWidth,11 -- размеры
  74.  
  75.     local FileFull = APanel.Current
  76.     local FileCurrent = mf.fsplit(FileFull,12)
  77.     local FileName, FileExt
  78.     if APanel.Folder then
  79.         FileName = FileCurrent
  80.         FileExt = ""
  81.     else
  82.         FileName = mf.fsplit(FileCurrent,4)
  83.         FileExt = mf.fsplit(FileCurrent,8):sub(2)
  84.     end
  85.     local FileNew = ""
  86.     local FileNameOut = FileName:len() <= DW-8-lang.FileNamePrompt:len() and FileName or FileName:sub(1,DW-11-lang.FileNamePrompt:len()).."..."
  87.     local FileExtOut = FileExt:len() <= DW-8-lang.FileExtPrompt:len() and FileExt or FileExt:sub(1,DW-11-lang.FileExtPrompt:len()).."..."
  88.     local FileNamePrompt = lang.FileNamePrompt:format(FileNameOut)
  89.     local FileExtPrompt = lang.FileExtPrompt:format(FileExtOut)
  90.  
  91.     local Items = {} -- for TestAddItem==0
  92.  
  93.     local D,DI,DL,DN = dialog.New { Guid=RENAME_GUID, X2=DW, Y2=DH, DlgProc=ReName_DlgProc, Title=lang.Title }
  94.  
  95.     if TestAddItem == 0 then -- классическая таблица с дополнительными полями
  96.         Items = {
  97.             --{ "DI_DOUBLEBOX", 3, DN(1), DW-4, DH-2, 0, 0, 0, 0, lang.Title },
  98.             { Name="FileNamePrompt", "DI_TEXT", D.LC, DN(1), 0, 0, 0, 0, 0, 0, FileNamePrompt },
  99.             { Name="FileName", "DI_EDIT", D.LC, DN(1), D.RC, 0, 0, cfg.FileNameHistory, 0, "DIF_HISTORY", FileName },
  100.             { Name="FileExtPrompt", "DI_TEXT", D.LC, DN(1), 0, 0, 0, 0, 0, 0, FileExtPrompt },
  101.             { "DI_TEXT", D.LC, DN(1), 0, 0, 0, 0, 0, 0, "." },
  102.             { Name="FileExt", "DI_EDIT", D.LC+1, DN(0), D.RC, 0, 0, cfg.FileExtHistory, 0, "DIF_HISTORY", FileExt },
  103.             { "DI_TEXT", 0, DN(1), 0, 0, 0, 0, 0, "DIF_SEPARATOR" },
  104.             { Name="OK", "DI_BUTTON", 0, DH-3, 0, 0, 0, 0, 0, {DIF_CENTERGROUP=1, DIF_DEFAULTBUTTON=1}, lang.OkButton, },
  105.             { Name="Cancel", "DI_BUTTON", 0, DH-3, 0, 0, 0, 0, 0, {DIF_CENTERGROUP=1}, lang.CancelButton },
  106.         }
  107.     elseif TestAddItem == 1 then -- обычный список
  108.         DI.FileNamePrompt = { "DI_TEXT", D.LC, DN(1), 0, 0, 0, 0, 0, 0, FileNamePrompt }
  109.         DI.FileName = { "DI_EDIT", D.LC, DN(1), D.RC, 0, 0, cfg.FileNameHistory, 0, "DIF_HISTORY", FileName }
  110.         DI.FileExtPrompt = { "DI_TEXT", D.LC, DN(1), 0, 0, 0, 0, 0, 0, FileExtPrompt }
  111.         DI._dot = { "DI_TEXT", D.LC, DN(1), 0, 0, 0, 0, 0, 0, "." }
  112.         DI.FileExt = { "DI_EDIT", D.LC+1, DN(0), D.RC, 0, 0, cfg.FileExtHistory, 0, "DIF_HISTORY", FileExt }
  113.         DI._sep = { "DI_TEXT", 0, DN(1), 0, 0, 0, 0, 0, "DIF_SEPARATOR" }
  114.         DI.OK = { "DI_BUTTON", 0, DH-3, 0, 0, 0, 0, 0, {DIF_CENTERGROUP=1, DIF_DEFAULTBUTTON=1}, lang.OkButton, }
  115.         DI.Cancel = { "DI_BUTTON", 0, DH-3, 0, 0, 0, 0, 0, {DIF_CENTERGROUP=1}, lang.CancelButton }
  116.     elseif TestAddItem == 2 then -- именованные параметры
  117.         DI.FileNamePrompt = { "DI_TEXT", X1=D.LC, YN=1, Text=FileNamePrompt }
  118.         DI.FileName = { "DI_EDIT", X1=D.LC, X2=D.RC, YN=1, History=cfg.FileNameHistory, Text=FileName }
  119.         DI.FileExtPrompt = { "DI_TEXT", X1=D.LC, YN=1, Text=FileExtPrompt }
  120.         DI._dot = { "DI_TEXT", X1=D.LC, YN=1, Text="." }
  121.         DI.FileExt = { "DI_EDIT", X1=D.LC+1, X2=D.RC, History=cfg.FileExtHistory, Text=FileExt }
  122.         DI._sep = { "DI_TEXT", YN=1, Flags="DIF_SEPARATOR" }
  123.         DI.OK = { "DI_BUTTON", YN=1, Flags={DIF_CENTERGROUP=1, DIF_DEFAULTBUTTON=1}, Text=lang.OkButton, }
  124.         DI.Cancel = { "DI_BUTTON", Flags={DIF_CENTERGROUP=1}, Text=lang.CancelButton }
  125.     elseif TestAddItem == 3 then -- сокращённое указание типа и флагов
  126.         DI.FileNamePrompt = { "t+", Text=FileNamePrompt }
  127.         DI.FileName = { "e+", History=cfg.FileNameHistory, Text=FileName }
  128.         DI.FileExtPrompt = { "t+", Text=FileExtPrompt }
  129.         DI._dot = { "t+", Text="." }
  130.         DI.FileExt = { "e", X1=D.LC+1, History=cfg.FileExtHistory, Text=FileExt }
  131.         DI._sep = { "s+" }
  132.         DI.OK = { "b=!+", Text=lang.OkButton }
  133.         DI.Cancel = { "b=", Text=lang.CancelButton }
  134.     elseif TestAddItem == 4 then -- AddItem
  135.         D:AddItem { "t+", Name="FileNamePrompt", Text=FileNamePrompt }
  136.         D:AddItem { "e+", Name="FileName", History=cfg.FileNameHistory, Text=FileName }
  137.         D:AddItem { "t+", Name="FileExtPrompt", Text=FileExtPrompt }
  138.         D:AddItem { "t+", Text="." }
  139.         D:AddItem { "e", Name="FileExt", X1=D.LC+1, History=cfg.FileExtHistory, Text=FileExt }
  140.         D:AddItem { "s+" }
  141.         D:AddItem { "b=!+", Name="OK", Text=lang.OkButton }
  142.         D:AddItem { "b=", Name="Cancel", Text=lang.CancelButton }
  143.     elseif TestAddItem == 5 then -- D.I(), D.Items()
  144.         D.Items { "t+", Name="FileNamePrompt", Text=FileNamePrompt }
  145.         D.Items { "e+", Name="FileName", History=cfg.FileNameHistory, Text=FileName }
  146.         D.Items { "t+", Name="FileExtPrompt", Text=FileExtPrompt }
  147.         D.Items { "t+", Text="." }
  148.         D.Items { "e", Name="FileExt", X1=D.LC+1, History=cfg.FileExtHistory, Text=FileExt }
  149.         D.Items { "s+" }
  150.         D.Items { "b=!+", Name="OK", Text=lang.OkButton }
  151.         D.Items { "b=", Name="Cancel", Text=lang.CancelButton }
  152.     else -- if TestAddItem == 6 then -- DI()
  153.         DI { "t+", Name="FileNamePrompt", Text=FileNamePrompt }
  154.         DI { "e+", Name="FileName", History=cfg.FileNameHistory, Text=FileName }
  155.         DI { "t+", Name="FileExtPrompt", Text=FileExtPrompt }
  156.         DI { "t+", Text="." }
  157.         DI { "e", Name="FileExt", X1=D.LC+1, History=cfg.FileExtHistory, Text=FileExt }
  158.         DI { "s+" }
  159.         DI { "b=!+", Name="OK", Text=lang.OkButton }
  160.         DI { "b=", Name="Cancel", Text=lang.CancelButton }
  161.     end
  162.  
  163.     local ret = D{Items=Items}
  164.    
  165.     if ret ~= -1 and ret ~= DI.Cancel.Id then
  166.         FileNew = DI.FileName.Text
  167.                 :gsub(cfg.FileNameRTrim and "["..cfg.FileNameRTrim.."%c]+$" or "[%c]+$","")
  168.                 :gsub(cfg.FileNameLTrim and "^["..cfg.FileNameLTrim.."%c]+" or "^[%c]+","")
  169.                 :gsub('"','')
  170.         FileExt = DI.FileExt.Text
  171.                 :gsub(cfg.FileExtRTrim and "["..cfg.FileExtRTrim.."%c]+$" or "[%c]+$","")
  172.                 :gsub(cfg.FileExtLTrim and "^["..cfg.FileExtLTrim.."%c]+" or "^[%c]+","")
  173.                 :gsub('"',''):gsub('\\+','')
  174.         if not APanelFolder and cfg.KillDupExt and mf.fsplit(FileNew,8):sub(2):lower()==FileExt:lower() and mf.fsplit(FileNew,4)~="" then
  175.             FileNew = mf.fsplit(FileNew,4)
  176.         end
  177.         if FileNew:sub(-1) ~= "\\" then -- если перемещение в папку, расширение игнорируем
  178.             FileNew = FileNew .. (FileExt~="" and "."..FileExt or "")
  179.         end
  180.         if FileCurrent ~= FileNew then
  181.             if TestRename==0 then
  182.                 Keys "ShiftF6"
  183.                 if Area.Dialog and Dlg.Id==MOVE_ID then
  184.                     if not cfg.MoveHist then
  185.                         Far.DisableHistory(8)
  186.                     end
  187.                     Keys "CtrlY"
  188.                     print(FileNew)
  189.                     Keys "CtrlEnter"
  190.                 end
  191.             else
  192.                 msgbox("RENAME",FileNew)
  193.             end
  194.         end
  195.     end
  196. end
  197.  
  198. if cfg.HotKeySwitch and cfg.HotKeySwitch~="" then
  199.     Macro {
  200.         description="Switch Rename/Move";
  201.         area="Dialog";
  202.         key=cfg.HotKeySwitch;
  203.         condition=function()
  204.             return Dlg.Id==RENAME_ID or Dlg.Id==MOVE_ID
  205.         end;
  206.         action=function()
  207.             if Dlg.Id==RENAME_ID then
  208.                 Keys("Esc ShiftF6")
  209.             else
  210.                 Keys("Esc")
  211.                 ReName()
  212.             end
  213.         end
  214.     }
  215. end
  216.  
  217. if cfg.HotKeyRename and cfg.HotKeyRename~="" then
  218.     Macro {
  219.         description="Rename";
  220.         area="Shell Search";
  221.         key=cfg.HotKeyRename;
  222.         condition=function()
  223.             local plugid = win.Uuid(panel.GetPanelDirectory(nil,1).PluginId):upper()
  224.             return APanel.Current~=".." and APanel.FilePanel and (not APanel.Plugin or plugid==TMPPANEL_ID)
  225.         end;
  226.         action=ReName
  227.     }
  228. end
  229.  
  230. if cfg.HotKeyMove and cfg.HotKeyMove~="" then
  231.     Macro {
  232.         description="Rename standart";
  233.         area="Shell Search";
  234.         key=cfg.HotKeyMove;
  235.         action=function()
  236.             Keys "ShiftF6"
  237.         end;
  238.     }
  239. end
Если кто-то использует - макрос был написан для тестирования (хотя оказался полезен). Можно выкинуть варианты вызова, оставив только один, например
  1. --[=[ ----------------------------------------------------------------------------------------------
  2. Макрос для переименования текущего файла - раздельно имя и расширение
  3. Служит также для демонстрации использования DiaologClass
  4. v.1.02 (C) Smitis, 2014-2015
  5. --]=] ----------------------------------------------------------------------------------------------
  6.  
  7. local TestRename = 0 -- тест: 1 - не делать реального переименования
  8. local dialog = require 'DialogClass'
  9. --local dialog = require 'DerivedDialogClass' -- тест для примера наследования
  10.  
  11. ----------------------------------------------------------------------------------------------------
  12.  
  13. local RENAME_ID = "C6A21A86-96AC-44FF-9046-CAF14EE76CD2"
  14. local RENAME_GUID = win.Uuid(RENAME_ID)
  15.  
  16. local MOVE_ID = "431A2F37-AC01-4ECD-BB6F-8CDE584E5A03" -- стандартный диалог RENAME/MOVE
  17. local TMPPANEL_ID = "B77C964B-E31E-4D4C-8FE5-D6B0C6853E7C"
  18.  
  19. local F = far.Flags
  20.  
  21. local cfg = {}
  22.  
  23. cfg.HotKeyRename = "" -- хоткей для макроса ReName
  24. cfg.HotKeyMove = "ShiftF6" -- хоткей для вызова стандартной функции переименования
  25. cfg.HotKeySwitch = "ShiftF6" -- хоткей макроса переключения диалогов
  26. cfg.FileNameHistory = "Rename" -- имя истории имён, в оригинальном диалоге используется "Copy"
  27. cfg.FileExtHistory = "RenameExt" -- имя истории расширений
  28. cfg.KillDupExt = true -- заменять повторяющиеся расширения на простые (типа .jpg.jpg на .jpg)
  29. cfg.DialogWidth = 76 -- ширина диалога
  30. cfg.FileNameRTrim = " ." -- символы, отбрасывамые от имени справа
  31. cfg.FileNameLTrim = " " -- символы, отбрасывамые от имени слева
  32. cfg.FileExtRTrim = " ." -- символы, отбрасывамые от расширения справа
  33. cfg.FileExtLTrim = " ." -- символы, отбрасывамые от расширения слева
  34. cfg.MoveHist = true -- вести историю в вызываемом стандартном диалоге
  35. cfg.FileNameChanged = false -- снимать состояние Unchanged для имени файла
  36. cfg.FileExtChanged = false -- снимать состояние Unchanged для расширения
  37.  
  38. ----------------------------------------------------------------------------------------------------
  39. -- Локализация
  40. ----------------------------------------------------------------------------------------------------
  41. local langs = { english = {}, russian = {} }
  42.  
  43. langs.english.Title           = 'Rename'
  44. langs.english.FileNamePrompt  = 'Change name "%s" to:'
  45. langs.english.FileExtPrompt   = 'Change extension "%s" to:'
  46. langs.english.OkButton        = 'Rename'
  47. langs.english.CancelButton    = 'Cancel'
  48.  
  49. langs.russian.Title           = 'Переименование'
  50. langs.russian.FileNamePrompt  = 'Изменить имя "%s" на:'
  51. langs.russian.FileExtPrompt   = 'Изменить расширение "%s" на:'
  52. langs.russian.OkButton        = 'Переименовать'
  53. langs.russian.CancelButton    = 'Отменить'
  54.  
  55. ----------------------------------------------------------------------------------------------------
  56.  
  57. local function ReName_DlgProc(hDlg,Msg,Param1,Param2,D,DI)
  58.     if Msg==F.DN_INITDIALOG then
  59.         DI.FileName:Unchanged(not cfg.FileNameChanged)
  60.         if APanel.Folder then
  61.             DI.FileExt:Enable(false)
  62.         else
  63.             DI.FileExt:Unchanged(not cfg.FileExtChanged)
  64.         end
  65.     end
  66. end
  67.  
  68. ----------------------------------------------------------------------------------------------------
  69.  
  70. local function ReName()
  71.     local lang = langs[win.GetEnv("FARLANG"):lower()] or langs.english
  72.     local DW,DH = cfg.DialogWidth,11 -- размеры
  73.  
  74.     local FileFull = APanel.Current
  75.     local FileCurrent = mf.fsplit(FileFull,12)
  76.     local FileName, FileExt
  77.     if APanel.Folder then
  78.         FileName = FileCurrent
  79.         FileExt = ""
  80.     else
  81.         FileName = mf.fsplit(FileCurrent,4)
  82.         FileExt = mf.fsplit(FileCurrent,8):sub(2)
  83.     end
  84.     local FileNew = ""
  85.     local FileNameOut = FileName:len() <= DW-8-lang.FileNamePrompt:len() and FileName or FileName:sub(1,DW-11-lang.FileNamePrompt:len()).."..."
  86.     local FileExtOut = FileExt:len() <= DW-8-lang.FileExtPrompt:len() and FileExt or FileExt:sub(1,DW-11-lang.FileExtPrompt:len()).."..."
  87.     local FileNamePrompt = lang.FileNamePrompt:format(FileNameOut)
  88.     local FileExtPrompt = lang.FileExtPrompt:format(FileExtOut)
  89.  
  90.     local D,DI,DL,DN = dialog.New { Guid=RENAME_GUID, X2=DW, Y2=DH, DlgProc=ReName_DlgProc, Title=lang.Title }
  91.  
  92.     DI { "t+", Name="FileNamePrompt", Text=FileNamePrompt }
  93.     DI { "e+", Name="FileName", History=cfg.FileNameHistory, Text=FileName }
  94.     DI { "t+", Name="FileExtPrompt", Text=FileExtPrompt }
  95.     DI { "t+", Text="." }
  96.     DI { "e", Name="FileExt", X1=D.LC+1, History=cfg.FileExtHistory, Text=FileExt }
  97.     DI { "s+" }
  98.     DI { "b=!+", Name="OK", Text=lang.OkButton }
  99.     DI { "b=", Name="Cancel", Text=lang.CancelButton }
  100.  
  101.     local ret = D()
  102.    
  103.     if ret ~= -1 and ret ~= DI.Cancel.Id then
  104.         FileNew = DI.FileName.Text
  105.                 :gsub(cfg.FileNameRTrim and "["..cfg.FileNameRTrim.."%c]+$" or "[%c]+$","")
  106.                 :gsub(cfg.FileNameLTrim and "^["..cfg.FileNameLTrim.."%c]+" or "^[%c]+","")
  107.                 :gsub('"','')
  108.         FileExt = DI.FileExt.Text
  109.                 :gsub(cfg.FileExtRTrim and "["..cfg.FileExtRTrim.."%c]+$" or "[%c]+$","")
  110.                 :gsub(cfg.FileExtLTrim and "^["..cfg.FileExtLTrim.."%c]+" or "^[%c]+","")
  111.                 :gsub('"',''):gsub('\\+','')
  112.         if not APanelFolder and cfg.KillDupExt and mf.fsplit(FileNew,8):sub(2):lower()==FileExt:lower() and mf.fsplit(FileNew,4)~="" then
  113.             FileNew = mf.fsplit(FileNew,4)
  114.         end
  115.         if FileNew:sub(-1) ~= "\\" then -- если перемещение в папку, расширение игнорируем
  116.             FileNew = FileNew .. (FileExt~="" and "."..FileExt or "")
  117.         end
  118.         if FileCurrent ~= FileNew then
  119.             if TestRename==0 then
  120.                 Keys "ShiftF6"
  121.                 if Area.Dialog and Dlg.Id==MOVE_ID then
  122.                     if not cfg.MoveHist then
  123.                         Far.DisableHistory(8)
  124.                     end
  125.                     Keys "CtrlY"
  126.                     print(FileNew)
  127.                     Keys "CtrlEnter"
  128.                 end
  129.             else
  130.                 msgbox("RENAME",FileNew)
  131.             end
  132.         end
  133.     end
  134. end
  135.  
  136. if cfg.HotKeySwitch and cfg.HotKeySwitch~="" then
  137.     Macro {
  138.         description="Switch Rename/Move";
  139.         area="Dialog";
  140.         key=cfg.HotKeySwitch;
  141.         condition=function()
  142.             return Dlg.Id==RENAME_ID or Dlg.Id==MOVE_ID
  143.         end;
  144.         action=function()
  145.             if Dlg.Id==RENAME_ID then
  146.                 Keys("Esc ShiftF6")
  147.             else
  148.                 Keys("Esc")
  149.                 ReName()
  150.             end
  151.         end
  152.     }
  153. end
  154.  
  155. if cfg.HotKeyRename and cfg.HotKeyRename~="" then
  156.     Macro {
  157.         description="Rename";
  158.         area="Shell Search";
  159.         key=cfg.HotKeyRename;
  160.         condition=function()
  161.             local plugid = win.Uuid(panel.GetPanelDirectory(nil,1).PluginId):upper()
  162.             return APanel.Current~=".." and APanel.FilePanel and (not APanel.Plugin or plugid==TMPPANEL_ID)
  163.         end;
  164.         action=ReName
  165.     }
  166. end
  167.  
  168. if cfg.HotKeyMove and cfg.HotKeyMove~="" then
  169.     Macro {
  170.         description="Rename standart";
  171.         area="Shell Search";
  172.         key=cfg.HotKeyMove;
  173.         action=function()
  174.             Keys "ShiftF6"
  175.         end;
  176.     }
  177. end
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1676
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 22 times
Been thanked: 52 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by Smitis »

v.1.08
- Исправлена ошибка, связанная с использованием параметра W диалога.
- Метод AddMainFrame исключён.
- Метод Clear исключён так как оказался практически ненужным (проще заново конструктор вызвать).
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1676
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 22 times
Been thanked: 52 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by Smitis »

v.1.09 Экспериментальная версия, поэтому в шапку пока не добавлял, вдруг что-нибудь всплывёт.
Продолжаю измываться над "классами" исполненными на Lua.
Для контейнера элементов диалога DialogItemsClass добавлена возможность... как бы это обозвать-то по-умному... "добавление новых именованных элементов диалога функциональным вызовом по их имени"... как-то так.
На практике это выгладит так, вместо присваивания DI.OK = { "b=!+", Text=lang.OkButton } можно писать DI.OK { "b=!+", Text=lang.OkButton }. Чисто для красивости. В примере RENAME добавление элементов этим способом будет выглядеть так:

Code: Select all

DI { "t+", Text=FileNamePrompt }
DI.FileName { "e+", History=cfg.FileNameHistory, Text=FileName }
DI { "t+", Text=FileExtPrompt }
DI { "t+", Text="." }
DI.FileExt { "e", X1=D.LC+1, History=cfg.FileExtHistory, Text=FileExt }
DI { "s+" }
DI.OK { "b=!+", Text=lang.OkButton }
DI.Cancel { "b=", Text=lang.CancelButton }
НЕОЖИДАННЫЕ побочные эффекты:
- Данный способ не позволяет добавлять элементы с одинаковыми именами. С одной строны плохо - остальные способы позволяют. С другой - хорошо, дополнительный контроль ошибок.
- В случае обращения по имени к несуществующему элементу вместо привычного сообщения, что элемент таблицы не существует, будет сообщение об ошибочном вызове функции.
  1. --[=[ ----------------------------------------------------------------------------------------------
  2. Модуль для работы с диалогами в стиле ООП.
  3. v. 1.09 (C) 2013-2015 Smitis
  4. viewtopic.php?t=8523
  5. --]=] ----------------------------------------------------------------------------------------------
  6.  
  7. local _version = "1.09"
  8. local F = far.Flags
  9.  
  10. local function log2num(b) return tonumber(b) or (b and 1) or 0 end
  11. local function state2num(b) return b==nil and -1 or log2num(b) end
  12.  
  13. -- Преобразование флагов, заданых в различном виде (число, строка, таблица) к единому числовому значению.
  14. local function flags2num(fx)
  15.     local fn = 0
  16.     if type(fx)=="string" then -- строка вида "DI_BUTTON"
  17.         fn = F[fx]
  18.     elseif type(fx)=="table" then -- таблица вида {DIF_CENTERGROUP=1, DIF_DEFAULTBUTTON=1}
  19.         for flag,v in pairs(fx) do
  20.             if v~=0 then
  21.                 fn = bor(fn,F[flag])
  22.             end
  23.         end
  24.     else -- числовое значение или nil
  25.         fn = fx or 0
  26.     end
  27.     return fn
  28. end
  29.  
  30. ----------------------------------------------------------------------------------------------------
  31. -- Класс DlgItem (элемент диалога)
  32. ----------------------------------------------------------------------------------------------------
  33.  
  34. local DlgItemClass = {}
  35.  
  36. DlgItemClass.NamedFields = {
  37.     Type=1, X1=2, Y1=3, X2=4, Y2=5, Selected=6, ListItems=6, VBuf=6,
  38.     History=7, Mask=8, Separator=8, Flags=9, Data=10, Text=10, MaxLength=11, UserData=12
  39. }
  40.  
  41. function DlgItemClass:__index(key)
  42.     if DlgItemClass.NamedFields[key] then
  43.         return rawget(self,DlgItemClass.NamedFields[key])
  44.     end
  45.     return rawget(self,key) or DlgItemClass[key]
  46. end
  47.  
  48. function DlgItemClass:__newindex(key,val)
  49.     rawset(self, DlgItemClass.NamedFields[key] or key, val)
  50. end
  51.  
  52. -- Отправить сообщение диалогу для данного элемента
  53. function DlgItemClass:Send(Msg,Param)
  54.     return self.Parent:Send(Msg,self.Id,Param)
  55. end
  56. -- Вкл./выкл элемент диалога
  57. function DlgItemClass:Enable(x)
  58.     return self:Send(F.DM_ENABLE,state2num(x)) == 1
  59. end
  60. -- Установить состояние EDITUNCHANGEDFLAG
  61. function DlgItemClass:Unchanged(x)
  62.     return self:Send(F.DM_EDITUNCHANGEDFLAG,state2num(x)) == 1
  63. end
  64. -- Показать/скрыть элемент диалога
  65. function DlgItemClass:Show(x)
  66.     return self:Send(F.DM_SHOWITEM,state2num(x)) == 1
  67. end
  68. -- Установить фокус на элемент диалога
  69. function DlgItemClass:Focus()
  70.     return self:Send(F.DM_SETFOCUS,0) == 1
  71. end
  72. -- Установить значение CHECKBOX или RADIOBUTTON
  73. function DlgItemClass:SetCheck(x)
  74.     return self:Send(F.DM_SETCHECK,x)
  75. end
  76. -- Получить значение CHECKBOX или RADIOBUTTON
  77. function DlgItemClass:GetCheck()
  78.     return self:Send(F.DM_GETCHECK,0)
  79. end
  80. -- Установить логическое состояние CHECKBOX или RADIOBUTTON
  81. function DlgItemClass:SetCheckState(x)
  82.     return self:SetCheck(log2num(x)) >= 1
  83. end
  84. -- Получить логическое состояние CHECKBOX или RADIOBUTTON
  85. function DlgItemClass:GetCheckState()
  86.     return self:GetCheck() >= 1
  87. end
  88. -- Установить текстовое значение
  89. function DlgItemClass:SetText(text)
  90.     return self:Send(F.DM_SETTEXT,text)
  91. end
  92. -- Получить текстовое значение
  93. function DlgItemClass:GetText()
  94.     return self:Send(F.DM_GETTEXT,0)
  95. end
  96. -- Установить текущую позицию для списка
  97. function DlgItemClass:SetListPos(pos,top)
  98.     return self:Send(F.DM_LISTSETCURPOS,{SelectPos=pos,TopPos=top})
  99. end
  100. -- Получить текущую позицию для списка
  101. function DlgItemClass:GetListPos()
  102.     local FarListPos = self:Send(F.DM_LISTGETCURPOS,0)
  103.     return FarListPos.SelectPos, FarListPos.TopPos
  104. end
  105. -- Установки значения в зависимости от типа элемента диалога
  106. -- [???] Если val таблица, посылать DM_SETDLGITEM?
  107. function DlgItemClass:SetValue(val,top)
  108.     if self.Type==F.DI_CHECKBOX or self.Type==F.DI_RADIOBUTTON then
  109.         return self:SetCheck(log2num(val))
  110.     elseif self.Type==F.DI_LISTBOX then
  111.         return self:SetListPos(val,top)
  112.     elseif self.Type==F.DI_COMBOBOX then
  113.         if type(val)=="number" then
  114.             return self:SetListPos(val,top)
  115.         else
  116.             return self:SetText(tostring(val))
  117.         end
  118.     else
  119.         return self:SetText(tostring(val))
  120.     end
  121. end
  122. -- Получения значения в зависимости от типа элемента диалога
  123. function DlgItemClass:GetValue()
  124.     if self.Type==F.DI_CHECKBOX or self.Type==F.DI_RADIOBUTTON then
  125.         return self:GetCheck()
  126.     elseif self.Type==F.DI_LISTBOX then
  127.         return self:GetListPos()
  128.     else
  129.         return self:GetText()
  130.     end
  131. end
  132.  
  133. ----------------------------------------------------------------------------------------------------
  134. -- Класс DlgItems (контейнер для всех dlgitem)
  135. -- Элементы с индексами <=0 являются private полями и нигде, кроме как здесь не должны использоваться.
  136. -- local __named__  =  0 -- Таблица имён элементов
  137. -- local __parent__ = -1 -- Ссылка на родительский диалог
  138. -- local __framed__ = -2 -- Ссылка на элемент рамки, добавленной методом AddMainFrame. Если nil или false - рамка не добавлялась.
  139. ----------------------------------------------------------------------------------------------------
  140.  
  141. local DlgItemsClass = {}
  142. --[=[
  143. function DlgItemsClass:__index(name)
  144.     return rawget(self, self[0][name] or name)
  145. end
  146. --]=]
  147. function DlgItemsClass:__index(name)
  148.     --local item = rawget(self, self[0][name] or name)
  149.     return rawget(self, self[0][name] or name) or function(newitem)
  150.         newitem.Name = name
  151.         self(newitem)
  152.     end
  153. end
  154.  
  155. -- Добавление нового элемента диалога
  156. function DlgItemsClass:__newindex(name,item)
  157.     local x
  158.     if type(item)=="table" then
  159.         local id = #self+1
  160.         local parent = self[-1]
  161.         item.Name = name or item.Name or "_"
  162.         item.Id = id
  163.         item.Parent = parent
  164.         self[0][item.Name] = id -- в список именованных элементов
  165.         -- копируем все виртуальные поля и удаляем их
  166.         for f,v in pairs(item) do
  167.             if DlgItemClass.NamedFields[f] then
  168.                 item[DlgItemClass.NamedFields[f]] = v
  169.                 item[f] = nil
  170.             end
  171.         end
  172.  
  173.         setmetatable(item,parent.DlgItemClass or DlgItemClass) -- объект
  174.  
  175.         item.Flags = flags2num(item.Flags) -- Flags [9] в number
  176.         if type(item.Type)=="number" or item.Type:sub(1,3)=="DI_" then
  177.             item.Type = item.Type and flags2num(item.Type) or F.DI_TEXT -- тип элемента в number или тип по умолчанию
  178.         else -- Если тип - строка начинающаяся не с DI_, это сокращённое обозначение типа элемента, параметров, опций
  179.             local typ = item.Type:sub(1,1)
  180.             local opt = item.Type:sub(2)
  181.             if typ == "b" then
  182.                 item.Type = F.DI_BUTTON
  183.                 if opt:find("b") then item.Flags = bor(item.Flags,F.DIF_NOBRACKETS) end
  184.                 if opt:find(";") then item.Flags = bor(item.Flags,F.DIF_BTNNOCLOSE) end
  185.             elseif typ == "f" then
  186.                 item.Type = opt:find("d") and F.DI_DOUBLEBOX or F.DI_SINGLEBOX
  187.             elseif typ == "t" then
  188.                 item.Type = opt:find("v") and F.DI_VTEXT or F.DI_TEXT
  189.                 -- DIF_WORDWRAP ???
  190.             elseif typ == "e" then
  191.                 item.Type = opt:find("f") and F.DI_FIXEDIT or F.DI_EDIT
  192.                 if opt:find("o") then item.Flags = bor(item.Flags,F.DIF_READONLY) end
  193.                 if opt:find("e") then item.Flags = bor(item.Flags,F.DIF_EDITOR) end
  194.                 if opt:find("h") then item.Flags = bor(item.Flags,F.DIF_HISTORY) end
  195.                 if opt:find("m") then item.Flags = bor(item.Flags,F.DIF_MANUALADDHISTORY) end
  196.                 if opt:find("l") then item.Flags = bor(item.Flags,F.DIF_USELASTHISTORY) end
  197.             elseif typ == "p" then
  198.                 item.Type = F.DI_PSWEDIT
  199.             elseif typ == "s" then -- DI_TEXT | DI_VTEXT & DIF_SEPARATOR | DIF_SEPARATOR2
  200.                 item.Type = opt:find("v") and F.DI_VTEXT or F.DI_TEXT
  201.                 item.Flags = bor(item.Flags,opt:find("d") and F.DIF_SEPARATOR2 or F.DIF_SEPARATOR)
  202.             elseif typ == "r" then
  203.                 item.Type = F.DI_RADIOBUTTON
  204.             elseif typ == "c" then
  205.                 item.Type = F.DI_CHECKBOX
  206.                 if opt:find("3") then item.Flags = bor(item.Flags,F.DIF_3STATE) end
  207.             elseif typ == "l" then
  208.                 item.Type = F.DI_LISTBOX
  209.             elseif typ == "x" then
  210.                 item.Type = F.DI_COMBOBOX
  211.                 if opt:find("d") then item.Flags = bor(item.Flags,F.DIF_DROPDOWNLIST) end
  212.             elseif typ == "u" then
  213.                 item.Type = F.DI_USERCONTROL
  214.             else
  215.                 item.Type = F.DI_TEXT
  216.             end
  217.             if opt:find("|") then item.Flags = bor(item.Flags,F.DIF_CENTERTEXT) end
  218.             if opt:find(">") then item.Flags = bor(item.Flags,F.DIF_RIGHTTEXT) end
  219.             if opt:find("<") then item.Flags = bor(item.Flags,F.DIF_LEFTTEXT) end
  220.             if opt:find("!") then item.Flags = bor(item.Flags,F.DIF_DEFAULTBUTTON) end
  221.             if opt:find("[=c]") then item.Flags = bor(item.Flags,F.DIF_CENTERGROUP) end
  222.             if opt:find("[:g]") then item.Flags = bor(item.Flags,F.DIF_GROUP) end
  223.             if opt:find("[?x]") then item.Flags = bor(item.Flags,F.DIF_DISABLE) end
  224.             if opt:find("[*s]") then item.Flags = bor(item.Flags,F.DIF_SELECTONENTRY) end
  225.             if opt:find("/") then item.Flags = bor(item.Flags,F.DIF_NOFOCUS) end
  226.             if opt:find("@") then item.Flags = bor(item.Flags,F.DIF_FOCUS) end
  227.             if opt:find("&") then item.Flags = bor(item.Flags,F.DIF_SHOWAMPERSAND) end
  228.             x = opt:gsub("[^+]","") -- подсчитываем "+"
  229.             if x:len()>0 then item[3] = parent:NewLine(x:len()) end
  230.             x = opt:gsub("[^%-]","") -- посчитываем "-"
  231.             if x:len()>0 then item[3] = parent:NewLine(-x:len()) end
  232.         end
  233.  
  234.         item.X1 = item.X1 or parent.LC   -- [2]
  235.         item.Y1 = item.Y1 or parent.Line -- [3]
  236.         item.X2 = item.X2 or parent.RC   -- [4]
  237.         if item.SL or item.YS or item.SetLine then item.Y1 = parent:SetLine(item.SL or item.YS or item.SetLine) end
  238.         if item.NL or item.YN or item.NewLine then item.Y1 = parent:NewLine(item.NL or item.YN or item.NewLine) end
  239.         if item.X2==0 and item.X1>0 then item.X2=item.X1 end -- исправляем X2
  240.         item.Y2 = item.Y2 or 0           -- [5]
  241.         if item.Y2==0 and item.Y1>0 then item.Y2=item.Y1 end -- исправляем Y2
  242.         if item.W then
  243.             item.X2 = item.X1>=0 and item.X1+item.W-1 or item.W
  244.             item.W = nil -- item.X1>=0 and item.X2-item.X1+1 or item.X2
  245.         end
  246.  
  247.         item.Selected = item.Selected or 0 -- Selected
  248.         if type(item.History)=="string" and item.History~="" then -- если есть History
  249.             item.Flags = bor(item.Flags,F.DIF_HISTORY)
  250.         end
  251.         if type(item.Separator)=="string" and item.Separator~="" then -- если есть Mask/Separator
  252.             if item.Type==F.DI_TEXT or item.Type==F.DI_VTEXT then
  253.                 item.Flags = bor(item.Flags,F.DIF_SEPARATORUSER)
  254.             else
  255.                 item.Flags = bor(item.Flags,F.DIF_MASKEDIT)
  256.             end
  257.         end
  258.         if item.Type==F.DI_BUTTON or item.Type==F.DI_CHECKBOX or item.Type==F.DI_RADIOBUTTON then
  259.             item.Text = item.Text or item.Name -- если не задана надпись на кнопке, берём имя элемента
  260.         end
  261.  
  262.         rawset(self,id,item) -- Добавляем
  263.     end
  264. end
  265.  
  266. -- Добавление DlgItem вызовом как функции
  267. function DlgItemsClass:__call(...)
  268.     DlgItemsClass.__newindex(self,false,...)
  269. end
  270.  
  271. -- Конструктор DlgItemsClass
  272. setmetatable( DlgItemsClass, {
  273.     __call = function(self,dlg)
  274.         return setmetatable({[-2]=false,[-1]=dlg,[0]={}},self)
  275.     end
  276. })
  277.  
  278. ----------------------------------------------------------------------------------------------------
  279. -- Класс Dialog
  280. ----------------------------------------------------------------------------------------------------
  281.  
  282. local DialogClass = {}
  283. DialogClass.__index = DialogClass
  284.  
  285. -- Подчинённые классы
  286. DialogClass.DlgItemClass = DlgItemClass
  287. DialogClass.DlgItemsClass = DlgItemsClass
  288.  
  289. ----------------------------------------------------------------------------------------------------
  290. -- Добавить элемент диалога
  291. function DialogClass:AddItem(item)
  292.     if type(item)=="table" then
  293.         self.Items[false] = item
  294.         return item
  295.     end
  296. end
  297. -- Добавить элементы диалога из массива
  298. function DialogClass:AddItems(items)
  299.     if type(items)=="table" then
  300.         for n,item in ipairs(items) do
  301.             self:AddItem(item)
  302.         end
  303.     end
  304.     return self
  305. end
  306.  
  307. -- Подготовка объекта диалога к новому применению, удаление всех dlgitem
  308. -- Если используется рамка, будет добавлен элемент диалога для рамки
  309. --[=[
  310. function DialogClass:Clear()
  311.     self.Items = (self.DlgItemsClass or DlgItemsClass)(D) -- self.Items = setmetatable({[-2]=false,[-1]=self,[0]={}},DlgItemsClass)
  312.     self.Guid = ""
  313.     self.Handle = 0
  314.     self.DlgProc = nil
  315.     self.HelpTopic = ""
  316.     self.Line = 0
  317.     self.MaxLine = 0
  318.     self.Ret = 0
  319.     return self
  320. end --]=]
  321.  
  322. -- Заполнения общих свойств диалога
  323. function DialogClass:SetProperties(Tab,...)
  324.     local Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc,Frame
  325.     if type(Tab)=="table" then
  326.         for i,v in pairs(Tab) do
  327.             if i == "Items" then
  328.                 Items = v
  329.             else
  330.                 self[i] = v
  331.             end
  332.         end
  333.     else
  334.         Guid = Tab
  335.         X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc = ...
  336.     end
  337.     self.Guid = Guid or self.Guid or ""
  338.     self.X1 = X1 or self.X1 or -1
  339.     self.Y1 = Y1 or self.Y1 or -1
  340.     self.X2 = X2 or self.X2 or 0
  341.     self.Y2 = Y2 or self.Y2 or 0
  342.     if self.W then
  343.         self.X2 = self.X1>=0 and self.X1+self.W-1 or self.W
  344.         self.W = nil -- self.X1>=0 and self.X2-self.X1+1 or self.X2
  345.     end
  346.     if self.H then
  347.         self.Y2 = self.Y1>=0 and self.Y1+self.H-1 or self.H
  348.         self.H = nil -- self.Y1>=0 and self.Y2-self.Y1+1 or self.Y2
  349.     end
  350.     self.LC = self.LC or 1
  351.     self.RC = self.RC or ( self.X1>=0 and self.X2-self.X1-1 or self.X2-2 )
  352.     self.Line = self.Line or 1
  353.     self.MaxLine = self.Y1>=0 and self.Y2-self.Y1-1 or self.Y2-2
  354.     self.HelpTopic = HelpTopic or self.HelpTopic
  355.     if (self.Frame or self.Title) and not self.Items[-2] then
  356.         self.Title = self.Title or ""
  357.         self.Frame = self.Frame or 2
  358.         self.Items[-2] = self:AddItem {self.Frame==1 and F.DI_SINGLEBOX or F.DI_DOUBLEBOX,3,1,(self.X1>=0 and self.X2-self.X1-3 or self.X2-4),(self.Y1>=0 and self.Y2-self.Y1-1 or self.Y2-2),0,0,0,0,self.Title}
  359.         self.Line = 1 -- на уровне рамки (не ниже - для упрощения использования опции +)
  360.         self.LC = 5 -- правее рамки через символ
  361.         self.RC = self.X1>=0 and self.X2-self.X1-5 or self.X2-6 -- левее рамки через символ
  362.     end
  363.     self:AddItems(Items)
  364.     self.Flags = flags2num(Flags or self.Flags)
  365.     self.DlgProc = DlgProc or self.DlgProc
  366.     self.Handle = self.Handle or 0
  367.     self.Refreshed = self.Refreshed or true
  368.     self.Ret = 0
  369.     return self
  370. end
  371. -- Отправка сообщения диалогу
  372. function DialogClass:Send(Msg,Param1,Param2)
  373.     return far.SendDlgMessage(self.Handle,Msg,Param1,Param2)
  374. end
  375. -- Аналог far.DialogInit()
  376. -- В DlgProc будут переданы два дополнительных параметра
  377. function DialogClass:Init(...)
  378.     self:SetProperties(...)
  379.     self.Handle =
  380.         far.DialogInit(
  381.             self.Guid,self.X1,self.Y1,self.X2,self.Y2,self.HelpTopic,self.Items,self.Flags,
  382.             self.DlgProc and function(hDlg,Msg,Param1,Param2) return self.DlgProc(hDlg,Msg,Param1,Param2,self,self.Items) end
  383.         )
  384.     return self.Handle
  385. end
  386. -- Аналог far.DialogRun()
  387. function DialogClass:Run()
  388.     self.Ret = far.DialogRun(self.Handle)
  389.     if self.Refreshed then self:Refresh() end
  390.     return self.Ret
  391. end
  392. -- Аналог far.DialogFree()
  393. function DialogClass:Free()
  394.     far.DialogFree(self.Handle)
  395.     self.Handle = 0
  396. end
  397. -- Аналог far.Dialog()
  398. function DialogClass:Exec(...)
  399.     self:Init(...) self:Run() self:Free()
  400.     return self.Ret
  401. end
  402. -- Функциональный запуск D() - то же, что D:Exec()
  403. function DialogClass:__call(...)
  404.     return self:Exec(...)
  405. end
  406. -- Установить фокус на элемент диалога
  407. function DialogClass:SetFocus(id)
  408.     return self:Send(F.DM_SETFOCUS,id,0)
  409. end
  410. -- Получить id элемента диалога в фокусе
  411. function DialogClass:GetFocus()
  412.     return self:Send(F.DM_GETFOCUS,0,0)
  413. end
  414. -- Вкл./выкл. автоматическую перерисовку
  415. function DialogClass:AutoRedraw(x)
  416.     return self:Send(F.DM_ENABLEREDRAW,log2num(x),0)
  417. end
  418. -- Перерисовать
  419. function DialogClass:Redraw()
  420.     return self:Send(F.DM_REDRAW,0,0)
  421. end
  422. ----------------------------------------------------------------------------------------------------
  423. -- Установить текущую строку.
  424. -- При отрицательном значении отсчёт от D.Opt.MaxLine или D.MaxLine
  425. function DialogClass:SetLine(n)
  426.     if n then self.Line = n<0 and self.MaxLine+1+n or n end
  427.     return self.Line
  428. end
  429. DialogClass.SL = DialogClass.SetLine
  430. -- Перейти на следующую строку или несколько строк относительно текущей
  431. function DialogClass:NewLine(n)
  432.     self.Line = self.Line+(n or 1)
  433.     return self.Line
  434. end
  435. DialogClass.NL = DialogClass.NewLine
  436. ----------------------------------------------------------------------------------------------------
  437. -- Сохранить все поля диалога, имена которых не начинаются с символа подчёркивания, в таблицу по условию.
  438. -- Возвращается ссылка на таблицу. Если таблица не задана, создаётся новая.
  439. function DialogClass:Save(_tab,condition)
  440.     if self.Handle==0 then return end
  441.     local tab = type(_tab)=="table" and _tab or {}
  442.     for id,item in ipairs(self.Items) do
  443.         if item.Name~="" and item.Name:sub(1,1)~="_" then -- если имя не начинается с подчёркивания
  444.             local typ = item.Type
  445.             if type(condition)=="string" then
  446.                 if item[condition] then
  447.                     tab[item.Name] = item:GetValue()
  448.                 end
  449.             elseif type(condition)=="function" then
  450.                 if condition(item) then
  451.                     tab[item.Name] = item:GetValue()
  452.                 end
  453.             elseif typ~=F.DI_BUTTON and typ~=F.DI_DOUBLEBOX and typ~=F.DI_SINGLEBOX and typ~=F.DI_USERCONTROL then
  454.                 tab[item.Name] = item:GetValue()
  455.             end
  456.         end
  457.     end
  458.     return tab
  459. end
  460. -- Скопировать все информационные поля items в таблицу, по аналогии с Save
  461. function DialogClass:Copy(_tab,condition)
  462.     local tab = type(_tab)=="table" and _tab or {}
  463.     for id,item in ipairs(self.Items) do
  464.         if item.Name~="" and item.Name:sub(1,1)~="_" then -- если имя не начинается с подчёркивания
  465.             local typ = item.Type
  466.             if type(condition)=="string" then
  467.                 if item[condition] then
  468.                     tab[item.Name] = item.Text
  469.                 end
  470.             elseif type(condition)=="function" then
  471.                 if condition(item) then
  472.                     tab[item.Name] = item.Selected
  473.                 end
  474.             elseif typ~=F.DI_BUTTON and typ~=F.DI_DOUBLEBOX and typ~=F.DI_SINGLEBOX and typ~=F.DI_USERCONTROL then
  475.                 tab[item.Name] = item:GetValue()
  476.             end
  477.         end
  478.     end
  479.     return tab
  480. end
  481. -- Обновить все исходные items значениями из диалога
  482. function DialogClass:Refresh()
  483.     for id,item in ipairs(self.Items) do
  484.         local real = far.GetDlgItem(self.Handle,id) -- можно бы сделать setmetatable, но нафиг
  485.         if type(item.Selected)=="table" then
  486.             item.Selected.SelectIndex = item:GetListPos()
  487.         else
  488.             item.Selected = real[6]
  489.         end
  490.         item.Text = real[10]
  491.     end
  492.  
  493. end
  494. -- Загрузить все поля диалога из таблицы по условию
  495. function DialogClass:Load(tab,condition)
  496.     if self.Handle==0 then return end
  497.     for id,item in ipairs(self.Items) do
  498.         if item.Name~="" and item.Name:sub(1,1)~="_" and tab[item.Name]~=nil then -- если имя не начинается с подчёркивания
  499.             if type(condition)=="string" then
  500.                 if item[condition] then
  501.                     item:SetValue(tab[item.Name])
  502.                 end
  503.             elseif type(condition)=="function" then
  504.                 if condition(item) then
  505.                     item:SetValue(tab[item.Name])
  506.                 end
  507.             else
  508.                 item:SetValue(tab[item.Name])
  509.             end
  510.         end
  511.     end
  512. end
  513. ----------------------------------------------------------------------------------------------------
  514. -- Конструктор
  515. local function New(...)
  516.     local D = {}
  517.     D.Items = DlgItemsClass(D) -- D.Items = setmetatable({[-2]=false,[-1]=D,[0]={}},DlgItemsClass)
  518.     D.I, D.i = D.Items, D.Items -- синонимы
  519.     setmetatable(D,DialogClass) -- объект
  520.     D:SetProperties(...)
  521.     -- Возвращаемые значения: сам диалог, таблица Items, функция SetLine, функция NewLine
  522.     return D, D.Items, function(n) return D:SetLine(n) end, function(n) return D:NewLine(n) end
  523. end
  524. ----------------------------------------------------------------------------------------------------
  525. return
  526.     {
  527.         New = New,
  528.         DialogClass=DialogClass,
  529.         DlgItemClass=DlgItemClass,
  530.         DlgItemsClass=DlgItemsClass,
  531.         log2num = log2num,
  532.         state2num = state2num,
  533.         flags2num = flags2num,
  534.         _VERSION = _version
  535.     }
  536. ----------------------------------------------------------------------------------------------------
Разум когда-нибудь победит.
User avatar
sToLp
Posts: 938
Joined: Thu 23 Jul, 2009 10:16
Has thanked: 107 times
Been thanked: 12 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by sToLp »

Smitis
Макрос переименования с новым модулем и внесёнными в макрос рекомендованными Вами правками работает хорошо.

Конструкции, которые Вы предлагаете, безусловно интересны и полезны для изучения. Но для повседневного использования они, на мой взгляд, весьма сложны.
Поэтому было бы хорошо, если бы Вы на базе модуля DialogClass создали бы ещё парочку-другую применяемых на практике макросов. На Ваше усмотрение, разумеется.

Например, полезно было бы иметь возможность вызывать диалог 'Копирование', в котором раздельно настраивать путь (пути), имя и расширение файла; и редакторные диалоги 'Открыть/создать файл' и 'Сохранить файл как' — путь, имя, расширение файла + кодовая страница.
User avatar
Smitis
Posts: 1676
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 22 times
Been thanked: 52 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by Smitis »

sToLp wrote:Конструкции, которые Вы предлагаете, безусловно интересны и полезны для изучения. Но для повседневного использования они, на мой взгляд, весьма сложны.
Удивило это мнение, ведь модуль создавался для облегчения работы с диалогами. Неужели всё настолько сложно (я имею ввиду не внутреннюю структуру, а именно использование)?
Разум когда-нибудь победит.
User avatar
sToLp
Posts: 938
Joined: Thu 23 Jul, 2009 10:16
Has thanked: 107 times
Been thanked: 12 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by sToLp »

Smitis wrote: модуль создавался для облегчения работы с диалогами
Применить макрос, созданный на основе модуля, естественно, не сложно. А вот само создание макросов с использованием модуля представляется мне делом затруднительным, требующим немалого дополнительного напряжения, да. Поэтому я бы предпочёл иметь несколько шаблонных макросов. Но, возможно, это сугубо субъективно.
User avatar
Smitis
Posts: 1676
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 22 times
Been thanked: 52 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by Smitis »

sToLp wrote:А вот само создание макросов с использованием модуля представляется мне делом затруднительным, требующим немалого дополнительного напряжения, да.
Напряжение менее, чем делать диалог без модуля - вводить меньше.
А один шаблон уже есть - это тот самый RENAME. В нём есть:
- Конфигурация вынесенная в начало скрипта (правда, не в отдельный файл).
- Локализация интерфейса.
- Простая диалоговая процедура.
- Вызов конструктора New.
- Добавление элементов диалога несколькими разными способами.
- Обработка результатов.

Будет ещё что-нибудь интересное - выложу.
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1676
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 22 times
Been thanked: 52 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by Smitis »

v.1.10
Описание в шапке пока дорабатываю

Изменения DialogClass:

- Допилены Save, Copy, Load. Я ими почти не пользовался, оказалось в них содержатся какие-то совершенно невнятные моменты.
- Рамка будет иметь имя __MainFrame
- Поле диалога WW (Width of Work area) содержит ширину области для элементов с учётом отступа от краёв и от рамки для удобства задания ширины элементов "во всю ширину".

Изменения DialogItemClass:

- Методы CheckType и CheckFlags (в большей степени для внутреннего использования)
- Поле H для задания высоты DI_LISTBOX, DI_COMBOBOX, DI_USERCONTROL
- Поле W для задания ширины
- Уточнение задаваемых координат по умолчанию для большего соответствия справке
- Сокращения для стандартных полей элемента T=Text, Max=MaxLength, F=Flags, His=History, LI=ListItems, S=Sel=Selected, Sep=Separator
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1676
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 22 times
Been thanked: 52 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by Smitis »

Ещё примеры использования http://forum.farmanager.com/viewtopic.p ... 08#p133908
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1676
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 22 times
Been thanked: 52 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by Smitis »

v.1.11

- DialogClass:ExistItem
Так как с некоторых пор (v.1.09) обращение по имени к несуществующему элементу вызывает конструктор нового элемента с данным именем, стало невозможным делать проверки на существование элемента (иногда нужно, когда элемент создаётся по условию). Проверить можно через D.Items[0]["имя_элемента"] или rawget или новым методом ExistItem. Метод возвращает либо таблицу элемента (по сути - прямой доступ к таблице через rawget) или nil.
- Доработан flags2num. Изменение не принципиальное, чисто для большей универсальности.
- GUID теперь можно задавать в любом из двух стандартных видов, как бинарную строку, так и в виде строки xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Преобразование в бинарную строку происходит автоматически.
- DlgItemClass:SetFlags(...) для задания флагов. Для удобства. По сути item.Flags = bor(item.Flags,...) c пребразованием флагов в виде строк и таблиц в number.
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1676
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 22 times
Been thanked: 52 times

DialogClass — модуль для работы с диалогами с стиле ООП

Post by Smitis »

v.1.15
Промежуточные версии не выкладывал, там ничего интересного, экспериментировал.
Изменения:
  • Теперь для каждого элемента можно указывать свой ItemProc. Принимает те же параметры, что и DlgProc, за исключением Param1. Если возвращает "истину", вызывается DlgProc, иначе обработка заканчивается.
  • Свойство Parent переименовано в Owner, чтобы было как в FAR-е.
  • Свойств SL, NL, YS, YN элементов диалога больше нет. Вместо них таблица WorkArea.
  • Удалены методы SetCheckState и GetCheckState как не вписывающиеся в общую концепцию.
    Вроде, ничего не забыл.
    Свойства LC, RC, MaxLine, LastLine на очереди к удалению. Пока не удалены, под вопросом.
Разум когда-нибудь победит.
Post Reply

Return to “Обсуждение макросов”