- Задание параметров диалога и элементов диалога в более нагладном виде - таблицами с именованными полями.
- Вся работа с диалогом и элементами осуществляется вызовом соответствующих методов без непосредственного вызова far.SendDlgMessage и других функций из таблицы far.
- Не требуется сохранять хендл диалога.
- Нет необходимости считать вручную и где-то сохранять ID элементов. Элементы диалога имеют дополнительные поля, в том числе поле Name, позволяющее обращаться к элементам диалога по именам.
- Специальные функции облегчают работу с созданием диалога "по строкам".
- Дополнительные методы облегчат сохранение всех значений элементов в таблицу. И наоборот, заполнение значений элементов из таблицы.
local dialog = require "DialogClass"
Возвращаемая таблица содержит:
dialog.New() - Конструктор. Создаётся новый объект
Использование:
D,DI,DL,DN = dialog.New(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc)
или
D,DI,DL,DN = dialog.New(Tab)
Параметры:
Tab - Таблица с параметрами диалога. Таблица может содержать любые параметры диалога в виде соответствующих именованных полей, например стандартные Guid,X1,Y1,X2,Y2 и т.д.
Guid,X1,Y1,X2,Y2,HelpTopic,Flags - Параметры, имеющие те же значения, что и передаваемые в far.DialogInit и far.Dialog.
Items - Массив элементов диалога. Добавляется через метод AddItems.
DlgProc - Диалоговая процедура. Организуется как обычно, но ей будут переданы два дополнительных параметра - ссылка на сам диалог и ссылка на таблицу Items диалога. Таким образом, формат вызова будет иметь вид DlgProc(hDlg,Msg,Param1,Param2,Dlg,DlgItems).
Ни один из передаваемых конструктору параметров не является обязательным (может быть nil). Все параметры могут быть переданны через методы Init, Exec или SetProperties.
Возвращаемые значения:
D - Собственно, объект DialogClass. Если задана Tab, то D = Tab.
DI - Таблица D.Items.
DL - Функция SetLine.
DN - Функция NewLine.
Возвращаемые значения DI, DL и DN добавлены исключительно для удобства, использование их не обязательно. В простейшем случае вызов конструктора выглядит так:
dialog.log2num(x) - вспомогательная функция для преобразования логических значений в числовые, по принципу nil или false - 0, true - 1, что требуется FarApi. Заодно и числа в строковой форме в number переводит.
dialog.state2num(x) - ещё одна вспомогательная функция. Если x=nil, возвращает -1, в остальных случаях аналогично log2num.
dialog.flags2num(x) - функция преобразования флагов, заданных строкой или таблицей в число.
dialog.DialogClass, dialog.DlgItemClass, dialog.DlgItemsClass - Ссылки на классы, для удобства организации наследования.
dialog._VERSION - строка, содержащая версию модуля.
Возвращаемая таблица содержит:
dialog.New() - Конструктор. Создаётся новый объект
Использование:
D,DI,DL,DN = dialog.New(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc)
или
D,DI,DL,DN = dialog.New(Tab)
Параметры:
Tab - Таблица с параметрами диалога. Таблица может содержать любые параметры диалога в виде соответствующих именованных полей, например стандартные Guid,X1,Y1,X2,Y2 и т.д.
Guid,X1,Y1,X2,Y2,HelpTopic,Flags - Параметры, имеющие те же значения, что и передаваемые в far.DialogInit и far.Dialog.
Items - Массив элементов диалога. Добавляется через метод AddItems.
DlgProc - Диалоговая процедура. Организуется как обычно, но ей будут переданы два дополнительных параметра - ссылка на сам диалог и ссылка на таблицу Items диалога. Таким образом, формат вызова будет иметь вид DlgProc(hDlg,Msg,Param1,Param2,Dlg,DlgItems).
Ни один из передаваемых конструктору параметров не является обязательным (может быть nil). Все параметры могут быть переданны через методы Init, Exec или SetProperties.
Возвращаемые значения:
D - Собственно, объект DialogClass. Если задана Tab, то D = Tab.
DI - Таблица D.Items.
DL - Функция SetLine.
DN - Функция NewLine.
Возвращаемые значения DI, DL и DN добавлены исключительно для удобства, использование их не обязательно. В простейшем случае вызов конструктора выглядит так:
D = dialog.New()
dialog.log2num(x) - вспомогательная функция для преобразования логических значений в числовые, по принципу nil или false - 0, true - 1, что требуется FarApi. Заодно и числа в строковой форме в number переводит.
dialog.state2num(x) - ещё одна вспомогательная функция. Если x=nil, возвращает -1, в остальных случаях аналогично log2num.
dialog.flags2num(x) - функция преобразования флагов, заданных строкой или таблицей в число.
dialog.DialogClass, dialog.DlgItemClass, dialog.DlgItemsClass - Ссылки на классы, для удобства организации наследования.
dialog._VERSION - строка, содержащая версию модуля.
D:AddItem(Item) - Добавить элемент, описаный таблицей Item, к диалогу. По сути, выполняет роль конструктора для DlgItemClass. Таблица Item станет объектом DlgItemClass. Возвращает Item.
D:AddItems(Items) - Массив элементов, описывающих элементы диалога. Элементы будут добавлены в массив Items диалога. Для того, чтобы элементы были доступны по именам, они должны иметь строковое поле Name содержащее будущее имя элемента. Все дабавленные элементы станут объектами DlgItemClass, сама таблица Items не изменится. Возвращает D.
D:SetProperties(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc) или D:SetProperties(Tab) - Установить свойства диалога. Возвращает D.
D:Send(Msg,Param1,Param2) - Отправить сообщение диалогу.
D:Init(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc) или D:Init(Tab) - аналог far.DialogInit. Возвращает хендл диалога.
D:Run() - аналог far.DialogRun. Если D.Refreshed=true, после закрытия диалога все значения считываются в таблицу D.Items.
D:Free() - аналог far.DialogFree.
D:Exec(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc) или D:Exec(Tab) - аналог far.Dialog, но вызывается не он, а последовательно методы Init, Run, Free.
D(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc) или D(Tab) - аналогично D:Exec.
D:SetFocus(Id) - Установливает фокус на элемент с заданным Id.
D:GetFocus() - Возвращает Id элемента диалога, имеющего фокус.
D:AutoRedraw(val) - Посылает сообщение DM_ENABLEREDRAW.
D:Redraw() - Принудительно перерисовать диалог, отсылается сообщение DM_REDRAW.
D.Line - Внутренняя переменная для удобства формирования диалога по строкам. Управляется методами SetLine и NewLine, а также возвращаемыми конструктором функциями DL и DN. По умолчанию устанавливается в 0. При задании Frame и/или Title устанавливается в 1.
D:SetLine(n) - Если указано n, устанавливает новое значение D.Line. Если n<0, отсчёт ведётся от переменной D.MaxLine. Возвращает значение D.Line.
D:SL(n) - Синоним для D:SetLine.
Использование:
D:SetLine() - Значение D.Line не изменяется.
D:SetLine(10) - Устанавливается новое значение D.Line.
D:NewLine(n) - Если указано n, изменяет D.Line на n. Если n не задано, увеличивает D.Line на 1. Возвращает значение D.Line.
D:NL(n) - Синоним для D:NewLine.
Использование:
D:NewLine() - Значение D.Line увеличивается на 1.
D:NewLine(5) - D.Line=D.Line+5
D:NewLine(-1) - D.Line=D.Line-1
D:Save(tab,condition) - Сохраняет все значения элементов диалога, с не пустыми именами не начинающимися с символа подчёркивания, в таблицу по условию. Возвращается ссылка на таблицу. Если таблица не задана, создаётся новая.
Условие может быть:
- Строка - содержит имя проверяемого поля таблицы задающей DlgItem. Если истино (не nil и не false) значение элемента диалога считывается методом GetValue и сохраняется в таблицу под тем же именем.
- Функция - Функции передаётся текущий обрабатываемый DlgItem. Сохранение просходит, если функция возвращает true.
- Если условие не заданно, считается, что оно true и проверяется только имя элемента.
D:Copy(tab,condition) - Аналогично методу Save, но сохраняемые значения берутся не через GetValue, а непосредственно из таблицы Items. Если перед этим был выполнен метод Refresh, результат будет аналогичен методу Save.
D:Load(tab,condition) - Из таблицы считыватся значения и элементам диалога устанавливаются новые значения через метод SetValue, если имя каждого обрабатываемого элемента диалога не пустое и не начинается с символа подчёркивания и существует одноимённое поле в таблице и выполняется заданное условие. Условие задаётся аналогично методу Save.
D:Refresh() - Значения элементов диалога считываются обратно в таблицу Items. Метод выполняется автоматически после закрытия диалога, если D.Refreshed=true.
D.LС - Содержит номер левого столбца, используемого для задания значения по умолчанию X1 элементов диалога. По умолчанию 1 (отступ на один символ от левого края). При задании Frame и/или Title устанавливается в 5 (отступ на один символ от левого края рамки).
D.RС - Содержит номер правого столбца, используемого для задания значения по умолчанию X2 элементов диалога. По умолчанию задаётся как отступ на один символ от правого края диалога. При задании Frame и/или Title устанавливается как отступ на один символ от правого края рамки.
D.Frame - Хранит тип рамки. После добавления элемента для рисования рамки, нигде больше не используется.
D.Title - Хранит заголовок. После добавления элемента для рисования рамки, нигде больше не используется.
D.Ret - Содержит код возврата Run или Exec. Не изменяется после Free.
D.Items - Объект DlgItemsClass, содержит все DlgItem.
D.I,D.i - Синонимы для D.Items
D.Handle - Хендл диалога, получаемый после D:Init. Обнуляется после D:Free.
D.MaxLine - Максимально возможный номер строки. Используется в SetLine.
D.Refreshed - Обновлять или нет автоматически значения элементов диалога.
D.Guid,D.X1,D.Y1,D.X2,D.Y2,D.HelpTopic,D.Flags,D.DlgProc - Стандартные свойства.
D:AddItems(Items) - Массив элементов, описывающих элементы диалога. Элементы будут добавлены в массив Items диалога. Для того, чтобы элементы были доступны по именам, они должны иметь строковое поле Name содержащее будущее имя элемента. Все дабавленные элементы станут объектами DlgItemClass, сама таблица Items не изменится. Возвращает D.
D:SetProperties(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc) или D:SetProperties(Tab) - Установить свойства диалога. Возвращает D.
D:Send(Msg,Param1,Param2) - Отправить сообщение диалогу.
D:Init(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc) или D:Init(Tab) - аналог far.DialogInit. Возвращает хендл диалога.
D:Run() - аналог far.DialogRun. Если D.Refreshed=true, после закрытия диалога все значения считываются в таблицу D.Items.
D:Free() - аналог far.DialogFree.
D:Exec(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc) или D:Exec(Tab) - аналог far.Dialog, но вызывается не он, а последовательно методы Init, Run, Free.
D(Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc) или D(Tab) - аналогично D:Exec.
D:SetFocus(Id) - Установливает фокус на элемент с заданным Id.
D:GetFocus() - Возвращает Id элемента диалога, имеющего фокус.
D:AutoRedraw(val) - Посылает сообщение DM_ENABLEREDRAW.
D:Redraw() - Принудительно перерисовать диалог, отсылается сообщение DM_REDRAW.
D.Line - Внутренняя переменная для удобства формирования диалога по строкам. Управляется методами SetLine и NewLine, а также возвращаемыми конструктором функциями DL и DN. По умолчанию устанавливается в 0. При задании Frame и/или Title устанавливается в 1.
D:SetLine(n) - Если указано n, устанавливает новое значение D.Line. Если n<0, отсчёт ведётся от переменной D.MaxLine. Возвращает значение D.Line.
D:SL(n) - Синоним для D:SetLine.
Использование:
D:SetLine() - Значение D.Line не изменяется.
D:SetLine(10) - Устанавливается новое значение D.Line.
D:NewLine(n) - Если указано n, изменяет D.Line на n. Если n не задано, увеличивает D.Line на 1. Возвращает значение D.Line.
D:NL(n) - Синоним для D:NewLine.
Использование:
D:NewLine() - Значение D.Line увеличивается на 1.
D:NewLine(5) - D.Line=D.Line+5
D:NewLine(-1) - D.Line=D.Line-1
D:Save(tab,condition) - Сохраняет все значения элементов диалога, с не пустыми именами не начинающимися с символа подчёркивания, в таблицу по условию. Возвращается ссылка на таблицу. Если таблица не задана, создаётся новая.
Условие может быть:
- Строка - содержит имя проверяемого поля таблицы задающей DlgItem. Если истино (не nil и не false) значение элемента диалога считывается методом GetValue и сохраняется в таблицу под тем же именем.
- Функция - Функции передаётся текущий обрабатываемый DlgItem. Сохранение просходит, если функция возвращает true.
- Если условие не заданно, считается, что оно true и проверяется только имя элемента.
D:Copy(tab,condition) - Аналогично методу Save, но сохраняемые значения берутся не через GetValue, а непосредственно из таблицы Items. Если перед этим был выполнен метод Refresh, результат будет аналогичен методу Save.
D:Load(tab,condition) - Из таблицы считыватся значения и элементам диалога устанавливаются новые значения через метод SetValue, если имя каждого обрабатываемого элемента диалога не пустое и не начинается с символа подчёркивания и существует одноимённое поле в таблице и выполняется заданное условие. Условие задаётся аналогично методу Save.
D:Refresh() - Значения элементов диалога считываются обратно в таблицу Items. Метод выполняется автоматически после закрытия диалога, если D.Refreshed=true.
D.LС - Содержит номер левого столбца, используемого для задания значения по умолчанию X1 элементов диалога. По умолчанию 1 (отступ на один символ от левого края). При задании Frame и/или Title устанавливается в 5 (отступ на один символ от левого края рамки).
D.RС - Содержит номер правого столбца, используемого для задания значения по умолчанию X2 элементов диалога. По умолчанию задаётся как отступ на один символ от правого края диалога. При задании Frame и/или Title устанавливается как отступ на один символ от правого края рамки.
D.Frame - Хранит тип рамки. После добавления элемента для рисования рамки, нигде больше не используется.
D.Title - Хранит заголовок. После добавления элемента для рисования рамки, нигде больше не используется.
D.Ret - Содержит код возврата Run или Exec. Не изменяется после Free.
D.Items - Объект DlgItemsClass, содержит все DlgItem.
D.I,D.i - Синонимы для D.Items
D.Handle - Хендл диалога, получаемый после D:Init. Обнуляется после D:Free.
D.MaxLine - Максимально возможный номер строки. Используется в SetLine.
D.Refreshed - Обновлять или нет автоматически значения элементов диалога.
D.Guid,D.X1,D.Y1,D.X2,D.Y2,D.HelpTopic,D.Flags,D.DlgProc - Стандартные свойства.
является контейнером для всех DlgItem, собственных методов не имеет. Функциональный вызов DlgItemsClass(Dlg) работает как конструктор, возвращает обект DlgItemsClass с полями {[-1]=Dlg,[0]={}}
Функциональный вызов объекта DlgItemsClass является эквивалентом методу AddItem.
Функциональный вызов объекта DlgItemsClass является эквивалентом методу AddItem.
I.Type,I.X1,I.Y1,I.X2,I.Y2,I.Selected,I.ListItems,I.VBuf,I.History,I.Mask,I.Flags,I.Data,I.Text,I.MaxLength,I.UserData - Именнованные стандартные свойства элемента диалога, для обращения к ним по имени, а не по индексу.
I.Name - Имя элемента диалога.
I.Id - ID элемента. Присваивается автоматически.
I.Parent - Ссылка на родительский диалог.
I:Send(Msg,Param) - Отправить сообщение диалогу для текущего элемента (Param1=I.Id)
I:Focus() - Установить фокус на элемент диалога.
I:Enable(x) - Вкл./выкл. элемент диалога. Возвращает предыдущее состояние. Если x=nil, возвращает текущее состояние без его изменения.
I:Show(x) - Показать/скрыть элемент диалога. Возвращает предыдущее состояние. Если x=nil, возвращает текущее состояние без его изменения.
I:Unchanged(x) - Управление EDITUNCHANGEDFLAG элемента диалога. Возвращает предыдущее состояние. Если x=nil, возвращает текущее состояние без его изменения.
I:SetCheck(n) - Изменить состояние CHECKBOX или RADIOBUTTON (0,1,2). Возвращает предыдущее состояние.
I:GetCheck() - Получить состояние CHECKBOX или RADIOBUTTON (0,1,2)
I:SetCheckState(x) - Установить логическое состояние CHECKBOX или RADIOBUTTON (true,false). Возвращает предыдущее логическое состояние.
I:GetCheckState() - Получить логическое состояние CHECKBOX или RADIOBUTTON (0-false, 1,2-true).
I:SetText(t) - Установить содержимое строки ввода или заголовка элемента диалога в новое значение.
I:GetText() - Получить содержимое строки ввода или заголовка элемента диалога.
I:SetListPos(pos,top) - Позиционировать курсор в списке COMBOBOX или LISTBOX.
I:GetListPos() - Получить текущую позицию курсора в списке COMBOBOX или LISTBOX (pos,top).
I:SetValue(val,top) - Установить значение в зависимости от типа элемента. SetCheck для CHECKBOX или RADIOBUTTON, SetListPos для LISTBOX, SetListPos или SetText для COMBOBOX в зависимости от типа значения, SetText для всех остальных.
I:GetValue() - Получить значение в зависимости от типа элемента.
I.Name - Имя элемента диалога.
I.Id - ID элемента. Присваивается автоматически.
I.Parent - Ссылка на родительский диалог.
I:Send(Msg,Param) - Отправить сообщение диалогу для текущего элемента (Param1=I.Id)
I:Focus() - Установить фокус на элемент диалога.
I:Enable(x) - Вкл./выкл. элемент диалога. Возвращает предыдущее состояние. Если x=nil, возвращает текущее состояние без его изменения.
I:Show(x) - Показать/скрыть элемент диалога. Возвращает предыдущее состояние. Если x=nil, возвращает текущее состояние без его изменения.
I:Unchanged(x) - Управление EDITUNCHANGEDFLAG элемента диалога. Возвращает предыдущее состояние. Если x=nil, возвращает текущее состояние без его изменения.
I:SetCheck(n) - Изменить состояние CHECKBOX или RADIOBUTTON (0,1,2). Возвращает предыдущее состояние.
I:GetCheck() - Получить состояние CHECKBOX или RADIOBUTTON (0,1,2)
I:SetCheckState(x) - Установить логическое состояние CHECKBOX или RADIOBUTTON (true,false). Возвращает предыдущее логическое состояние.
I:GetCheckState() - Получить логическое состояние CHECKBOX или RADIOBUTTON (0-false, 1,2-true).
I:SetText(t) - Установить содержимое строки ввода или заголовка элемента диалога в новое значение.
I:GetText() - Получить содержимое строки ввода или заголовка элемента диалога.
I:SetListPos(pos,top) - Позиционировать курсор в списке COMBOBOX или LISTBOX.
I:GetListPos() - Получить текущую позицию курсора в списке COMBOBOX или LISTBOX (pos,top).
I:SetValue(val,top) - Установить значение в зависимости от типа элемента. SetCheck для CHECKBOX или RADIOBUTTON, SetListPos для LISTBOX, SetListPos или SetText для COMBOBOX в зависимости от типа значения, SetText для всех остальных.
I:GetValue() - Получить значение в зависимости от типа элемента.
Параметры диалога могут задаваться в конструкторе New, при вызове методов Init, Exec, SetProperties или непосредственным присваиванием соответствующим полям объекту DialogClass (в последнем случае кроме Items).
Параметры могут передаваться "классическим" способом - списком, например:
local D = dialog.New("06C907A6-0612-4346-A51B-BD5BC8388493",-1,-1,20,10,nil,dlg_items,nil,dlg_proc)
(в примере параметры передаются через конструктор) или таблицей с именованными полями:
local ret = D:Init(Guid="06C907A6-0612-4346-A51B-BD5BC8388493",X2=20,Y2=10,Items=dlg_items,DlgProc=dlg_proc)
(в примере параметры передаются через метод Init) или непосредственным присваиванием:
D.Guid = "06C907A6-0612-4346-A51B-BD5BC8388493"
В последнем случае, присваивание параметров Guid, X1, Y1, X2, Y2, HelpTopic, Flags, DlgProc, естественно, должно быть выполнено до вызова Init или Exec.
В случае, если один и тот же параметр передаётся в нескольких местах (например, GUID передаётся сначала через New, а потом через Init), каждый раз новое значение будет переписывать старое. Это не относится к добавлению элементов диалога таблицей Items - каждый раз элементы диалога будут добавляться к уже существующим.
Все параметры, кроме Items, W и H, записываются в одноимённые поля диалога.
Могут использоваться следующие параметры:
Guid,X1,Y1,X2,Y2,HelpTopic,Flags - Параметры, имеющие те же значения, что и передаваемые в far.DialogInit и far.Dialog.
Items - Массив элементов диалога. Добавляются через метод AddItems. Внимание! В отличие от других параметров, свойство диалога Items не то же самое, что параметр Items!
DlgProc - Диалоговая процедура. Организуется как обычно, но ей будут переданы два дополнительных параметра - ссылка на сам диалог и ссылка на таблицу Items диалога. Таким образом, формат вызова будет иметь вид DlgProc(hDlg,Msg,Param1,Param2,Dlg,DlgItems). DlgItems передаётся для удобства, это то же самое, что и Dlg.Items.
Name - Имя диалога (зарезервированно).
Line - Внутренний счётчик для методов SetLine и NewLine и т.п. В качестве параметра, задаёт начальное значение.
MaxLine - Максимальное значение счётчика строк для отсчёта с конца диалога методами SetLine и NewLine и т.п.
Refreshed - Если истина, после закрытия диалога (Run, Exec) для диалога выполняется метод Refresh.
W - Ширина диалога.
H - Высота диалога.
Frame - Тип рамки диалога.
Title - Заголовок диалога (по сути - Text для рамки).
Не заданым параметрам присваиваются значения по умолчанию:
X1 = -1
Y1 = -1
X2 - если задан параметр W, то если X1>=0, то X2=X1+W-1, иначе (центрирование) X2=W.
Y2 - если задан параметр H, то если Y1>=0, то Y2=Y1+H-1, иначе (центрирование) Y2=H.
Line - если заданы параметры Frame и/или Title то 1, иначе 0.
MaxLine = 0
При использовании параметров Frame и/или Title автоматически добавляется элемент диалога, рисующий рамку с заголовком, аналогичную типичным диалогам ФАРа. Frame задаёт тип рамки, если 1 - одинарная, другие значения или если параметр отсутствует - двойная. Title задаёт заголовок. По умолчанию заголовок пустой. Если задан Title без Frame, рисуется двойная рамка.
Рекомендуется задавать Frame и Title в конструкторе диалога New, вмести с параметрами, задающими размер диалога. Тогда, во-первых, будут правильные переменные типа Line, LC, RC. Во-вторых, элемент для рамки добавится первым и будет правильно определяться Object.Title.
Рамка добавляется только один раз. Повторные заданиая Frame и Title игнорируются.
Параметры могут передаваться "классическим" способом - списком, например:
local D = dialog.New("06C907A6-0612-4346-A51B-BD5BC8388493",-1,-1,20,10,nil,dlg_items,nil,dlg_proc)
(в примере параметры передаются через конструктор) или таблицей с именованными полями:
local ret = D:Init(Guid="06C907A6-0612-4346-A51B-BD5BC8388493",X2=20,Y2=10,Items=dlg_items,DlgProc=dlg_proc)
(в примере параметры передаются через метод Init) или непосредственным присваиванием:
D.Guid = "06C907A6-0612-4346-A51B-BD5BC8388493"
В последнем случае, присваивание параметров Guid, X1, Y1, X2, Y2, HelpTopic, Flags, DlgProc, естественно, должно быть выполнено до вызова Init или Exec.
В случае, если один и тот же параметр передаётся в нескольких местах (например, GUID передаётся сначала через New, а потом через Init), каждый раз новое значение будет переписывать старое. Это не относится к добавлению элементов диалога таблицей Items - каждый раз элементы диалога будут добавляться к уже существующим.
Все параметры, кроме Items, W и H, записываются в одноимённые поля диалога.
Могут использоваться следующие параметры:
Guid,X1,Y1,X2,Y2,HelpTopic,Flags - Параметры, имеющие те же значения, что и передаваемые в far.DialogInit и far.Dialog.
Items - Массив элементов диалога. Добавляются через метод AddItems. Внимание! В отличие от других параметров, свойство диалога Items не то же самое, что параметр Items!
DlgProc - Диалоговая процедура. Организуется как обычно, но ей будут переданы два дополнительных параметра - ссылка на сам диалог и ссылка на таблицу Items диалога. Таким образом, формат вызова будет иметь вид DlgProc(hDlg,Msg,Param1,Param2,Dlg,DlgItems). DlgItems передаётся для удобства, это то же самое, что и Dlg.Items.
Name - Имя диалога (зарезервированно).
Line - Внутренний счётчик для методов SetLine и NewLine и т.п. В качестве параметра, задаёт начальное значение.
MaxLine - Максимальное значение счётчика строк для отсчёта с конца диалога методами SetLine и NewLine и т.п.
Refreshed - Если истина, после закрытия диалога (Run, Exec) для диалога выполняется метод Refresh.
W - Ширина диалога.
H - Высота диалога.
Frame - Тип рамки диалога.
Title - Заголовок диалога (по сути - Text для рамки).
Не заданым параметрам присваиваются значения по умолчанию:
X1 = -1
Y1 = -1
X2 - если задан параметр W, то если X1>=0, то X2=X1+W-1, иначе (центрирование) X2=W.
Y2 - если задан параметр H, то если Y1>=0, то Y2=Y1+H-1, иначе (центрирование) Y2=H.
Line - если заданы параметры Frame и/или Title то 1, иначе 0.
MaxLine = 0
При использовании параметров Frame и/или Title автоматически добавляется элемент диалога, рисующий рамку с заголовком, аналогичную типичным диалогам ФАРа. Frame задаёт тип рамки, если 1 - одинарная, другие значения или если параметр отсутствует - двойная. Title задаёт заголовок. По умолчанию заголовок пустой. Если задан Title без Frame, рисуется двойная рамка.
Рекомендуется задавать Frame и Title в конструкторе диалога New, вмести с параметрами, задающими размер диалога. Тогда, во-первых, будут правильные переменные типа Line, LC, RC. Во-вторых, элемент для рамки добавится первым и будет правильно определяться Object.Title.
Рамка добавляется только один раз. Повторные заданиая Frame и Title игнорируются.
Элементы диалога могут иметь имена, задаваемые полем Name при добавлении элемента или непосредственным присваиванием значения именованному полю таблицы D.Items. Если имя не задано, по умолчанию используется имя "_". Имена, начинающиеся с символа подчёркивания не обрабатываются методами Save, Load и аналогичными. Элементы с совпадающими именами в любом случае добавляются в D.Items не переписывая одноимённые, но доступ по имени будет возможен только к добавленному последним. К остальным одноимённым элементам сохранится прямой доступ по индексу (ID).
Элемент диалога описывается таблицей, в простейшем случае представляющий собой массив (все поля - позиционные), описывающий структуру tFarDialogItem. Кроме (вместо) позиционных, могут использоваться именованные поля, задающие как те же параметры, так и дополнительные (см. описание DlgItemClass).
Соответствие именованых полей элементам массива:
[1] - Type
[2] - X1
[3] - Y1
[4] - X2
[5] - Y2
[6] - Selected, ListItems, VBuf
[7] - History
[8] - Mask, Separator
[9] - Flags
[10] - Data, Text
[11] - MaxLength
[12] - UserData
При одновременном использовании позиционных и именованных полей, будут использованы значения именованных полей, если это не значения nil или false.
Отсутствующие поля по умолчанию принимаются:
Type = far.Flags.DI_TEXT
X1 = D.LC
Y1 = D.Line
X2 = D.RC
Y2 = Y1
Selected = 0
Flags = 0
Type и Flags заданные строкой или таблицей конвертируются в число.
Может использоваться параметр W для задания ширины элемента. В этом случае пересчитывается X2 - если X1>=0, то X2=X1+W-1, иначе X2=W. Сам параметр W в таблице элемента не сохраняется.
Таблица описывающая элемент диалога, становится объектом DlgItemClass и привязана к конкретному объекту DialogClass. Поэтому, элемент диалога не может использоваться одновременно более чем с одним обектом DialogClass.
Элементы диалога могут быть заданы таблицей и добавлены "кучей" при использовании New, Init, Exec, SetProperties или AddItems, при этом они не перекрывают другие, а добавляются к уже существующим элементам.
Элементы диалога могут добавляться "по одному" следующими способами (примеры):
Типы элементов:
f - рамка (frame), в зависимости от наличия флага "d" DI_SINGLEBOX или DI_DOUBLEBOX.
t - текст (text), в зависимости от наличия флага "v" DI_TEXT или DI_VTEXT.
s - разделитель (separator) в зависимости от наличия флага "v" DI_TEXT или DI_VTEXT, в зависимости от наличия флага "d" DIF_SEPARATOR или DIF_SEPARATOR2.
b - DI_BUTTON. Флаги: b = DIF_NOBRACKETS, ; (точка с запятой) = DIF_BTNNOCLOSE.
c - DI_CHECKBOX.
r - DI_RADIOBUTTON.
l - DI_LISTBOX.
x - DI_COMBOBOX. Флаг d = DIF_DROPDOWNLIST.
e - поле редактирования, в зависимости от наличия флага "f" DI_EDIT или DI_FIXEDIT. Флаги только для поля редактирования: o = DIF_READONLY, e = DIF_EDITOR, h = DIF_HISTORY, m = DIF_MANUALADDHISTORY, l = DIF_USELASTHISTORY.
u - DI_USERCONTROL.
Общие флаги для всех элементов (правильность соответствия флагов типу элемента не проверяется):
! - DIF_DEFAULTBUTTON.
| - DIF_CENTERTEXT.
Элемент диалога описывается таблицей, в простейшем случае представляющий собой массив (все поля - позиционные), описывающий структуру tFarDialogItem. Кроме (вместо) позиционных, могут использоваться именованные поля, задающие как те же параметры, так и дополнительные (см. описание DlgItemClass).
Соответствие именованых полей элементам массива:
[1] - Type
[2] - X1
[3] - Y1
[4] - X2
[5] - Y2
[6] - Selected, ListItems, VBuf
[7] - History
[8] - Mask, Separator
[9] - Flags
[10] - Data, Text
[11] - MaxLength
[12] - UserData
При одновременном использовании позиционных и именованных полей, будут использованы значения именованных полей, если это не значения nil или false.
Отсутствующие поля по умолчанию принимаются:
Type = far.Flags.DI_TEXT
X1 = D.LC
Y1 = D.Line
X2 = D.RC
Y2 = Y1
Selected = 0
Flags = 0
Type и Flags заданные строкой или таблицей конвертируются в число.
Может использоваться параметр W для задания ширины элемента. В этом случае пересчитывается X2 - если X1>=0, то X2=X1+W-1, иначе X2=W. Сам параметр W в таблице элемента не сохраняется.
Таблица описывающая элемент диалога, становится объектом DlgItemClass и привязана к конкретному объекту DialogClass. Поэтому, элемент диалога не может использоваться одновременно более чем с одним обектом DialogClass.
Элементы диалога могут быть заданы таблицей и добавлены "кучей" при использовании New, Init, Exec, SetProperties или AddItems, при этом они не перекрывают другие, а добавляются к уже существующим элементам.
Элементы диалога могут добавляться "по одному" следующими способами (примеры):
- Методом AddItem диалога
D:AddItem { "DI_DOUBLEBOX", 3, 1, 20, 10, Text="Title", Name="Frame" } - Вызовом D.Items как функции
D.Items { "DI_DOUBLEBOX", 3, 1, 20, 10, Text="Title", Name="Frame" }
или с использование синонима
D.I { "DI_DOUBLEBOX", 3, 1, 20, 10, Text="Title", Name="Frame" } - Присваиванием значения именованному полю D.Items
D.I.Frame = { "DI_DOUBLEBOX", 3, 1, 20, 10, Text="Title" }
- Если Y1 не задана (или nil), будет использовано текущее значение D.Line.
- Обычное задание Y1=n.
- Использованием специальных полей таблицы, описывающей элемент диалога:
YN=n - аналогично применению метода NewLine: Y1=D:NewLine(n). Синонимы YN: NL, NewLine.
YS=n - аналогично применению метода SetLine: Y1=D:SetLine(n). Синонимы YS: SL, SetLine.
Типы элементов:
f - рамка (frame), в зависимости от наличия флага "d" DI_SINGLEBOX или DI_DOUBLEBOX.
t - текст (text), в зависимости от наличия флага "v" DI_TEXT или DI_VTEXT.
s - разделитель (separator) в зависимости от наличия флага "v" DI_TEXT или DI_VTEXT, в зависимости от наличия флага "d" DIF_SEPARATOR или DIF_SEPARATOR2.
b - DI_BUTTON. Флаги: b = DIF_NOBRACKETS, ; (точка с запятой) = DIF_BTNNOCLOSE.
c - DI_CHECKBOX.
r - DI_RADIOBUTTON.
l - DI_LISTBOX.
x - DI_COMBOBOX. Флаг d = DIF_DROPDOWNLIST.
e - поле редактирования, в зависимости от наличия флага "f" DI_EDIT или DI_FIXEDIT. Флаги только для поля редактирования: o = DIF_READONLY, e = DIF_EDITOR, h = DIF_HISTORY, m = DIF_MANUALADDHISTORY, l = DIF_USELASTHISTORY.
u - DI_USERCONTROL.
Общие флаги для всех элементов (правильность соответствия флагов типу элемента не проверяется):
! - DIF_DEFAULTBUTTON.
| - DIF_CENTERTEXT.
- DIF_RIGHTTEXT.
< - DIF_LEFTTEXT.
= или c - DIF_CENTERGROUP.
: или g - DIF_GROUP.
? или x - DIF_DISABLE.
- или s - DIF_SELECTONENTRY.
/ - DIF_NOFOCUS.
@ - DIF_FOCUS.
& - DIF_SHOWAMPERSAND.
Дополнительно может быть указано один или несколько символов "+" или "-" - будет выполнен метод D:NewLine на количество строк, соответствующее количеству этих символов вперёд или назад.
Конфликты при задании Y1, YN, YS и параметров "+" и "-":- Если при задании Y1 использовались методы (функции) SetLine, NewLine, естественно, сначала будут выполнены они и D.Line будет переустановлена.
- Так, как непосредственное задание Y1 не влияет на счётчик строк D.Line, любое заданное значение будет проигнорировано (точнее, переписано тем значением D.Line, которое будет получено после выполнения всех команд SetLine и NewLine).
- Будет выполнено изменение D.Line в соответсвии с YN и YS (так как порядок обработки элементов таблицы в LUA не определён, не рекомендуется смешивать эти параметры).
- Будет выполнен метод NewLine на количество строк, заданом количеством символов "+" и результат присвоен Y1.
Примеры:
Двойная рамкаD.I { "fd+", X1=3, X2=20, Y2=10, Text="Title" }
Разделитель со следующей строкиD.I { "s+" }
Кнопка по умолчаниюD.I { "b=!", Name="OK", YS=13, Text="Готово!" }
Некоторые идеи честно стырены из исходников luafar4editor
DialogClass 1.15
Code: Select all
--[=[ ------------------------------------------------------------------------------------------------------------------
Модуль для работы с диалогами в стиле ООП.
v. 1.15 (C) 2013-2022 Smitis
http://forum.farmanager.com/viewtopic.php?t=8523
--]=] ------------------------------------------------------------------------------------------------------------------
local _version = "1.15"
local F = far.Flags
local bor = bor or bit64.bor
local band = band or bit64.band
local function log2num(b) return tonumber(b) or (b and 1) or 0 end
local function state2num(b) return b==nil and -1 or log2num(b) end
-- Преобразование флагов, заданых в различном виде (число, строка, таблица) к единому числовому значению.
local function flags2num(...)
local flags = 0
for i=1,select("#",...) do
local x = select(i,...)
if type(x)=="table" then -- таблица вида {DIF_CENTERGROUP=1, DIF_DEFAULTBUTTON=1}
for f,v in pairs(x) do
if v~=0 then
flags = bor(flags,F[f])
end
end
elseif type(x)=="string" then -- строки вида "DI_BUTTON"
flags = bor(flags,F[x])
else -- числа или nil
flags = bor(flags,x or 0)
end
end
return flags
end
------------------------------------------------------------------------------------------------------------------------
-- Класс DlgItem (элемент диалога)
------------------------------------------------------------------------------------------------------------------------
local DlgItemClass = {}
DlgItemClass.NamedFields = {
Type=1, X1=2, Y1=3, X2=4, Y2=5, Selected=6, Sel=6, S=6, ListItems=6, LI=6, VBuf=6, History=7, His=7,
Mask=8, Separator=8, Sep=8, Flags=9, F=9, Data=10, Text=10, T=10, MaxLength=11, Max=11, UserData=12
}
function DlgItemClass:__index(key)
if DlgItemClass.NamedFields[key] then
return rawget(self,DlgItemClass.NamedFields[key])
end
return rawget(self,key) or DlgItemClass[key]
end
function DlgItemClass:__newindex(key,val)
rawset(self, DlgItemClass.NamedFields[key] or key, val)
end
-- Отправить сообщение диалогу для данного элемента
function DlgItemClass:Send(Msg,Param)
return self.Owner:Send(Msg,self.Id,Param)
end
-- Проверить тип элемента. Истина, если совпадает хотя бы с одним
function DlgItemClass:CheckType(...)
for i=1,select("#",...) do
local tp = select(i,...)
if self.Type==(F[tp] or tp) then return true end
end
return false
end
-- Проверить флаги элемента. Истина, если установлен хотя бы один флаг
function DlgItemClass:CheckFlags(...)
return band(self.Flags,flags2num(...))~=0
end
-- Установить флаги элемента
function DlgItemClass:SetFlags(...)
self.Flags = bor(self.Flags,flags2num(...))
return self.Flags
end
-- Вкл./выкл элемент диалога
function DlgItemClass:Enable(x)
return self:Send(F.DM_ENABLE,state2num(x)) == 1
end
-- Установить состояние EDITUNCHANGEDFLAG
function DlgItemClass:Unchanged(x)
return self:Send(F.DM_EDITUNCHANGEDFLAG,state2num(x)) == 1
end
-- Показать/скрыть элемент диалога
function DlgItemClass:Show(x)
return self:Send(F.DM_SHOWITEM,state2num(x)) == 1
end
-- Установить фокус на элемент диалога
function DlgItemClass:Focus()
return self:Send(F.DM_SETFOCUS,0) == 1
end
-- Установить значение CHECKBOX или RADIOBUTTON
function DlgItemClass:SetCheck(x)
return self:Send(F.DM_SETCHECK,x)
end
-- Получить значение CHECKBOX или RADIOBUTTON
function DlgItemClass:GetCheck()
return self:Send(F.DM_GETCHECK,0)
end
-- Установить текстовое значение
function DlgItemClass:SetText(text)
return self:Send(F.DM_SETTEXT,text)
end
-- Получить текстовое значение
function DlgItemClass:GetText()
return self:Send(F.DM_GETTEXT,0)
end
-- Установить текущую позицию для списка
function DlgItemClass:SetListPos(pos,top)
return self:Send(F.DM_LISTSETCURPOS,{SelectPos=pos,TopPos=top})
end
-- Получить текущую позицию для списка
function DlgItemClass:GetListPos()
local FarListPos = self:Send(F.DM_LISTGETCURPOS,0)
return FarListPos.SelectPos, FarListPos.TopPos
end
-- Установки значения в зависимости от типа элемента диалога
-- [???] Если val таблица, посылать DM_SETDLGITEM?
function DlgItemClass:SetValue(val,top)
if self:CheckType(F.DI_CHECKBOX,F.DI_RADIOBUTTON) then
return self:SetCheck(log2num(val))
elseif self:CheckType(F.DI_LISTBOX) then
return self:SetListPos(val,top)
elseif self:CheckType(F.DI_COMBOBOX) then
if type(val)=="number" then
return self:SetListPos(val,top)
else
return self:SetText(tostring(val))
end
else
return self:SetText(tostring(val))
end
end
-- Получения значения в зависимости от типа элемента диалога
function DlgItemClass:GetValue()
if self:CheckType(F.DI_CHECKBOX,F.DI_RADIOBUTTON) then
return self:GetCheck()
elseif self:CheckType(F.DI_LISTBOX) then
return self:GetListPos()
else
return self:GetText()
end
end
------------------------------------------------------------------------------------------------------------------------
-- Класс DlgItems (контейнер для всех dlgitem)
-- Элементы с индексами <=0 являются private полями и нигде, кроме как здесь не должны использоваться.
-- 0 -- Таблица имён элементов
-- -1 -- Ссылка на родительский диалог
-- -2 -- Ссылка на элемент рамки. Если nil или false - рамка не добавлялась.
------------------------------------------------------------------------------------------------------------------------
local DlgItemsClass = {}
function DlgItemsClass:__index(name)
--return rawget(self, self[0][name] or name)
-- Если элемент не существует, вернём функцию, которая этот элемент добавит
return rawget(self, self[0][name] or name) or
function(newitem)
newitem.Name = name
self(newitem)
end
end
-- Добавление нового элемента диалога
function DlgItemsClass:__newindex(name,item)
if type(item)=="table" then
self[-1]:AddItem(item,name)
end
end
-- Добавление DlgItem вызовом как функции
function DlgItemsClass:__call(...)
DlgItemsClass.__newindex(self,false,...)
end
-- Конструктор DlgItemsClass
setmetatable( DlgItemsClass, {
__call = function(self,dlg)
return setmetatable({[-2]=false,[-1]=dlg,[0]={}},self)
end
})
------------------------------------------------------------------------------------------------------------------------
-- Класс Dialog
------------------------------------------------------------------------------------------------------------------------
local DialogClass = {}
DialogClass.__index = DialogClass
-- Подчинённые классы (для удобства наследования)
DialogClass.DlgItemClass = DlgItemClass
DialogClass.DlgItemsClass = DlgItemsClass
------------------------------------------------------------------------------------------------------------------------
-- Добавить элемент диалога
function DialogClass:AddItem(item,name)
if type(item)~="table" then return nil end
local x
local items = self.Items
local id = #items+1
item.Name = name or item.Name or "_"
item.Id = id
item.Owner = self
items[0][item.Name] = id -- в список именованных элементов
-- копируем все виртуальные поля и удаляем их
for f,v in pairs(item) do
if DlgItemClass.NamedFields[f] then
item[DlgItemClass.NamedFields[f]] = v
item[f] = nil
end
end
setmetatable(item,self.DlgItemClass or DlgItemClass) -- объект
item.Flags = flags2num(item.Flags) -- Flags [9] в number
if type(item.Type)=="number" or item.Type:sub(1,3)=="DI_" then
item.Type = item.Type and flags2num(item.Type) or F.DI_TEXT -- тип элемента в number или тип по умолчанию
else -- Если тип - строка начинающаяся не с DI_, это сокращённое обозначение типа элемента, параметров, опций
local typ = item.Type:sub(1,1)
local opt = item.Type:sub(2)
if typ == "b" then
item.Type = F.DI_BUTTON
if opt:find("b") then item:SetFlags(F.DIF_NOBRACKETS) end
if opt:find(";") then item:SetFlags(F.DIF_BTNNOCLOSE) end
elseif typ == "f" then
item.Type = opt:find("d") and F.DI_DOUBLEBOX or F.DI_SINGLEBOX
elseif typ == "t" then
item.Type = opt:find("v") and F.DI_VTEXT or F.DI_TEXT
-- DIF_WORDWRAP ???
elseif typ == "e" then
item.Type = opt:find("f") and F.DI_FIXEDIT or F.DI_EDIT
if opt:find("o") then item:SetFlags(F.DIF_READONLY) end
if opt:find("e") then item:SetFlags(F.DIF_EDITOR) end
if opt:find("h") then item:SetFlags(F.DIF_HISTORY) end
if opt:find("m") then item:SetFlags(F.DIF_MANUALADDHISTORY) end
if opt:find("l") then item:SetFlags(F.DIF_USELASTHISTORY) end
elseif typ == "p" then
item.Type = F.DI_PSWEDIT
elseif typ == "s" then -- DI_TEXT | DI_VTEXT & DIF_SEPARATORUSER | DIF_SEPARATOR | DIF_SEPARATOR2
item.Type = opt:find("v") and F.DI_VTEXT or F.DI_TEXT
if opt:find("u") or item.Separator then
item:SetFlags(F.DIF_SEPARATORUSER)
elseif opt:find("d") then
item:SetFlags(F.DIF_SEPARATOR2)
else
item:SetFlags(F.DIF_SEPARATOR)
end
elseif typ == "r" then
item.Type = F.DI_RADIOBUTTON
elseif typ == "c" then
item.Type = F.DI_CHECKBOX
if opt:find("3") then item:SetFlags(F.DIF_3STATE) end
elseif typ == "l" then
item.Type = F.DI_LISTBOX
elseif typ == "x" then
item.Type = F.DI_COMBOBOX
if opt:find("d") then item:SetFlags(F.DIF_DROPDOWNLIST) end
elseif typ == "u" then
item.Type = F.DI_USERCONTROL
else
item.Type = F.DI_TEXT
end
if opt:find("|") then item:SetFlags(F.DIF_CENTERTEXT) end
if opt:find(">") then item:SetFlags(F.DIF_RIGHTTEXT) end
if opt:find("<") then item:SetFlags(F.DIF_LEFTTEXT) end
if opt:find("!") then item:SetFlags(F.DIF_DEFAULTBUTTON) end
if opt:find("[=c]") then item:SetFlags(F.DIF_CENTERGROUP) end
if opt:find("[:g]") then item:SetFlags(F.DIF_GROUP) end
if opt:find("[?x]") then item:SetFlags(F.DIF_DISABLE) end
if opt:find("%.") then item:SetFlags(F.DIF_HIDDEN) end
if opt:find("[*s]") then item:SetFlags(F.DIF_SELECTONENTRY) end
if opt:find("/") then item:SetFlags(F.DIF_NOFOCUS) end
if opt:find("@") then item:SetFlags(F.DIF_FOCUS) end
if opt:find("&") then item:SetFlags(F.DIF_SHOWAMPERSAND) end
x = opt:gsub("[^+]","") -- подсчитываем "+"
if x:len()>0 then item[3] = self:NewLine(x:len()) end
x = opt:gsub("[^%-]","") -- посчитываем "-"
if x:len()>0 then item[3] = self:NewLine(-x:len()) end
end
if type(item.Selected)=="boolean" then -- item[6]
item.Selected = state2num(item.Selected)
else
item.Selected = item.Selected or 0
end
if type(item.History)=="string" and item.History~="" then -- если есть History
item:SetFlags(F.DIF_HISTORY)
end
if type(item.Separator)=="string" and item.Separator~="" then -- если есть Mask/Separator
if item:CheckType(F.DI_TEXT,F.DI_VTEXT) then
item:SetFlags(F.DIF_SEPARATORUSER)
else
item:SetFlags(F.DIF_MASKEDIT)
end
end
if item:CheckType(F.DI_BUTTON,F.DI_CHECKBOX,F.DI_RADIOBUTTON) then
item.Text = item.Text or item.Name -- если не задана надпись на кнопке, берём имя элемента
end
-- Координаты
if item.L then item.Y1 = item.L>=0 and self.WorkArea.Y1+item.L or self.WorkArea.Y2+item.L self.Line = item.Y1 end
if item.C then item.X1 = item.C>=0 and self.WorkArea.X1+item.C or self.WorkArea.X2+item.C end
if item.WX1 then item.X1 = item.WX1>=0 and self.WorkArea.X1+item.WX1 or self.WorkArea.X2+item.WX1 end
if item.WX2 then item.X2 = item.WX2>=0 and self.WorkArea.X1+item.WX2 or self.WorkArea.X2+item.WX2 end
if item.WY1 then item.Y1 = item.WY1>=0 and self.WorkArea.Y1+item.WY1 or self.WorkArea.Y2+item.WY1 end
if item.WY2 then item.Y2 = item.WY2>=0 and self.WorkArea.Y1+item.WY2 or self.WorkArea.Y2+item.WY2 end
if item:CheckType(F.DI_BUTTON,F.DI_CHECKBOX,F.DI_RADIOBUTTON) then
item.X2, item.Y2, item.W, item.H = 0, nil, nil, nil
end
if item:CheckType(F.DI_EDIT,F.DI_FIXEDIT) then
item.Y2, item.H = nil, nil
end
if item:CheckType(F.DI_TEXT) then
item.H = nil
if item:CheckFlags(F.DIF_SEPARATOR2,F.DIF_SEPARATOR) then
item.X1, item.X2, item.W = item.X1 or -1, 0, nil
elseif not item:CheckFlags(F.DIF_SEPARATORUSER,F.DIF_CENTERTEXT) then
item.X2 = item.X2 or 0
end
end
if item:CheckType(F.DI_VTEXT) then
item.W = nil
if item:CheckFlags(F.DIF_SEPARATOR2,F.DIF_SEPARATOR) then
item.Y1, item.Y2, item.H = item.Y1 or -1, 0, nil
elseif not item:CheckFlags(F.DIF_SEPARATORUSER,F.DIF_CENTERTEXT) then
item.Y2 = item.Y2 or 0
end
end
item.X1 = item.X1 or self.WorkArea.X1
item.X2 = item.W and item.X1+item.W-1 or item.X2 or self.WorkArea.X2
item.Y1 = item.Y1 or self.Line
item.Y2 = item.H and item.Y1+item.H-1 or item.Y2 or item.Y1
self.LastLine = math.max(self.LastLine,item.Y2) -- deprecated?
rawset(items,id,item) -- Добавляем
return item
end
-- Добавить элементы диалога из массива
function DialogClass:AddItems(items)
if type(items)=="table" then
for n,item in ipairs(items) do
self:AddItem(item)
end
end
return self
end
-- Проверить наличие элемента, вернуть элемент или nil
-- Такой метод необходим, так как нельзя просто проверить несуществующий элемент в Items (вернётся функция)
function DialogClass:ExistItem(name)
return rawget(self.Items, self.Items[0][name])
end
-- Заполнения свойств диалога
function DialogClass:SetProperties(Tab,...)
local Guid,X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc,Frame
if type(Tab)=="table" then -- свойства переданы таблицей, всё после Tab игнорируется
for i,v in pairs(Tab) do
if i == "Items" then -- таблица элементов диалога, потом добавим через AddItems
Items = v
else
self[i] = v
end
end
else -- свойства переданы обычным, не табличным, способом
Guid = Tab
X1,Y1,X2,Y2,HelpTopic,Items,Flags,DlgProc = ...
end
self.Guid = Guid or self.Guid or ""
--if self.Guid:match("%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x") then
if string.match(self.Guid,"%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x") then
self.Guid=win.Uuid(self.Guid)
end
self.X1 = X1 or self.X1 or -1
self.Y1 = Y1 or self.Y1 or -1
self.X2 = X2 or self.X2 or 0
self.Y2 = Y2 or self.Y2 or 0
if self.W then
self.X2 = self.X1>=0 and self.X1+self.W-1 or self.W
end
if self.H then
self.Y2 = self.Y1>=0 and self.Y1+self.H-1 or self.H
end
self.W = self.X1>=0 and self.X2-self.X1+1 or self.X2
self.H = self.Y1>=0 and self.Y2-self.Y1+1 or self.Y2
self.WorkArea = self.WorkArea or {X1=0,Y1=0,X2=0,Y2=0,DX=0,DY=0}
self.LC = self.LC or 1
self.RC = self.RC or ( self.X1>=0 and self.X2-self.X1-1 or self.X2-2 )
self.Line = self.Line or 1
self.MaxLine = self.Y1>=0 and self.Y2-self.Y1-1 or self.Y2-2
self.LastLine = self.LastLine or 0
if (self.Frame or self.Title) and not self.Items[-2] then
self.Title = self.Title or ""
self.Frame = self.Frame or 2
-- добавить элемент, сохраняя LastLine
self.LastLine, self.Items.__MainFrame = self.LastLine, {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}
--self.LastLine, self.Items.__MainFrame = self.LastLine, {self.Frame==1 and F.DI_SINGLEBOX or F.DI_DOUBLEBOX,1,1,40,40,0,0,0,0,self.Title}
self.Items[-2] = true --self.Items.__MainFrame
self.Line = 1 -- на уровне рамки (не ниже - для упрощения использования опции +)
self.LC = 5 -- правее рамки через символ
self.RC = self.X1>=0 and self.X2-self.X1-5 or self.X2-6 -- левее рамки через символ
self.WorkArea.Y1 = 1
self.WorkArea.X1 = 5
self.WorkArea.X2 = self.X1>=0 and self.X2-self.X1-5 or self.X2-6
self.WorkArea.Y2 = self.Y1>=0 and self.Y2-self.Y1-2 or self.Y2-3
self.WorkArea.W = self.WorkArea.X2-self.WorkArea.X1+1
self.WorkArea.H = self.WorkArea.Y2-self.WorkArea.Y1+1
end
self.HelpTopic = HelpTopic or self.HelpTopic
self:AddItems(Items)
self.Flags = flags2num(Flags or self.Flags)
self.DlgProc = DlgProc or self.DlgProc
self.Handle = self.Handle or 0
self.Refreshed = self.Refreshed or true
self.Ret = 0
return self
end
-- Отправка сообщения диалогу
function DialogClass:Send(Msg,Param1,Param2)
return far.SendDlgMessage(self.Handle,Msg,Param1,Param2)
end
-- Аналог far.DialogInit()
-- В DlgProc будут переданы два дополнительных параметра
-- Будут обработаны DlgProc для каждого элемента.
function DialogClass:Init(...)
self:SetProperties(...)
self.Handle =
far.DialogInit(
self.Guid,self.X1,self.Y1,self.X2,self.Y2,self.HelpTopic,self.Items,self.Flags,
--self.DlgProc and function(hDlg,Msg,Param1,Param2) return self.DlgProc(hDlg,Msg,Param1,Param2,self,self.Items) end
function(hDlg,Msg,Param1,Param2)
local item = self.Items[Param1]
if (Param1<=0 or not item.ItemProc or not item.ItemProc(hDlg,Msg,Param2,item,self,self.Items)) and self.DlgProc then
return self.DlgProc(hDlg,Msg,Param1,Param2,self,self.Items)
end
end
)
return self.Handle
end
-- Аналог far.DialogRun()
function DialogClass:Run()
self.Ret = far.DialogRun(self.Handle)
if self.Refreshed then self:Refresh() end
return self.Ret
end
-- Аналог far.DialogFree()
function DialogClass:Free()
far.DialogFree(self.Handle)
self.Handle = 0
end
-- Аналог far.Dialog()
function DialogClass:Exec(...)
self:Init(...) self:Run() self:Free()
return self.Ret
end
-- Функциональный запуск D() - то же, что D:Exec()
function DialogClass:__call(...)
return self:Exec(...)
end
-- Установить фокус на элемент диалога
function DialogClass:SetFocus(id)
return self:Send(F.DM_SETFOCUS,id,0)
end
-- Получить id элемента диалога в фокусе
function DialogClass:GetFocus()
return self:Send(F.DM_GETFOCUS,0,0)
end
-- Вкл./выкл. автоматическую перерисовку
function DialogClass:AutoRedraw(x)
return self:Send(F.DM_ENABLEREDRAW,log2num(x),0)
end
-- Перерисовать
function DialogClass:Redraw()
return self:Send(F.DM_REDRAW,0,0)
end
-- Обновить все исходные items значениями из диалога
function DialogClass:Refresh()
for id,item in ipairs(self.Items) do
local real = far.GetDlgItem(self.Handle,id) -- можно даже сделать setmetatable
if item:CheckType(F.DI_LISTBOX) then
item.Selected.SelectIndex = item:GetListPos()
elseif item:CheckType(F.DI_COMBOBOX) then
item.Selected.SelectIndex = item:GetListPos()
item.Text = real[10]
elseif item:CheckType(F.DI_CHECKBOX,F.DI_RADIOBUTTON) then
item.Selected = real[6]
else
item.Text = real[10]
end
end
end
function DialogClass:SetLine(n)
if n then self.Line = n<0 and self.MaxLine+1+n or n end
return self.Line
end
function DialogClass:NewLine(n)
self.Line = self.Line+(n or 1)
return self.Line
end
------------------------------------------------------------------------------------------------------------------------
-- Конструктор
local function New(...)
local D = {}
D.Items = DlgItemsClass(D) -- D.Items = setmetatable({[-2]=false,[-1]=D,[0]={}},DlgItemsClass)
D.I, D.i = D.Items, D.Items -- синонимы
setmetatable(D,DialogClass) -- объект
D:SetProperties(...)
-- Возвращаемые значения: сам диалог, таблица Items
return D, D.Items
end
------------------------------------------------------------------------------------------------------------------------
return
{
New = New,
DialogClass=DialogClass,
DlgItemClass=DlgItemClass,
DlgItemsClass=DlgItemsClass,
log2num = log2num,
state2num = state2num,
flags2num = flags2num,
_VERSION = _version
}
------------------------------------------------------------------------------------------------------------------------
Пример наследования классов: MultiPagesDialogClass
Code: Select all
--[=[ ----------------------------------------------------------------------------------------------
Расширение модуля DialogClass для имитации TabControl
v. 1.01 (C) 2013-2022 Smitis
Сделаны два дополнения для DialogClass:
Дополнение 1.
- Новое поле в объектах DlgItemClass Hidden для скрытия элементов диалога при вызове Show.
- Перегруженный метод Show - элемент диалога всегда скрывается, если его свойство Hidden==true, независимо от параметра, переданного в Show.
Дополнение 2. Имитируем многостраничный диалог (типа TabControl, но без вкладок).
- Страницы нумеруем от 1 до некоторого максимального значения, определяемого новым свойством диалога MaxPage.
- Номер текущей страницы хранится в поле Page диалога.
- Для переключения страниц добавляем новые методы ShowPage(page), NextPage(), PrevPage()
Кроме всего прочего, метод проверяет переданный номер, на попадаение в диапазон 1...MaxPage и обеспечивает циклическое переключение страниц вызовами, подобными D:ShowPage(D.Page+1) и D:ShowPage(D.Page-1).
Метод устанавливает свойство Page в новое значение.
- При создании элементов диалога, могут использоваться методы PageBegin(page) для задания страницы по-умолчанию для всех последующих добавленных элементов и метод PageEnd() для отключения действия BeginPage.
- Переключение страниц имитируем показом/скрытием элементов диалога. Для этого каждый элемент диалог может иметь свойство Page, задающий номер страницы, на которой элемент показывается, для остальных страниц он скрывается.
Для показа элемента на нескольких страницах, Page задаём массивом номеров страниц или строкой, содержащей номера страниц разделённых нецифровыми символами или таблицей.
Элементы диалога, не имеющие свойство Page при переключении страниц не затрагиваются.
- Начальную страницу можно задать через свойство Page диалога.
- Для каждой страницы сохраняется фокус текущего элемента в свойстве диалога массиве PageFocus.
Все перегружаемые методы используют старые методы в качестве базовых.
--]=] ----------------------------------------------------------------------------------------------
local dialog = require("DialogClass")
--local dialognew = { unpack(dialog) } -- клонируем dialog (достаточно одного уровня)
local dialognew = {}
--for k,v in pairs(dialog) do dialognew[k]=v end -- клонируем dialog (достаточно одного уровня)
local DlgItemClassNamedFields = dialog.DlgItemClass.NamedFields
----------------------------------------------------------------------------------------------------
local DlgItemClassNew = {}
----------------------------------------------------------------------------------------------------
-- Приходится повторять __index из базового класса
function DlgItemClassNew:__index(key)
if DlgItemClassNamedFields[key] then
return rawget(self,DlgItemClassNamedFields[key])
end
return rawget(self,key) or DlgItemClassNew[key]
end
----------------------------------------------------------------------------------------------------
-- Перегрузка метода Show
function DlgItemClassNew:Show(x)
--dbgprint(tostring(self.Name).." : "..tostring(self.Hidden and 0 or dialog.log2num(x)))
return dialog.DlgItemClass.Show(self,self.Hidden and 0 or dialog.log2num(x))
end
----------------------------------------------------------------------------------------------------
DlgItemClassNew.__newindex = dialog.DlgItemClass.__newindex
setmetatable(DlgItemClassNew,dialog.DlgItemClass)
----------------------------------------------------------------------------------------------------
local DialogClassNew = {}
DialogClassNew.DlgItemClass = DlgItemClassNew
DialogClassNew.DlgItemsClass = dialog.DlgItemsClass
----------------------------------------------------------------------------------------------------
-- Перегрузка метода AddItem
local AddItemOld = dialog.DialogClass.AddItem
function DialogClassNew:AddItem(item,name)
item.Page = item.Page or self.CurrentPage
return AddItemOld(self,item,name)
end
----------------------------------------------------------------------------------------------------
-- Переключение на заданную страницу.
function DialogClassNew:ShowPage(page)
local prev = self.Page
-- Если page не задана, будет повторно обработана текущая страница.
page = tonumber(page or self.Page)
if page>self.MaxPage then page=1 elseif page<1 then page=self.MaxPage end
self:AutoRedraw(false)
self.PageFocus[self.Page] = self:GetFocus()
self.Page = page
page = '%D'..tostring(page)..'%D' -- шаблон проверки
for id,item in ipairs(self.Items) do
if item.Hidden then
item:Show(0)
elseif item.Page then
item:Show((";"..(type(item.Page)=="table" and table.concat(item.Page,";") or tostring(item.Page))..";"):find(page)~=nil)
end
end
self:SetFocus(self.PageFocus[self.Page])
self:AutoRedraw(true)
return prev
end
----------------------------------------------------------------------------------------------------
-- Следующая страница
function DialogClassNew:NextPage()
self:ShowPage(self.Page+1)
end
----------------------------------------------------------------------------------------------------
-- Предыдущая страница
function DialogClassNew:PrevPage()
self:ShowPage(self.Page-1)
end
----------------------------------------------------------------------------------------------------
-- Начать новую страницу при создании элементов диалога
function DialogClassNew:PageBegin(page)
self.CurrentPage = page
self.Line = self.BeginLine or self.Line
self.BeginLine = self.Line
end
----------------------------------------------------------------------------------------------------
-- Закончить страницу при создании элементов диалога
function DialogClassNew:PageEnd(page)
self.CurrentPage = nil
end
----------------------------------------------------------------------------------------------------
-- Перегрузка Clear
--[=[
function DialogClassNew:Clear()
dialog.DialogClass.Clear(self)
self.Page = 1
self.MaxPage = 1
self.PageFocus = {0}
return self
end
--]=]
----------------------------------------------------------------------------------------------------
-- Перегрузка Init
function DialogClassNew:Init(...)
local ret = dialog.DialogClass.Init(self,...)
self:ShowPage() -- иницилизация начальной страницы self.Page
return ret
end
----------------------------------------------------------------------------------------------------
DialogClassNew.__call = dialog.DialogClass.__call
DialogClassNew.__index = setmetatable(DialogClassNew,dialog.DialogClass)
----------------------------------------------------------------------------------------------------
-- Новый конструктор
local function New(...)
-- В качестве базового используем старый конструктор, но вызываем его без параметров, иначе все Items будут старыми DlgItemClass.
-- Сохраняем всё возвращённое конструктором, не разбирая что там, как таблицу, на случай будущих изменений в базовом конструкторе.
local DA = { dialog.New() }
-- Первый элемент - диалог, остальные нас не интересуют
local D = DA[1]
-- Новая метатаблица для диалога
setmetatable(D,DialogClassNew)
-- Иницилизация новых полей
D.Page, D.MaxPage, D.CurrentPage = 1, 1, nil
D.PageFocus = {0}
-- Вот теперь можно задавать параметры
D:SetProperties(...)
-- Возвращаем то, что вернул старый конструктор
return unpack(DA)
end
----------------------------------------------------------------------------------------------------
dialognew.DialogClass = DialogClassNew
dialognew.DlgItemClass = DlgItemClassNew
dialognew.New = New
return dialognew
----------------------------------------------------------------------------------------------------