--[[
@Title: GRO BMD Index Citations
@Type: Standard
@Author: John Elvin
@Contributors: Mike Tate
@Version: 1.2
@Keywords: GRO
@LastUpdated: 26 March 2025
@Licence: This plugin is copyright (c) 2024 John Elvin & contributors and is licensed under the MIT License which
is hereby incorporated by reference (see https://pluginstore.family-historian.co.uk/fh-plugin-licence)
@Description: Add a GRO Index Source Citation to an birth, marriage or death with GRO reference in Where Within and
additional information in Text from Source; event is created or optionally updated with the date and/or place.
Also has option to set birth date from Age, year of birth or date of birth from Death citation.
It cannot be used outside of a project (i.e. with standalone GEDCOM).
@V0.1: Loosely based on Add GRO Index Source Citation
• reference is stored in Where Within Source, additional information in Text from Source
• choice of which parts of event details are to be updated if they already exist
• offers to set birth date from age at death or date of birth given in death index
• configuration of the labels for the fields in the citation text
• district name can be first part only in the citation but the whole place is used when creating/updating events
• many other usability enhancements
@V0.1.1 • Correct comparison of death age
• Remove spurious leading space on text from source if text from source headers are blank
@V0.2 • Copy existing name - surname. For a female picks up last spouse's surname (if present)
• Allow year only birth date for death events
@V0.2.1 • Correct creation of birth event when adding death citation
• Correct substitution of ^ in text from source
• Amend tag in settings for District name only to clarify function
• Change way non-configured source records are handled - button(s) for associated events are disabled
• Disable help button pending writing of help
• Change label on Exit button to Close to match FH dialogs
• Change default setting for Full month names to Off
• Remove superfluous retry cancel after select individual/family dialogs - user can retry from main menu
• Correct trucated labels in settings dialog on systems with different font
• Clarify copying existing names by changing label and adding tips to boxes
@v0.2.2 • Correct disabling of main menu buttons when source(s) not selected
• Move Name(s) section of main dialog above event specific options
• Allow death without Age or DOB (early FreeBMD (and others) had neither)
• Move Event label (Birth, Marriage or Death) to Where Within Source, not Text from Source
• Change Citation date text in settings to clarify functionality
• Support for user defined fonts
• Trailing space on end of italic tags to prevent last character being clipped
• Move button to reset main dialog screen position from settings to main menu. Button only active if dialog moved
@v0.2.3 • Change validation of source settings to make sure templated sources are always detected and highlight
invalid ids without wiping them
• Correct setting of Source to be used by each event
• Add Source Id to Confirmation of changes dialog
• Correct truncation of label in confirmation of changes dialog
@0.3 • Add option to capitalise letters as keyed in Volume, District No. and Register No.
• Enable keying Ctrl ' to insert Mother's surname in Mother's Maiden Name field
• Death: If entered birth date (or implied birth date) is same as existing birth date disable option to update
• Prevent error if using option Only first field of district and entered data begins with a comma
• Correct error whereby for Death, a citation was always being added to the birth fact
• Put Citation Labels and Options in Settings dialog on to tabs to reduce height of dialog and make room
for more options
• Move cursor to end of the name after inserting a name using CTRL ' (applies to given, surname and mother)
• Add option to add a citation to the Mother's name, including adding new individual as the mother and
creating the family as required. Settings has an option to set the Mother's Given name to be used when
it is not known.
• Allow alpha in the page number (have found entries with alpha page suffix)
• Change layout of Name panel
• Ctrl tab in any of the reference fields (Volume, Page etc.) will jump focus to the first field in the
Name panel (Add Citation to Name)
• Death - Date of Birth: Allow part date of mmm yyyy (as well as year only)
• Death - Birth Date update options: change last option to 'Don't add citation' if the date matches
• Some code rationalisation
@0.4 • Replace iup.messagesdlg with custom function - error messages will display using the same user's font
as in all the dialogs
• Apply name format rule to mother's surname in the citation text from source
@0.4.1 • Restructure to ensure all messages and dialogs are children of their parent dialog
• Prevent a family consisting of only one individual being given a marriage citation
• Give consistent titles to all message
• Improve all tips displayed on mouseover
• Add link to help and add button for settings help on settings dialog
• Improve display of current record selection in main menu
• GRO reference labels in Where Within: Don't add a space if label begins with / or -
• Improve validation of DOB on death event
• Ensure the main dialog is not off the top of the screen if the FH window is smaller than the main dialog
and near the top of the screen
• Change CTRL TAB on reference fields to jump to first Given name
• Ensure & is displayed correctly in existing citations message and Places in the comparison of event details
@1.0 Release to plugin store
@1.1 • Add option for using a list of GRO District names:
List can be maintained from settings, or from a button beside the District name on the main entry screen.
Optionally, the years the district was valid can be added. These will be shown in the drop down list
and the year selected will be checked against the range(s)
• Add option to update name when adding Birth citation
• Allow selection of quarter by keying 1, 2, 3, or 4
• Ensure & is correctly displayed in messages
• Ensure & in an address is correctly displayed in existing event details dialog
• Improve display of existing citations (particularly when there are multiple citations)
@1.1.1 • Correct selection of quarter to prevent error if control key used
@1.2 Add checking for updated version in plugin store (Check frequency configured in settings)
]]
Version = '1.2'
fhInitialise(7,0,0,'save_recommended')
fhfu = require('fhFileUtils')
fhu = require('fhutils')
fhu.setIupDefaults()
require('iupluaimglib')
require('luacom')
iup.SetGlobal('IMAGESTOCKSIZE', 32)
function main()
if fhGetContextInfo('CI_APP_MODE') ~= 'Project Mode' then
OkOnlyMessage(fhGetContextInfo('CI_PLUGIN_NAME'), 'This plugin does not support running in Gedcom Mode', 'ERROR')
return
end
Initialise()
function CheckSource(SourceId) -- Check source exists and is not templated
if SourceId == 0 then
return false
end
local ptrSource = fhNewItemPtr()
ptrSource:MoveToRecordById('SOUR', SourceId)
if ptrSource:IsNull() then
return false
end
local ptrTemplate = fhGetItemPtr(ptrSource, '~._SRCT>')
if ptrTemplate:IsNotNull() then
return false
end
return true
end -- function CheckSource
function SetSource(SourceId)
gtblData.id = SourceId
gtblData.ptr:MoveToRecordById('SOUR', SourceId)
gtblData.name = fhGetDisplayText(gtblData.ptr)
end
repeat
local Exit = false
local selMain = Menu()
if selMain == 1 then
Exit = MainDialog('Birth', gtblData.arrInd1Details, nil, nil, gtblData.FirstYear, gtblData.LastYear)
end
if selMain == 2 then
Exit = MainDialog('Marriage', gtblData.arrInd1Details, gtblData.arrInd2Details, gtblData.arrFamilyDetails,
gtblData.FirstYear, gtblData.LastYear)
end
if selMain == 3 then
Exit = MainDialog('Death', gtblData.arrInd1Details, nil, nil, gtblData.FirstYear, gtblData.LastYear)
end
if selMain == 9 then
config()
end
if Exit then -- Task complete ar Exit selected
return
end
until not selMain or selMain == 0
end -- function Main
--======================================================================================================================
function Menu() -- Main menu
-- Get display name of current record (individual or family)
local ptrList = fhGetCurrentRecordSel("INDI")
local strCurrent
if #ptrList == 1 then
strCurrent = fhIndGetName(ptrList[1], false, false)
elseif #ptrList > 1 then
strCurrent = ''
else
local ptrList = fhGetCurrentRecordSel('FAM')
if #ptrList ==1 then
strCurrent = 'Family ' .. fhGetItemText(ptrList[1], '~'):sub(4)
elseif #ptrList > 1 then
strCurrent = ''
else
ptrList = fhGetCurrentRecordSel()
if #ptrList == 0 then
strCurrent = ''
else
if #ptrList ==1 then
strCurrent = fhGetTypeInfo(ptrList[1], 'label') .. ': ' .. fhGetItemText(ptrList[1], '~')
else
strCurrent = ''
end
end
end
end
local lblCurrentRecord = iup.flatlabel{title = strCurrent, textwrap = 'YES', size= '180x18', expand = 'VERTICAL'}
lblCurrentRecord.fontstyle = 'Bold'
local hboxCurrentRecord = iup.hbox{
iup.label{title = 'Current Record:'}, lblCurrentRecord;
gap = 4, margin = '0x0', alignment = 'ATOP'
}
local selection
-- Main actions buttons
-- Birth
local btnBirth = iup.button{ title = 'Birth Citation', padding = '10x3'}
if not CheckSource(gtblSettings.SourceIdBirth) then
btnBirth.active = 'NO'
end
-- Marriage
local btnMarriage = iup.button{ title = 'Marriage Citation', padding = '10x3'}
if not CheckSource(gtblSettings.SourceIdMarriage) then
btnMarriage.active = 'NO'
end
-- Death
local btnDeath = iup.button{ title = 'Death Citation', padding = '10x3' }
if not CheckSource(gtblSettings.SourceIdDeath) then
btnDeath.active = 'NO'
end
local btnScreenPosReset = iup.button{
title = 'Reset Dialog Position', padding = '16x0',
tip = 'Reset position of the citation dialog to\ncentered on Family Historian Window',
}
if gtblSettings.ScreenPosX == iup.CENTERPARENT and gtblSettings.ScreenPosX == iup.CENTERPARENT then
btnScreenPosReset.active = 'NO'
end
function btnScreenPosReset:action()
gtblSettings.ScreenPosX = iup.CENTERPARENT
gtblSettings.ScreenPosY = iup.CENTERPARENT
SaveSettings()
btnScreenPosReset.active = 'NO' -- Stop it being pressed twice
end
local btnConfig = iup.button{ title = 'Settings', padding = '10x3',
action = function(self) selection = 9 return iup.CLOSE end }
-- Footer buttons
local btnHelp = iup.button{ title = 'Help',padding = '10x3', tip = 'Display plugin help page'}
function btnHelp:action()
fhShellExecute('https://pluginstore.family-historian.co.uk/page/help/gro-bmd-index-citations')
end
local btnExit = iup.button{ title = 'Close', padding = '10x3', tip = 'Exit plugin' }
function btnExit:action()
selection = 0
return iup.CLOSE
end
-- Assemble form
local vboxMainForm = iup.vbox{
hboxCurrentRecord,
iup.frame{
iup.vbox{
iup.hbox{
btnBirth, btnMarriage, btnDeath;
normalizesize = 'BOTH', gap = 6, margin = '10x10'
},
btnScreenPosReset;
alignment = 'ACENTER'
}
},
iup.hbox{
iup.fill{}, btnConfig, btnHelp, btnExit, iup.fill{};
normalizesize = 'BOTH', margin = 'x10', gap = 50
};
gap = 10, margin = '10x10'
}
local dialogMenu = iup.dialog{
vboxMainForm; resize = 'No', minbox = 'No', maxbox = 'No', title = gPluginName .. ' (v' .. Version .. ')',
tipballoon = 'YES', tipdelay = 10000, tipballoontitleicon = '1'
}
iup.SetAttribute(dialogMenu, 'NATIVEPARENT', fhGetContextInfo('CI_PARENT_HWND'))
--******************************* Action functions for Birth, Marriage, Death buttons ********************************
function btnBirth:action()
local ptrInd = GetIndividual()
if ptrInd == nil then
return
end
if ExistingCitation(ptrInd, '~.BIRT', gtblSettings.SourceIdBirth) then -- Check for existing citation to source
return
end
local arrIndDetails = GetIndDetails(ptrInd)
if arrIndDetails['LatestBirth'] < 1837 and arrIndDetails['LatestBirth'] ~= 0 then
OkOnlyMessage('GRO Index Birth Citation', arrIndDetails['DispName'] .. ' was born before GRO index starts',
'WARNING', dialogMenu)
return
end
-- Range to be used for the year drop down
gtblData.FirstYear = math.max(arrIndDetails['EarliestBirth'], 1837)
gtblData.LastYear = math.min(arrIndDetails['LatestBirth'], gtblConstants.CurrYear)
SetSource(gtblSettings.SourceIdBirth)
gtblData.arrInd1Details = arrIndDetails
selection = 1
return iup.CLOSE
end
------------------------------------------------------------------------------------------------------------------------
function btnMarriage:action()
local ptrFamily = GetFamily()
if ptrFamily == nil then
return
end
if ExistingCitation(ptrFamily, '~.MARR', gtblSettings.SourceIdMarriage) then -- Check for existing citation to source
return
end
-- Get details of the two individuals & predict date range for marriage
local ptrInd1 = fhNewItemPtr()
ptrInd1:MoveTo(ptrFamily,'~.~SPOU[1]>')
if ptrInd1:IsNull() then
local strMessage = 'Selected family has no parents'
OkOnlyMessage('GRO Index Marriage Citation', strMessage, 'ERROR', dialogMenu)
return
end
local arrIndDetails1 = GetIndDetails(ptrInd1)
local ptrInd2 = fhNewItemPtr()
local arrIndDetails2
ptrInd2:MoveTo(ptrFamily,'~.~SPOU[2]>')
if ptrInd2:IsNotNull() then
arrIndDetails2 = GetIndDetails(ptrInd2)
else
local strMessage = 'Selected family only has one parent'
OkOnlyMessage('GRO Index Marriage Citation', strMessage, 'ERROR', dialogMenu)
return
end
local arrFamDetails = {}
arrFamDetails['Ptr'] = ptrFamily
arrFamDetails['DispName'] = fhGetItemText(ptrFamily, '~')
arrFamDetails['MarriageDatePtr'] = fhGetItemPtr(ptrFamily, '~.MARR.DATE')
local EarliestYear, LatestYear
if arrFamDetails['MarriageDatePtr']:IsNotNull() then
local dtDate = fhGetValueAsDate(arrFamDetails['MarriageDatePtr'])
local dpDate = dtDate:GetDatePt1()
EarliestYear = dpDate:GetYear()
dpDate = dtDate:GetDatePt2()
if dpDate:IsNull() then
LatestYear = EarliestYear
else
LatestYear = dpDate:GetYear()
end
elseif arrIndDetails2 ~= nil then
EarliestYear = math.max(arrIndDetails1['EarliestBirth'], arrIndDetails2['EarliestBirth']) + 12
LatestYear = math.min(arrIndDetails1['LatestDeath'], arrIndDetails2['LatestDeath'])
else
EarliestYear = arrIndDetails1['EarliestBirth'] + 12
LatestYear = arrIndDetails1['LatestDeath']
end
LatestYear = math.min(LatestYear, gtblConstants.CurrYear)
if LatestYear < 1837 then
OkOnlyMessage('GRO Index Marriage Citation',
arrFamDetails['DispName']:sub(7) .. ' married before GRO index starts', 'WARNING', dialogMenu)
return
end
gtblData.FirstYear = math.max(EarliestYear, 1837)
gtblData.LastYear = LatestYear
--return MainDialog('Marriage', arrIndDetails1, arrIndDetails2, arrFamDetails, EarliestYear, LatestYear)
SetSource(gtblSettings.SourceIdMarriage)
gtblData.arrInd1Details = arrIndDetails1
gtblData.arrInd2Details = arrIndDetails2
gtblData.arrFamilyDetails = arrFamDetails
selection = 2
return iup.CLOSE
end
------------------------------------------------------------------------------------------------------------------------
function btnDeath:action()
local ptrInd = GetIndividual()
if ptrInd == nil then
return
end
if ExistingCitation(ptrInd, '~.DEAT', gtblSettings.SourceIdBirth) then -- Check for existing citation to source
return
end
local arrIndDetails = GetIndDetails(ptrInd)
if arrIndDetails['LatestDeath'] < 1837 then
OkOnlyMessage('GRO Index Death Citation' , arrIndDetails['DispName'] .. ' died before GRO index starts',
'WARNING', dialogMenu)
return
end
-- Range to be used for the year drop down
gtblData.FirstYear = math.max(arrIndDetails['EarliestDeath'], 1837)
gtblData.LastYear = math.min(arrIndDetails['LatestDeath'], gtblConstants.CurrYear)
SetSource(gtblSettings.SourceIdDeath)
gtblData.arrInd1Details = arrIndDetails
selection = 3
return iup.CLOSE
end
-- **************************** Common routines used by functions Birth, Marriage, Death *****************************
function GetIndividual() -- Get current individual or prompt if no current
local ptrList = fhGetCurrentRecordSel("INDI")
while #ptrList ~= 1 do
ptrList = fhPromptUserForRecordSel("INDI", 1, dialogMenu.HWND)
if #ptrList ~= 1 then
return nil
end
end
return ptrList[1]
end -- function GetIndividual
------------------------------------------------------------------------------------------------------------------------
function GetFamily() -- Get current family or family of current individual; if neither prompt
local ptrListF = fhGetCurrentRecordSel('FAM')
if #ptrListF == 1 then
return ptrListF[1] -- Just one family selected
end
local ptrListI = {} -- Initialise arrays so test to prompt for family below doesn't fail
local arrFams = {}
if #ptrListF == 0 then -- No family selected
ptrListI = fhGetCurrentRecordSel('INDI')
if #ptrListI == 1 then -- Just one individual seleted - find their family(s)
local ptrFams = fhNewItemPtr()
ptrFams:MoveTo(ptrListI[1],'~.FAMS')
while ptrFams:IsNotNull() do
table.insert(arrFams,fhGetValueAsLink(ptrFams))
ptrFams:MoveNext('SAME_TAG')
end
if #arrFams == 1 then -- Individual has only one family
return arrFams[1]
end
end
end
-- If multiple families selected OR not just one individual selected OR selected individual has no families prompt for selection
-- Prompt for family if nothing possible seleted
if #ptrListF > 1 or #ptrListI ~= 1 or #arrFams == 0 then
while #ptrListF ~= 1 do
ptrListF = fhPromptUserForRecordSel('FAM', 1)
if #ptrListF ~= 1 then
return nil
end
end
return ptrListF[1]
end
-- No family selected, a single individual is selected and they have multiple families
-- We already have array of families (arrFams) - get spouses for them
local listFamilies = iup.list{}
local ptrSpouse = fhNewItemPtr()
for i = 1, #arrFams do
ptrSpouse:MoveTo(ptrListI[1],'~.~SPOU[' .. i .. ']>')
if ptrSpouse:IsNotNull() then
listFamilies[i] = fhGetDisplayText(ptrListI[1]) .. ' and ' .. fhGetDisplayText(ptrSpouse)
else
listFamilies[i] = fhGetDisplayText(ptrListI[1]) .. ' and <>'
end
end
local btnOK =iup.button{title = 'OK', padding = '10x3'}
local Continue
local btnCancel = iup.button{
title = 'Cancel', padding = '10x3',
action = function(self) Continue = false return iup.CLOSE end
}
strTitle = 'GRO Index Marriage Citation'
local dialogFamily = iup.dialog{
iup.vbox{
iup.label{title = fhGetDisplayText(ptrListI[1]) .. ' has multiple families\nSelect family for this marriage';
padding = '0x4', alignment = 'ACENTER:ATOP', expand = 'YES'
},
listFamilies,
iup.hbox{
iup.fill{}, btnOK, btnCancel, iup.fill{};
normalizesize = 'BOTH', margin = '0x0', gap = 40
};
gap = 10, margin = '10x10'
};
resize = 'No', minbox = 'No', maxbox = 'No', helpbutton = 'Yes',
title = strTitle,
defaultesc = btnCancel,
PARENTDIALOG = dialogMenu,
tipballoon = 'YES', tipdelay = 10000, tipballoontitleicon = '1'
}
function btnOK:action()
if listFamilies.value == "0" then
OkOnlyMessage(strTitle, 'Selection of family required', 'ERROR', dialogFamily)
return
end
Continue = true
return iup.CLOSE
end
dialogFamily:popup(iup.CENTERPARENT, iup.CENTERPARENT)
local Selection = nil
if Continue then
Selection = arrFams[tonumber(listFamilies.value)]
end
dialogFamily:destroy()
return Selection
end -- function GetFamily
------------------------------------------------------------------------------------------------------------------------
function GetIndDetails(ptrInd)
local arrDetails = {}
arrDetails['Ptr'] = ptrInd
arrDetails['Id'] = fhGetRecordId(ptrInd)
arrDetails['DispNameFull'] = fhIndGetName(ptrInd, true, false)
arrDetails['DispName'] = fhIndGetName(ptrInd, false, false)
local strNameStored =fhGetItemText(ptrInd,'INDI.NAME[1]:STORED')
local strGiven
if strNameStored:sub(-1) == '/' then
strGiven = strNameStored:match('^[^/]*')
arrDetails['Surname'] = strNameStored:match('%b//'):gsub('/','')
arrDetails['NameOrder'] = 1
elseif strNameStored:sub(1, 1) == '/' then
strGiven = strNameStored:match('[^/]*$')
arrDetails['Surname'] = strNameStored:match('%b//'):gsub('/','')
arrDetails['NameOrder'] = 2
else -- Indeterminate name structure, put in given name so user controls capitalisation
strGiven = strNameStored
arrDetails['Surname'] = ''
arrDetails['NameOrder'] = 3
end
arrDetails['GivenName'] = strGiven:match('^%s*(.-)%s*$')
arrDetails['ptrMother'] = fhGetItemPtr(ptrInd,'~.FAMC>WIFE>')
arrDetails['ptrFamily'] = fhGetItemPtr(ptrInd,'~.FAMC>')
arrDetails['Mother'] = Capitalise(fhGetItemText(ptrInd, 'INDI.~MOTH[1]>NAME[1]:SURNAME'))
arrDetails['EarliestBirth'] = fhCallBuiltInFunction('EstimatedBirthDate', ptrInd, 'EARLIEST',3):GetYear()
arrDetails['LatestBirth'] = fhCallBuiltInFunction('EstimatedBirthDate', ptrInd, 'LATEST',3):GetYear()
arrDetails['EarliestDeath'] = fhCallBuiltInFunction('EstimatedDeathDate', ptrInd, 'EARLIEST',3):GetYear()
local LatestDeath = fhCallBuiltInFunction('EstimatedDeathDate', ptrInd, 'LATEST',3):GetYear()
arrDetails['LatestDeath'] = math.max(LatestDeath, gtblConstants.CurrYear) -- Latest estimated death can be zero
return arrDetails
end -- function GetIndDetails
------------------------------------------------------------------------------------------------------------------------
function ExistingCitation (ptrRecord, EventRef, SourceId) -- Checks for existing citation to source
-- Returns true if found and user cancels
local ptrEventSource = fhNewItemPtr()
local ptrEventSourceRecord = fhNewItemPtr()
local ptrTemp = fhNewItemPtr()
local bExisting = false
local strCitations = ''
ptrEventSource:MoveTo(ptrRecord, EventRef .. '.SOUR')
while ptrEventSource:IsNotNull() do
ptrEventSourceRecord = fhGetValueAsLink(ptrEventSource)
if fhGetRecordId(ptrEventSourceRecord) == SourceId then
bExisting = true
strCitations = strCitations .. '\n'
ptrTemp = fhGetItemPtr(ptrEventSource, '~.PAGE')
if ptrTemp:IsNotNull() then
strCitations = strCitations .. '\n' .. fhGetValueAsText(ptrTemp)
end
ptrTemp = fhGetItemPtr(ptrEventSource, '~.DATA.TEXT')
if ptrTemp:IsNotNull() then
strCitations = strCitations .. '\n' .. fhGetValueAsText(ptrTemp)
end
end
ptrEventSource:MoveNext('SAME_TAG')
end
if bExisting then
local strMessage = 'Existing ' .. GetSource(SourceId) .. ' citation(s) found:' .. strCitations
.. '\n\nContinue?'
if MessageBox(gPluginName, strMessage, 'OKCANCEL', 'QUESTION', 1, dialogMenu) == 2 then
return true
end
end
return false
end
-- *************************End of Common routines used by functions Birth, Marriage, Death ***************************
dialogMenu:show()
iup.MainLoop()
dialogMenu:destroy()
return selection
end -- function Menu
--======================================================================================================================
function config() -- Configuration dialog
local dialogSettings -- 'forward' declaration
-- Sources
-- Birth
local lblBirth = iup.flatlabel{title = 'Birth', size = '40x11', alignment = 'ALEFT:ACENTRE'}
local txtBirthSourceId = iup.text{
visiblecolumns = 3, alignment = 'ACENTER', filter = 'NUMBER'
}
local lblBirthSource = iup.flatlabel{
title = ' ', border = 'YES', size = '140x11', alignment = 'ALEFT:ACENTRE', padding = '4,0'
}
if gtblSettings.SourceIdBirth ~= 0 then
txtBirthSourceId.value = gtblSettings.SourceIdBirth
local SourceName, Templated = GetSource(gtblSettings.SourceIdBirth)
if SourceName ~= '' then
if Templated then
lblBirthSource.title = ''
txtBirthSourceId.bgcolor = gtblConstants.Yellow
else
lblBirthSource.title = SourceName
end
else
lblBirthSource.title = ''
txtBirthSourceId.bgcolor = gtblConstants.Yellow
end
else
lblBirthSource.title = ''
end
local btnBirthSource = iup.button{title = 'Select', padding = '2x0'}
local hboxBirthSource = iup.hbox{
lblBirth, txtBirthSourceId, lblBirthSource, btnBirthSource, iup.fill{};
gap = 10, margin = '5x0'
}
-- Marriage
local lblMarriage = iup.flatlabel{title = 'Marriage', size = '40x11', alignment = 'ALEFT:ACENTRE'}
local txtMarriageSourceId = iup.text{
visiblecolumns = 3, alignment = 'ACENTER', filter = 'NUMBER'
}
local lblMarriageSource = iup.flatlabel{
title = ' ', border = 'YES', size = '140x11', alignment = 'ALEFT:ACENTRE', padding = '4,0'
}
if gtblSettings.SourceIdMarriage ~= 0 then
txtMarriageSourceId.value = gtblSettings.SourceIdMarriage
local SourceName, Templated = GetSource(gtblSettings.SourceIdMarriage)
if SourceName ~= '' then
if Templated then
lblMarriageSource.title = 'Source ' .. txtMarriageSourceId.value .. ' is templated'
txtMarriageSourceId.bgcolor = gtblConstants.Yellow
else
lblMarriageSource.title = SourceName
end
else
lblMarriageSource.title = ''
txtMarriageSourceId.bgcolor = gtblConstants.Yellow
end
else
lblMarriageSource.title = ''
end
local btnMarriageSource = iup.button{title = 'Select', padding = '2x0'}
local hboxMarriageSource = iup.hbox{
lblMarriage, txtMarriageSourceId, lblMarriageSource, btnMarriageSource, iup.fill{};
gap = 10, margin = '5x0'
}
-- Death
local lblDeath = iup.flatlabel{title = 'Death', size = '40x11', alignment = 'ALEFT:ACENTRE'}
local txtDeathSourceId = iup.text{
visiblecolumns = 3, alignment = 'ACENTER', filter = 'NUMBER'
}
local lblDeathSource = iup.flatlabel{
title = ' ', border = 'YES', size = '140x11', alignment = 'ALEFT:ACENTRE', padding = '4,0'
}
if gtblSettings.SourceIdDeath ~= 0 then
txtDeathSourceId.value = gtblSettings.SourceIdDeath
local SourceName, Templated = GetSource(gtblSettings.SourceIdDeath)
if SourceName ~= '' then
if Templated then
lblDeathSource.title = 'Source ' .. txtDeathSourceId.value .. ' is templated'
txtDeathSourceId.bgcolor = gtblConstants.Yellow
else
lblDeathSource.title = SourceName
end
else
lblDeathSource.title = ''
txtDeathSourceId.bgcolor = gtblConstants.Yellow
end
else
lblDeathSource.title = ''
end
local btnDeathSource = iup.button{title = 'Select', padding = '2x0'}
local hboxDeathSource = iup.hbox{
lblDeath, txtDeathSourceId, lblDeathSource, btnDeathSource, iup.fill{};
gap = 10, margin = '5x0'
}
local frameSources = iup.frame{
iup.vbox{
hboxBirthSource, hboxMarriageSource, hboxDeathSource;
expandchildren = 'YES', gap = '2', margin = '6x3', fontstyle = ''
},
title = 'Sources', fontstyle = 'Bold'
}
-- Citation labels
-- Where Within Source Headers
local txtLabelPrefixBirth = iup.text{value = gtblSettings.LabelPrefixBirth, visiblecolumns = '8'}
local vboxLabelPrefixBirth = iup.vbox{iup.label{title = 'Birth'}, txtLabelPrefixBirth; gap = '2'}
local txtLabelPrefixMarriage = iup.text{value = gtblSettings.LabelPrefixMarriage, visiblecolumns = '8'}
local vboxLabelPrefixMarriage = iup.vbox{iup.label{title = 'Marriage'}, txtLabelPrefixMarriage; gap = '2'}
local txtLabelPrefixDeath = iup.text{value = gtblSettings.LabelPrefixDeath, visiblecolumns = '8'}
local vboxLabelPrefixDeath = iup.vbox{iup.label{title = 'Death'}, txtLabelPrefixDeath; gap = '2'}
local lblTFSHeaders = iup.label{title = 'Where Within Source\nheaders', size = '0x0', multiline = 'yes', padding = '0x4', fgcolor = gtblConstants.Blue}
local hboxCitatationLabels = iup.hbox{
iup.frame{
iup.hbox{
lblTFSHeaders,
vboxLabelPrefixBirth, iup.fill{},
vboxLabelPrefixMarriage, iup.fill{},
vboxLabelPrefixDeath;
margin = '5x2', alignment = 'ABOTTOM', gap = '10'
},
sunken = 'YES'
},
margin = '5x0'
}
-- GRO Reference Labels
local txtLabelDistrictName = iup.text{value = gtblSettings.LabelDistrictName, visiblecolumns = '6'}
local hboxLabelDistrictName = iup.hbox{iup.label{title = 'District'}, iup.fill{}, txtLabelDistrictName; alignment = 'ACENTER'}
local txtLabelVolume = iup.text{value = gtblSettings.LabelVolume, visiblecolumns = '6'}
local hboxLabelVolume = iup.hbox{iup.label{title = 'Volume'}, iup.fill{}, txtLabelVolume; alignment = 'ACENTER'}
local txtLabelPage = iup.text{value = gtblSettings.LabelPage, visiblecolumns = '6'}
local hboxLabelPage = iup.hbox{iup.label{title = 'Page'}, iup.fill{}, txtLabelPage; alignment = 'ACENTER'}
local txtLabelDistrictNo = iup.text{value = gtblSettings.LabelDistrictNo, visiblecolumns = '6'}
local hboxLabelDistrictNo = iup.hbox{iup.label{title = 'District No.'}, iup.fill{}, txtLabelDistrictNo; alignment = 'ACENTER'}
local txtLabelRegister = iup.text{value = gtblSettings.LabelRegister, visiblecolumns = '6'}
local hboxLabelRegister = iup.hbox{iup.label{title = 'Register No.'}, iup.fill{}, txtLabelRegister; alignment = 'ACENTER'}
local txtLabelEntry = iup.text{value = gtblSettings.LabelEntry, visiblecolumns = '6'}
local hboxLabelEntry = iup.hbox{iup.label{title = 'Entry No.'}, iup.fill{}, txtLabelEntry; alignment = 'ACENTER'}
local vboxGRORef1 = iup.vbox{hboxLabelDistrictName, hboxLabelVolume, hboxLabelPage; gap = '0', margin = '2x2'}
local vboxGRORef2 = iup.vbox{hboxLabelDistrictNo, hboxLabelRegister, hboxLabelEntry; gap = '0', margin = '2x2'}
local lblWWSLabels = iup.flatlabel{title = 'Where within Source\nLabels', size = '0x0', multiline='yes', padding = '0x4', fgcolor = gtblConstants.Blue}
local hboxGRORefLabels = iup.hbox{
iup.frame{
iup.hbox{
lblWWSLabels, vboxGRORef1, iup.fill{}, vboxGRORef2;
margin = '5x2', alignment = 'ATOP', gap = '10'
},
sunken = 'YES'
},
margin = '5x0'
}
-- Event Specific Labels
local txtLabelMother = iup.text{value = gtblSettings.LabelMother, expand = 'HORIZONTAL'}
local hboxLabelMother = iup.hbox{
iup.label{title = 'Birth', size = '30x0'},
iup.label{title = 'Mother\'s Maiden Name'},
txtLabelMother;
gap = '10', margin = '0x0', alignment = 'ACENTER'
}
local txtLabelAge = iup.text{value = gtblSettings.LabelAge, visiblecolumns = '6'}
local hboxLabelAge = iup.hbox{iup.label{title = 'Death', size = '30x0'}, iup.label{title= 'Age'}, txtLabelAge; alignment = 'ACENTER'}
local txtLabelDOB = iup.text{value = gtblSettings.LabelDOB, visiblecolumns = '6'}
local hboxLabelDOB = iup.hbox{iup.label{title = 'Date of Birth'}, txtLabelDOB; alignment = 'ACENTER'}
local hboxLabelsDeath = iup.hbox{hboxLabelAge, iup.fill{}, hboxLabelDOB; gap = '10', margin = '0x0'}
local lblTFSEventLabels = iup.flatlabel{title = 'Text from Source\nEvent Specific Labels',
size = '0x0', multiline='yes', padding = '0x4', fgcolor = gtblConstants.Blue}
local hboxEventLabels = iup.hbox{
iup.frame{
iup.hbox{
lblTFSEventLabels,
iup.vbox{
hboxLabelMother,
iup.label{separator = 'HORIZONTAL'},
hboxLabelsDeath;
gap = '4', margin = '3x0'
};
margin = '6x2', alignment = 'ATOP', gap = '10'
},
sunken = 'YES'
},
margin = '5x0'
}
local vboxLabels = iup.vbox{
iup.hbox{
iup.fill{},
iup.label{
title = 'Use ^ to specify trailing spaces on labels; $ to embed data within label ',
fontstyle = 'Italic', alignment= 'ACENTRE'
},
iup.fill{}
},
hboxCitatationLabels, hboxGRORefLabels, hboxEventLabels;
expandchildren = 'YES', margin = '5x2', gap = '2', fontstyle = '',
tabtitle = ' Citation Labels '
}
-- Options settings
function ItalicLabel (strTitle)
local label = iup.label{title = strTitle}
label.fontstyle = 'Italic'
return label
end -- function ItalicLabel
local lblQtrMonthNames = iup.label{title = 'Full Month Names && Quarter Months in Citation Text'}
local tglQtrMonthNames = iup.toggle{value = ToggleValue(gtblSettings.QtrMonthNames),
tipballoontitle = 'Month and quarter names in citation', tip = 'OFF: Q1, Jan etc.\nON: Q1 Jan-Feb-Mar, January etc.'}
local lblUCRefs = iup.label{title = 'Make alpha characters in reference upper case'}
local tglUCRefs = iup.toggle{value = ToggleValue(gtblSettings.UCRefs),
tipballoontitle = 'Where within source references',
tip = 'Convert lower case characters in Volume,\nDistrict, and Register numbers to upper case'}
local lblUseGRODistricts = iup.label{title = 'Use GRO District List'}
local tglUseGRODistricts = iup.toggle{value = ToggleValue(gtblSettings.UseGRODistricts),
tipballoontitle = 'Use GRO District List',
tip ='Use list of GRO District Names instead of all Places in project'}
local btnGRODistricts = iup.button{
title = 'Edit GRO District List', padding = '8x0',
action = function(self) GRODistricts(dialogSettings) end
}
if not gtblSettings.UseGRODistricts then
btnGRODistricts.visible = 'NO'
else
btnGRODistricts.visible = 'YES'
end
local hboxGRODistricts = iup.hbox{
tglUseGRODistricts, btnGRODistricts;
gap = '8', alignment = 'ACENTER', margin = '0x0'}
function tglUseGRODistricts:action(state)
if state == 0 then
btnGRODistricts.visible = 'NO'
else
btnGRODistricts.visible = 'YES'
end
end
local lblShortPlaces = iup.label{title = 'Only first field of District Name in Citation Text'}
local tglShortPlaces = iup.toggle{value = ToggleValue(gtblSettings.ShortPlaces),
tipballoontitle = 'Where within source Registration District Names',
tip ='The district name should be entered as a full place\n'
.. 'Enable this option to use the first field only in Where Within Source'}
local lblIncNameInCitation = iup.hbox{
iup.label{title ='Include Name(s) in Citation Text '}, ItalicLabel('(default) ');
gap = 0, margin = '0x0' }
local tglIncNameInCitation = iup.toggle{ ['3state'] = 'YES', value = gtblSettings.IncNameInCitation,
tipballoontitle = 'Include name(s) in Citation Text',
tip = 'This specifies the initial setting in the BMD dialogs\n'
.. 'which can be changed for individual citations.\n'
.. 'Options are: Always, Only if adding citation to name and Never'
}
local lblIncNameState = iup.label{title = ' ', size = '120x0'}
local hboxIncNameInCitation = iup.hbox{tglIncNameInCitation, lblIncNameState, gap = 4, margin = '0x0'}
local lblNameFormat = iup.label{title='Format of Names'}
local listNameFormat = iup.list{
'Surname, Given', 'SURNAME, Given', 'Given Surname', 'Given SURNAME',
value = gtblSettings.NameFormat, dropdown = 'YES', size = '95x0',
tipballoontitle = 'Format of names',
tip = 'Select how names are to be capitalised in citations\n'
.. 'Also applies to mother\'s maiden name'
}
local lblCitationForName = iup.hbox{
iup.label{title ='Add Citation to Name(s) '}, ItalicLabel('(default) ');
gap = 0, margin = '0x0' }
local tglCitationNameBirth = iup.toggle{value = ToggleValue(gtblSettings.CitationNameBirth), title = 'Births',
tipballoontitle = 'Add Citation to Name',
tip = 'This specifies the initial setting in the Birth dialog\n'
.. 'which can be changed for individual citations.\n'
}
local tglCitationNameMarriage = iup.toggle{value = ToggleValue(gtblSettings.CitationNameMarriage), title = 'Marriages',
tipballoontitle = 'Add Citation to Names',
tip = 'This specifies the initial setting in the Marriage dialog\n'
.. 'which can be changed for individual citations.\n'
}
local tglCitationNameDeath = iup.toggle{value = ToggleValue(gtblSettings.CitationNameDeath), title = 'Deaths',
tipballoontitle = 'Add Citation to Name',
tip = 'This specifies the initial setting in the Death dialog\n'
.. 'which can be changed for individual citations.\n'
}
local hboxCitationNames = iup.hbox{tglCitationNameBirth,tglCitationNameMarriage,tglCitationNameDeath;
margin = '0x0'}
local function SetlblIncNameState()
local strState
if tglIncNameInCitation.value == 'ON' then
strState = 'Always'
elseif tglIncNameInCitation.value == 'OFF' then
strState = 'Never'
else
strState = 'Only if adding citation to name'
end
lblIncNameState.title = strState
end
SetlblIncNameState()
function tglCitationNameBirth:action()
if not ValidateCitationToName() then
tglCitationNameBirth.value = 'OFF'
end
end
function tglCitationNameMarriage:action()
if not ValidateCitationToName() then
tglCitationNameMarriage.value = 'OFF'
end
end
function tglCitationNameDeath:action()
if not ValidateCitationToName() then
tglCitationNameDeath.value = 'OFF'
end
end
local lblCitationToMotherDefault = iup.hbox{
iup.label{title ='Add Birth Citation to Mother\'s Name '},
ItalicLabel('(default) ');
gap = 0, margin = '0x0'
}
local tglCitationToMotherDefault = iup.toggle{value = ToggleValue(gtblSettings.CitationToMotherDefault),
tipballoontitle= 'Add Birth Citation to Mother\'s Name',
tip = 'This specifies the initial setting in the Birth dialog\n'
.. 'which can be changed for individual citations.\n'
}
local lblNewMotherGivenName = iup.label{title = 'Given name for new Birth Mother records'}
local txtNewMotherGivenName = iup.text{
value = gtblSettings.NewMotherGivenName, visiblecolumns = '8',
tipballoontitle = 'Given name for new Birth Mother records',
tip = 'If Add Birth Citation to Mother\'s Name is on and the Mother\'s record\n'
.. 'is to be created (or existing record has no name)\n'
.. 'this name will be combined with the entered Surname'
}
local lblCitationEntryDate = iup.label{title = 'Citation Date'}
local listCitationEntryDate = iup.list{
'No Date', 'Current Date', 'GRO Index Reg. Date',
value = gtblSettings.CitationEntryDate,
dropdown = 'YES', size = '95x0',
tipballoontitle = 'Citation Date',
tip = 'Date to be recorded in the Citation Specific Date'
}
local lblCitationAssess = iup.hbox{
iup.label{title ='Citation Assessment '}, ItalicLabel('(default) ');
gap = 0, margin = '0x0' }
local listCitationAssess = iup.list{
dropdown = 'YES', size = '95x0', visibleitems = 6,
tipballoontitle = 'Citation Assessment',
tip = 'This specifies the initial setting in the BMD dialogs\n'
.. 'which can be changed for individual citations.\n'
}
PopulateList(listCitationAssess, gtblConstants.CitationAssess)
listCitationAssess.value = gtblSettings.CitationAssess
local gridboxOptions = iup.gridbox{
lblQtrMonthNames, tglQtrMonthNames,
lblUCRefs, tglUCRefs,
lblUseGRODistricts, hboxGRODistricts,
lblShortPlaces, tglShortPlaces,
lblIncNameInCitation, hboxIncNameInCitation,
lblNameFormat, listNameFormat,
lblCitationForName, hboxCitationNames,
lblCitationToMotherDefault, tglCitationToMotherDefault,
lblNewMotherGivenName, txtNewMotherGivenName,
lblCitationEntryDate, listCitationEntryDate,
lblCitationAssess, listCitationAssess;
numdiv = 2, sizelin = -1, sizecol = -1, gapcol = 32, gaplin = 6, alignmentlin = 'ACENTER',
padding = '0x0' -- Set for inheritance
}
local hboxOptions = iup.hbox{
iup.frame{
iup.hbox{
gridboxOptions;
expandchildren = 'YES', margin = '3x2', fontstyle = ''
},
sunken = 'YES',
};
margin = '5x2',
tabtitle = ' Options '
}
-- Update Checks
function FormatYMDdate(Date) -- Date yyyy-mm-dd
return os.date('%d %b %Y',os.time(YMDtoTable(Date)))
end
local lblAutoCheck = iup.label{title = 'Auto Check for Plugin Updates'}
local tglAutoCheck = iup.toggle{}
if gtblSettings.VersionCheckInterval ~= 0 then
tglAutoCheck.value = 'ON'
end
local lblCheckFrequency = iup.label{title = 'Auto Check Frequency'}
local i
for k, v in pairs(gtblConstants.VersionCheckFrequency) do
if gtblSettings.VersionCheckInterval == v then
i = k
break
end
end
local listCheckFrequency = iup.list{
'Daily', 'Weekly', 'Fortnightly', 'Four Weekly',
dropdown = 'YES', value = i
}
if gtblSettings.VersionCheckInterval == 0 then
lblCheckFrequency.active = 'NO'
listCheckFrequency.active = 'NO'
end
local lblLastCheck = iup.label{title = 'Last Auto Check Date'}
local txtLastCheck = iup.text{
value = FormatYMDdate(gtblSettings.VersionCheckedDate),
visiblecolumns = 8, readonly = 'YES', canfocus = 'NO'
}
local lblNextCheck = iup.label{title = 'Next Auto Check Date'}
local txtNextCheck = iup.text{
visiblecolumns = 8, readonly = 'YES', canfocus = 'NO'
}
if gtblSettings.VersionCheckInterval ~= 0 then
txtNextCheck.value = FormatYMDdate(gtblSettings.VersionNextCheck)
end
function NextCheck(Date, Interval) -- Date yyyy-mm-dd
while Date <= os.date('%Y-%m-%d') do
Date = DateAdd(Date, Interval)
end
return Date
end
function tglAutoCheck:action(state)
if state == 1 then
lblCheckFrequency.active = 'YES'
listCheckFrequency.active = 'YES'
if listCheckFrequency.value == '0' then
listCheckFrequency.value = 2
local Interval = gtblConstants.VersionCheckFrequency[listCheckFrequency.value]
txtNextCheck.value = FormatYMDdate(NextCheck(gtblSettings.VersionCheckedDate, Interval))
end
else
lblCheckFrequency.active = 'NO'
listCheckFrequency.active = 'NO'
txtNextCheck.value = ''
end
end
function listCheckFrequency:valuechanged_cb()
local Interval = gtblConstants.VersionCheckFrequency[listCheckFrequency.value]
txtNextCheck.value = FormatYMDdate(NextCheck(gtblSettings.VersionCheckedDate, Interval))
end
local gridboxUpdateCheck = iup.gridbox{
lblAutoCheck, tglAutoCheck,
lblCheckFrequency, listCheckFrequency,
lblLastCheck, txtLastCheck,
lblNextCheck, txtNextCheck;
numdiv = 2, sizelin = -1, sizecol = -1, gapcol = 32, gaplin = 6, alignmentlin = 'ACENTER',
padding = '0x0' -- Set for inheritance
}
local btnUpdateCheck = iup.button{
title = 'Check for Update', padding = '10x3'
}
function btnUpdateCheck:action()
local bOK, strMsg = VersionCheck(dialogSettings)
if not bOK then
strMsg = 'Check for plugin update failed\n\n' .. strMsg
OkOnlyMessage(gPluginName, strMsg, 'ERROR, dialogSettings')
else
if strMsg == 'Y' then
strMsg = 'You are running the latest version'
OkOnlyMessage(gPluginName, strMsg, 'INFORMATION', dialogSettings)
end
end
end
local hboxUpdateCheck = iup.hbox{
iup.fill{},
iup.frame{
iup.vbox{
gridboxUpdateCheck, iup.label{separator='HORIZONTAL'}, btnUpdateCheck;
expandchildren = 'NO', margin = '3x2', fontstyle = '', cgap = 8
},
sunken = 'YES',
},
iup.fill{};
margin = '5x2',
tabtitle = ' Update Check '
}
------------------------------------------------------------------------------------------------------------------------
-- Footer Buttons
local btnSave = iup.button{
title = 'Save', image = 'IUP_FileSave', padding = '10x0'
}
function btnSave:action()
if txtBirthSourceId.bgcolor == gtblConstants.Yellow or txtMarriageSourceId.bgcolor == gtblConstants.Yellow
or txtDeathSourceId.bgcolor == gtblConstants.Yellow then
OkOnlyMessage(gPluginName, 'Source(s) are invalid', 'ERROR', dialogSettings)
return
end
local bAnyChanged = false
-- Sources
gtblSettings.SourceIdBirth, bAnyChanged = SettingUpdate(txtBirthSourceId.value, gtblSettings.SourceIdBirth, bAnyChanged)
gtblSettings.SourceIdMarriage, bAnyChanged = SettingUpdate(txtMarriageSourceId.value, gtblSettings.SourceIdMarriage, bAnyChanged)
gtblSettings.SourceIdDeath, bAnyChanged = SettingUpdate(txtDeathSourceId.value, gtblSettings.SourceIdDeath, bAnyChanged)
-- Citation Prefixes
gtblSettings.LabelPrefixBirth, bAnyChanged = SettingUpdate(txtLabelPrefixBirth.value, gtblSettings.LabelPrefixBirth, bAnyChanged)
gtblSettings.LabelPrefixMarriage, bAnyChanged = SettingUpdate(txtLabelPrefixMarriage.value, gtblSettings.LabelPrefixMarriage, bAnyChanged)
gtblSettings.LabelPrefixDeath, bAnyChanged = SettingUpdate(txtLabelPrefixDeath.value, gtblSettings.LabelPrefixDeath, bAnyChanged)
-- GRO Reference Labels
gtblSettings.LabelDistrictName, bAnyChanged = SettingUpdate(txtLabelDistrictName.value, gtblSettings.LabelDistrictName, bAnyChanged)
gtblSettings.LabelVolume, bAnyChanged = SettingUpdate(txtLabelVolume.value, gtblSettings.LabelVolume, bAnyChanged)
gtblSettings.LabelPage, bAnyChanged = SettingUpdate(txtLabelPage.value, gtblSettings.Page, bAnyChanged)
gtblSettings.LabelDistrictNo, bAnyChanged = SettingUpdate(txtLabelDistrictNo.value, gtblSettings.LabelDistrictNo, bAnyChanged)
gtblSettings.LabelRegister, bAnyChanged = SettingUpdate(txtLabelRegister.value, gtblSettings.LabelRegister, bAnyChanged)
gtblSettings.LabelEntry, bAnyChanged = SettingUpdate(txtLabelEntry.value, gtblSettings.LabelEntry, bAnyChanged)
-- Event Specific Labels
gtblSettings.LabelMother, bAnyChanged = SettingUpdate(txtLabelMother.value, gtblSettings.LabelMother, bAnyChanged)
gtblSettings.LabelAge, bAnyChanged = SettingUpdate(txtLabelAge.value, gtblSettings.LabelAge, bAnyChanged)
gtblSettings.LabelDOB, bAnyChanged = SettingUpdate(txtLabelDOB.value, gtblSettings.LabelDOB, bAnyChanged)
-- Other settings
gtblSettings.QtrMonthNames, bAnyChanged = SettingUpdate(tglQtrMonthNames.value, gtblSettings.QtrMonthNames, bAnyChanged)
gtblSettings.UCRefs, bAnyChanged = SettingUpdate(tglUCRefs.value, gtblSettings.UCRefs, bAnyChanged)
gtblSettings.UseGRODistricts, bAnyChanged = SettingUpdate(tglUseGRODistricts.value, gtblSettings.UseGRODistricts, bAnyChanged)
gtblSettings.ShortPlaces, bAnyChanged = SettingUpdate(tglShortPlaces.value, gtblSettings.ShortPlaces, bAnyChanged)
gtblSettings.IncNameInCitation, bAnyChanged = SettingUpdate(tglIncNameInCitation.value, gtblSettings.IncNameInCitation, bAnyChanged)
gtblSettings.NameFormat, bAnyChanged = SettingUpdate(listNameFormat.value, gtblSettings.NameFormat, bAnyChanged)
gtblSettings.CitationNameBirth, bAnyChanged = SettingUpdate(tglCitationNameBirth.value, gtblSettings.CitationNameBirth, bAnyChanged)
gtblSettings.CitationNameMarriage, bAnyChanged = SettingUpdate(tglCitationNameMarriage.value, gtblSettings.CitationNameMarriage, bAnyChanged)
gtblSettings.CitationNameDeath, bAnyChanged = SettingUpdate(tglCitationNameDeath.value, gtblSettings.CitationNameDeath, bAnyChanged)
gtblSettings.CitationToMotherDefault, bAnyChanged = SettingUpdate(tglCitationToMotherDefault.value, gtblSettings.CitationToMotherDefault, bAnyChanged)
gtblSettings.NewMotherGivenName, bAnyChanged = SettingUpdate(txtNewMotherGivenName.value, gtblSettings.NewMotherGivenName, bAnyChanged)
gtblSettings.CitationEntryDate, bAnyChanged = SettingUpdate(listCitationEntryDate.value, gtblSettings.CitationEntryDate, bAnyChanged)
gtblSettings.CitationAssess, bAnyChanged = SettingUpdate(listCitationAssess.value, gtblSettings.CitationAssess, bAnyChanged)
-- Update Check
local Interval, NextCheckDate
if tglAutoCheck.value == 'OFF' then
Interval = 0
NextCheckDate = gtblSettings.VersionNextCheck
else
Interval = gtblConstants.VersionCheckFrequency[listCheckFrequency.value]
NextCheckDate = NextCheck(gtblSettings.VersionCheckedDate, Interval)
end
gtblSettings.VersionCheckInterval, bAnyChanged = SettingUpdate(Interval, gtblSettings.VersionCheckInterval, bAnyChanged)
gtblSettings.VersionNextCheck, bAnyChanged = SettingUpdate(NextCheckDate, gtblSettings.VersionNextCheck, bAnyChanged)
if bAnyChanged then
SaveSettings()
end
return iup.CLOSE
end
function SettingUpdate(NewValue, CurrSetting, bAnyChanged)
-- Force new settings to same types as current settings
local NewSetting
if type(CurrSetting) == 'boolean' then
NewSetting = false
if NewValue == 'ON' then
NewSetting = true
end
elseif type(CurrSetting) == 'number' then
if NewValue ~= '' then
NewSetting = tonumber(NewValue)
else
NewSetting = 0
end
else
NewSetting = NewValue
end
if NewSetting ~= CurrSetting then
return NewSetting, true
else
return CurrSetting, bAnyChanged
end
end
------------------------------------------------------------------------------------------------------------------------
local btnCancel = iup.button{
title = 'Cancel', padding = '10x3',
action = function(self) return iup.CLOSE end
}
local btnHelp = iup.button{
title = 'Help', padding = '10x3',
tipballoontitle = 'Settings', tip = 'Display Settings help page'
}
function btnHelp:action()
fhShellExecute('https://pluginstore.family-historian.co.uk/page/help/gro-bmd-index-citations-settings')
end
------------------------------------------------------------------------------------------------------------------------
dialogSettings = iup.dialog{
iup.vbox{
frameSources,
iup.tabs{vboxLabels, hboxOptions, hboxUpdateCheck; fontstyle = 'Bold'},
iup.hbox{
iup.fill{}, btnSave, btnHelp, btnCancel, iup.fill{};
normalizesize = 'BOTH', margin = '0x0', gap = 40
};
gap = 10, margin = '10x10'
};
resize = 'No', minbox = 'No', maxbox = 'No', helpbutton = 'Yes',
title = gPluginName .. ' - Settings',
defaultesc = btnCancel,
taskbarbutton = 'SHOW',
tipballoon = 'YES', tipdelay = 10000, tipballoontitleicon = '1'
}
iup.SetAttribute(dialogSettings, 'NATIVEPARENT', fhGetContextInfo('CI_PARENT_HWND'));
function SourceCheck(SourceId)
local SourceName, Templated = GetSource(tonumber(SourceId))
if Templated then
OkOnlyMessage(gPluginName, 'Templated sources are not currently supported', 'WARNING', dialogSettings)
return false, ''
end
if SourceName ~= '' then
return true, SourceName
else
OkOnlyMessage(gPluginName, 'Invalid Source Record Id', 'ERROR', dialogSettings)
return false, ''
end
end
------------------ Birth functions and call backs ------------------------------------------------------------------
function txtBirthSourceId:valuechanged_cb() -- Clear title if ID changed
txtBirthSourceId.bgcolor = gtblConstants.White
lblBirthSource.title = ''
end
function txtBirthSourceId:killfocus_cb()
if lblBirthSource.title == '' then
SetBirthTitle()
end
end
function txtBirthSourceId:k_any(c)
if c == iup.K_CR then
if lblBirthSource.title == '' then
SetBirthTitle()
end
end
end
function btnBirthSource:action()
local ptrlist = fhPromptUserForRecordSel('SOUR', 1, dialogSettings.HWND)
if #ptrlist ~= 0 then
txtBirthSourceId.value = fhGetRecordId(ptrlist[1])
txtBirthSourceId.bgcolor = gtblConstants.White
SetBirthTitle()
end
end
function SetBirthTitle()
if txtBirthSourceId.value == 0 or txtBirthSourceId.value == '' then
lblBirthSource.title = ''
return
end
local SrcValid
SrcValid, lblBirthSource.title = SourceCheck(txtBirthSourceId.value)
if not SrcValid then
txtBirthSourceId.bgcolor = gtblConstants.Yellow
end
end
------------------ Marriage functions and call backs ---------------------------------------------------------------
function txtMarriageSourceId:valuechanged_cb() -- Clear title if ID changed
txtMarriageSourceId.bgcolor = gtblConstants.White
lblMarriageSource.title = ''
end
function txtMarriageSourceId:killfocus_cb()
if lblMarriageSource.title == '' then
SetMarriageTitle()
end
end
function txtMarriageSourceId:k_any(c)
if c == iup.K_CR then
if lblMarriageSource.title == '' then
SetMarriageTitle()
end
end
end
function btnMarriageSource:action()
local ptrlist = fhPromptUserForRecordSel('SOUR', 1, dialogSettings.HWND)
if #ptrlist ~= 0 then
txtMarriageSourceId.value = fhGetRecordId(ptrlist[1])
txtMarriageSourceId.bgcolor = gtblConstants.White
SetMarriageTitle()
end
end
function SetMarriageTitle()
if txtMarriageSourceId.value == 0 or txtMarriageSourceId.value == '' then
lblMarriageSource.title = ''
return
end
local SrcValid
SrcValid, lblMarriageSource.title =SourceCheck(txtMarriageSourceId.value)
if not SrcValid then
txtMarriageSourceId.bgcolor = gtblConstants.Yellow
end
end
------------------ Death functions and call backs ------------------------------------------------------------------
function txtDeathSourceId:valuechanged_cb() -- Clear title if ID changed
txtDeathSourceId.bgcolor = gtblConstants.White
lblDeathSource.title = ''
end
function txtDeathSourceId:killfocus_cb()
if lblDeathSource.title == '' then
SetDeathTitle()
end
end
function txtDeathSourceId:k_any(c)
if c == iup.K_CR then
if lblDeathSource.title == '' then
SetDeathTitle()
end
end
end
function btnDeathSource:action()
local ptrlist = fhPromptUserForRecordSel('SOUR', 1, dialogSettings.HWND)
if #ptrlist ~= 0 then
txtDeathSourceId.value = fhGetRecordId(ptrlist[1])
txtDeathSourceId.bgcolor = gtblConstants.White
SetDeathTitle()
end
end
function SetDeathTitle()
if txtDeathSourceId.value == 0 or txtDeathSourceId.value == '' then
lblDeathSource.title = ''
return
end
local SrcValid
SrcValid, lblDeathSource.title = SourceCheck(txtDeathSourceId.value)
if not SrcValid then
txtDeathSourceId.bgcolor = gtblConstants.Yellow
end
end
--------------------------------------------------------------------------------------------------------------------
function tglIncNameInCitation:action()
if tglIncNameInCitation.value == 'OFF' then
if tglCitationNameBirth.value == 'ON'
or tglCitationNameMarriage.value == 'ON'
or tglCitationNameDeath.value == 'ON' then
local strMsg = 'Include Name(s) in Citation Text must be set to\n\n'
.. '"Always" or "Only if adding citation to name"\n\n'
.. 'if any Add Citation to Name option is on'
OkOnlyMessage(gPluginName, strMsg, 'WARNING',dialogSettings)
tglIncNameInCitation.value = 'ON'
end
end
SetlblIncNameState()
end
function ValidateCitationToName()
if tglIncNameInCitation.value == 'OFF' then
local strMsg = 'Not permitted if Include Name(s) in Citation Text\nis set to Never'
OkOnlyMessage(gPluginName, strMsg, 'ERROR', dialogSettings)
return false
end
return true
end
-- Equalise section label sizes in Citation Labels frame
dialogSettings:map()
local LabelSize = lblWWSLabels.size
local LabelWidth = tonumber(LabelSize:match('^(%d*)'))
LabelSize = lblTFSHeaders.size
if tonumber(LabelSize:match('^(%d*)')) > LabelWidth then
LabelWidth = tonumber(LabelSize:match('^(%d*)'))
end
LabelSize = lblTFSEventLabels.size
if tonumber(LabelSize:match('^(%d*)')) > LabelWidth then
LabelWidth = tonumber(LabelSize:match('^(%d*)'))
end
LabelSize = tostring(LabelWidth) .. 'x0'
lblWWSLabels.size = LabelSize
lblTFSHeaders.size = LabelSize
lblTFSEventLabels.size = LabelSize
dialogSettings:popup(IUP_CENTERPARENT, IUP_CENTERPARENT)
dialogSettings:destroy()
end -- function config
function GetSource(Id) -- Check source exists, returns empty string if not found
-- if found returns name and true/false if templated or not
local ptrSource = fhNewItemPtr()
local ptrTemplate = fhNewItemPtr()
ptrSource:MoveToRecordById('SOUR',Id)
if ptrSource:IsNull() then
return '', false
else
ptrTemplate = fhGetItemPtr(ptrSource, '~._SRCT>')
if ptrTemplate:IsNotNull() then
return fhGetDisplayText(ptrSource), true
else
return fhGetDisplayText(ptrSource), false
end
end
end -- fuction GetSource
--======================================================================================================================
--==== Main Dialog used for Births, Marriages and Deaths ====
--======================================================================================================================
function MainDialog(Event, arrInd1, arrInd2, arrFam, intFirstYear, intLastYear)
-- arrInd2 and arrFam are nil for birth and death
-- arrInd2 will be blank if family only has one individual
local arrActions = {}
local strTitle = 'GRO Index ' .. Event .. ' Citation'
local strHeader = 'Citation for ' .. Event .. ' of ' .. arrInd1['DispNameFull']
if Event == 'Marriage' then
strHeader = strHeader .. '\nand '
if arrInd2 ~= nil then
strHeader = strHeader .. arrInd2['DispNameFull']
else
strHeader = strHeader .. '<>'
end
end
local vboxFormHead = iup.vbox{
iup.label{title = strHeader, fontstyle = 'Bold', padding = '0x0', alignment = 'ACENTER', multiline = 'YES'},
alignment = 'ACENTER', normalizesize = 'horizontal', expandchildren = 'YES'
}
------------------------ Registration details panel --------------------
-- Make array of years for listbox
local addrange = 3 -- Number of years to extend range if very narrow
local ExactYear = nil
if intFirstYear == intLastYear then
ExactYear = intFirstYear
end
if intLastYear - intFirstYear < addrange * 2 + 1 then
intFirstYear = math.max(intFirstYear - addrange, 1837)
intLastYear = math.min(intLastYear + addrange, gtblConstants.CurrYear)
end
local arrYears = {}
for Yr = intFirstYear, intLastYear do
table.insert(arrYears, Yr)
end
local listYear = iup.list{dropdown = 'YES'; editbox = 'YES', visibleitems = 10, visiblecolumns = 3}
PopulateList(listYear, arrYears)
if ExactYear ~= nil then
listYear.value = ExactYear
end
local listQtrMonth = iup.list{ dropdown = 'YES', visibleitems = 10, visiblecolumns = 8, bgcolor = gtblConstants.White}
PopulateList(listQtrMonth, gtblConstants.PeriodsLong)
local hboxWhen = iup.hbox{
iup.label{title = 'Year:', size = '35x0', padding = '2x0'}, listYear, iup.fill{},
iup.label{title = 'Quarter or Month:'}, listQtrMonth, iup.fill{}, iup.fill{};
gap = 4, margin = '0x0', alignment = 'ACENTER'
}
local listDistrictName = iup.list{dropdown = 'YES', visibleitems = 15, expand = 'HORIZONTAL'}
if not gtblSettings.UseGRODistricts then
listDistrictName.editbox = 'YES'
for i,v in pairs(tblPlaces) do
listDistrictName[tostring(i)] = v[1]
end
else
listDistrictName.editbox = 'NO'
PopulateListFromtblGROPlaces(listDistrictName)
end
local strDistrictNameFilter = ''
local hboxDistrictName = iup.hbox{
iup.label{title='District:', size = '35x0', padding = '2x0'}, listDistrictName;
alignment = 'ACENTER'
}
local btnGRODistricts = iup.button{title = 'Add/Edit', padding = '4x1'}
if gtblSettings.UseGRODistricts then
hboxDistrictName:append(btnGRODistricts)
end
local txtVolume = iup.text {visiblecolumns = 4}
local vboxVolume = iup.vbox{iup.label{title = 'Volume'}, txtVolume; alignment = 'ACENTER', gap = 2}
local txtPage = iup.text {visiblecolumns = 4}
local vboxPage = iup.vbox{iup.label{title = 'Page'}, txtPage; alignment = 'ACENTER', gap = 2}
local txtDistNo = iup.text {visiblecolumns = 4}
local vboxDistNo = iup.vbox{iup.label{title = 'District No.'}, txtDistNo; alignment = 'ACENTER', gap = 2}
local txtRegister = iup.text {visiblecolumns = 4}
local vboxRegister = iup.vbox{iup.label{title = 'Register No.'}, txtRegister; alignment = 'ACENTER', gap = 2}
local txtEntry = iup.text {visiblecolumns = 6, filter = 'NUMBER'}
local vboxEntry = iup.vbox{iup.label{title = 'Entry No.'}, txtEntry; alignment = 'ACENTER', gap = 2}
local hboxRefs = iup.hbox{iup.label{size = '21x0'},vboxVolume, vboxPage, vboxDistNo, vboxRegister, vboxEntry;
gap = 25, margin = '0x0', padding = '0x0'}
local txtCitationNote = iup.text{expand = 'HORIZONTAL'}
local hboxCitationNote = iup.hbox{
iup.label{title = 'Citation Specific Note: ', padding = '2x0'}, txtCitationNote;
alignment = 'ACENTER'
}
local frameRegistration = iup.frame{
iup.hbox{
iup.frame{
iup.vbox{
hboxWhen, hboxDistrictName, hboxRefs, hboxCitationNote;
gap = 2, margin = '2x4', fontstyle= ''
},
sunken = 'YES'
},
padding = '5x0'
},
title='Registration Details', fontstyle= 'Bold'
}
--------- Event specific details - Birth (mother), Death (age/DOB) ---------
local txtMother = iup.text{
size = '115x0', padding = '0x0',
tipballoontitle = 'Mother\'s Maiden Name',
tip = "Ctrl ' (single quote) to copy '" .. arrInd1['Mother'] .. "'"}
local tglCitationToMother = iup.toggle{
title = 'Add Citation to Mother\'s Name:', value = ToggleValue(gtblSettings.CitationToMotherDefault), rightbutton = 'YES'
}
local txtAge = iup.text{visiblecolumns = 3, padding = '0x0', filter = 'NUMBER'}
local txtDOB = iup.text{visiblecolumns = 10, padding = '0x0'}
local boxEvent
if Event == 'Birth' then
boxEvent = iup.vbox{
iup.hbox{
iup.label{title = 'Mother\'s Maiden Name:'; padding = '0x0'}, txtMother,
iup.label{title = '(Ctrl \' to copy Mother\'s name) ', fontstyle = 'Italic'}; iup.fill{};
gap = 4, margin = '0x0', alignment='ACENTER'
},
iup.hbox{
tglCitationToMother, iup.fill{};
margin = '0x0'
};
margin = '4x2'
}
elseif Event == 'Death' then
boxEvent = iup.hbox{
iup.label{title = 'Age:', size = '35x0'}, txtAge, iup.fill{},
iup.label{title = 'Date of Birth or birth year:', size = '0x0'}, txtDOB,
iup.fill{},iup.fill{};
gap = 4, margin = '0x4', alignment = 'ACENTER'
}
end
local frameEvent
if Event ~= 'Marriage' then
frameEvent = iup.frame{
iup.hbox{
iup.frame{
boxEvent;
sunken = 'YES'
},
padding = '5x0', fontstyle = ''
},
title = Event, fontstyle = 'Bold'
}
end
function ValidateDate(strDate, PartDate) -- Returns true/false, date formated to FH preferred short date format
-- and a date object if valid
local dtDate = fhNewDate()
if not dtDate:SetValueAsText(strDate, false) then
return false
end
local strType = dtDate:GetType()
if strType ~= 'Simple' then
return false
end
local dpDatePt = dtDate:GetDatePt1()
local Day = dpDatePt:GetDay()
local Month = dpDatePt:GetMonth()
local Year = dpDatePt:GetYear()
if Year < 1730 then -- Earliest DOB of a death in 1837 is ~100 years before
return false
end
local FmtDate = dtDate:GetDisplayText('COMPACT')
if PartDate and Day == 0 then
return true, FmtDate, dtDate
end
if Day == 0 or Month == 0 or Month > 12 then
return false
end
local DaysInMonth = {31,29,31,30,31,30,31,31,30,31,30,31}
if Day > DaysInMonth[Month] then
return false
end
if Month ==2 and Day == 29 then
if Year%4 ~= 0 then
return false
end
if Year%100 == 0 and Year%400 ~=0 then
return false
end
end
return true, FmtDate, dtDate
end
------------------------ Name(s) for citation panel ------------------------
local titleFrame = 'Name'
local CitationToNameDefault
if Event == 'Birth' then
CitationToNameDefault = gtblSettings.CitationNameBirth
elseif Event == 'Marriage' then
CitationToNameDefault = gtblSettings.CitationNameMarriage
else
CitationToNameDefault = gtblSettings.CitationNameDeath
end
local tglCitationToNames = iup.toggle{
title = 'Add Citation to Name:', value = ToggleValue(CitationToNameDefault), rightbutton = 'YES'
}
local tglIncNameInCitation = iup.toggle{
title ='Include Name in Citation:', margin = '0x0', rightbutton = 'YES', ['3state'] = 'YES',
value = gtblSettings.IncNameInCitation
}
local lblIncNameState = iup.label{title = ' ', expand = 'HORIZONTAL'}
function SurnameToCopy() -- Get surname for first individual to be used if Ctrl ' keyed
-- For death of a wife it will be her married name
if Event ~= 'Death' then
return arrInd1['Surname']
else
local ptrField = fhNewItemPtr()
ptrField:MoveTo(arrInd1.Ptr, '~.SEX')
if fhGetValueAsText(ptrField) ~= 'Female' then
return arrInd1['Surname']
else
ptrField:MoveTo(arrInd1.Ptr, 'INDI.~SPOU[LAST]>')
if ptrField:IsNull() then
return arrInd1['Surname']
else
return fhu.getSurname(fhGetItemText(ptrField, '~.NAME:STORED'))
end
end
end
end
local txtGiven = iup.text{size = '150x0', tip = "Ctrl ' (single quote) to copy '" .. arrInd1['GivenName'] .. "'"}
local txtSurname = iup.text{size = '115x0', tip = "Ctrl ' (single quote) to copy '" .. SurnameToCopy() .. "'"}
local txtGiven2 = iup.text{size = '150x0'}
local txtSurname2 = iup.text{size = '115x0'}
local lblRow = 'Citation Name'
local hboxNameLabels = iup.hbox{
iup.label{title = 'Given', size = '150x0', padding = '4x0'},
iup.label{title = 'Surname', size = '0x0', padding = '4x0'};
gap = 2, margin = '0x0'
}
local hboxCitationName1 = iup.hbox{txtGiven, txtSurname; gap = 2, margin = '0x1'}
local hboxCitationName2 = iup.hbox{txtGiven2, txtSurname2; gap = 2, margin = '0x3'}
local vboxCitationNames = iup.vbox{
hboxNameLabels, hboxCitationName1;
gap = 0, padding = '2x0',
tipballoontitle = 'Citation names'
}
if arrInd2 ~= nil then
lblRow = lblRow .. '(s)'
tglIncNameInCitation.title = tglIncNameInCitation.title:gsub('Name','Name(s)')
tglCitationToNames.title = tglCitationToNames.title:gsub('Name','Name(s)')
titleFrame = titleFrame .. '(s)'
txtGiven2.tip = "Ctrl ' (single quote) to copy '" .. arrInd2['GivenName'] .. "'"
txtSurname2.tip = "Ctrl ' (single quote) to copy '" .. arrInd1['Surname'] .. "'"
iup.Append(vboxCitationNames, hboxCitationName2)
end
local function SetlblIncNameState()
local strState
if tglIncNameInCitation.value == 'ON' then
strState = 'Yes'
elseif tglIncNameInCitation.value == 'OFF' then
strState = 'No'
else
strState = 'Only if adding citation to name'
end
lblIncNameState.title = strState
end
SetlblIncNameState()
local frameNames = iup.frame{
iup.hbox{
iup.frame {
iup.vbox{
iup.hbox{tglCitationToNames, iup.space{size = '12x0'}, tglIncNameInCitation, lblIncNameState;
gap = 4, margin = '0x0'},
iup.hbox{
iup.vbox{
iup.flatlabel{title = lblRow},
iup.label{title = '(Ctrl \' to copy\nexisting name) ', fontstyle = 'Italic'};
gap = 0, margin = '0x0'
},
iup.fill{}, vboxCitationNames; --vboxGiven, vboxSurname;
gap = 4, alignment = 'ACENTER', margin = '0x0'
};
--tglCitationToNames;
gap = 4, alignment = 'ALEFT', margin = '4x2',
padding = '0x0' -- Set for inheritance
},
sunken = 'YES'
};
padding = '5x2', fontstyle = ''
},
title = titleFrame, fontstyle = 'Bold'
}
----------------------- Citation text preview panel ------------------------
local lblWhereWithin = iup.flatlabel{
title = ' ', size = '350x18', fgcolor = gtblConstants.Blue, padding = '2x0',
textwrap = 'YES', alignment = 'ALEFT:ATOP', border = 'YES'
}
local vboxWhereWithin = iup.vbox{
iup.label{title = 'Where Within', padding = '2x0'}, lblWhereWithin;
gap = '0', margin = '0x0'
}
local lblTextFromSource = iup.flatlabel{
title = ' ', size = '350x18', fgcolor = gtblConstants.Blue, padding = '2x0',
textwrap = 'YES', alignment = 'ALEFT:ATOP', border = 'YES'
}
local vboxTextFromSource = iup.vbox{
iup.label{title = 'Text from Source', padding = '2x0'}, lblTextFromSource;
gap = '0', margin = '0x0'
}
local listCitationAssess = iup.list{
dropdown = 'YES', size = '95x0', visibleitems = 6}
PopulateList(listCitationAssess, gtblConstants.CitationAssess)
listCitationAssess.value = gtblSettings.CitationAssess
local hboxCitationAssess = iup.hbox{
iup.label{title ='Citation Assessment: ', padding = '2x0'}, listCitationAssess;
margin = '0x0', alignment = 'ACENTER'}
local framePreview = iup.frame{
iup.hbox{
iup.frame{
iup.vbox{
vboxWhereWithin, vboxTextFromSource,
hboxCitationAssess;
gap = 6, margin = '4x2'
},
sunken = 'YES'
},
padding = '5x2', fontstyle = ''
},
title = 'Citation', fontstyle = 'Bold'
}
------------------------------ Footer buttons ------------------------------
local btnContinue = iup.button{
title = 'Continue', padding = '10x0'
}
local btnCancel = iup.button{
title = 'Cancel', padding = '10x3',
action = function(self) return iup.CLOSE end
}
local hboxFooter = iup.hbox{
iup.fill{}, btnContinue, btnCancel, iup.fill{};
normalizesize = 'BOTH', margin = '0x5', gap = 40
};
---------------------- Assemble and display the dialog ---------------------
local vboxMain = iup.vbox{
vboxFormHead,
frameRegistration,
frameNames,
frameEvent,
framePreview,
hboxFooter;
gap = 5, margin = '10x5', alighment = 'ACENTER'
};
local dialogMain = iup.dialog{
vboxMain;
resize = 'No', minbox = 'No', maxbox = 'No',
title = 'GRO Index ' .. Event .. ' Citation',
defaultesc = btnCancel,
taskbarbutton = 'SHOW',
tipballoon = 'YES', tipdelay = 10000, tipballoontitleicon = '1'
}
iup.SetAttribute(dialogMain, 'NATIVEPARENT', fhGetContextInfo('CI_PARENT_HWND'))
--------------------------------------------------------------------------------------------------------------------
function FormatName(Given, Surname) -- 1 = Surname, Given 3 = Given Surname
if gtblSettings.NameFormat%2 == 0 then -- 2 = SURNAME, Given 4 = Given SURNAME
Surname = Surname:upper()
end
if not Given then
return Surname
end
if gtblSettings.NameFormat < 3 then
return Surname .. ', ' .. Given
else
return Given .. ' ' .. Surname
end
end
--------------------------------------------------------------------------------------------------------------------
function WhereWithin()
local WhereWithin = ''
if Event == 'Birth' then
WhereWithin = gtblSettings.LabelPrefixBirth
elseif Event == 'Marriage' then
WhereWithin = gtblSettings.LabelPrefixMarriage
else
WhereWithin = gtblSettings.LabelPrefixDeath
end
WhereWithin = WhereWithin .. listYear.value
local intSel = tonumber(listQtrMonth.value)
if intSel ~= 0 then
if gtblSettings.QtrMonthNames then
WhereWithin = WhereWithin .. ' ' .. gtblConstants.PeriodsLong[intSel]
else
WhereWithin = WhereWithin .. ' ' .. gtblConstants.Periods[intSel]
end
end
if listDistrictName.value ~= '' then
local strDistrict
if not gtblSettings.UseGRODistricts then
strDistrict = listDistrictName.value
else
if listDistrictName.value ~= '0' then
strDistrict = listDistrictName.valuestring:match('^(.*)%s%[') or listDistrictName.valuestring
else
strDistrict = ''
end
end
if gtblSettings.ShortPlaces then
local strValue = strDistrict
strValue = strValue:match('^([^,]+)')
if strValue ~= null then
WhereWithin = WhereWithin .. ' ' .. LabelData(gtblSettings.LabelDistrictName, strValue)
end
else
WhereWithin = WhereWithin .. ' ' .. LabelData(gtblSettings.LabelDistrictName, strDistrict)
end
end
if txtVolume.value ~= '' then
WhereWithin = WhereWithinRefs(WhereWithin, LabelData(gtblSettings.LabelVolume, txtVolume.value))
end
if txtPage.value ~= '' then
WhereWithin = WhereWithinRefs(WhereWithin , LabelData(gtblSettings.LabelPage, txtPage.value))
end
if txtDistNo.value ~= '' then
WhereWithin = WhereWithinRefs(WhereWithin, LabelData(gtblSettings.LabelDistrictNo, txtDistNo.value))
end
if txtRegister.value ~= '' then
WhereWithin = WhereWithinRefs(WhereWithin, LabelData(gtblSettings.LabelRegister, txtRegister.value))
end
if txtEntry.value ~= '' then
WhereWithin = WhereWithinRefs(WhereWithin, LabelData(gtblSettings.LabelEntry, txtEntry.value))
end
WhereWithin = WhereWithin:gsub('%^',' ')
return WhereWithin
end -- function WhereWithin
function WhereWithinRefs(strWW, strLabelledData)
if strLabelledData:find('^[-/]') then
return strWW .. strLabelledData -- No space before label beginning with - or /
else
return strWW .. ' ' .. strLabelledData
end
end
function WhereWithinUpdate()
lblWhereWithin.title = WhereWithin():gsub('&', '&&')
end
--------------------------------------------------------------------------------------------------------------------
function TextFromSrc()
local TextFromSrc = ''
if tglIncNameInCitation.value == 'ON' or tglCitationToNames.value == 'ON' then
TextFromSrc = TextFromSrc .. ' ' .. FormatName(txtGiven.value, txtSurname.value)
if Event == 'Marriage' then
if arrInd2 ~= nil then
TextFromSrc = TextFromSrc .. ', ' .. FormatName(txtGiven2.value, txtSurname2.value)
else
TextFromSrc = TextFromSrc .. ', '
end
end
end
if Event == 'Birth' and txtMother.value ~= '' then
TextFromSrc = TextFromSrc .. ' ' .. LabelData(gtblSettings.LabelMother, FormatName(nil, txtMother.value))
end
if Event == 'Death' then
if txtAge.value ~= '' then
TextFromSrc = TextFromSrc .. ' ' .. LabelData(gtblSettings.LabelAge, txtAge.value)
end
if txtDOB.value ~= '' and txtDOB.bgcolor ~= gtblConstants.Red then -- Don't add if not valid
TextFromSrc = TextFromSrc .. ' ' .. LabelData(gtblSettings.LabelDOB, txtDOB.value)
end
end
TextFromSrc = TextFromSrc:sub(2) -- drop leading space
TextFromSrc = TextFromSrc:gsub('%^',' ')
return TextFromSrc
end -- function TextFromSrc
function TextFromSrcUpdate()
lblTextFromSource.title = TextFromSrc():gsub('&','&&')
end
--------------------------------------------------------------------------------------------------------------------
function LabelData(Label, Data) -- Combine label and data
if Label:find('%$') then
return Label:gsub('%$', Data)
else
return Label .. Data
end
end
--------------------------------------------------------------------------------------------------------------------
function listYear:valuechanged_cb()
listYear.bgcolor = gtblConstants.White
WhereWithinUpdate()
end
function listYear:killfocus_cb()
if listYear.bgcolor == gtblConstants.Red then
return
end
if listYear.value ~= '' then
if listYear.value:find("%D")
or tonumber(listYear.value) < 1837
or tonumber(listYear.value) > gtblConstants.CurrYear then
OkOnlyMessage(strTitle, 'Invalid Year (must be between 1837 and ' .. gtblConstants.CurrYear .. ')',
'ERROR', dialogMain)
listYear.bgcolor = gtblConstants.Red
end
if gtblSettings.UseGRODistricts and not GRODistrictYear() then
OkOnlyMessage(strTitle, 'GRO District was not active in ' .. listYear.value, 'WARNING', dialogMain)
end
end
end
function listYear:k_any()
listYear.bgcolor = gtblConstants.White
end
function listQtrMonth:valuechanged_cb()
WhereWithinUpdate()
end
function listQtrMonth:k_any(v)
if iup.isprint(v) then
local k = string.char(v)
if k >= '1' and k <= '4' then
listQtrMonth.value = tonumber(k)
end
end
end
function listDistrictName:valuechanged_cb()
WhereWithinUpdate()
end
function listDistrictName:killfocus_cb()
if gtblSettings.UseGRODistricts and not GRODistrictYear() then
OkOnlyMessage(strTitle, 'GRO District was not active in ' .. listYear.value, 'WARNING', dialogMain)
end
end
function listDistrictName:k_any(k)
if gtblSettings.UseGRODistricts then
if iup.isprint(k) then
-- List will be on first entry with that starting letter
strDistrictNameFilter = strDistrictNameFilter .. string.char(k):upper()
if #strDistrictNameFilter > 1 then
local i = tonumber(listDistrictName.value) -- Must be forward from current line
local InList = false
while i <= tonumber(listDistrictName.count) do
if listDistrictName[tostring(i)]:upper():find('^' .. strDistrictNameFilter) then
iup.Flush()
listDistrictName.value = i
WhereWithinUpdate()
InList = true
break
elseif listDistrictName[tostring(i)]:upper() > strDistrictNameFilter then
break
end
i = i + 1
end
if not InList then
strDistrictNameFilter = string.char(k):upper() -- List will be on first entry with that starting letter
end
else
iup.Flush()
if listDistrictName.value == '0' then
strDistrictNameFilter = '' -- No districts matching initial letter keyed
end
end
end
if k == iup.K_BS then
iup.Flush()
if #strDistrictNameFilter <= 1 then
listDistrictName.value = 0
WhereWithinUpdate()
strDistrictNameFilter = ''
else
strDistrictNameFilter = strDistrictNameFilter:sub(1, -2)
local i = 1
while i <= tonumber(listDistrictName.count) do
if listDistrictName[tostring(i)]:upper():find('^' .. strDistrictNameFilter) then
listDistrictName.value = i
InList = true
break
elseif listDistrictName[tostring(i)]:upper() > strDistrictNameFilter then
break
end
i = i + 1
end
if not InList then
listDistrictName.value = 0
end
WhereWithinUpdate()
end
end
end
end
function btnGRODistricts:action()
SelectedGRODistrict = GRODistricts(dialogMain)
PopulateListFromtblGROPlaces(listDistrictName) -- Refresh in case change made
listDistrictName.value = SelectedGRODistrict
end
function RefToUpper(txtField)
if gtblSettings.UCRefs then
if txtField.value ~= txtField.value:upper() then
local pos = txtField.caret
txtField.value = txtField.value:upper()
txtField.caret = pos
end
end
end
function txtVolume:valuechanged_cb()
RefToUpper(txtVolume)
WhereWithinUpdate()
end
function txtVolume:k_any(c)
if c == iup.XkeyCtrl(iup.K_TAB) then
iup.SetFocus(txtGiven)
end
end
function txtPage:valuechanged_cb()
RefToUpper(txtPage)
WhereWithinUpdate()
end
function txtPage:k_any(c)
if c == iup.XkeyCtrl(iup.K_TAB) then
iup.SetFocus(txtGiven)
end
end
function txtDistNo:valuechanged_cb()
RefToUpper(txtDistNo)
WhereWithinUpdate()
end
function txtDistNo:k_any(c)
if c == iup.XkeyCtrl(iup.K_TAB) then
iup.SetFocus(txtGiven)
end
end
function txtRegister:valuechanged_cb()
RefToUpper(txtRegister)
WhereWithinUpdate()
end
function txtRegister:k_any(c)
if c == iup.XkeyCtrl(iup.K_TAB) then
iup.SetFocus(txtGiven)
end
end
function txtEntry:valuechanged_cb()
WhereWithinUpdate()
end
function txtEntry:k_any(c)
if c == iup.XkeyCtrl(iup.K_TAB) then
iup.SetFocus(txtGiven)
end
end
function txtMother:k_any(c)
if c == iup.XkeyCtrl(iup.K_apostrophe) then
txtMother.value = arrInd1['Mother']
txtMother.bgcolor = gtblConstants.White
txtMother.CaretPos = #arrInd1['Mother']
TextFromSrcUpdate()
end
end
function txtMother:valuechanged_cb()
txtMother.bgcolor = gtblConstants.White
TextFromSrcUpdate()
end
function txtAge:valuechanged_cb()
TextFromSrcUpdate()
end
function GRODistrictYear() -- If GRO has years active check if year is in range
if listYear.value ~= '' and listDistrictName.value ~= '0' then
local strYears = tblGROPlaces[tonumber(listDistrictName.value)][2]
if strYears == '' then
return true -- No years specified - anything goes
end
local P = '(%d*%-?%d*)' -- Pattern for matching yyyy-yyyy, second only or both can be blank
local tblFromTo = {strYears:match(P .. ',?' .. P .. ',?' .. P .. ',?' .. P)}
for i,v in pairs(tblFromTo) do
From, To = v:match('(%d*)%-(%d*)')
if From == nil or tonumber(listYear.value) < tonumber(From) then
return false
end
if To == '' then
return true -- Open ended range
end
if tonumber(listYear.value) <= tonumber(To) then
return true
end
end
return false
end
return true
end
function ValidateDOB()
if txtDOB.bgcolor ~= gtblConstants.White then
return
end
if txtDOB.value == '' then
txtDOB.bgcolor = gtblConstants.White
TextFromSrcUpdate()
return
end
local DateValid, Formatted, dtDate = ValidateDate(txtDOB.value, true) -- true to allow year or month/year only
if not DateValid then
txtDOB.bgcolor = gtblConstants.Red
OkOnlyMessage(strTitle, 'Invalid Date of Birth', 'ERROR', dialogMain)
return
end
local DOBYear = dtDate:GetDatePt1():GetYear()
if DOBYear < arrInd1.EarliestBirth or DOBYear > arrInd1.LatestBirth then
txtDOB.bgcolor = gtblConstants.PaleYellow
OkOnlyMessage(strTitle, 'Date outside of expected range', 'WARNING', dialogMain)
end
txtDOB.value = Formatted
TextFromSrcUpdate()
end
function txtDOB:k_any(c)
if c == iup.K_CR then
ValidateDOB()
txtDOB.caretpos = #txtDOB.value
return IUP_CONTINUE
end
if c ~= iup.K_TAB then
txtDOB.bgcolor = gtblConstants.White
return IUP_CONTINUE
else
if txtDOB.bgcolor == gtblConstants.White then
ValidateDOB()
if txtDOB.bgcolor == gtblConstants.Red then
iup.SetFocus(txtDOB)
return
end
end
return IUP_CONTINUE
end
end
function txtDOB:killfocus_cb()
if txtDOB.bgcolor ~= gtblConstants.White then
return
end
ValidateDOB()
end
function txtDOB:getfocus_cb()
txtDOB.caretpos = #txtDOB.value
end
function tglIncNameInCitation:action()
if tglIncNameInCitation.value == 'OFF' and tglCitationToNames.value == 'ON' then
local strMsg = 'Include Name(s) in Citation Text must be set to\n'
.. '"Always" or "Only if adding citation to name"\n'
.. 'if Add Citation to Name option is on'
OkOnlyMessage(strTitle, strMsg, 'ERROR', dialogMain)
tglIncNameInCitation.value = 'ON'
end
SetlblIncNameState()
TextFromSrcUpdate()
end
function tglCitationToNames:action()
if tglCitationToNames.value == 'ON' and tglIncNameInCitation.value == 'OFF' then
local strMsg = 'Requires Include Name(s) in Citation Text\nnot to be set to "No"'
OkOnlyMessage(strTitle, strMsg, 'ERROR', dialogMain)
tglCitationToNames.value = 'OFF'
end
TextFromSrcUpdate()
end
function txtGiven:k_any(c)
if c == iup.XkeyCtrl(iup.K_apostrophe) then
txtGiven.value = arrInd1['GivenName']
txtGiven.bgcolor = gtblConstants.White
txtGiven.CaretPos = #arrInd1['GivenName']
TextFromSrcUpdate()
end
end
function txtGiven:valuechanged_cb()
txtGiven.bgcolor = gtblConstants.White
TextFromSrcUpdate()
end
function txtSurname:k_any(c)
if c == iup.XkeyCtrl(iup.K_apostrophe) then
txtSurname.value = SurnameToCopy()
txtSurname.bgcolor = gtblConstants.White
txtSurname.CaretPos = #txtSurname.value
TextFromSrcUpdate()
end
end
function txtSurname:valuechanged_cb()
txtSurname.bgcolor = gtblConstants.White
TextFromSrcUpdate()
end
function txtGiven2:k_any(c)
if c == iup.XkeyCtrl(iup.K_apostrophe) then
txtGiven2.value = arrInd2['GivenName']
txtGiven2.bgcolor = gtblConstants.White
txtGiven2.CaretPos = #arrInd2['GivenName']
TextFromSrcUpdate()
end
end
function txtGiven2:valuechanged_cb()
if arrInd2 ~= nil then
txtGiven2.bgcolor = gtblConstants.White
TextFromSrcUpdate()
end
end
function txtSurname2:k_any(c)
if c == iup.XkeyCtrl(iup.K_apostrophe) then
txtSurname2.value = arrInd2['Surname']
txtSurname2.bgcolor = gtblConstants.White
txtSurname2.CaretPos = #arrInd2['Surname']
TextFromSrcUpdate()
end
end
function txtSurname2:valuechanged_cb()
if arrInd2 ~= nil then
txtSurname2.bgcolor = gtblConstants.White
TextFromSrcUpdate()
end
end
----------------------------------- Validate data and if OK create citations etc. ----------------------------------
function btnContinue:action()
-- Validate input
if listYear.value == '' or listYear.bgcolor == gtblConstants.Red then
OkOnlyMessage(strTitle, 'Year not selected', 'WARNING', dialogMain)
return
end
if listQtrMonth.value == '0' then
OkOnlyMessage(strTitle, 'Quarter/Month not selected', 'WARNING', dialogMain)
return
end
if listDistrictName.value == '' or listDistrictName.value == '0' then
OkOnlyMessage(strTitle, 'District not entered/selected', 'WARNING', dialogMain)
return
end
if gtblSettings.UseGRODistricts and not GRODistrictYear() then
OkOnlyMessage(strTitle, 'GRO District was not active in ' .. listYear.value, 'ERROR', dialogMain)
return
end
-- Count completed reference fields - there should be at least two
local intCount = 0
if txtVolume.value ~= '' then
intCount = intCount + 1
end
if txtPage.value ~= '' then
intCount = intCount + 1
end
if txtDistNo.value ~= '' then
intCount = intCount + 1
end
if txtRegister.value ~= '' then
intCount = intCount + 1
end
if txtEntry.value ~= '' then
intCount = intCount + 1
end
if intCount < 2 then
OkOnlyMessage(strTitle, 'GRO Reference details incomplete', 'WARNING', dialogMain)
return
end
-- Birth: if mothers name is to be given citation it must be entered
if Event == 'Birth' then
if tglCitationToMother.value == 'ON' and txtMother.value == '' then
txtMother.bgcolor = gtblConstants.Yellow
OkOnlyMessage(strTitle, 'Mother\'s name required if being given citation', 'WARNING', dialogMain)
return
end
end
-- Death requires age or date of birth but not both
if Event == 'Death' then
if txtAge.value == '' then
if txtDOB.value == '' then
local strMessage = 'Neither Age nor Date of Birth entered\n\nContinue?\n\n'
.. '(Tip: Age or Date of Birth can usually be found at '
.. 'https://www.gro.gov.uk/gro/content/certificates/login.asp)'
if MessageBox(gPluginName, strMessage, 'OKCANCEL', 'WARNING', 2, dialogMain) == 2 then
return
end
elseif txtDOB.bgcolor == gtblConstants.Red then
OkOnlyMessage(strTitle, 'Date of Birth invalid', 'WARNING', dialogMain)
return
end
elseif txtDOB.value ~= '' then
OkOnlyMessage(strTitle, 'Enter either Age or Date of Birth (not both)', 'WARNING', dialogMain)
return
end
end
if tglIncNameInCitation.value == 'ON' or tglCitationToNames.value == 'ON' then
local BlankName = false
if txtGiven.value == '' or txtSurname.value == '' then
BlankName = true
elseif arrInd2 ~= nil and txtGiven2.value == '' or txtSurname2.value =='' then
BlankName = true
end
if BlankName then -- At least one missing - flag all empty
if txtGiven.value == '' then
txtGiven.bgcolor = gtblConstants.Yellow
end
if txtSurname.value == '' then
txtSurname.bgcolor = gtblConstants.Yellow
end
if arrInd2 ~= nil then
if txtGiven2.value == '' then
txtGiven2.bgcolor = gtblConstants.Yellow
end
if txtSurname2.value == '' then
txtSurname2.bgcolor = gtblConstants.Yellow
end
end
OkOnlyMessage(strTitle, 'Names required for inclusion in citation', 'WARNING', dialogMain)
return
end
end
-- Determine actions to be taken
local strEvent = ''
local ptrRecord = fhNewItemPtr()
if Event == 'Birth' then
strEvent = 'BIRT'
ptrRecord = arrInd1.Ptr
elseif Event == 'Marriage' then
strEvent = 'MARR'
ptrRecord = arrFam.Ptr
else
strEvent = 'DEAT'
ptrRecord = arrInd1.Ptr
end
local EventDate = gtblConstants.Periods[tonumber(listQtrMonth.value)] .. ' ' .. listYear.value
local dteEventDate = fhNewDate()
dteEventDate:SetValueAsText(EventDate)
arrActions.ptrRecord = ptrRecord
arrActions.strEvent = strEvent
arrActions.dteEventDate = dteEventDate
if not gtblSettings.UseGRODistricts then
arrActions.txtEventPlace = listDistrictName.value
else
arrActions.txtEventPlace = listDistrictName.valuestring:match('^(.*)%s%[') or listDistrictName.valuestring
end
local bContinue
bContinue, arrActions.Event, arrActions.EventDate, arrActions.EventPlace
= CompareEvent(ptrRecord, Event, strEvent, EventDate, arrActions.txtEventPlace, dialogMain)
if not bContinue then
return -- User cancelled
end
function CompareName(ExistingName, EnteredGiven, EnteredSurname)
-- Compares names and offers to update. Does not offer if entered is shorter because it has initials
-- that match instead of given names
local ExistingGiven, ExistingSurname, EnteredFullName
if ExistingName:sub(-1) == '/' then
ExistingGiven = ExistingName:match('^[^/]*')
ExistingSurname = ExistingName:match('%b//'):gsub('/','')
EnteredFullName = EnteredGiven .. ' /' .. EnteredSurname .. '/'
elseif ExistingName:sub(1, 1) == '/' then
ExistingGiven = ExistingName:match('[^/]*$')
ExistingSurname = ExistingName:match('%b//'):gsub('/','')
EnteredFullName = '/' .. EnteredSurname .. '/ ' .. EnteredGiven
else -- Indeterminate name structure, can't do update
return true, false -- Continue, don't update
end
ExistingGiven = ExistingGiven:match('^%s*(.-)%s*$') -- Remove leading/trailing spaces
if ExistingName == EnteredFullName then
return true, false -- Continue, don't update
end
local bOfferUpdate = false
if EnteredSurname == ExistingSurname then
local ExistingGivenNames = {}
local EnteredGivenNames = {}
for str in ExistingGiven:gmatch("([^ ]+)") do
table.insert(ExistingGivenNames, str)
end
for str in EnteredGiven:gmatch("([^ ]+)") do
table.insert(EnteredGivenNames, str)
end
if #ExistingGivenNames > #EnteredGivenNames then -- fewer given names entered so don't offer to update
return true, false -- Continue, don't update
else
local i = 0
while i < #ExistingGivenNames do
i = i + 1
if ExistingGivenNames[i] ~= EnteredGivenNames[i]
and ExistingGivenNames[i]:sub(1,1) ~= EnteredGivenNames[i] then
bOfferUpdate = true
break
end
end
if bOfferUpdate ~= true and #ExistingGivenNames < #EnteredGivenNames then -- More names/initials entered
bOfferUpdate = true
end
end
else
bOfferUpdate = true -- Surname doesn't match
end
if bOfferUpdate then
local strMsg = 'Name entered does not match current name\n\n'
.. 'Current: ' .. ExistingName .. '\n'
.. 'Entered: ' .. EnteredFullName .. '\n\n'
.. 'Update name?'
local Ans = MessageBox(strTitle, strMsg, 'YESNOCANCEL', 'QUESTION', 3, dialogMain)
if Ans == 3 then
return false -- Cancelled, don't continue
elseif Ans == 1 then
return true, true, EnteredFullName -- Continue, update, new name
else
return true, false -- Continue, don't update
end
end
return true, false -- Continue, don't update
end
-- Adding citation to names - check for multiple names and if so select name number
local Ind1Name, Ind2Name
if tglCitationToNames.value == 'ON' then
if Event ~= 'Marriage' then
bContinue, arrActions.Ind1NameNo, Ind1Name = MultNameCheck(ptrRecord, Event, 'Individual', dialogMain)
if not bContinue then
return -- User cancelled
end
arrActions.ptrInd1 = ptrRecord
-- Check if Birth name is different to stored
if Event == 'Birth' then
bContinue, arrActions.UpdateName, arrActions.NewName = CompareName(Ind1Name, txtGiven.value, txtSurname.value)
if not bContinue then
return -- User cancelled
end
end
else
bContinue, arrActions.Ind1NameNo, Ind1Name = MultNameCheck(arrInd1.Ptr, Event, 'Husband', dialogMain)
if not bContinue then
return -- User cancelled
end
arrActions.ptrInd1 = arrInd1.Ptr
if arrInd2 ~= nil then
bContinue, arrActions.Ind2NameNo, Ind2Name = MultNameCheck(arrInd2.Ptr, Event, 'Wife', dialogMain)
if not bContinue then
return -- User cancelled
end
arrActions.ptrInd2 = arrInd2.Ptr
else
arrActions.Ind2NameNo = 0 -- Family only has one parent (odd but possible!)
end
end
else
arrActions.Ind1NameNo = 0
arrActions.Ind2NameNo = 0
end
-- Adding birth citation to mother's name - check for mother's record
if Event == 'Birth' and tglCitationToMother.value == 'ON' then
arrActions.CitationMother = true
if arrInd1.ptrMother:IsNull() then
arrActions.MotherName = gtblSettings.NewMotherGivenName .. ' /'.. txtMother.value .. '/'
local strMessage
if arrInd1.ptrFamily:IsNull() then
arrActions.Mother = 'F'
strMessage = 'Create new family and add Mother?'
else
arrActions.Mother = 'I'
strMessage = 'Add Mother to family ' .. fhGetItemText(arrInd1.ptrFamily, '~'):sub(7)
end
strMessage = strMessage .. '?\n\nName: ' .. arrActions.MotherName
if MessageBox(gPluginName, strMessage, 'OKCANCEL', 'QUESTION', 1, dialogMain) == 2 then
return
end
arrActions.MotherNameNo = 1
elseif fhGetItemPtr(arrInd1.ptrMother, '~.NAME'):IsNull() then
arrActions.Mother = 'A'
arrActions.MotherName = gtblSettings.NewMotherGivenName .. ' /'.. txtMother.value .. '/'
arrActions.MotherNameNo = 1
else
local strCurrMother
bContinue, arrActions.MotherNameNo, strCurrMother = MultNameCheck(arrInd1.ptrMother, Event, 'Mother', dialogMain)
if not bContinue then
return -- User cancelled
end
local MotherSurname = strCurrMother:match('/(.*)/')
if txtMother.value:upper() ~= MotherSurname:upper() then
local strNewMother = Replace(strCurrMother, '/' .. MotherSurname .. '/', '/' .. txtMother.value .. '/') -- Replace family name
local strMessage = 'Mother\'s maiden name entered does not match existing name\n\n'
.. 'Existing name: ' .. strCurrMother .. '\n'
.. 'Maiden name entered: ' .. txtMother.value .. '\n\n'
.. 'YES Change Mother\'s name to ' .. strNewMother .. '\n'
.. 'NO Add citation without changing Mother\'s name'
local response = MessageBox(gPluginName, strMessage, 'YESNOCANCEL', 'QUESTION', 1, dialogMain)
if response == 1 then
arrActions.Mother = 'U'
arrActions.MotherName = strNewMother
elseif response == 2 then
arrActions.Mother = 'X'
arrActions.MotherName = strCurrMother
else
return
end
else
arrActions.Mother = 'X'
arrActions.MotherName = strCurrMother
end
end
end
-- Death - decide if anything needs doing with age or birth date
if Event == 'Death' then
bContinue, arrActions.DeathAge, arrActions.ageDeathAge = DeathAge(ptrRecord, txtAge.value, dialogMain)
if not bContinue then
return -- User cancelled
end
bContinue, arrActions.DeathDOB, arrActions.dteDOB = DeathDOB(ptrRecord, txtAge.value, txtDOB.value, dteEventDate, dialogMain)
if not bContinue then
return -- User cancelled
end
end
-- Have all the information - display what will be done & get confirmation to proceed
local strHeader = 'Citation for ' .. Event .. ' of ' .. arrInd1['DispNameFull']
if Event == 'Marriage' then
strHeader = strHeader .. '\nand '
if arrInd2 ~= nil then
strHeader = strHeader .. arrInd2['DispNameFull']
else
strHeader = strHeader .. '<>'
end
end
strHeader = strHeader .. '\n\nConfirmation of changes'
local lblHeading = iup.label{title = strHeader, fontstyle = 'Bold', alignment = 'ACENTER'}
-- Data changes
local strDataChanges
local bDataChanges = false
if Event ~= 'Marriage' then
strDataChanges = arrInd1.DispName
else
strDataChanges = 'Family ' .. arrFam.DispName:sub(4)
end
local NewLine = '\n' .. string.rep(' ', 4)
if arrActions.UpdateName then
local strNo = ''
if arrActions.Ind1NameNo ~= 1 then
strNo = '[' .. arrActions.Ind1NameNo .. ']'
end
strDataChanges = strDataChanges .. NewLine .. 'Change Name' .. strNo .. ' to: ' .. arrActions.NewName
bDataChanges = true
end
if arrActions.Event then
strDataChanges = strDataChanges .. NewLine .. 'Create ' .. Event .. ' Event'
bDataChanges = true
end
if arrActions.EventDate == 'C' then
strDataChanges = strDataChanges .. NewLine .. Event .. ' date: ' .. EventDate
bDataChanges = true
elseif arrActions.EventDate == 'U' then
strDataChanges = strDataChanges .. NewLine .. 'Change ' .. Event .. ' date to: ' .. EventDate
bDataChanges = true
end
if arrActions.EventPlace ~= 'X' then
if arrActions.EventPlace == 'C' then
strDataChanges = strDataChanges .. NewLine .. Event .. ' place: ' .. arrActions.txtEventPlace
bDataChanges = true
elseif arrActions.EventPlace == 'U' then
strDataChanges = strDataChanges .. NewLine .. 'Change ' .. Event .. ' place to: ' .. arrActions.txtEventPlace
bDataChanges = true
end
strDataChanges = strDataChanges .. NewLine .. Event .. ' address: Registration District'
bDataChanges = true
end
if Event == 'Death' then
if arrActions.DeathAge == 'A' then
strDataChanges = strDataChanges .. NewLine .. 'Death Age: ' .. txtAge.value
bDataChanges = true
elseif arrActions.DeathAge == 'U' then
strDataChanges = strDataChanges .. NewLine .. 'Change Death Age to: ' .. txtAge.value
bDataChanges = true
end
if arrActions.DeathDOB == 'A' then
strDataChanges = strDataChanges .. NewLine .. 'Birth Date: '
.. arrActions.dteDOB:GetDisplayText('COMPACT')
bDataChanges = true
elseif arrActions.DeathDOB == 'U' then
strDataChanges = strDataChanges .. NewLine .. 'Change Birth Date to: '
.. arrActions.dteDOB:GetDisplayText('COMPACT')
bDataChanges = true
end
-- Check for Living flag to be removed
if fhGetItemText(ptrRecord, '~._FLGS.__LIVING') == 'Y' then
arrActions.UnsetLiving = true
strDataChanges = strDataChanges .. NewLine .. 'Unset Living flag'
bDataChanges = true
else
arrActions.UnsetLiving = false
end
end
if not bDataChanges then
strDataChanges = strDataChanges .. NewLine .. 'No changes'
end
if Event == 'Birth' and arrActions.CitationMother and arrActions.Mother ~= 'X' then
if arrActions.Mother == 'A' then
strDataChanges = strDataChanges .. '\n[unnamed person] (Mother)'
.. NewLine .. 'Add Name: ' .. arrActions.MotherName
bDataChanges = true
elseif arrActions.Mother == 'U' then
strDataChanges = strDataChanges .. '\n' .. fhGetItemText(ptrRecord, '~.~MOTH[1]>NAME[' .. arrActions.MotherNameNo .. ']:STORED') .. ' (Mother)'
.. NewLine .. 'Change Name to: ' .. arrActions.MotherName
bDataChanges = true
else -- Mother to be added
strDataChanges = strDataChanges .. '\nNew Individual (Mother)'
.. NewLine .. 'Name: ' .. arrActions.MotherName
.. NewLine .. 'Sex: Female'
.. NewLine .. 'Family'
if arrActions.Mother == 'F' then
strDataChanges = strDataChanges .. ' (new): '
else -- arrActions.Mother == 'I'
local ptrFather = fhGetItemPtr(ptrRecord,'~.FAMC>HUSB>')
if not ptrFather:IsNull() then
strDataChanges = strDataChanges .. ': Spouse ' .. fhGetItemText(ptrRecord, 'INDI.~FATH[1]>NAME[1]:STORED')
else
strDataChanges = strDataChanges .. ': '
end
end
end
end
local boxWidth = tostring(tonumber(dialogMain.Size:match('(%d+)')) - 43) -- Make this dialog the same width as dialogMain
local frameActions = iup.frame{
iup.hbox{
iup.frame{
iup.hbox{
iup.label{title = strDataChanges};
padding = '0x0', margin = '10x5', size = boxWidth .. 'x0'
},
bgcolor = gtblConstants.White, sunken = 'YES'
},
margin = '4x2', fontstyle = ''
},
title = 'Data Updates', fontstyle = 'Bold'
}
-- Citation details
local dteCitationDate = fhNewDate()
if gtblSettings.CitationEntryDate > 1 then
arrActions.CitationDate = true
if gtblSettings.CitationEntryDate == 2 then
dteCitationDate:SetSimpleDate(fhCallBuiltInFunction("today"))
else
dteCitationDate:SetValueAsText(EventDate)
end
arrActions.dteCitationDate = dteCitationDate
else
arrActions.CitationDate = false
end
arrActions.txtCitationAssess = gtblConstants.CitationAssess[tonumber(listCitationAssess.value)]
if listCitationAssess.value ~= '1' then
arrActions.CitationAssess = true
else
arrActions.CitationAssess = false
end
if txtCitationNote.value ~= '' then
arrActions.CitationNote = true
arrActions.txtCitationNote = txtCitationNote.value
else
arrActions.CitationNote = false
end
local strTmp = WhereWithin()
arrActions.WhereWithin = strTmp
local lblWhereWithin = iup.flatlabel{ -- This may be resized after dialog mapped if multi-line
title = strTmp:gsub('&', '&&'),
textwrap = 'YES', expand = 'VERTICAL'
}
strTmp = TextFromSrc()
arrActions.TextFromSrc = strTmp
local lblTextFromSrc = iup.flatlabel{ -- This may be resized after dialog mapped if multi-line
title = strTmp:gsub('&','&&'),
textwrap = 'YES', expand = 'VERTICAL'
}
local frameCitation = iup.frame{
iup.hbox{
iup.frame{
iup.gridbox{
iup.label{title = 'Source:'},
iup.label{title = gtblData.name .. '[' .. gtblData.id .. ']'},
iup.label{title = 'Where within:'},
lblWhereWithin,
iup.label{title = 'Date:'},
iup.label{title = dteCitationDate:GetDisplayText('COMPACT')},
iup.label{title = 'Assessment:'},
iup.label{title = arrActions.txtCitationAssess},
iup.label{title = 'Note:'},
iup.label{title = arrActions.txtCitationNote},
iup.label{title = 'Text from Source:'},
lblTextFromSrc;
orientation = 'horizontal', numdiv = 2, sizelin = -1, sizecol = -1, cgapcol = 4,
size = boxWidth .. 'x0'
},
bgcolor = gtblConstants.White, sunken = 'YES'
},
margin = '4x2', fontstyle = ''
},
title = 'Citation', fontstyle = 'Bold'
}
-- Facts to be given Citations
local strFacts
if Event ~= 'Marriage' then
strFacts = Event:upper() .. ' : ' .. arrInd1.DispName
else
strFacts = 'MARRIAGE : ' .. arrFam.DispName:sub(7)
end
if tglCitationToNames.value == 'ON' then
if arrActions.Ind1NameNo == 1 then
strFacts = strFacts .. '\nNAME : ' .. Ind1Name
else
strFacts = strFacts .. '\nNAME[' .. arrActions.Ind1NameNo .. '] : ' .. Ind1Name
end
if Event == 'Marriage' then
if arrActions.Ind2NameNo == 1 then
strFacts = strFacts .. '\nNAME : ' .. Ind2Name
elseif arrActions.Ind2NameNo > 1 then
strFacts = strFacts .. '\nNAME[' .. arrActions.Ind2NameNo .. '] : ' .. Ind2Name
end
end
end
if Event == 'Birth' and arrActions.CitationMother then
strFacts = strFacts .. '\nNAME'
if arrActions.MotherNameNo ~= 1 then
strFacts = strFacts .. '[' .. arrActions.MotherNameNo .. ']'
end
strFacts = strFacts .. ' : ' .. arrActions.MotherName .. ' (Mother)'
end
if Event == 'Death' and arrActions.DeathDOB ~= 'X' then
strFacts = strFacts .. '\nBIRTH : ' .. arrInd1.DispName
end
local frameFacts = iup.frame{
iup.hbox{
iup.frame{
iup.hbox{
iup.label{title = strFacts};
padding = '0x0', margin = '10x5', size = boxWidth .. 'x0'
},
bgcolor = gtblConstants.White, sunken = 'YES'
},
margin = '4x2', fontstyle = ''
},
title = 'Facts to be given citations', fontstyle = 'Bold'
}
-- Footer Buttons
local bContinue
local btnSave = iup.button{
title = 'Save', image = 'IUP_FileSave', padding = '10x0',
action = function(self)
bContinue = true
return iup.CLOSE
end
}
local btnCancel = iup.button{
title = 'Cancel', padding = '10x3',
action = function(self)
bContinue = false
return iup.CLOSE
end
}
local hboxFooter = iup.hbox{
btnSave, btnCancel;
normalizesize = 'BOTH', margin = '0x5', gap = 40
}
local dialogConfirm = iup.dialog{
iup.vbox{
lblHeading, frameActions, frameCitation, frameFacts, hboxFooter;
margin = '15x5', gap = 5, alignment = 'ACENTER'
};
resize = 'No', minbox = 'No', maxbox = 'No',
title = 'GRO Index ' .. Event .. ' Citation',
defaultesc = btnCancel,
PARENTDIALOG = dialogMain
}
-- Resize citation labels to fit if they need multiple lines
dialogConfirm:map()
local MaxLabelWidth = boxWidth - 87
local bRefresh = false
local Xwidth = dialogConfirm.Size
local size = iup.GetAttribute(lblWhereWithin, 'SIZE')
local isize = tonumber(size:match('^%d+'))
if isize > MaxLabelWidth then
if isize < MaxLabelWidth * 2 then
lblWhereWithin.size = tostring(MaxLabelWidth) .. 'x16' -- two lines
else
lblWhereWithin.size = tostring(MaxLabelWidth) .. 'x24' -- three lines
end
bRefresh = true
end
size = iup.GetAttribute(lblTextFromSrc, 'SIZE')
isize = tonumber(size:match('^%d+'))
if isize > MaxLabelWidth then
if isize < MaxLabelWidth * 2 then
lblTextFromSrc.size = tostring(MaxLabelWidth) .. 'x16' -- two lines
else
lblTextFromSrc.size = tostring(MaxLabelWidth) .. 'x24' -- three lines
end
bRefresh = true
end
if bRefresh then
iup.SetAttribute(dialogConfirm, 'SIZE', '')
iup.Refresh(dialogConfirm)
end
local dialogMainPosX, dialogMainPosY = dialogMain.ScreenPosition:match('([^,]+),([^,]+)')
dialogMainPosX = tonumber(dialogMainPosX)
dialogMainPosY = tonumber(dialogMainPosY) + 32 -- Down relative to dialogMain by default caption height
dialogConfirm:popup(dialogMainPosX, dialogMainPosY)
dialogConfirm:destroy()
if not bContinue then
Exit = false
return
end
-- User has confirmed to go ahead and make the changes
Exit = true
return iup.CLOSE
end -- function btnContinue:action
------------------------------------------------------------------------------------------------------------------------
dialogMain:map()
WhereWithinUpdate()
TextFromSrcUpdate()
local ScreenPosX = gtblSettings.ScreenPosX
local ScreenPosY = gtblSettings.ScreenPosY
local bFirstMove = true
function dialogMain:move_cb(x, y)
if bFirstMove then
bFirstMove = false -- Ignore call back that occurs during popup of dialog
else
ScreenPosX = x
ScreenPosY = y
end
end
function dialogMain:show_cb(state) -- Make sure dialog is not off the top of the screen
if state == 0 then
local x, y = dialogMain.screenposition:match('([^,]*),([^,]*)')
if tonumber(y) < 0 then
ScreenPosX = x
ScreenPosY = 0
dialogMain:showxy(ScreenPosX, ScreenPosY)
end
end
end
dialogMain:popup(ScreenPosX, ScreenPosY)
dialogMain:destroy()
if ScreenPosX ~= gtblSettings.ScreenPosX or ScreenPosY ~= gtblSettings.ScreenPosY then
gtblSettings.ScreenPosX = ScreenPosX
gtblSettings.ScreenPosY = ScreenPosY
SaveSettings()
end
if Exit then
DoActions(arrActions)
end
return Exit
end -- function MainDialog
--======================================================================================================================
-- Populate an iuplist with values from an array
function PopulateList(iuplist, tblVals)
local is_indexed = (rawget( tblVals, 1 ) ~= nil)
if not is_indexed then
local i=1
for k, _ in pairs(tblVals) do
iuplist[tostring(i)]=k
i=i+1
end
else
for i, v in ipairs(tblVals) do
iuplist[tostring(i)]=v
end
end
end
------------------------------------------------------------------------------------------------------------------------
function ToggleValue(bValue) -- Toggle on/off from setting true/false
if bValue then
return'ON'
else
return 'OFF'
end
end -- function SetToggleValue
--======================================================================================================================
-- Check for existing event and if there compare data; user decides what to update if existing data
function CompareEvent(ptrRecord, Event, strEvent, EventDate, District, dialogMain)
-- Returns: bContinue - false if user cancelled
-- Event - true if event to be created, false if already exists
-- Date - "C"reate, "U"pdate, "X" do nothing
-- Place (and address) - "C"reate, "U"pdate, "X" do nothing
local ptrEvent = fhNewItemPtr()
local ptrField = fhNewItemPtr()
ptrEvent:MoveTo(ptrRecord, '~.' .. strEvent)
if ptrEvent:IsNull() then
return true, true, 'C', 'C'
end
ptrField:MoveTo(ptrEvent,'~.DATE')
local ExistingDate = fhGetValueAsDate(ptrField):GetDisplayText('COMPACT')
local ExistingPlace = fhGetItemText(ptrEvent, '~.PLAC')
local ExistingAddress = fhGetItemText(ptrEvent, '~.ADDR')
if ExistingDate == '' and ExistingPlace == '' then
return true, false, 'C', 'C'
end
-- Compare data with existing event data
if EventDate == ExistingDate and District == ExistingPlace then
return true, false, 'X', 'X'
end
-- Get user to choose whether to update event
local hboxExistingDate = iup.hbox{iup.label{title = 'Date:', size = '50x0'}, iup.label{title = ExistingDate}}
local hboxExistingPlace = iup.hbox{
iup.label{title = 'Place:', size = '50x0'}, iup.label{title = ExistingPlace:gsub('&', '&&')}}
local hboxExistingAddress = iup.hbox{
iup.label{title = 'Address:', size = '50x0'}, iup.label{title = ExistingAddress:gsub('&', '&&')}}
local frameExisting = iup.frame{
iup.hbox{
iup.frame{
iup.hbox{
iup.vbox{hboxExistingDate, hboxExistingPlace,hboxExistingAddress; gap = 0, margin = '2x2' },
iup.fill{};
padding = '0x0', gap = 15, margin = '10x5'
},
bgcolor = gtblConstants.White, sunken = 'YES'
},
margin = '4x2', fontstyle = ''
},
title = 'Existing ' .. Event .. ' Details', fontstyle = 'Bold'
}
local hboxEventDate = iup.hbox{iup.label{title = 'Date:', size = '50x0'}, iup.label{title = EventDate}}
local hboxEventPlace = iup.hbox{iup.label{title = 'Place:', size = '50x0'}, iup.label{title = District:gsub('&', '&&')}}
local hboxEventAddress = iup.hbox{iup.label{title = 'Address:', size = '50x0'}, iup.label{title = 'Registration District' }}
local frameEvent = iup.frame{
iup.hbox{
iup.frame{
iup.hbox{
iup.vbox{hboxEventDate, hboxEventPlace,hboxEventAddress; gap = 0, margin = '2x2' },
iup.fill{};
padding = '0x0', gap = 15, margin = '10x5'
},
bgcolor = gtblConstants.White, sunken = 'YES'
},
margin = '4x2', fontstyle = ''
},
title = 'Suggested by this Citation', fontstyle = 'Bold'
}
local tglPlaceOnly = iup.toggle{name = 'Place', title = 'Replace just ' .. Event .. ' place* with suggested place'}
local tglDateOnly = iup.toggle{name = 'Date', title = 'Replace just ' .. Event .. ' date with suggested date'}
local tglBoth = iup.toggle{name = 'Both', title = 'Replace ' .. Event .. ' date and place* with suggested date and place'}
local tglNeither = iup.toggle{name = 'Neither', title = 'Don\'t change '.. Event .. ' event'}
local radioAction = iup.radio{
iup.vbox{
tglPlaceOnly, tglDateOnly, tglBoth, tglNeither,
iup.label{title = '* Address will be changed when replacing Place'};
gap = 1, margin = '10x5',
}
}
if EventDate == ExistingDate then
tglDateOnly.active = 'NO'
tglBoth.active = 'NO'
elseif District == ExistingPlace then
tglPlaceOnly.active = 'NO'
tglBoth.active = 'NO'
end
radioAction.value = tglNeither
local bContinue
local btnContinue = iup.button{
title = 'Continue', padding = '10x0',
action = function(self)
bContinue = true
return iup.CLOSE
end
}
local btnCancel = iup.button{
title = 'Cancel', padding = '10x3',
action = function(self)
bContinue = false
return iup.CLOSE
end
}
local hboxFooter = iup.hbox{
iup.fill{}, btnContinue, btnCancel, iup.fill{};
normalizesize = 'BOTH', margin = '0x5', gap = 40
}
local dialogEventData = iup.dialog{
iup.vbox{frameExisting, frameEvent, radioAction, hboxFooter; margin = '15x5', gap = 5};
resize = 'No', minbox = 'No', maxbox = 'No',
title = 'GRO Index ' .. Event .. ' Citation',
defaultesc = btnCancel,
PARENTDIALOG = dialogMain
}
dialogEventData:popup(iup.CENTERPARENT, iup.CENTERPARENT)
local DateAction = 'X'
local PlaceAction = 'X'
if bContinue then
if tglDateOnly.value == 'ON' or tglBoth.value == 'ON' then
if ExistingDate == '' then
DateAction = 'C'
else
DateAction = 'U'
end
end
if tglPlaceOnly.value == 'ON' or tglBoth.value == 'ON' then
if ExistingPlace == '' then
PlaceAction = 'C'
else
PlaceAction = 'U'
end
end
end
dialogEventData:destroy()
return bContinue, false, DateAction, PlaceAction
end -- function CompareEvent
--======================================================================================================================
-- Death: Decide if age in the death event needs adding/updating
function DeathAge(ptrRecord, Age, dialogMain)
-- Returns: bContinue - false if user cancelled
-- Action - "A" Add DOB to birth event, "U"pdate, "X" do nothing
-- Death age object
if Age == '' then
return true, 'X', nil
end
local ageEntered = fhNewAge()
ageEntered:SetValue('=', tonumber(Age))
local ageExisting
local ptrEvent = fhNewItemPtr()
local ptrField = fhNewItemPtr()
ptrEvent:MoveTo(ptrRecord, '~.DEAT')
if ptrEvent:IsNull() then
return true, 'A', ageEntered
else
ptrField:MoveTo(ptrEvent, '~.AGE')
ageExisting = fhGetValueAsAge(ptrField)
end
if ageExisting:IsNull() then
return true, 'A', ageEntered
end
if ageEntered:GetYears() == ageExisting:GetYears() then
return true, 'X', ''
end
local strMessage = 'Age does not match existing death age\n\n'
.. 'Existing: ' .. ageExisting:GetDisplayText() .. '\n'
.. 'Entered: ' .. ageEntered:GetDisplayText() .. '\n\n'
.. 'Overwrite death Age?'
local Response = MessageBox('GRO Index Death Citation', strMessage, 'YESNOCANCEL', 'QUESTION', 3, dialogMain)
if Response == 3 then
return false, ''
end
if Response == 1 then
return true, 'U', ageEntered
else
return true, 'X', nil
end
end
--======================================================================================================================
-- Death: decide whether to change individuals date of birth
function DeathDOB(ptrRecord, Age, DOB, dteEventDate, dialogMain)
-- Returns: bContinue - false if user cancelled
-- Action - "A" Add DOB to birth event, "U"pdate, "C"itation only, "X" do nothing
-- Date object containing date of birth
if Age == '' and DOB == '' then
return true, 'X', fhNewDatePt() -- Neither entered so nothing to do
end
local ptrEvent = fhNewItemPtr()
local ptrField = fhNewItemPtr()
local dteExistingDOB
ptrEvent:MoveTo(ptrRecord, '~.BIRT')
if ptrEvent:IsNull() then
dteExistingDOB = fhNewDate()
else
ptrField:MoveTo(ptrEvent, '~.DATE')
dteExistingDOB = fhGetValueAsDate(ptrField)
end
local dteNewDOB = fhNewDate()
if Age ~= '' then
dteNewDOB = fhu.calcBirth(dteEventDate, Age)
else
dteNewDOB:SetValueAsText(DOB)
end
local hboxExisting = iup.hbox{iup.label{title = 'Existing Date:', size = '120x0'}, iup.label{title = dteExistingDOB:GetDisplayText('COMPACT')}}
local hboxSuggested = iup.hbox{iup.label{title = 'Date from GRO Death:', size = '120x0'}, iup.label{title = dteNewDOB:GetDisplayText('COMPACT')}}
local frameDOB = iup.frame{
iup.hbox{
iup.frame{
iup.hbox{
iup.vbox{hboxExisting, hboxSuggested; gap = 0, margin = '2x2' },
iup.fill{};
padding = '0x0', gap = 15, margin = '10x5'
},
bgcolor = gtblConstants.White, sunken = 'YES'
},
margin = '4x2', fontstyle = ''
},
title = 'Birth Date', fontstyle = 'Bold'
}
local AddUpdate
if dteExistingDOB:IsNull() then
AddUpdate = 'Add'
else
AddUpdate = 'Update'
end
local tglAddUpdate = iup.toggle{title = AddUpdate .. ' Birth Date'}
local tglCitation = iup.toggle{title = 'Only add Citation to Birth Date'}
local tglNothing = iup.toggle{title = 'Don\'t ' .. AddUpdate .. ' Birth Date or add citation'}
local radioAction = iup.radio{
iup.vbox{
tglAddUpdate, tglCitation, tglNothing;
gap = 1, margin = '10x5'
}
}
if not dteExistingDOB:IsNull() then
if dteNewDOB:GetValueAsText() == dteExistingDOB:GetValueAsText() then
tglAddUpdate.active = 'NO'
tglNothing .title = 'Don\'t add citation'
radioAction.value = tglCitation
else
radioAction.value = tglNothing
end
else
tglCitation.active = 'NO' -- Disable citation only if no existing date
end
local bContinue
local btnContinue = iup.button{
title = 'Continue', padding = '10x0',
action = function(self)
bContinue = true
return iup.CLOSE
end
}
local btnCancel = iup.button{
title = 'Cancel', padding = '10x3',
action = function(self)
bContinue = false
return iup.CLOSE
end
}
local hboxFooter = iup.hbox{
iup.fill{}, btnContinue, btnCancel, iup.fill{};
normalizesize = 'BOTH', margin = '0x5', gap = 40
}
local dialogDeathDOB = iup.dialog{
iup.vbox{frameDOB, radioAction, hboxFooter; margin = '15x5', gap = 5};
resize = 'No', minbox = 'No', maxbox = 'No',
title = 'GRO Index Death Citation',
defaultesc = btnCancel,
PARENTDIALOG = dialogMain
}
dialogDeathDOB:popup(iup.CENTERPARENT, iup.CENTERPARENT)
local Action = 'X'
if bContinue then
if tglAddUpdate.value == 'ON' then
if dteExistingDOB:IsNull() then
Action = 'A'
else
Action = 'U'
end
elseif tglCitation.value == 'ON' then
Action = 'C'
end
end
dialogDeathDOB:destroy()
return bContinue, Action, dteNewDOB
end -- function DeathDOB
--======================================================================================================================
-- Citations being added to name(s) - check for multiple and if so pick which one
function MultNameCheck(ptrRecord, Event, Role, dialogMain)
local ptrField = fhNewItemPtr()
ptrField:MoveTo(ptrRecord, '~.NAME')
if ptrField:IsNull() then
OkOnlyMessage(gPluginName, Role .. ' has no name', 'ERROR', dialogMain)
return false, 0
end
local arrNames = {}
while ptrField:IsNotNull() do
table.insert(arrNames, fhGetItemText(ptrField, '~:STORED'))
ptrField:MoveNext('SAME_TAG')
end
if #arrNames == 1 then
return true, 1, arrNames[1]
end
lblHeading = iup.label{title= Role .. ' has Multiple names\n\nSelect name to be given the citation', expand = 'HORIZONTAL'}
listNames = iup.list{visiblecolumns = 25, visiblelines = 3}
PopulateList(listNames, arrNames)
local frameNames = iup.frame{
iup.hbox{
iup.frame{
iup.hbox{
iup.vbox{lblHeading, listNames; gap = 2, margin = '2x2' },
iup.fill{};
padding = '0x0', gap = 15, margin = '10x5'
},
bgcolor = gtblConstants.White, sunken = 'YES'
},
margin = '4x2', fontstyle = ''
},
title = 'Multiple Names', fontstyle = 'Bold'
}
local bContinue
local btnContinue = iup.button{
title = 'Continue', padding = '10x0'
}
function btnContinue:action()
if listNames.value == "0" then
OkOnlyMessage(gPluginName, "Name not selected", 'WARNING', dialogMain)
return
end
bContinue = true
return iup.CLOSE
end
local btnCancel = iup.button{
title = 'Cancel', padding = '10x3',
action = function(self)
bContinue = false
return iup.CLOSE
end
}
local hboxFooter = iup.hbox{
iup.fill{}, btnContinue, btnCancel, iup.fill{};
normalizesize = 'BOTH', margin = '0x5', gap = 40
}
local dialogMultName = iup.dialog{
iup.vbox{frameNames, hboxFooter; margin = '15x5', gap = 5};
resize = 'No', minbox = 'No', maxbox = 'No',
title = 'GRO Index ' .. Event .. ' Citation',
defaultesc = btnCancel,
PARENTDIALOG = dialogMain
}
dialogMultName:popup(iup.CENTERPARENT, iup.CENTERPARENT)
local SelName = listNames.value
local SelNameDisp = arrNames[tonumber(SelName)]
dialogMultName:destroy()
return bContinue, tonumber(SelName), SelNameDisp
end -- function MultNameCheck
--======================================================================================================================
function DoActions(arrActions)
--[[All the actions to be taken and data needed is in arrActions
arrActions.ptrRecord ptr Individual or family record to have event added
.strEvent str Event item (BIRT, MARR or DEAT)
.Event boo true=Create event, false= event exists
.EventDate str 'C'reate, 'U'pdate, 'X' do nothing
.dteEventDate dte Event date object
.EventPlace str 'C'reate, 'U'pdate, 'X' do nothing
.txtEventPlace str Full place of district
.DeathAge str 'C'reate, 'U'pdate, 'X' do nothing
.ageDeathAge age Age at death
.DeathDOB str 'A'dd DOB to birth event, 'U'pdate DOB, 'C'itation only, 'X' do nothing
.dteDOB dte Date of birth date object
.UpdateName boo Individiduals name to be updated (birth Only)
.NewName str New name for update
.Ind1NameNo str Individual 1 Number of name for citation (0 if no citation to be added)
.ptrInd1 ptr Individual 1 record for name citation (marriage only)
.Ind2NameNo str Individual 2 Number of name for citation (0 if no citation to be added)
.ptrInd2 ptr Individual 2 record for name citation (marriage only)
.CitationMother boo True = Add citation to mother's name
.MotherNameNo str Mother - Number of name for citation and, if required, updating
.Mother str 'U'pdate name, 'F'amily and individual to be created,
'I' Create individual and add to existing family as mother,
'A'dd name to existing unnamed person, 'X' do nothing
.MotherName str Full Name of Mother
.CitationDate boo True=Add date to citation
.dteCitationDate dte Citation date object
.CitationAssess boo true=Add assessment to citation
.txtCitationAssess str Assessment
.UnsetLiving boo true=Delete living flag
.WhereWithin str Citation's Where Within
.TextFromSrc str Citation's Text From Source - may be blank
]]
if DEBUG_MODE and debug then
io.write(dumpstr(arrActions, '==Actions=='))
end
local ptrEvent = fhNewItemPtr()
local ptrField = fhNewItemPtr()
local bOK
if arrActions.UpdateName then
ptrField:MoveTo(arrActions.ptrRecord, '~.NAME[' .. arrActions.Ind1NameNo .. ']')
bOK = fhSetValueAsText(ptrField, arrActions.NewName)
if not bOK then error('Updating Name') end
end
ptrEvent:MoveTo(arrActions.ptrRecord, '~.' .. arrActions.strEvent)
if arrActions.Event then -- Event to be created
if ptrEvent:IsNotNull() then
error('Event found when expecting to create event')
end
ptrEvent = fhCreateItem(arrActions.strEvent, arrActions.ptrRecord)
else
if ptrEvent:IsNull() then
error('Event not found when expecting to update event')
end
end
if arrActions.EventDate ~= 'X' then
ptrField:MoveTo(ptrEvent, '~.DATE')
if arrActions.EventDate == 'C' then
if ptrField:IsNotNull() then
if fhGetDisplayText(ptrField, '', 'min') ~= '' then -- Field there - should be empty
error('Field found when expecting to create date')
end
else
ptrField = fhCreateItem("DATE",ptrEvent)
end
else
if ptrField:IsNull() then
error('Field not found when expecting to update date')
end
end
bOK = fhSetValueAsDate(ptrField, arrActions.dteEventDate)
if not bOK then error('Setting event date') end
-- Check date doesn't give fh warnings
local i = 0
local strWarning
local strMessage = ''
repeat
i = i + 1
strWarning = fhCallBuiltInFunction("GetDataWarning", ptrField, i)
if strWarning ~= '' then
strMessage = strMessage .. '\n' .. strWarning
end
until strWarning == ''
if strMessage ~= '' then
strMessage = strMessage .. '\n\nDo you wish to undo the entry?'
local Response = MessageBox('Event date warning', strMessage, 'YESNO', 'WARNING' , 1)
if Response == 1 then
error('\nPlugin aborting - select \'Yes\' to undo this entry')
end
end
end
if arrActions.EventPlace ~= 'X' then
ptrField:MoveTo(ptrEvent, '~.PLAC')
if arrActions.EventPlace == 'C' then
if ptrField:IsNotNull() then
if fhGetItemText(ptrField, '~') ~= '' then -- Field there - should be empty
error('Field found when expecting to create place')
end
else
ptrField = fhCreateItem("PLAC",ptrEvent)
end
else
if ptrField:IsNull() then
error('Field not found when expecting to update place')
if not bOK then error('Setting age') end
end
end
bOK = fhSetValueAsText(ptrField,arrActions.txtEventPlace)
if not bOK then error('Setting Event Place') end
ptrField:MoveTo(ptrEvent, '~.ADDR')
if ptrField:IsNull() then
ptrField = fhCreateItem('ADDR', ptrEvent)
end
fhSetValueAsText(ptrField, 'Registration District')
end
if arrActions.strEvent == 'DEAT' then
if arrActions.DeathAge ~= 'X' then
ptrField:MoveTo(ptrEvent,"~.AGE")
if ptrField:IsNull() then
ptrField = fhCreateItem("AGE",ptrEvent)
end
bOK = fhSetValueAsAge(ptrField, arrActions.ageDeathAge)
if not bOK then error('Setting age') end
end
if arrActions.DeathDOB == 'A' or arrActions.DeathDOB == 'U' then
ptrEvent:MoveTo(arrActions.ptrRecord, '~.BIRT')
if ptrEvent:IsNull() then
ptrEvent = fhCreateItem('BIRT', arrActions.ptrRecord)
end
ptrField:MoveTo(ptrEvent,'~.DATE')
if ptrField:IsNull() then
ptrField = fhCreateItem('DATE',ptrEvent)
end
bOK = fhSetValueAsDate(ptrField, arrActions.dteDOB)
if not bOK then error('Setting DOB') end
-- Check date doesn't give fh warnings
local i = 0
local strWarning
local strMessage = ''
repeat
i = i + 1
strWarning = fhCallBuiltInFunction("GetDataWarning", ptrField, i)
if strWarning ~= '' then
strMessage = strMessage .. '\n' .. strWarning
end
until strWarning == ''
if strMessage ~= '' then
strMessage = strMessage .. '\n\nDo you wish to undo the entry?'
local Response = MessageBox('Date of birth warning', strMessage, 'YESNO', 'WARNING' , 1)
if Response == 1 then
error('\nPlugin aborting - select \'Yes\' to undo this entry')
end
end
end
if arrActions.UnsetLiving then
ptrField:MoveTo(arrActions.ptrRecord, '~._FLGS.__LIVING')
bOK = fhDeleteItem(ptrField)
if not bOK then error('Unsetting Living Flag') end
end
end
local ptrMother = fhNewItemPtr()
local ptrFamily = fhNewItemPtr()
ptrMother = fhGetItemPtr(arrActions.ptrRecord,'~.FAMC>WIFE>') -- May be null but will be set below if Mother is added
if arrActions.CitationMother and arrActions.Mother ~= 'X' then -- Data changes needed for Mother
if arrActions.Mother == 'U' then -- Change Mother's name
ptrField:MoveTo(ptrMother, '~.NAME[' .. arrActions.MotherNameNo .. ']')
bOK = fhSetValueAsText(ptrField, arrActions.MotherName)
if not bOK then error('Updating Mother\'s name') end
elseif arrActions.Mother == 'A' then -- Add Mother's name to currently unnamed Mother
ptrField = fhGetItemPtr(ptrMother, '~.NAME') -- Name field could be present but empty
if ptrField:IsNull() then
ptrField = fhCreateItem('NAME', ptrMother)
end
bOK = fhSetValueAsText(ptrField, arrActions.MotherName)
if not bOK then error('Adding Mother\'s name') end
else -- Must be 'F' or 'I'
if arrActions.Mother == 'F' then -- Family (and Mother) to be created
ptrFamily = fhCreateItem('FAM') -- Create family
ptrField = fhCreateItem('CHIL', ptrFamily)
bOK = fhSetValueAsLink(ptrField, arrActions.ptrRecord) -- Link individual as child in new family
if not bOK then error ('Creating new family and linking child') end
else
ptrFamily = fhGetItemPtr(arrActions.ptrRecord,'~.FAMC>')
if ptrFamily:IsNull() then error('Expected family not found') end
end
-- Create mother and add to existing family or newly created family
ptrMother = fhCreateItem('INDI')
ptrField = fhCreateItem('NAME', ptrMother)
bOK = fhSetValueAsText(ptrField, arrActions.MotherName)
if not bOK then error('Setting new Mother\'s name') end
ptrField = fhCreateItem('SEX', ptrMother)
bOK = fhSetValueAsText(ptrField, 'F')
if not bOK then error('Setting new Mother\'s sex') end
ptrField =fhGetItemPtr(ptrFamily, '~.WIFE') -- There could be an empty WIFE
if ptrField:IsNull() then
ptrField = fhCreateItem('WIFE', ptrFamily)
end
bOK = fhSetValueAsLink(ptrField, ptrMother)
if not bOK then error('Adding new Mother to family') end
end
end
--------------------------------------------------------------------------------------------------------------------
function AddCitation(ptrRecord, fact)
local bOK
local ptrFact = fhNewItemPtr()
local ptrField = fhNewItemPtr()
local ptrData = fhNewItemPtr()
ptrFact:MoveTo(ptrRecord, '~.' .. fact)
if ptrFact:IsNull() then
error('Fact ' .. fact .. ' not found on ' .. fhGetDisplayText(ptrRecord))
end
local ptrCitation = fhCreateItem('SOUR', ptrFact)
bOK = fhSetValueAsLink(ptrCitation, gtblData.ptr)
if not bOK then
error('Setting citation link on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact)
end
ptrField = fhCreateItem('PAGE', ptrCitation)
if ptrField:IsNull() then
error('Create PAGE failed on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR')
end
bOK = fhSetValueAsText(ptrField, arrActions.WhereWithin)
if not bOK then
error('Setting Where Within on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR.PAGE')
end
ptrData = fhCreateItem('DATA', ptrCitation)
if ptrData:IsNull() then
error('Create DATA failed on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR')
end
if arrActions.CitationDate then
ptrField = fhCreateItem('DATE', ptrData)
if ptrField:IsNull() then
error('Create DATE failed on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR.DATA')
end
bOK = fhSetValueAsDate(ptrField, arrActions.dteCitationDate)
if not bOK then
error('Setting date on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR.DATA.DATE')
end
end
if arrActions.TextFromSrc ~= '' then
ptrField = fhCreateItem('TEXT', ptrData)
if ptrField:IsNull() then
error('Create TEXT failed on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR.DATA')
end
bOK = fhSetValueAsText(ptrField, arrActions.TextFromSrc)
if not bOK then
error('Setting Text from Source on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR.DATA.TEXT')
end
end
if arrActions.CitationAssess then
ptrField = fhCreateItem('QUAY', ptrCitation)
if ptrField:IsNull() then
error('Create QUAY failed on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR')
end
bOK = fhSetValueAsText(ptrField, arrActions.txtCitationAssess)
if not bOK then
error('Setting Assessment on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR.QUAY')
end
end
if arrActions.CitationNote then
ptrField = fhCreateItem('NOTE2', ptrCitation)
if ptrField:IsNull() then
error('Create NOTE2 failed on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR')
end
bOK = fhSetValueAsText(ptrField, arrActions.txtCitationNote)
if not bOK then
error('Setting Assessment on ' .. fhGetDisplayText(ptrRecord) .. ' ' .. fact .. '.SOUR.NOTE2')
end
end
end --function AddCitation
--------------------------------------------------------------------------------------------------------------------
AddCitation(arrActions.ptrRecord, arrActions.strEvent) -- Add citation to event
if arrActions.Ind1NameNo ~= 0 then
AddCitation(arrActions.ptrInd1, 'NAME[' .. arrActions.Ind1NameNo .. ']') -- Add citation to name (or 1st name in a marriage)
end
if arrActions.strEvent == 'MARR' and arrActions.Ind2NameNo ~= 0 then
AddCitation(arrActions.ptrInd2, 'NAME[' .. arrActions.Ind2NameNo .. ']') -- Add citation to 2nd name in a marriage
end
if arrActions.strEvent == 'DEAT' and arrActions.DeathDOB ~= "X" then
AddCitation(arrActions.ptrRecord, 'BIRT') -- Add citation to birth (Death event)
end
if arrActions.strEvent == 'BIRT' and arrActions.CitationMother then
AddCitation(ptrMother, 'NAME[' .. arrActions.MotherNameNo .. ']')
end
end -- function DoActions
--======================================================================================================================
function GRODistricts(ParentDialog) --[[Maintain the list of GRO districts
Called from main BMD entry screen or from settings
]]
local dialogGRODistricts, listPlaces, listGROPlaces, btnSaveYears -- Forward declares
local tblYears = {}
function Populate_listPlaces()
listPlaces['1'] = nil -- Empty list
for i,v in pairs(tblPlaces) do
if not IntblGROPlaces(tblGROPlaces, v[1]) then
listPlaces[tostring(i)] = v[1]
else
listPlaces[tostring(i)] = v[1] ..' *'
end
end
end
function IntblGROPlaces(Table, PlaceName)
for _, v in pairs(tblGROPlaces) do
if PlaceName == v[1] then
return true
end
if PlaceName < v[1] then -- List is alphbetic order and we've gone past where it should be
break
end
end
return false
end
-- Create list box with all places, existing tblGROPlaces marked * plus edit box to allow entry of totally new
listPlaces = iup.list{dropdown = 'YES', editbox = 'YES', visibleitems = 10, expand = 'HORIZONTAL'}
Populate_listPlaces()
local btnUKBMD = iup.button{
title = 'UKBMD District Information',
image =iup.image{
width = 12, height = 12, pixels = {
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0,
0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,
0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
},
colors = {"0 0 0", "255 255 255"}
},
imageposition = 'RIGHT', spacing = '8', padding = '8x0',
action = function() fhShellExecute('https://www.ukbmd.org.uk/reg/districts/index.html') end
}
local btnAdd = iup.button{title = 'Add Place to GRO Districts', padding = '8x2'}
function listPlaces:valuechanged_cb()
if not IntblGROPlaces(tblGROPlaces, listPlaces.value:gsub('%s%*?$', '')) then
if listPlaces.value:find('%*$') then
local SavePos = listPlaces.caretpos
listPlaces.value = listPlaces.value:sub(1,-3)
listPlaces.caretpos = SavePos
end
btnAdd.visible = 'YES'
else
if not listPlaces.value:find('%*$') then
local SavePos = listPlaces.caretpos
listPlaces.value = listPlaces.value .. ' *'
listPlaces.caretpos = SavePos
end
btnAdd.visible= 'NO'
end
end
local frameAddDistrict = iup.frame{
iup.vbox{
iup.frame{
iup.vbox{
iup.label{title = 'Select or enter place to add to GRO Districts (* Existing GRO district)'},
listPlaces,
iup.hbox{btnUKBMD, iup.fill{}, btnAdd; normalizesize = 'VERTICAL', margin = '0x0'};
gap = 2, margin = '4x4', fontstyle= ''
},
sunken = 'YES', margin = '4x0'
},
margin = '4x0'
};
title = 'Add GRO district', fontstyle = 'Bold'
}
function btnAdd:action()
if listPlaces.value ~= '' then
local ptrPlace = fhNewItemPtr()
for i, v in pairs(tblPlaces) do
if listPlaces.value == v[1] then
ptrPlace:MoveToRecordById('_PLAC', v[2])
break
end
if listPlaces.value < v[1] then -- List is in alpha order and we've gone past where it should be
break
end
end
if ptrPlace:IsNull() then
ptrPlace = fhCreateItem('_PLAC')
if ptrPlace:IsNull() then
error('Creating place record')
end
local ptrText = fhCreateItem('TEXT', ptrPlace, true) -- ReuseEmpties flag set
if not fhSetValueAsText(ptrText, listPlaces.value) then
error ('Setting Place text')
end
table.insert(tblPlaces,{fhGetDisplayText(ptrPlace), fhGetRecordId(ptrPlace)})
table.sort(tblPlaces, function(k1, k2) return k1[1] < k2[1] end)
end
local ptrNote = fhCreateItem('NOTE2', ptrPlace)
if not fhSetValueAsText(ptrNote, 'GRO District') then
error ('Adding GRO District Note')
end
table.insert(tblGROPlaces,{fhGetDisplayText(ptrPlace), '', fhGetRecordId(ptrPlace)})
table.sort(tblGROPlaces, function(k1, k2) return k1[1] < k2[1] end)
Populate_listPlaces()
PopulateListFromtblGROPlaces(listGROPlaces)
ClearYears()
-- Position lists on newly added place
listPlaces.value = fhGetDisplayText(ptrPlace) .. ' *'
for i, v in pairs(tblGROPlaces) do
if v[1] == fhGetDisplayText(ptrPlace) then
listGROPlaces.value = i
break
end
end
for _, v in pairs(tblYears) do
v.active = 'YES'
end
btnSaveYears.active = 'NO'
fhUpdateDisplay()
OkOnlyMessage(dialogGRODistricts.title, fhGetDisplayText(ptrPlace) .. '\n\nadded to GRO Districts',
'INFORMATION', dialogGRODistricts)
iup.SetFocus(tblYears[1])
end
end
listGROPlaces = iup.list{dropdown = 'NO', visiblelines = 5, expand = 'HORIZONTAL', editbox = 'NO'}
PopulateListFromtblGROPlaces(listGROPlaces)
local btnRemove = iup.button{title = 'Remove from GRO Districts', padding = '8x2'}
function btnRemove:action()
if listGROPlaces.value == '0' then
return
end
local Ans = MessageBox(dialogGRODistricts.title,
'Remove ' ..tblGROPlaces[tonumber(listGROPlaces.value)][1] .. ' from GRO Districts?\n\n'
.. '(The Place record will not be deleted)',
'OKCANCEL', 'QUESTION', 2, dialogGRODistricts)
if Ans == 1 then
local ptrPlace = fhNewItemPtr()
ptrPlace:MoveToRecordById('_PLAC', tblGROPlaces[tonumber(listGROPlaces.value)][3])
local ptrNote = fhGetItemPtr(ptrPlace, '~.NOTE2')
while ptrNote:IsNotNull() do
local strNote = fhGetItemText(ptrNote,'~')
if strNote:match('GRO District') then
break
end
ptrNote:MoveNext('SAME_TAG')
end
if ptrNote:IsNull() then
error('GRO District note found')
end
if not fhDeleteItem(ptrNote) then
error('Delete GRO District note failed')
end
table.remove(tblGROPlaces, tonumber(listGROPlaces.value))
Populate_listPlaces()
PopulateListFromtblGROPlaces(listGROPlaces)
ClearYears()
fhUpdateDisplay()
OkOnlyMessage(dialogGRODistricts.title, fhGetDisplayText(ptrPlace) .. ' removed from GRO Districts',
'INFORMATION', dialogGRODistricts)
end
end
function TextBoxYear(i)
local txtYear = iup.text{
nc = '4', filter = 'NUMERIC', alignment = 'ACENTER', visiblecolumns = 3,
active = 'NO'
}
function txtYear:getfocus_cb()
if tblYears[i].value ~= '' then
tblYears[i].selection = 'ALL'
end
end
function txtYear:action()
tblYears[i].bgcolor = gtblConstants.White
btnSaveYears.active = 'YES'
end
function txtYear:killfocus_cb()
tblYears[i].selection = 'NONE'
if tblYears[i].value ~= '' then
if tonumber(tblYears[i].value) < 1837 or tonumber(tblYears[i].value) > gtblConstants.CurrYear then
tblYears[i].bgcolor = gtblConstants.Red
tblYears[i].selection = 'ALL'
iup.SetFocus(tblYears[i])
return iup.IGNORE
else
tblYears[i].bgcolor = gtblConstants.White
end
end
end
function txtYear:k_any(keycode)
if keycode == iup.K_TAB then
if tblYears[i].value == '' then
iup.SetFocus(btnSaveYears)
return iup.IGNORE
end
end
end
return txtYear
end
for i = 1, 8 do
tblYears[i] = TextBoxYear(i)
end
local tblYearsFromTo = {}
for i = 1, 4 do
tblYearsFromTo[i] = {tblYears[(i * 2) - 1], tblYears[(i * 2)]}
end
function ClearYears()
for _, v in pairs(tblYears) do
v.value = ''
v.bgcolor = gtblConstants.White
v.active = 'NO'
end
end
function PopulateYears(ItemNo)
local strYears = tblGROPlaces[tonumber(ItemNo)][2]
local FromToPattern = '(%d*%-?%d*)'
local tblFromTo = {strYears:match(FromToPattern .. ',?' .. FromToPattern .. ',?' .. FromToPattern .. ',?' .. FromToPattern)}
for i,v in pairs(tblFromTo) do
From, To = v:match('(%d*)%-?(%d*)')
tblYearsFromTo[i][1].value = From or ''
tblYearsFromTo[i][2].value = To or ''
end
-- Make all years active
for _, v in pairs(tblYears) do
v.active = 'YES'
end
end
function listGROPlaces:action(text, item, state)
if state == 1 then
PopulateYears(item)
else
ClearYears()
end
btnSaveYears.active = 'NO'
end
function hboxFromTo(i)
return iup.hbox{
iup.label{title = tostring(i) .. ' From'}, tblYearsFromTo[i][1],
iup.label{title = 'To'}, tblYearsFromTo[i][2],
cgap = '6', alignment = 'ACENTER'
}
end
local gridYears = iup.gridbox{
hboxFromTo(1), hboxFromTo(2),
iup.fill{size = '12'},iup.fill{size = '12'},
hboxFromTo(3), hboxFromTo(4),
numdiv = '2', cgaplin = '2', sizecol = '-1', orientation = 'VERTICAL'}
btnSaveYears = iup.button{title = 'Save Active Years', padding = '8x2', active = 'NO'}
function ValidateYears()
for i,v in pairs(tblYearsFromTo) do
if v[1].bgcolor == gtblConstants.Red or v[2].bgcolor == gtblConstants.Red then
return false
end
end
-- Values are all 4 digit numeric or they would be red so they can be compared as strings
local bBlank = false
for i, v in pairs(tblYearsFromTo) do -- Check all pairs are valid, nothing after first blank
if bBlank and v[1].value ~= '' then
tblYearsFromTo[i-1][2].bgcolor = gtblConstants.Red
return false
end
if v[2].value ~= '' then
if v[1].value == '' or v[1].value > v[2].value then
v[2].bgcolor = gtblConstants.Red
return false
end
else
bBlank = true
end
if v[1].value ~= '' and i > 1 and tonumber(v[1].value) <= tonumber(tblYearsFromTo[i-1][2].value) + 1 then
v[1].bgcolor = gtblConstants.Red -- Ranges must be in order with a gap (contiguous ranges must be merged)
return false
end
end
return true
end
function btnSaveYears:action()
if listGROPlaces.value == '0' then
return
end
if not ValidateYears() then
OkOnlyMessage(dialogGRODistricts.title, 'Years District Active are invalid',
'ERROR', dialogGRODistricts)
iup.SetFocus(tblYears[1])
return
end
local SaveGROSelection = listGROPlaces.value
local strYears = ''
for _, v in pairs(tblYearsFromTo) do
if v[1].value ~= '' then
strYears = strYears .. v[1].value .. '-' .. v[2].value .. ','
end
end
strYears = strYears:gsub(',$', '')
local ptrPlace = fhNewItemPtr()
ptrPlace:MoveToRecordById('_PLAC', tblGROPlaces[tonumber(listGROPlaces.value)][3])
local ptrNote = fhGetItemPtr(ptrPlace, '~.NOTE2')
while ptrNote:IsNotNull() do
local strNote = fhGetItemText(ptrNote,'~')
if strNote:match('GRO District') then
break
end
ptrNote:MoveNext('SAME_TAG')
end
if ptrNote:IsNull() then
error('GRO District note note found')
end
if not fhSetValueAsText(ptrNote, 'GRO District\nYears: ' .. strYears) then
error ('Adding GRO District Note')
end
tblGROPlaces[tonumber(listGROPlaces.value)][2] = strYears
PopulateListFromtblGROPlaces(listGROPlaces)
listGROPlaces.value = SaveGROSelection
btnSaveYears.active = 'NO'
OkOnlyMessage(dialogGRODistricts.title, fhGetDisplayText(ptrPlace) .. '\n\nYears Active saved',
'INFORMATION', dialogGRODistricts)
end
local frameEditDistrict = iup.frame{
iup.vbox{
iup.frame{
iup.vbox{
iup.hbox{iup.label{title = 'Select GRO District'}, iup.fill{}; margin = '0x0'},
listGROPlaces,
iup.hbox{iup.fill{}, btnRemove; margin = '0x4'},
iup.frame{
iup.vbox{
gridYears,
iup.hbox{
iup.fill{},
iup.label{title = 'Leave final "To" blank \nif District still active', fontstyle = 'Italic'},
iup.fill{},
btnSaveYears;
cmargin = '8x0', expand = 'YES'
};
margin = '6x2', expand = 'NO', cgap = '4'
},
title = 'Years District Active (optional)'
};
alignment = 'ACENTER', gap = '2'
},
margin = '10x2', sunken = 'YES'
};
margin = '4x2', fontstyle = ''
};
title = 'Edit GRO District', fontstyle = 'Bold'
}
local btnClose = iup.button{
title = 'Close', padding = '10x3',
action = function() return iup.CLOSE end
}
local hboxFooter = iup.hbox{
iup.fill{}, btnClose, iup.fill{};
normalizesize = 'BOTH', margin = '0x5', gap = 40
}
dialogGRODistricts = iup.dialog{
iup.vbox{frameAddDistrict, frameEditDistrict, hboxFooter; margin = '15x5', gap = 5};
resize = 'No', minbox = 'No', maxbox = 'No',
title = 'GRO Districts',
defaultesc = btnClose,
PARENTDIALOG = ParentDialog
}
dialogGRODistricts:popup(iup.CENTERPARENT, iup.CENTERPARENT)
local SaveGROListSelection = listGROPlaces.value
dialogGRODistricts:destroy()
return SaveGROListSelection
end
--======================================================================================================================
function PopulateListFromtblGROPlaces(List) -- Populate an iuplist from GROPlaces
List['1'] = nil -- Empty the list
for i,v in pairs(tblGROPlaces) do
if v[2] ~= '' then
List[tostring(i)] = v[1] .. ' [' .. v[2] .. ']'
else
List[tostring(i)] = v[1]
end
end
end
--======================================================================================================================
function Initialise() -- Create global variables and fetch/set default settings
gPluginName = fhGetContextInfo('CI_PLUGIN_NAME'):gsub(' %(.*', '') -- Without a dev/test version in brackets
-- Set parameter types for processing configuration file
gtblSettingsTypeBoolean = {
['QtrMonthNames'] = true, ['UCRefs'] = true, ['ShortPlaces'] = true, --['IncNameInCitation'] = true,
['CitationNameBirth'] = true, ['CitationNameMarriage'] = true, ['CitationNameDeath'] = true,
['CitationToMotherDefault'] = true, ['UseGRODistricts'] = true
}
GetSettings()
if gtblSettings.VersionCheckInterval ~= 0 and gtblSettings.VersionNextCheck <= os.date('%Y-%m-%d') then
local bOK, strMsg = VersionCheck()
if not bOK then
strMsg = 'Check for plugin update failed\n\n' .. strMsg
.. '\n\nPostpone checking for a day?'
if MessageBox (gPluginName, strMsg, 'YESNO', 'WARNING') == 1 then
gtblSettings.VersionNextCheck = DateAdd(os.date('%Y-%m-%d'), 1)
SaveSettings()
end
else
while gtblSettings.VersionNextCheck <= os.date('%Y-%m-%d') do
gtblSettings.VersionNextCheck = DateAdd(gtblSettings.VersionNextCheck, gtblSettings.VersionCheckInterval)
end
gtblSettings.VersionCheckedDate = os.date('%Y-%m-%d')
SaveSettings()
end
end
gtblConstants = {}
gtblConstants.Periods = {'Q1';'Q2';'Q3';'Q4';'Jan';'Feb';'Mar';'Apr';'May';'Jun';'Jul';'Aug';'Sep';'Oct';'Nov';'Dec';}
gtblConstants.PeriodsLong = {'Q1 Jan-Feb-Mar';'Q2 Apr-May-Jun';'Q3 Jul-Aug-Sep';'Q4 Oct-Nov-Dec';
'January';'February';'March';'April';'May';'June';
'July';'August';'September';'October';'November';'December';}
gtblConstants.CurrYear = fhCallBuiltInFunction('today'):GetYear()
gtblConstants.CitationAssess = {'None', 'Unreliable', 'Questionable', 'Secondary Evidence', 'Primary Evidence'}
gtblConstants.White = '255 255 255'
gtblConstants.Red = '255 31 31'
gtblConstants.Blue = '0 0 255'
gtblConstants.Yellow = '255 255 0'
gtblConstants.PaleYellow = '255 255 127'
gtblConstants.VersionCheckFrequency = {['0']= 0, ['1']=1, ['2']=7, ['3']=14, ['4']=28 }
tblPlaces = {}
tblGROPlaces = {}
local ptrPlace = fhNewItemPtr()
local ptrNote = fhNewItemPtr()
ptrPlace:MoveToFirstRecord('_PLAC')
while ptrPlace:IsNotNull() do
table.insert(tblPlaces,{fhGetDisplayText(ptrPlace), fhGetRecordId(ptrPlace)})
local ptrNote = fhGetItemPtr(ptrPlace, '~.NOTE2')
while ptrNote:IsNotNull() do
local strNote = fhGetItemText(ptrNote,'~')
if strNote:match('GRO District') then
table.insert(tblGROPlaces,{fhGetDisplayText(ptrPlace),
strNote:match('Years:%s*(.*)$') or '',
fhGetRecordId(ptrPlace)})
break
end
ptrNote:MoveNext('SAME_TAG')
end
ptrPlace:MoveNext()
end
table.sort(tblPlaces, function(k1, k2) return k1[1] < k2[1] end)
if gtblSettings.UseGRODistricts then
table.sort(tblGROPlaces, function(k1, k2) return k1[1] < k2[1] end)
end
gtblData = {} -- Data for the main dialog - source being cited, the event and the records selected
gtblData.ptr = fhNewItemPtr()
end -- function Initialise
------------------------------------------------------------------------------------------------------------------------
function GetSettings() -- Read settings from file in Plugin Data - create default if it doesn't exist
gtblSettings = {}
local SettingsFile = fhGetContextInfo('CI_PROJECT_DATA_FOLDER') .. '\\Plugin Data\\'
.. gPluginName .. '.ini'
if not fhfu.fileExists(SettingsFile) then
DefaultSettings()
SaveSettings()
return
end
local strData = fhLoadTextFile(SettingsFile)
for strLine in strData:gmatch('[^\r\n]+') do
local Parameter, Value = strLine:match('^(%w+)=([%g%s]*)$')
if gtblSettingsTypeBoolean[Parameter] then
if Value == 'N' then
gtblSettings[Parameter] = false
else
gtblSettings[Parameter] = true
end
else
if not Value:find('^-?%d+$') or Value == '' then -- Not integer starting with optional - sign?
gtblSettings[Parameter] = Value
else
gtblSettings[Parameter] = tonumber(Value)
end
end
end
-- Check for new settings not in current ini file
if DefaultSettings() then
SaveSettings()
end
if gtblSettings.Version ~= Version then
-- Place to do any conversions for new version
gtblSettings.Version = Version
SaveSettings()
end
end -- function GetSettings
------------------------------------------------------------------------------------------------------------------------
function SaveSettings() -- Save settings to file in Plugin Data
local SettingsFolder = fhGetContextInfo('CI_PROJECT_DATA_FOLDER') .. '\\Plugin Data'
if not fhfu.folderExists(SettingsFolder) then
fhfu.createFolder(SettingsFolder)
end
local SettingsFile = SettingsFolder .. '\\' .. gPluginName .. '.ini'
-- Build table of lines to go in the settings file
local tblLines = {}
for Parameter, Value in pairs(gtblSettings) do
if gtblSettingsTypeBoolean[Parameter] then
local str = 'N'
if Value then
str = 'Y'
end
table.insert(tblLines, Parameter .. '=' .. str)
elseif type(Value) ~= 'number' then -- Any non-numeric characters?
table.insert(tblLines, Parameter .. '=' .. Value)
else -- must be a number
table.insert(tblLines, Parameter .. '=' .. tostring(Value))
end
end
-- Prepare ini file with lines sorted alphabetically
table.sort(tblLines)
local str = ''
for _, line in ipairs(tblLines) do
str = str .. line .. '\n'
end
fhSaveTextFile(SettingsFile, str)
end -- function SaveSettings
------------------------------------------------------------------------------------------------------------------------
function DefaultSettings() -- Default settings for first run or if new settings parameter(s) introduced
local Changes = false
-- Sources
if gtblSettings.SourceIdBirth == nil then
gtblSettings.SourceIdBirth = 0
Changes = true
end
if gtblSettings.SourceIdMarriage == nil then
gtblSettings.SourceIdMarriage = 0
Changes = true
end
if gtblSettings.SourceIdDeath == nil then
gtblSettings.SourceIdDeath = 0
Changes = true
end
-- Citation text labels
if gtblSettings.LabelPrefixBirth == nil then
gtblSettings.LabelPrefixBirth = 'Birth^'
Changes = true
end
if gtblSettings.LabelPrefixMarriage == nil then
gtblSettings.LabelPrefixMarriage = 'Marriage^'
Changes = true
end
if gtblSettings.LabelPrefixDeath == nil then
gtblSettings.LabelPrefixDeath = 'Death^'
Changes = true
end
-- GRO Reference Labels
if gtblSettings.LabelDistrictName == nil then
gtblSettings.LabelDistrictName = ''
Changes = true
end
if gtblSettings.LabelVolume == nil then
gtblSettings.LabelVolume = 'Vol:^'
Changes = true
end
if gtblSettings.LabelPage == nil then
gtblSettings.LabelPage = 'Page:^'
Changes = true
end
if gtblSettings.LabelDistrictNo == nil then
gtblSettings.LabelDistrictNo = 'District:^'
Changes = true
end
if gtblSettings.LabelRegister == nil then
gtblSettings.LabelRegister = 'Reg:^'
Changes = true
end
if gtblSettings.LabelEntry == nil then
gtblSettings.LabelEntry = 'Entry:^'
Changes = true
end
-- Event Specific Labels
if gtblSettings.LabelMother == nil then
gtblSettings.LabelMother = 'Mother\'s Maiden Surname:^'
Changes = true
end
if gtblSettings.LabelAge == nil then
gtblSettings.LabelAge = 'Age:^'
Changes = true
end
if gtblSettings.LabelDOB == nil then
gtblSettings.LabelDOB = 'DOB:^'
Changes = true
end
-- Options
if gtblSettings.QtrMonthNames == nil then -- Full or abrieviated month names in citation text
gtblSettings.QtrMonthNames = false
Changes = true
end
if gtblSettings.UCRefs == nil then -- Make alpha characters in reference upper case
gtblSettings.UCRefs = false
Changes = true
end
if gtblSettings.ShortPlaces == nil then -- District name only in citation text
gtblSettings.ShortPlaces = true
Changes = true
end
if gtblSettings.IncNameInCitation == nil then -- Name(s) to be included in citation text
gtblSettings.IncNameInCitation = 'ON'
Changes = true
end
if gtblSettings.NameFormat == nil then -- Format of Names
gtblSettings.NameFormat = 3 -- Given Surname (as entered in FH)
Changes = true
end
if gtblSettings.CitationNameBirth == nil then -- Add citation to Name for Birth
gtblSettings.CitationNameBirth = true
Changes = true
end
if gtblSettings.CitationNameMarriage == nil then -- Add citation to Name for Marriage
gtblSettings.CitationNameMarriage = false
Changes = true
end
if gtblSettings.CitationNameDeath == nil then -- Add citation to Name for Death
gtblSettings.CitationNameDeath = true
Changes = true
end
if gtblSettings.CitationToMotherDefault == nil then -- Add birth citation to Mother's name
gtblSettings.CitationToMotherDefault = false
Changes = true
end
if gtblSettings.NewMotherGivenName == nil then -- Given name to use for new mother's when recording a birth
gtblSettings.NewMotherGivenName = ''
Changes = true
end
if gtblSettings.CitationEntryDate == nil then -- Date to record in Citation Specific Date
gtblSettings.CitationEntryDate = 1 -- "No Date"
Changes = true
end
if gtblSettings.CitationAssess == nil then -- Default citation assessment
gtblSettings.CitationAssess = 1 -- "None"
Changes = true
end
if gtblSettings.UseGRODistricts == nil then -- Use places marked as GRO districts
gtblSettings.UseGRODistricts = false
Changes = true
end
-- Main dialog screen position
if gtblSettings.ScreenPosX == nil then
gtblSettings.ScreenPosX = iup.CENTERPARENT
Changes = true
end
if gtblSettings.ScreenPosY == nil then
gtblSettings.ScreenPosY = iup.CENTERPARENT
Changes = true
end
-- Version Control
if gtblSettings.Version == nil then
gtblSettings.Version = Version
gtblSettings.VersionCheckedDate = '2000-01-01'
gtblSettings.VersionNextCheck = os.date('%Y-%m-%d') -- Force check on first run
gtblSettings.VersionCheckInterval = 7
Changes = true
end
return Changes
end -- function DefaultSettings
--======================================================================================================================
function VersionCheck(dialogParent)
local dialogChecking = iup.dialog{
iup.label{title = 'Checking for update...', padding = '40x16'},
title = gPluginName,
dialogframe = 'Yes', menubox = 'No', parentdialog = dialogParent
}
dialogChecking:showxy(iup.CENTERPARENT, iup.CENTERPARENT)
fhUpdateDisplay()
local function httpRequest(strRequest)
local http = luacom.CreateObject("winhttp.winhttprequest.5.1")
http:Open("GET",strRequest,false)
http:Send()
return http.Responsebody
end -- local function httpRequest
local strRequest ='http://www.family-historian.co.uk/lnk/checkpluginversion.php?name=' .. gPluginName
local isOK, strReturn = pcall(httpRequest,strRequest)
local StoreVersion = ''
dialogChecking:destroy()
if not isOK then
return false, 'Call to plugin store to check latest version failed'
-- Do nothing - will check again after today
else
if strReturn ~= nil then
StoreVersion = strReturn:match('([%d%.]*),') -- Version digits & dots then comma
else
return false, 'nil return from plugin store'
end
end
local Latest
if StoreVersion > Version then
local strMsg = 'A later version of this plugin is available\nfrom the Family Historian Plugin Store\n\n'
.. 'Current version: ' .. Version ..'\n'
.. 'Store version: ' .. StoreVersion ..'\n\n'
.. 'Go to ' .. gPluginName .. '\non the Plugin Store?'
if MessageBox('Plugin update available', strMsg, 'YESNO', 'INFORMATION', 1, dialogParent) == 1 then
fhShellExecute('https://pluginstore.family-historian.co.uk/page/plugin/gro-bmd-index-citations')
end
Latest = 'N'
else
Latest = 'Y'
end
return true, Latest
end
------------------------------------------------------------------------------------------------------------------------
function DateAdd(Date, Days)
local tblDate =YMDtoTable(Date)
SecondsToAdd = Days * 24 * 60 * 60
return os.date('%Y-%m-%d', os.time(tblDate) + SecondsToAdd)
end
function YMDtoTable(Date)
local tblDate = {}
tblDate.year = tonumber(Date:sub(1,4))
tblDate.month = tonumber(Date:sub(6,7))
tblDate.day = tonumber(Date:sub(9,10))
return tblDate
end
-- ============================================ General purpose routines -- ============================================
function Capitalise(str) -- Make string title capitalised (1st letter each word capital, rest lower)
str = str:gsub('(%a)([%w_]*)', UpperFirst)
return str
end
function UpperFirst(first, rest)
return first:upper() .. rest:lower()
end
------------------------------------------------------------------------------------------------------------------------
function Replace(strTxt,strOld,strNew,intNum) -- replace is plain text version of gsub() - function courtesy of Mike Tate
local strMagic = "([%^%$%(%)%%%.%[%]%*%+%-%?])" -- UTF-8 replacement for "(%W)"
strOld = tostring(strOld or ""):gsub(strMagic,"%%%1") -- Hide magic pattern symbols
return tostring(strTxt or ""):gsub(strOld,function() return strNew end,tonumber(intNum))
end -- function Replace
------------------------------------------------------------------------------------------------------------------------
function OkOnlyMessage(strTitle, strMessage, strDialogType, ParentDialog) -- Display a message with only an OK button
-- strDialogType: "MESSAGE" (No Icon), "ERROR" (Stop-sign), "WARNING" (Exclamation-point), "QUESTION" (Question-mark) or "INFORMATION" (Letter "i").
MessageBox(strTitle, strMessage, 'OK', strDialogType, 1, ParentDialog)
end -- function OkOnlyMessage
--[[====================================================================================================================
Replacement for iup.messagedlg
Call: MessageBox(strTitle, strMessage, strButtons, strDialogType, strDefault, ParentDialog)
strButtons 'OK', 'OKCANCEL', 'RETRYCANCEL', 'YESNO', or 'YESNOCANCEL'
strDialogType: 'MESSAGE' (No Icon) (default)
'ERROR' (Stop-sign)
'WARNING' (Exclamation-point)
'QUESTION' (Question-mark)
'INFORMATION' (Letter 'i')
strDefault; Number of the default button, if omitted defaults to 1
ParentDialog: If called from within an iup dialog this should be the handle of the dialog. If not given
the message box will not centre on the parent dialog
Omit if not called from another dialog
Returns: Number of the button pressed
If Esc keyed or close button (X) is keyed it returns number of the last button (same as iup.messagedlg)
Example:
dialogExample = iup.dialog{...}
...
Response = MessageBox('Demo Title', 'Hello World', 'OKCANCEL', 'QUESTION', dialogExample)
----------------------------------------------------------------------------------------------------------------------]]
function MessageBox(strTitle, strMessage, strButtons, strDialogType, strDefault, ParentDialog)
local MaxLineLength = 80 -- Maximum characters per line used for word wrapping
function create_image_Information()
local Information = iup.image{
width = 32,
height = 32,
pixels = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,5,5,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,3,6,7,8,9,10,11,11,10,9,8,7,6,3,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,12,6,13,14,11,11,11,11,11,11,11,11,11,11,14,13,6,12,0,0,0,0,0,0,0,
0,0,0,0,0,1,3,15,9,11,11,11,11,11,11,11,11,11,11,11,11,11,11,9,15,3,1,0,0,0,0,0,
0,0,0,0,1,16,7,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,7,16,1,0,0,0,0,
0,0,0,0,3,7,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,7,3,0,0,0,0,
0,0,0,12,15,10,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,10,15,12,0,0,0,
0,0,1,6,9,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,9,6,1,0,0,
0,0,3,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13,3,0,0,
0,1,6,14,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,14,6,1,0,
0,2,7,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,7,2,0,
0,3,8,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,8,3,0,
0,4,9,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,9,4,0,
0,5,10,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,10,5,0,
0,5,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,5,0,
0,5,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,5,0,
0,5,10,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,10,5,0,
0,4,9,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,9,4,0,
0,3,8,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,8,3,0,
0,2,7,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,7,2,0,
0,1,6,14,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,14,6,1,0,
0,0,3,13,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,13,3,0,0,
0,0,1,6,9,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,9,6,1,0,0,
0,0,0,12,15,10,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,10,15,12,0,0,0,
0,0,0,0,3,7,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,7,3,0,0,0,0,
0,0,0,0,1,16,7,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,7,16,1,0,0,0,0,
0,0,0,0,0,1,3,15,9,11,11,11,11,11,11,11,11,11,11,11,11,11,11,9,15,3,1,0,0,0,0,0,
0,0,0,0,0,0,0,12,6,13,14,11,11,11,11,11,11,11,11,11,11,14,13,6,12,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,3,6,7,8,9,10,11,11,10,9,8,7,6,3,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,5,5,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
},
colors = {
'255 255 255', '239 243 247', '159 188 211', '96 144 183', '64 122 168',
'0 78 140', '16 89 147', '0 86 154', '0 99 178', '0 110 196',
'0 117 210', '0 120 215', '143 177 204', '0 94 168', '0 115 206',
'0 83 149', '48 111 161'
}
}
return Information
end
function create_image_Warning()
local Warning = iup.image{width = 32, height = 32,
pixels = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,6,6,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,6,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,1,3,6,6,6,6,3,1,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,6,6,6,4,2,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,1,3,6,6,6,6,6,6,3,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,2,4,6,6,6,6,6,6,4,2,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,3,6,6,6,6,6,6,6,6,3,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,2,4,6,6,6,6,6,6,6,6,4,2,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,1,3,6,6,6,6,7,7,6,6,6,6,3,1,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,2,4,6,6,6,6,7,7,6,6,6,6,4,2,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,3,6,6,6,6,6,7,7,6,6,6,6,6,3,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,2,4,6,6,6,6,6,7,7,6,6,6,6,6,4,2,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,3,6,6,6,6,6,6,7,7,6,6,6,6,6,6,3,1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,2,4,6,6,6,6,6,6,7,7,6,6,6,6,6,6,4,2,0,0,0,0,0,0,0,
0,0,0,0,0,0,1,3,6,6,6,6,6,6,6,7,7,6,6,6,6,6,6,6,3,1,0,0,0,0,0,0,
0,0,0,0,0,0,2,4,6,6,6,6,6,6,6,7,7,6,6,6,6,6,6,6,4,2,0,0,0,0,0,0,
0,0,0,0,0,1,3,6,6,6,6,6,6,6,6,7,7,6,6,6,6,6,6,6,6,3,1,0,0,0,0,0,
0,0,0,0,0,2,4,6,6,6,6,6,6,6,6,7,7,6,6,6,6,6,6,6,6,4,2,0,0,0,0,0,
0,0,0,0,1,3,6,6,6,6,6,6,6,6,6,7,7,6,6,6,6,6,6,6,6,6,3,1,0,0,0,0,
0,0,0,0,2,4,6,6,6,6,6,6,6,6,6,7,7,6,6,6,6,6,6,6,6,6,4,2,0,0,0,0,
0,0,0,1,3,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,3,1,0,0,0,
0,0,0,2,4,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,4,2,0,0,0,
0,0,1,3,6,6,6,6,6,6,6,6,6,6,6,7,7,6,6,6,6,6,6,6,6,6,6,6,3,1,0,0,
0,0,2,4,6,6,6,6,6,6,6,6,6,6,6,7,7,6,6,6,6,6,6,6,6,6,6,6,4,2,0,0,
0,1,3,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,3,1,0,
0,2,4,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,4,2,0,
1,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,3,1,
2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2
},
colors = {
'255 255 255', '255 228 159', '255 193 32', '255 188 0', '254 205 0',
'253 213 0', '252 225 0', '0 0 0'
}
}
return Warning
end
function create_image_Error()
local Error = iup.image{
width = 32,
height = 32,
pixels = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,5,5,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,3,6,7,8,9,10,11,11,10,9,8,7,6,3,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,12,6,13,14,11,11,11,11,11,11,11,11,11,11,14,13,6,12,0,0,0,0,0,0,0,
0,0,0,0,0,1,3,15,9,11,11,11,11,11,11,11,11,11,11,11,11,11,11,9,15,3,1,0,0,0,0,0,
0,0,0,0,1,16,7,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,7,16,1,0,0,0,0,
0,0,0,0,3,7,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,7,3,0,0,0,0,
0,0,0,12,15,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,15,12,0,0,0,
0,0,1,6,9,11,11,11,17,18,19,11,11,11,11,11,11,11,11,11,11,19,18,17,11,11,11,9,6,1,0,0,
0,0,3,13,11,11,11,11,18,0,20,19,11,11,11,11,11,11,11,11,19,20,0,18,11,11,11,11,13,3,0,0,
0,1,6,14,11,11,11,11,19,20,0,20,19,11,11,11,11,11,11,19,20,0,20,19,11,11,11,11,14,6,1,0,
0,2,7,11,11,11,11,11,11,19,20,0,20,19,11,11,11,11,19,20,0,20,19,11,11,11,11,11,11,7,2,0,
0,3,8,11,11,11,11,11,11,11,19,20,0,20,19,11,11,19,20,0,20,19,11,11,11,11,11,11,11,8,3,0,
0,4,9,11,11,11,11,11,11,11,11,19,20,0,20,19,19,20,0,20,19,11,11,11,11,11,11,11,11,9,4,0,
0,5,10,11,11,11,11,11,11,11,11,11,19,20,0,20,20,0,20,19,11,11,11,11,11,11,11,11,11,10,5,0,
0,5,11,11,11,11,11,11,11,11,11,11,11,19,20,0,0,20,19,11,11,11,11,11,11,11,11,11,11,11,5,0,
0,5,11,11,11,11,11,11,11,11,11,11,11,19,20,0,0,20,19,11,11,11,11,11,11,11,11,11,11,11,5,0,
0,5,10,11,11,11,11,11,11,11,11,11,19,20,0,20,20,0,20,19,11,11,11,11,11,11,11,11,11,10,5,0,
0,4,9,11,11,11,11,11,11,11,11,19,20,0,20,19,19,20,0,20,19,11,11,11,11,11,11,11,11,9,4,0,
0,3,8,11,11,11,11,11,11,11,19,20,0,20,19,11,11,19,20,0,20,19,11,11,11,11,11,11,11,8,3,0,
0,2,7,11,11,11,11,11,11,19,20,0,20,19,11,11,11,11,19,20,0,20,19,11,11,11,11,11,11,7,2,0,
0,1,6,14,11,11,11,11,19,20,0,20,19,11,11,11,11,11,11,19,20,0,20,19,11,11,11,11,14,6,1,0,
0,0,3,13,11,11,11,11,18,0,20,19,11,11,11,11,11,11,11,11,19,20,0,18,11,11,11,11,13,3,0,0,
0,0,1,6,9,11,11,11,17,18,19,11,11,11,11,11,11,11,11,11,11,19,18,17,11,11,11,9,6,1,0,0,
0,0,0,12,15,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,15,12,0,0,0,
0,0,0,0,3,7,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,7,3,0,0,0,0,
0,0,0,0,1,16,7,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,7,16,1,0,0,0,0,
0,0,0,0,0,1,3,15,9,11,11,11,11,11,11,11,11,11,11,11,11,11,11,9,15,3,1,0,0,0,0,0,
0,0,0,0,0,0,0,12,6,13,14,11,11,11,11,11,11,11,11,11,11,14,13,6,12,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,1,3,6,7,8,9,10,11,11,10,9,8,7,6,3,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,5,5,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
},
colors = {
'255 255 255', '249 241 240', '221 173 166', '198 119 107', '187 92 78',
'165 39 20', '170 51 34', '179 42 20', '203 48 20', '221 53 22',
'235 57 22', '240 58 22', '215 159 151', '193 47 20', '231 55 22',
'174 40 20', '181 78 63', '241 70 39', '251 206 197', '243 95 67',
'254 243 241'
}
}
return Error
end
function create_image_Question()
local Question = iup.image{
width = 32,
height = 32,
pixels = {
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,7,14,6,13,12,12,12,12,13,6,14,7,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,7,6,9,4,10,5,1,0,0,1,5,10,4,9,6,7,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,11,9,8,2,0,0,0,0,0,0,0,0,0,0,2,8,9,11,3,3,3,3,3,3,3,
3,3,3,3,3,7,6,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,1,5,4,6,7,3,3,3,3,3,
3,3,3,3,7,13,4,1,0,0,0,0,0,0,0,2,5,5,2,0,0,0,0,0,2,4,13,7,3,3,3,3,
3,3,3,3,6,4,1,0,0,0,0,0,2,8,9,6,11,11,6,4,5,0,0,1,1,2,4,6,3,3,3,3,
3,3,3,11,4,1,0,0,0,0,0,5,13,15,3,3,3,3,3,7,13,5,1,1,1,1,2,4,11,3,3,3,
3,3,7,9,5,0,0,0,0,0,0,5,11,3,7,14,11,15,3,3,7,9,1,1,1,1,1,5,9,7,3,3,
3,3,6,8,0,0,0,0,0,0,0,5,11,14,9,10,5,10,6,3,3,6,5,1,1,1,1,1,8,6,3,3,
3,7,9,2,0,0,0,0,0,0,0,5,9,8,0,0,0,1,10,15,3,15,10,1,1,1,1,1,5,9,7,3,
3,14,4,0,0,0,0,0,0,0,0,5,8,0,0,0,0,0,10,15,3,15,10,1,1,1,1,1,1,4,14,3,
3,6,10,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,4,7,3,11,5,1,1,1,1,1,2,10,6,3,
3,13,5,0,0,0,0,0,0,0,0,0,0,0,0,0,1,10,6,3,3,9,2,1,1,1,1,1,2,5,13,3,
3,12,1,0,0,0,0,0,0,0,0,1,0,1,0,0,10,6,3,3,11,10,1,1,1,1,1,2,2,2,12,3,
3,12,0,0,0,0,0,0,0,0,0,0,0,0,1,10,6,3,3,14,8,1,1,1,1,1,2,2,2,2,12,3,
3,12,0,0,0,0,0,0,0,0,1,0,0,1,5,6,3,3,14,8,2,1,1,1,1,2,2,2,2,2,12,3,
3,12,1,0,0,0,0,0,0,1,0,0,1,1,8,7,3,14,8,1,1,1,1,1,2,2,2,2,2,2,12,3,
3,13,5,0,0,0,0,0,0,0,0,1,1,0,4,3,3,13,2,1,1,1,1,2,2,2,2,2,2,5,13,3,
3,6,10,0,0,0,0,0,1,0,1,1,1,1,4,3,3,4,1,1,1,1,2,2,2,2,2,2,2,10,6,3,
3,14,4,0,1,0,1,0,0,1,1,1,1,1,8,3,3,4,1,1,1,2,2,2,2,2,2,2,2,4,14,3,
3,7,9,2,0,0,0,0,1,0,1,1,1,1,4,4,4,8,1,1,2,2,2,2,2,2,2,2,5,9,7,3,
3,3,6,8,0,0,0,1,1,1,1,1,1,1,10,4,4,8,1,2,2,2,2,2,2,2,2,2,8,6,3,3,
3,3,7,9,5,0,1,0,1,1,1,1,1,1,4,3,3,4,2,2,2,2,2,2,2,2,2,5,9,7,3,3,
3,3,3,11,4,2,1,1,1,1,1,1,1,1,4,3,3,4,2,2,2,2,2,2,2,2,5,4,11,3,3,3,
3,3,3,3,6,4,2,1,1,1,1,1,1,1,8,4,4,8,2,2,2,2,2,2,2,2,4,6,3,3,3,3,
3,3,3,3,7,13,4,2,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,5,4,13,7,3,3,3,3,
3,3,3,3,3,7,6,4,5,1,1,1,1,1,2,2,2,2,2,2,2,2,2,5,4,6,7,3,3,3,3,3,
3,3,3,3,3,3,3,11,9,8,5,1,1,2,2,2,2,2,2,2,2,5,8,9,11,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,7,6,9,4,10,5,2,2,2,2,5,10,4,9,6,7,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,7,14,6,13,12,12,12,12,13,6,14,7,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
},
colors = {
'0 110 202', '0 106 199', '0 103 197', '255 255 255', '9 75 132',
'0 97 181', '102 138 167', '238 242 246', '6 83 147', '26 82 126',
'6 88 159', '142 168 190', '9 69 115', '63 110 147', '166 187 205',
'199 212 223'
}
}
return Question
end
-- function textwrap takes a string of text which can incude line breaks and returns a string with long lines split if needed
function textwrap(strText, maxchars)
-- Split string in to an array
local arrLines = {}
strText = strText .. '\n'
strText:gsub('(.-)\n', function(strLine) arrLines[#arrLines+1] = strLine end)
-- Split long lines
local i = 1
repeat
if #arrLines[i] > maxchars + 1 then -- Each line has \n at the end so new line after maxlen is OK
--splitpos = maxchars
local splitpos = arrLines[i]:sub(1,maxchars):find('[%s][^%s]*$') or maxchars
local strRest = arrLines[i]:sub(splitpos +1):gsub('^(%s*)','')
table.insert(arrLines, i + 1, strRest)
arrLines[i] = arrLines[i]:sub(1,splitpos)
end
i = i + 1
until i > #arrLines
-- Make string from the array
local str = ''
for _, line in ipairs(arrLines) do
str = str .. line .. '\n'
end
return str:sub(1,-2)
end
strMessage = textwrap(strMessage, MaxLineLength)
strMessage = strMessage:gsub('&', '&&')
strButtons = tostring(strButtons):upper()
strDialogType = tostring(strDialogType):upper()
if type(strDefault) == 'nil' then
intDefault = 1
elseif type(strDefault) == 'number' then
intDefault = strDefault
elseif type(strDefault) == 'string' then
if strDefault:match("%D+") then
error('Invalid strDefault: "' .. strDefault .. '"\n')
else
intDefault = tonumber(strDefault)
end
else
error('Invalid strDefault: "' .. type(strDefault) .. '"\n')
end
local selection
local lblMessage = iup.flatlabel{title = strMessage, padding = '4x0', textwrap = 'NO',
expand = 'VERTICAL'}
local hboxMessage
if strDialogType == 'MESSAGE' then
hboxMessage = iup.hbox{}
else
if strDialogType == 'ERROR' then
hboxMessage = iup.hbox{iup.label{image = create_image_Error()}}
elseif strDialogType == 'WARNING' then
hboxMessage = iup.hbox{iup.label{image = create_image_Warning()}}
elseif strDialogType == 'QUESTION' then
hboxMessage = iup.hbox{iup.label{image = create_image_Question()}}
elseif strDialogType == 'INFORMATION' then
hboxMessage = iup.hbox{iup.label{image = create_image_Information()}}
else
error('Invalid strDialogType Setting\n')
end
hboxMessage:append(iup.space{size = '8x0'})
end
hboxMessage:append(lblMessage)
hboxMessage:append(iup.fill{}) -- Needed to pad box if short message
hboxMessage.padding = '0x2'
hboxMessage.expand = 'VERTICAL'
hboxMessage.cmargin = '16x8'
function Button(Value)
return iup.button{title = ' ', size = '48x0',
action = function(self) selection = Value return iup.CLOSE end }
end
local Button1 = Button(1)
local Button2 = Button(2)
local Button3 = Button(3)
local hboxButtons
if strButtons == 'OK' then
Button1.title = 'OK'
hboxButtons = iup.hbox{Button1;}
elseif strButtons == 'OKCANCEL' then
Button1.title = 'OK'
Button2.title = 'Cancel'
hboxButtons = iup.hbox{Button1, Button2;}
elseif strButtons == 'RETRYCANCEL' then
Button1.title = 'Retry'
Button2.title = 'Cancel'
hboxButtons = iup.hbox{Button1, Button2;}
elseif strButtons == 'YESNO' then
Button1.title = 'Yes'
Button2.title = 'No'
hboxButtons = iup.hbox{Button1, Button2;}
elseif strButtons == 'YESNOCANCEL' then
Button1.title = 'Yes'
Button2.title = 'No'
Button3.title = 'Cancel'
hboxButtons = iup.hbox{Button1, Button2, Button3;}
else
error('Invalid strButtons setting: "' ..strButtons .. '"\n')
end
local ButtonCount = iup.GetChildCount(hboxButtons)
if intDefault > ButtonCount then
error ('Invalid default button: "'.. intDefault .. '\n')
end
hboxButtons:insert(nil, iup.fill{})
-- hboxButtons:append(iup.fill{}) -- Activate this line to makes buttons centered rather than right aligned
hboxButtons.gap = 6
hboxButtons.margin = '12x10'
local dialogMessage = iup.dialog{
iup.vbox{iup.flatframe{hboxMessage; framecolor = '255 255 255', bgcolor = '255 255 255'}, hboxButtons};
title = strTitle, dialogframe = 'Yes'
}
if intDefault == 2 then
dialogMessage.startfocus = Button2
elseif intDefault == 3 then
dialogMessage.startfocus = Button3
end
if ButtonCount == 1 then
dialogMessage.defaultesc = Button1
elseif ButtonCount == 2 then
dialogMessage.defaultesc = Button2
else
dialogMessage.defaultesc = Button3
end
if ParentDialog ~= nil then
dialogMessage.PARENTDIALOG = ParentDialog
end
selection = ButtonCount -- Default if dialog closed without clicking a button
dialogMessage:popup(IUP_CENTERPARENT, IUP_CENTERPARENT)
dialogMessage:destroy()
return tonumber(selection)
end -- function MessageBox
--======================================================================================================================
--[[ =============== Debugging utilities ===============]]
function dumpstr (tt, label,indent, done, str)
local t = {}
if label == nil then
label = 'Dump'
end
done = done or {}
indent = indent or 0
if type(tt) == 'table' then
if indent == 0 then
table.insert(t,string.rep (' ', indent))
table.insert(t,label..'\n')
end
for key, value in pairs (tt) do
table.insert(t,string.rep (' ', indent)) -- indent it
if type (value) == 'table' and not done [value] then
done [value] = true
table.insert(t,string.format('[%s] => table\n', tostring (key)));
table.insert(t,string.rep (' ', indent+4)) -- indent it
table.insert(t,'(\n');
table.insert(t,dumpstr (value, tostring(key),indent + 7, done, str))
table.insert(t,string.rep (' ', indent+4)) -- indent it
table.insert(t,')\n');
else
table.insert(t,string.format('[%s] => %s\n',
tostring (key), tostring(value)))
end
end
else
table.insert(t,tostring(label) .. ':' .. tostring(tt))
end
if indent == 0 then
table.insert(t,'\n')
end
if str == nil then
return table.concat(t)
else
return table.concat(t)
end
end -- function dumpstr
--======================================================================================================================
debug = false
main()
debug = false
if DEBUG_MODE and debug then
io.write(dumpstr(gtblSettings, '==Settings=='))
io.write(dumpstr(gtblConstants,'==gtblConstants=='))
iup.Message('Debug','End of plugin')
end
-- End of plugin
--======================================================================================================================