Ancestral Sources Launcher.fh_lua--[[
@Title: Ancestral Sources Launcher
@Type: Standard
@Author: Mark Draper
@Contributors: Mike Tate, Nick Walker
@Version: 2.1
@LastUpdated: 16 Mar 2025
@Licence: This plugin is copyright (c) 2025 Mark Draper and is licensed under the MIT License
which is hereby incorporated by reference
(see https://pluginstore.family-historian.co.uk/fh-plugin-licence)
@Description: This plugin provides a simple method for immediately launching the
separate Ancestral Sources application from within Family Historian. It is recommended
that the plugin is added to the user's Tools Menu if used frequently.
]]
--[[
Mar 2025 - 2.1
Workaround to ensure FH prompts for updates (see FHUG description)
]]
fhInitialise(5,0,0, 'save_recommended')
require 'luacom'
require('iuplua')
iup.SetGlobal('CUSTOMQUITMESSAGE', 'YES')
FSO = luacom.CreateObject('Scripting.FileSystemObject')
-- *********************************************************************
function main()
-- get installed versions of AS
local tblV = GetVersions()
local versions = 0
for k, v in pairs(tblV) do
versions = versions + 1
end
-- warn if no version is installed
local link = 'https://apps.microsoft.com/detail/9MXZ7Q1WZ1SS'
if versions == 0 then
local msg = 'Ancestral Sources is not installed on this PC.\n\nDo you want to be redirected ' ..
'to the Microsoft Store for a download link?'
if MessageBox(msg, 'YESNO', 'QUESTION') == 1 then fhShellExecute(link) end
return
end
-- set path if just a single version
local exe_file
local tblS = {}
if versions == 1 then
if tblV.Store then exe_file = tblV.Store.Path
elseif tblV.Local then exe_file = tblV.Local.Path end
else
-- check versions unchanged if previous selection used
tblS, exe_file = GetSavedVersions()
local display_menu
if (tblV.Store.Version or '') ~= (tblS.StoreVersion or '') then display_menu = true end
if tblV.Local and (tblV.Local.Version or '') ~= (tblS.LocalVersion or '') then display_menu = true end
if iup.GetGlobal('SHIFTKEY') == 'ON' then display_menu = true end
if display_menu then
exe_file = SelectVersion(tblV)
if not exe_file then return end
end
end
local GEDCOM_file = fhGetContextInfo('CI_GEDCOM_FILE')
if GEDCOM_file == '' then
local msg = 'Ancestral Sources requires an existing GEDCOM file to operate.'
MessageBox(msg, 'OK', 'ERROR')
return
end
local file_option, id_option, msg = '-FILE "' .. GEDCOM_file .. '"', ''
local pI = fhGetCurrentRecordSel('INDI')[1]
if pI then
id_option = ' -IND ' .. fhGetRecordId(pI)
else
local pF = fhGetCurrentRecordSel('FAM')[1]
if pF then
local tblSpouses = {}
for _, reference in ipairs{'~.~SPOU[1]>', '~.~SPOU[2]>'} do
local p = fhGetItemPtr(pF, reference)
if p:IsNotNull() then table.insert(tblSpouses, p:Clone()) end
end
if #tblSpouses == 0 then
msg = 'Selected family has no parents'
elseif #tblSpouses == 1 then
id_option = ' -IND ' .. fhGetRecordId(tblSpouses[1])
else
local i = SelectSpouse(tblSpouses)
if not i then
return
elseif i == 0 then
msg = 'No individual has been selected'
else
id_option = ' -IND ' .. fhGetRecordId(tblSpouses[i])
end
end
else
MessageBox('Selected Record is not an Individual or Family.', 'OK', 'ERROR')
return
end
end
if msg then
msg = msg .. ', so Ancestral Sources will be opened with default options.'
if MessageBox(msg, 'OKCANCEL', 'WARNING') ~= 1 then return end
else if MessageBox('Click OK to launch Ancestral Sources','OKCANCEL','INFORMATION') ~= 1 then return end
end
fhShellExecute(exe_file, file_option .. id_option)
end
-- *********************************************************************
function CheckStore()
-- look for preferred Microsoft Store version
local HKCUapp = 'HKCU\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\' ..
'CurrentVersion\\AppModel\\Repository\\Packages'
local RegQuery = 'REG QUERY "{HKCU}" /F "AncestralSources" /REG:64 > "{Keys}"'
local QueryFile = os.getenv('TMP') .. '\\~fhASkeys.tmp'
RegQuery = RegQuery:gsub('{HKCU}', HKCUapp) -- Insert registry key
RegQuery = RegQuery:gsub('{Keys}', QueryFile) -- Insert keys file for pipe
local luaShell = luacom.CreateObject("WScript.Shell")
pcall(function() luaShell:Run("cmd.exe /C " .. RegQuery, 2, true) end)
for Line in io.lines(QueryFile) do
AppPath = Line:match("\\(AncestralSources.+)") -- path to Store version in its protected space
if AppPath then
Version = AppPath:match("_([%d.]+)%.0_") -- Extract the AS Version
AppName = AppPath:gsub("_([%d.]+)%.0_x64_","")
AppPath = 'shell:appsFolder\\' .. AppName .. '!App'
break
end
end
return AppPath, Version
end
-- *********************************************************************
function GetVersions()
local tblV = {}
-- check for Microsoft Store version
local StorePath, StoreVersion = CheckStore()
if StorePath then
tblV.Store = {Path = StorePath, Version = StoreVersion}
end
-- check for local version
local LocalPath = GetRegKey('HKLM\\SOFTWARE\\Ancestral Sources\\App Path')
if FSO:FileExists(LocalPath) then
tblV.Local = {Path = LocalPath, Version = GetRegKey('HKLM\\SOFTWARE\\Ancestral Sources\\Version')}
end
return tblV
end
-- *********************************************************************
function GetSavedVersions()
local OptionsFile = fhGetContextInfo('CI_APP_DATA_FOLDER') .. '\\Plugin Data\\' ..
fhGetContextInfo('CI_PLUGIN_NAME') .. '.ini'
local tblS = {}
local exe_file
if FSO:FileExists(OptionsFile) then
for line in io.lines(OptionsFile) do
local i = line:find('=')
if i and line:sub(1, i-1) == 'Store Version' then tblS.StoreVersion = line:sub(i+1) end
if i and line:sub(1, i-1) == 'Local Version' then tblS.LocalVersion = line:sub(i+1) end
if i and line:sub(1, i-1) == 'Path' then exe_file = line:sub(i+1) end
end
end
return tblS, exe_file
end
-- *********************************************************************
function SaveVersions(tblV, optStore, optDirect, optRemember, exe_file)
local OptionsFile = fhGetContextInfo('CI_APP_DATA_FOLDER') .. '\\Plugin Data\\' ..
fhGetContextInfo('CI_PLUGIN_NAME') .. '.ini'
-- save or clear options, as defined
if optRemember.Value == 'OFF' and FSO:FileExists(OptionsFile) then
FSO:DeleteFile(OptionsFile)
return
end
local F = io.open(OptionsFile, 'w')
if not F then
MessageBox('Cannot open options file.', 'OK', 'ERROR', 'File Access Error')
return
end
F:write('[Options]\n')
if tblV.Store then F:write('Store Version=' .. tblV.Store.Version .. '\n') end
if tblV.Local then F:write('Local Version=' .. tblV.Local.Version .. '\n') end
if exe_file then F:write('Path=' .. exe_file .. '\n') end
F:close()
end
-- *********************************************************************
function SelectVersion(tblV)
-- display menu to show preferred source
local optStore = iup.toggle{title = 'Microsoft Store', active = 'NO'}
local optLocal = iup.toggle{title = 'Direct Download', active = 'NO'}
local optRemember = iup.toggle{title = ' Remember this selection\n (hold down Shift key when\n' ..
' launching plugin to reset)'}
local vbox = iup.vbox{optStore, optLocal}
local radio = iup.radio{vbox}
local frame = iup.frame{radio, title = 'Installed Versions'}
if tblV.Store then
optStore.Title = 'Microsoft Store (Version ' .. tblV.Store.Version .. ')'
optStore.Active = 'YES'
end
if tblV.Local then
optLocal.Title = 'Direct Download (Version ' .. tblV.Local.Version .. ')'
optLocal.Active = 'YES'
end
local ok
local btnOK = iup.button{title = 'OK', action = function(self) ok = true return iup.CLOSE end}
local btnHelp = iup.button{title = 'Help', action = function(self)
fhShellExecute('https://pluginstore.family-historian.co.uk/page/help/ancestral-sources-launcher')
end}
local btnCancel = iup.button{title = 'Cancel', action = function(self) return iup.CLOSE end,
padding = '10x3'}
local buttons = iup.hbox{btnOK, btnHelp, btnCancel;
normalizesize = 'BOTH'; gap = 20, margin = '20x20'}
local vbox2 = iup.vbox{frame, optRemember, buttons; alignment = 'ACENTER', gap = 10,
margin = '20x20'}
local dialog = iup.dialog{vbox2, title = 'Select Ancestral Sources Version', border = '30x30',
minbox='NO', maxbox='NO'; defaultesc = btnCancel}
if fhGetAppVersion() > 6 then
iup.SetAttribute(dialog, 'NATIVEPARENT', fhGetContextInfo('CI_PARENT_HWND'))
end
dialog:popup()
if not ok then return end
local exe_file
if optStore.Value == 'ON' then
exe_file = tblV.Store.Path
else
exe_file = tblV.Local.Path
end
SaveVersions(tblV, optStore, optLocal, optRemember, exe_file)
return exe_file
end
-- *********************************************************************
function SelectSpouse(tblSpouses)
local dialog
local selection, ScreenPosition
local file = fhGetContextInfo('CI_APP_DATA_FOLDER') ..
'\\Plugin Data\\Ancestral Sources Launcher.ini'
local label = iup.label{title = 'Select spouse to load into Ancestral Sources', expand = 'YES'}
local btnS1 = iup.button{title = fhGetDisplayText(tblSpouses[1]), padding = '10x3',
action = function(self) selection = 1 return iup.CLOSE end}
local btnS2 = iup.button{title = fhGetDisplayText(tblSpouses[2]), padding = '10x3',
action = function(self) selection = 2 return iup.CLOSE end}
local btnN = iup.button{title = 'Neither',
action = function(self) selection = 0 return iup.CLOSE end}
local btnX = iup.button{title = 'Cancel',
action = function(self)
return iup.CLOSE
end}
local vbox1 = iup.vbox{btnS1, btnS2, btnN, btnX; alignment = 'ACENTER', expand = 'YES', gap = 10,
NORMALIZESIZE = 'BOTH'}
local vbox2 = iup.vbox{label, vbox1; alignment = 'ACENTER', gap = 30, margin = '20x20'}
dialog = iup.dialog{vbox2; title = fhGetContextInfo('CI_PLUGIN_NAME'), border = '30x30',
minbox='NO', maxbox='NO'}
if fhGetAppVersion() > 6 then
iup.SetAttribute(dialog, 'NATIVEPARENT', fhGetContextInfo('CI_PARENT_HWND'))
iup.ShowXY(dialog, IUP_CENTERPARENT, IUP_CENTERPARENT)
local position = dialog.ScreenPosition
local FHx, FHy = position:match('([^,]*),([^,]*)')
FHx, FHy = tonumber(FHx), tonumber(FHy)
local size = dialog.NaturalSize
local x, y, w, h
w, h = size:match('^(%d+)x(%d+)$')
local xMid = FHx + tonumber(w) / 2
local yMid = FHy + tonumber(h) / 2
local mi = iup.GetGlobal('MONITORSINFO')
for m in mi:gmatch('[^\r\n]+') do
x, y, w, h = m:match('^(%S+)%s(%S+)%s(%S+)%s(%S+)$')
x, y, w, h = tonumber(x), tonumber(y), tonumber(w), tonumber(h)
if xMid >= x and xMid <= x + w and yMid >= y and yMid <= y + h then -- this monitor
break
end
end
if FHx >= x and FHx <= x + w and FHy >= y and FHy <= y + h then -- visible
dialog:popup(FHx, FHy)
else
dialog:popup(x, y) -- corner
end
else
local F = io.open(file, 'r')
local x, y
if F then
local options = F:read("*a")
F:close()
local vs = options:match('VirtualScreen=(%C+)')
if vs and vs == iup.GetGlobal('VIRTUALSCREEN') and iup.GetGlobal('SHIFTKEY') == 'OFF' then
x, y = options:match('ScreenPosition=(%S+),(%S+)\n')
end
end
if x and y then
dialog:popup(x, y)
else
dialog:popup(IUP_CENTERPARENT, IUP_CENTERPARENT)
end
end
local F = io.open(file, 'w')
if F then
F:write('[Options]\nVirtualScreen=' .. iup.GetGlobal('VIRTUALSCREEN') ..
'\nScreenPosition=' .. dialog.ScreenPosition .. '\n')
F:close()
end
return selection
end
-- *********************************************************************
function GetRegKey(key)
local sh = luacom.CreateObject 'WScript.Shell'
local ans
if pcall(function () ans = sh:RegRead(key) end) then
return ans
else
return nil,true
end
end
-- *********************************************************************
function MessageBox(Message, Buttons, Icon)
-- replaces built-in function with custom version containing more options
local msgdlg = iup.messagedlg{value = Message, buttons = Buttons, dialogtype = Icon,
title = fhGetContextInfo('CI_PLUGIN_NAME')}
msgdlg:popup()
return tonumber(msgdlg.ButtonResponse)
end
-- *********************************************************************
main()
--[[
@Title: Ancestral Sources Launcher
@Type: Standard
@Author: Mark Draper
@Contributors: Mike Tate, Nick Walker
@Version: 2.1
@LastUpdated: 16 Mar 2025
@Licence: This plugin is copyright (c) 2025 Mark Draper and is licensed under the MIT License
which is hereby incorporated by reference
(see https://pluginstore.family-historian.co.uk/fh-plugin-licence)
@Description: This plugin provides a simple method for immediately launching the
separate Ancestral Sources application from within Family Historian. It is recommended
that the plugin is added to the user's Tools Menu if used frequently.
]]
--[[
Mar 2025 - 2.1
Workaround to ensure FH prompts for updates (see FHUG description)
]]
fhInitialise(5,0,0, 'save_recommended')
require 'luacom'
require('iuplua')
iup.SetGlobal('CUSTOMQUITMESSAGE', 'YES')
FSO = luacom.CreateObject('Scripting.FileSystemObject')
-- *********************************************************************
function main()
-- get installed versions of AS
local tblV = GetVersions()
local versions = 0
for k, v in pairs(tblV) do
versions = versions + 1
end
-- warn if no version is installed
local link = 'https://apps.microsoft.com/detail/9MXZ7Q1WZ1SS'
if versions == 0 then
local msg = 'Ancestral Sources is not installed on this PC.\n\nDo you want to be redirected ' ..
'to the Microsoft Store for a download link?'
if MessageBox(msg, 'YESNO', 'QUESTION') == 1 then fhShellExecute(link) end
return
end
-- set path if just a single version
local exe_file
local tblS = {}
if versions == 1 then
if tblV.Store then exe_file = tblV.Store.Path
elseif tblV.Local then exe_file = tblV.Local.Path end
else
-- check versions unchanged if previous selection used
tblS, exe_file = GetSavedVersions()
local display_menu
if (tblV.Store.Version or '') ~= (tblS.StoreVersion or '') then display_menu = true end
if tblV.Local and (tblV.Local.Version or '') ~= (tblS.LocalVersion or '') then display_menu = true end
if iup.GetGlobal('SHIFTKEY') == 'ON' then display_menu = true end
if display_menu then
exe_file = SelectVersion(tblV)
if not exe_file then return end
end
end
local GEDCOM_file = fhGetContextInfo('CI_GEDCOM_FILE')
if GEDCOM_file == '' then
local msg = 'Ancestral Sources requires an existing GEDCOM file to operate.'
MessageBox(msg, 'OK', 'ERROR')
return
end
local file_option, id_option, msg = '-FILE "' .. GEDCOM_file .. '"', ''
local pI = fhGetCurrentRecordSel('INDI')[1]
if pI then
id_option = ' -IND ' .. fhGetRecordId(pI)
else
local pF = fhGetCurrentRecordSel('FAM')[1]
if pF then
local tblSpouses = {}
for _, reference in ipairs{'~.~SPOU[1]>', '~.~SPOU[2]>'} do
local p = fhGetItemPtr(pF, reference)
if p:IsNotNull() then table.insert(tblSpouses, p:Clone()) end
end
if #tblSpouses == 0 then
msg = 'Selected family has no parents'
elseif #tblSpouses == 1 then
id_option = ' -IND ' .. fhGetRecordId(tblSpouses[1])
else
local i = SelectSpouse(tblSpouses)
if not i then
return
elseif i == 0 then
msg = 'No individual has been selected'
else
id_option = ' -IND ' .. fhGetRecordId(tblSpouses[i])
end
end
else
MessageBox('Selected Record is not an Individual or Family.', 'OK', 'ERROR')
return
end
end
if msg then
msg = msg .. ', so Ancestral Sources will be opened with default options.'
if MessageBox(msg, 'OKCANCEL', 'WARNING') ~= 1 then return end
else if MessageBox('Click OK to launch Ancestral Sources','OKCANCEL','INFORMATION') ~= 1 then return end
end
fhShellExecute(exe_file, file_option .. id_option)
end
-- *********************************************************************
function CheckStore()
-- look for preferred Microsoft Store version
local HKCUapp = 'HKCU\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\' ..
'CurrentVersion\\AppModel\\Repository\\Packages'
local RegQuery = 'REG QUERY "{HKCU}" /F "AncestralSources" /REG:64 > "{Keys}"'
local QueryFile = os.getenv('TMP') .. '\\~fhASkeys.tmp'
RegQuery = RegQuery:gsub('{HKCU}', HKCUapp) -- Insert registry key
RegQuery = RegQuery:gsub('{Keys}', QueryFile) -- Insert keys file for pipe
local luaShell = luacom.CreateObject("WScript.Shell")
pcall(function() luaShell:Run("cmd.exe /C " .. RegQuery, 2, true) end)
for Line in io.lines(QueryFile) do
AppPath = Line:match("\\(AncestralSources.+)") -- path to Store version in its protected space
if AppPath then
Version = AppPath:match("_([%d.]+)%.0_") -- Extract the AS Version
AppName = AppPath:gsub("_([%d.]+)%.0_x64_","")
AppPath = 'shell:appsFolder\\' .. AppName .. '!App'
break
end
end
return AppPath, Version
end
-- *********************************************************************
function GetVersions()
local tblV = {}
-- check for Microsoft Store version
local StorePath, StoreVersion = CheckStore()
if StorePath then
tblV.Store = {Path = StorePath, Version = StoreVersion}
end
-- check for local version
local LocalPath = GetRegKey('HKLM\\SOFTWARE\\Ancestral Sources\\App Path')
if FSO:FileExists(LocalPath) then
tblV.Local = {Path = LocalPath, Version = GetRegKey('HKLM\\SOFTWARE\\Ancestral Sources\\Version')}
end
return tblV
end
-- *********************************************************************
function GetSavedVersions()
local OptionsFile = fhGetContextInfo('CI_APP_DATA_FOLDER') .. '\\Plugin Data\\' ..
fhGetContextInfo('CI_PLUGIN_NAME') .. '.ini'
local tblS = {}
local exe_file
if FSO:FileExists(OptionsFile) then
for line in io.lines(OptionsFile) do
local i = line:find('=')
if i and line:sub(1, i-1) == 'Store Version' then tblS.StoreVersion = line:sub(i+1) end
if i and line:sub(1, i-1) == 'Local Version' then tblS.LocalVersion = line:sub(i+1) end
if i and line:sub(1, i-1) == 'Path' then exe_file = line:sub(i+1) end
end
end
return tblS, exe_file
end
-- *********************************************************************
function SaveVersions(tblV, optStore, optDirect, optRemember, exe_file)
local OptionsFile = fhGetContextInfo('CI_APP_DATA_FOLDER') .. '\\Plugin Data\\' ..
fhGetContextInfo('CI_PLUGIN_NAME') .. '.ini'
-- save or clear options, as defined
if optRemember.Value == 'OFF' and FSO:FileExists(OptionsFile) then
FSO:DeleteFile(OptionsFile)
return
end
local F = io.open(OptionsFile, 'w')
if not F then
MessageBox('Cannot open options file.', 'OK', 'ERROR', 'File Access Error')
return
end
F:write('[Options]\n')
if tblV.Store then F:write('Store Version=' .. tblV.Store.Version .. '\n') end
if tblV.Local then F:write('Local Version=' .. tblV.Local.Version .. '\n') end
if exe_file then F:write('Path=' .. exe_file .. '\n') end
F:close()
end
-- *********************************************************************
function SelectVersion(tblV)
-- display menu to show preferred source
local optStore = iup.toggle{title = 'Microsoft Store', active = 'NO'}
local optLocal = iup.toggle{title = 'Direct Download', active = 'NO'}
local optRemember = iup.toggle{title = ' Remember this selection\n (hold down Shift key when\n' ..
' launching plugin to reset)'}
local vbox = iup.vbox{optStore, optLocal}
local radio = iup.radio{vbox}
local frame = iup.frame{radio, title = 'Installed Versions'}
if tblV.Store then
optStore.Title = 'Microsoft Store (Version ' .. tblV.Store.Version .. ')'
optStore.Active = 'YES'
end
if tblV.Local then
optLocal.Title = 'Direct Download (Version ' .. tblV.Local.Version .. ')'
optLocal.Active = 'YES'
end
local ok
local btnOK = iup.button{title = 'OK', action = function(self) ok = true return iup.CLOSE end}
local btnHelp = iup.button{title = 'Help', action = function(self)
fhShellExecute('https://pluginstore.family-historian.co.uk/page/help/ancestral-sources-launcher')
end}
local btnCancel = iup.button{title = 'Cancel', action = function(self) return iup.CLOSE end,
padding = '10x3'}
local buttons = iup.hbox{btnOK, btnHelp, btnCancel;
normalizesize = 'BOTH'; gap = 20, margin = '20x20'}
local vbox2 = iup.vbox{frame, optRemember, buttons; alignment = 'ACENTER', gap = 10,
margin = '20x20'}
local dialog = iup.dialog{vbox2, title = 'Select Ancestral Sources Version', border = '30x30',
minbox='NO', maxbox='NO'; defaultesc = btnCancel}
if fhGetAppVersion() > 6 then
iup.SetAttribute(dialog, 'NATIVEPARENT', fhGetContextInfo('CI_PARENT_HWND'))
end
dialog:popup()
if not ok then return end
local exe_file
if optStore.Value == 'ON' then
exe_file = tblV.Store.Path
else
exe_file = tblV.Local.Path
end
SaveVersions(tblV, optStore, optLocal, optRemember, exe_file)
return exe_file
end
-- *********************************************************************
function SelectSpouse(tblSpouses)
local dialog
local selection, ScreenPosition
local file = fhGetContextInfo('CI_APP_DATA_FOLDER') ..
'\\Plugin Data\\Ancestral Sources Launcher.ini'
local label = iup.label{title = 'Select spouse to load into Ancestral Sources', expand = 'YES'}
local btnS1 = iup.button{title = fhGetDisplayText(tblSpouses[1]), padding = '10x3',
action = function(self) selection = 1 return iup.CLOSE end}
local btnS2 = iup.button{title = fhGetDisplayText(tblSpouses[2]), padding = '10x3',
action = function(self) selection = 2 return iup.CLOSE end}
local btnN = iup.button{title = 'Neither',
action = function(self) selection = 0 return iup.CLOSE end}
local btnX = iup.button{title = 'Cancel',
action = function(self)
return iup.CLOSE
end}
local vbox1 = iup.vbox{btnS1, btnS2, btnN, btnX; alignment = 'ACENTER', expand = 'YES', gap = 10,
NORMALIZESIZE = 'BOTH'}
local vbox2 = iup.vbox{label, vbox1; alignment = 'ACENTER', gap = 30, margin = '20x20'}
dialog = iup.dialog{vbox2; title = fhGetContextInfo('CI_PLUGIN_NAME'), border = '30x30',
minbox='NO', maxbox='NO'}
if fhGetAppVersion() > 6 then
iup.SetAttribute(dialog, 'NATIVEPARENT', fhGetContextInfo('CI_PARENT_HWND'))
iup.ShowXY(dialog, IUP_CENTERPARENT, IUP_CENTERPARENT)
local position = dialog.ScreenPosition
local FHx, FHy = position:match('([^,]*),([^,]*)')
FHx, FHy = tonumber(FHx), tonumber(FHy)
local size = dialog.NaturalSize
local x, y, w, h
w, h = size:match('^(%d+)x(%d+)$')
local xMid = FHx + tonumber(w) / 2
local yMid = FHy + tonumber(h) / 2
local mi = iup.GetGlobal('MONITORSINFO')
for m in mi:gmatch('[^\r\n]+') do
x, y, w, h = m:match('^(%S+)%s(%S+)%s(%S+)%s(%S+)$')
x, y, w, h = tonumber(x), tonumber(y), tonumber(w), tonumber(h)
if xMid >= x and xMid <= x + w and yMid >= y and yMid <= y + h then -- this monitor
break
end
end
if FHx >= x and FHx <= x + w and FHy >= y and FHy <= y + h then -- visible
dialog:popup(FHx, FHy)
else
dialog:popup(x, y) -- corner
end
else
local F = io.open(file, 'r')
local x, y
if F then
local options = F:read("*a")
F:close()
local vs = options:match('VirtualScreen=(%C+)')
if vs and vs == iup.GetGlobal('VIRTUALSCREEN') and iup.GetGlobal('SHIFTKEY') == 'OFF' then
x, y = options:match('ScreenPosition=(%S+),(%S+)\n')
end
end
if x and y then
dialog:popup(x, y)
else
dialog:popup(IUP_CENTERPARENT, IUP_CENTERPARENT)
end
end
local F = io.open(file, 'w')
if F then
F:write('[Options]\nVirtualScreen=' .. iup.GetGlobal('VIRTUALSCREEN') ..
'\nScreenPosition=' .. dialog.ScreenPosition .. '\n')
F:close()
end
return selection
end
-- *********************************************************************
function GetRegKey(key)
local sh = luacom.CreateObject 'WScript.Shell'
local ans
if pcall(function () ans = sh:RegRead(key) end) then
return ans
else
return nil,true
end
end
-- *********************************************************************
function MessageBox(Message, Buttons, Icon)
-- replaces built-in function with custom version containing more options
local msgdlg = iup.messagedlg{value = Message, buttons = Buttons, dialogtype = Icon,
title = fhGetContextInfo('CI_PLUGIN_NAME')}
msgdlg:popup()
return tonumber(msgdlg.ButtonResponse)
end
-- *********************************************************************
main()Source:Ancestral-Sources-Launcher-6.fh_lua