diff --git a/Archived/CrownHelper.py b/Archived/CrownHelper.py new file mode 100644 index 0000000..f52f4c1 --- /dev/null +++ b/Archived/CrownHelper.py @@ -0,0 +1,83 @@ +import traceback +import logging +# from signal import signal, SIGINT + +import discord # noqa +from discord.ext import commands + +logging.basicConfig(level=logging.ERROR) + +token = 'NTg4NDcwNDkzNjg3MDU0MzY2.XQFyBw.v3wp-PB2Eep0J_cXAv8bejTonRA' + + +class CrownHelper(commands.Cog): + """ + Handle events and messaging channels and users. + """ + def __init__(self, bot): + self.bot = bot + self._last_member = None + + # @commands.Cog.listener() + # async def on_member_join(self, member): + # channel = member.guild.system_channel + # if channel is not None: + # await channel.send('Welcome {0.mention}.'.format(member)) + + @commands.Cog.listener() + async def on_message(message): + if message.author == client.user: + return + + if message.content.startswith('hello'): + await message.channel.send('Hello!') + + @commands.command() + async def quit(self, ctx): + await self.logout() + + @commands.command() + async def ping(self, ctx, *, member: discord.Member = None): + """Says pong""" + member = member or ctx.author + if self._last_member is None or self._last_member.id != member.id: + await ctx.send('Pong {0.name}~'.format(member)) + else: + await ctx.send('Pong {0.name}... This feels familiar.'.format(member)) + self._last_member = member + + +# client = discord.Client() +client = commands.Bot(command_prefix='!') + + +@client.event +async def on_ready(): + print('We have logged in as {0.user}'.format(client)) + + +@client.event +async def on_error(event, *args, **kwargs): + message = args[0] # Gets the message object + traceback.format_exc() + # Send the message to the channel. + await client.send_message(message.channel, "You caused an error!") + + +client.add_cog(CrownHelper(client)) + +print('Bot running...') +try: + client.run(token) +except Exception as e: + print(e) + + +# def signalHandler(signal_received, frame): +# global bot +# print('Quitting...') +# async await bot.logout() +# quit() + + +# signal(SIGINT, signalHandler) diff --git a/Gematriaz b/Archived/Gematriaz similarity index 100% rename from Gematriaz rename to Archived/Gematriaz diff --git a/Illustro+ & MSI Afterburner & HWInfo_1.0.rmskin b/Archived/Illustro+ & MSI Afterburner & HWInfo_1.0.rmskin similarity index 100% rename from Illustro+ & MSI Afterburner & HWInfo_1.0.rmskin rename to Archived/Illustro+ & MSI Afterburner & HWInfo_1.0.rmskin diff --git a/Illustro+ & MSI Afterburner_1.2.rmskin b/Archived/Illustro+ & MSI Afterburner_1.2.rmskin similarity index 100% rename from Illustro+ & MSI Afterburner_1.2.rmskin rename to Archived/Illustro+ & MSI Afterburner_1.2.rmskin diff --git a/Archived/Run/Run.exe b/Archived/Run/Run.exe new file mode 100644 index 0000000..6d0573f Binary files /dev/null and b/Archived/Run/Run.exe differ diff --git a/Archived/Run/Run.py b/Archived/Run/Run.py new file mode 100644 index 0000000..a8cdd6e --- /dev/null +++ b/Archived/Run/Run.py @@ -0,0 +1,13 @@ +import wx + +app = wx.App(0) +dialog = wx.MessageDialog(None, 'There is nowhere you can run.', 'Warning', wx.OK|wx.ICON_ERROR) +res = dialog.ShowModal() +dialog.Destroy() +app.MainLoop() + +### To build the EXE for fun: ### +# mkdir ./venv +# python -m venv ./venv +# python -m pip install pyinstaller wxPython +# pyinstaller Run.py --noconsole -F --clean --icon "running.ico" --upx-dir "C:\upx-3.96-win64" --exclude-module select --exclude-module unicodedata --exclude-module socket --exclude-module decimal --exclude-module overlapped --exclude-module ssl --exclude-module asyncio --exclude-module queue --exclude-module ctypes --exclude-module multiprocessing --exclude-module pyexpat --exclude-module hashlib --exclude-module lzma --exclude-module bz2 --exclude-module libssl-1_1 --exclude-module libcrypto-1_1 --exclude-module libffi-7 \ No newline at end of file diff --git a/Archived/Run/running.ico b/Archived/Run/running.ico new file mode 100644 index 0000000..1c65949 Binary files /dev/null and b/Archived/Run/running.ico differ diff --git a/Archived/Run/stop.ico b/Archived/Run/stop.ico new file mode 100644 index 0000000..6451772 Binary files /dev/null and b/Archived/Run/stop.ico differ diff --git a/TinychatCleanup b/Archived/Tinychat/TinychatCleanup similarity index 100% rename from TinychatCleanup rename to Archived/Tinychat/TinychatCleanup diff --git a/TinychatFullPage b/Archived/Tinychat/TinychatFullPage similarity index 100% rename from TinychatFullPage rename to Archived/Tinychat/TinychatFullPage diff --git a/BestFriends2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/BestFriends2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua deleted file mode 100644 index 50696f4..0000000 --- a/BestFriends2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua +++ /dev/null @@ -1,1226 +0,0 @@ --- LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah) -- --- Distributed under The Artistic License 2.0 (see LICENSE) -- ------------------------------------------------------------------- - - ---Register LAM with LibStub -local MAJOR, MINOR = "LibAddonMenu-2.0", _LAM2_VERSION_NUMBER or -1 -local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) -if not lam then return end --the same or newer version of this lib is already loaded into memory - -local messages = {} -local MESSAGE_PREFIX = "[LAM2] " -local function PrintLater(msg) - if CHAT_SYSTEM.primaryContainer then - d(MESSAGE_PREFIX .. msg) - else - messages[#messages + 1] = msg - end -end - -local function FlushMessages() - for i = 1, #messages do - d(MESSAGE_PREFIX .. messages[i]) - end - messages = {} -end - -if LAMSettingsPanelCreated and not LAMCompatibilityWarning then - PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") - LAMCompatibilityWarning = true -end - ---UPVALUES-- -local wm = WINDOW_MANAGER -local em = EVENT_MANAGER -local sm = SCENE_MANAGER -local cm = CALLBACK_MANAGER -local tconcat = table.concat -local tinsert = table.insert - -local MIN_HEIGHT = 26 -local HALF_WIDTH_LINE_SPACING = 2 -local OPTIONS_CREATION_RUNNING = 1 -local OPTIONS_CREATED = 2 -local LAM_CONFIRM_DIALOG = "LAM_CONFIRM_DIALOG" -local LAM_DEFAULTS_DIALOG = "LAM_DEFAULTS" -local LAM_RELOAD_DIALOG = "LAM_RELOAD_DIALOG" - -local addonsForList = {} -local addonToOptionsMap = {} -local optionsState = {} -lam.widgets = lam.widgets or {} -local widgets = lam.widgets -lam.util = lam.util or {} -local util = lam.util -lam.controlsForReload = lam.controlsForReload or {} -local controlsForReload = lam.controlsForReload - -local function GetDefaultValue(default) - if type(default) == "function" then - return default() - end - return default -end - -local function GetStringFromValue(value) - if type(value) == "function" then - return value() - elseif type(value) == "number" then - return GetString(value) - end - return value -end - -local function CreateBaseControl(parent, controlData, controlName) - local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) - control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent - control.data = controlData - - control.isHalfWidth = controlData.width == "half" - local width = 510 -- set default width in case a custom parent object is passed - if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end - control:SetWidth(width) - return control -end - -local function CreateLabelAndContainerControl(parent, controlData, controlName) - local control = CreateBaseControl(parent, controlData, controlName) - local width = control:GetWidth() - - local container = wm:CreateControl(nil, control, CT_CONTROL) - container:SetDimensions(width / 3, MIN_HEIGHT) - control.container = container - - local label = wm:CreateControl(nil, control, CT_LABEL) - label:SetFont("ZoFontWinH4") - label:SetHeight(MIN_HEIGHT) - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetText(GetStringFromValue(controlData.name)) - control.label = label - - if control.isHalfWidth then - control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) - label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) - label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) - container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING) - else - control:SetDimensions(width, MIN_HEIGHT) - container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) - label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) - label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0) - end - - control.data.tooltipText = GetStringFromValue(control.data.tooltip) - control:SetMouseEnabled(true) - control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - return control -end - -local function GetTopPanel(panel) - while panel.panel and panel.panel ~= panel do - panel = panel.panel - end - return panel -end - -local function IsSame(objA, objB) - if #objA ~= #objB then return false end - for i = 1, #objA do - if objA[i] ~= objB[i] then return false end - end - return true -end - -local function RefreshReloadUIButton() - lam.requiresReload = false - - for i = 1, #controlsForReload do - local reloadControl = controlsForReload[i] - if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then - lam.requiresReload = true - break - end - end - - lam.applyButton:SetHidden(not lam.requiresReload) -end - -local function RequestRefreshIfNeeded(control) - -- if our parent window wants to refresh controls, then fire the callback - local panel = GetTopPanel(control.panel) - local panelData = panel.data - if panelData.registerForRefresh then - cm:FireCallbacks("LAM-RefreshPanel", control) - end - RefreshReloadUIButton() -end - -local function RegisterForRefreshIfNeeded(control) - -- if our parent window wants to refresh controls, then add this to the list - local panel = GetTopPanel(control.panel) - local panelData = panel.data - if panelData.registerForRefresh or panelData.registerForDefaults then - tinsert(panel.controlsToRefresh or {}, control) -- prevent errors on custom panels - end -end - -local function RegisterForReloadIfNeeded(control) - if control.data.requiresReload then - tinsert(controlsForReload, control) - control.startValue = {control.data.getFunc()} - end -end - -local function GetConfirmDialog() - if(not ESO_Dialogs[LAM_CONFIRM_DIALOG]) then - ESO_Dialogs[LAM_CONFIRM_DIALOG] = { - canQueue = true, - title = { - text = "", - }, - mainText = { - text = "", - }, - buttons = { - [1] = { - text = SI_DIALOG_CONFIRM, - callback = function(dialog) end, - }, - [2] = { - text = SI_DIALOG_CANCEL, - } - } - } - end - return ESO_Dialogs[LAM_CONFIRM_DIALOG] -end - -local function ShowConfirmationDialog(title, body, callback) - local dialog = GetConfirmDialog() - dialog.title.text = title - dialog.mainText.text = body - dialog.buttons[1].callback = callback - ZO_Dialogs_ShowDialog(LAM_CONFIRM_DIALOG) -end - -local function GetDefaultsDialog() - if(not ESO_Dialogs[LAM_DEFAULTS_DIALOG]) then - ESO_Dialogs[LAM_DEFAULTS_DIALOG] = { - canQueue = true, - title = { - text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP, - }, - mainText = { - text = SI_OPTIONS_RESET_PROMPT, - }, - buttons = { - [1] = { - text = SI_OPTIONS_RESET, - callback = function(dialog) end, - }, - [2] = { - text = SI_DIALOG_CANCEL, - } - } - } - end - return ESO_Dialogs[LAM_DEFAULTS_DIALOG] -end - -local function ShowDefaultsDialog(panel) - local dialog = GetDefaultsDialog() - dialog.buttons[1].callback = function() - panel:ForceDefaults() - RefreshReloadUIButton() - end - ZO_Dialogs_ShowDialog(LAM_DEFAULTS_DIALOG) -end - -local function DiscardChangesOnReloadControls() - for i = 1, #controlsForReload do - local reloadControl = controlsForReload[i] - if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then - reloadControl:UpdateValue(false, unpack(reloadControl.startValue)) - end - end - lam.requiresReload = false - lam.applyButton:SetHidden(true) -end - -local function StorePanelForReopening() - local saveData = ZO_Ingame_SavedVariables["LAM"] or {} - saveData.reopenPanel = lam.currentAddonPanel:GetName() - ZO_Ingame_SavedVariables["LAM"] = saveData -end - -local function RetrievePanelForReopening() - local saveData = ZO_Ingame_SavedVariables["LAM"] - if(saveData) then - ZO_Ingame_SavedVariables["LAM"] = nil - return _G[saveData.reopenPanel] - end -end - -local function HandleReloadUIPressed() - StorePanelForReopening() - ReloadUI() -end - -local function HandleLoadDefaultsPressed() - ShowDefaultsDialog(lam.currentAddonPanel) -end - -local function GetReloadDialog() - if(not ESO_Dialogs[LAM_RELOAD_DIALOG]) then - ESO_Dialogs[LAM_RELOAD_DIALOG] = { - canQueue = true, - title = { - text = util.L["RELOAD_DIALOG_TITLE"], - }, - mainText = { - text = util.L["RELOAD_DIALOG_TEXT"], - }, - buttons = { - [1] = { - text = util.L["RELOAD_DIALOG_RELOAD_BUTTON"], - callback = function() ReloadUI() end, - }, - [2] = { - text = util.L["RELOAD_DIALOG_DISCARD_BUTTON"], - callback = DiscardChangesOnReloadControls, - } - }, - noChoiceCallback = DiscardChangesOnReloadControls, - } - end - return ESO_Dialogs[LAM_CONFIRM_DIALOG] -end - -local function ShowReloadDialogIfNeeded() - if lam.requiresReload then - local dialog = GetReloadDialog() - ZO_Dialogs_ShowDialog(LAM_RELOAD_DIALOG) - end -end - -local function UpdateWarning(control) - local warning - if control.data.warning ~= nil then - warning = util.GetStringFromValue(control.data.warning) - end - - if control.data.requiresReload then - if not warning then - warning = string.format("|cff0000%s", util.L["RELOAD_UI_WARNING"]) - else - warning = string.format("%s\n\n|cff0000%s", warning, util.L["RELOAD_UI_WARNING"]) - end - end - - if not warning then - control.warning:SetHidden(true) - else - control.warning.data = {tooltipText = warning} - control.warning:SetHidden(false) - end -end - -local localization = { - en = { - PANEL_NAME = "Addons", - AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" - VERSION = "Version: <>", - WEBSITE = "Visit Website", - PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", - RELOAD_UI_WARNING = "Changes to this setting require an UI reload in order to take effect.", - RELOAD_DIALOG_TITLE = "UI Reload required", - RELOAD_DIALOG_TEXT = "Some changes require an UI reload in order to take effect. Do you want to reload now or discard the changes?", - RELOAD_DIALOG_RELOAD_BUTTON = "Reload", - RELOAD_DIALOG_DISCARD_BUTTON = "Discard", - }, - it = { -- provided by JohnnyKing - PANEL_NAME = "Addon", - VERSION = "Versione: <>", - WEBSITE = "Visita il Sitoweb", - RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", - RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", - RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", - RELOAD_DIALOG_RELOAD_BUTTON = "Ricarica", - RELOAD_DIALOG_DISCARD_BUTTON = "Annulla", - }, - fr = { -- provided by Ayantir - PANEL_NAME = "Extensions", - WEBSITE = "Visiter le site Web", - RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", - RELOAD_DIALOG_TITLE = "Reload UI requis", - RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", - RELOAD_DIALOG_RELOAD_BUTTON = "Recharger", - RELOAD_DIALOG_DISCARD_BUTTON = "Annuler", - }, - de = { -- provided by sirinsidiator - PANEL_NAME = "Erweiterungen", - WEBSITE = "Webseite besuchen", - RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", - RELOAD_DIALOG_TITLE = "Neuladen benötigt", - RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", - RELOAD_DIALOG_RELOAD_BUTTON = "Neu laden", - RELOAD_DIALOG_DISCARD_BUTTON = "Verwerfen", - }, - ru = { -- provided by TERAB1T - PANEL_NAME = "Дополнения", - VERSION = "Версия: <>", - WEBSITE = "Посетить сайт", - PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", - RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", - RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", - RELOAD_DIALOG_TEXT = "Для применения некоторых изменений необходима перезагрузка интерфейса. Перезагрузить интерфейс сейчас или отменить изменения?", - RELOAD_DIALOG_RELOAD_BUTTON = "Перезагрузить", - RELOAD_DIALOG_DISCARD_BUTTON = "Отменить изменения", - }, - es = { -- provided by Morganlefai, checked by Kwisatz - PANEL_NAME = "Configuración", - VERSION = "Versión: <>", - WEBSITE = "Visita la página web", - RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", - RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", - RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", - RELOAD_DIALOG_RELOAD_BUTTON = "Recargar", - RELOAD_DIALOG_DISCARD_BUTTON = "Cancelar", - }, - jp = { -- provided by k0ta0uchi - PANEL_NAME = "アドオン設定", - WEBSITE = "ウェブサイトを見る", - }, - zh = { -- provided by bssthu - PANEL_NAME = "插件", - VERSION = "版本: <>", - WEBSITE = "访问网站", - PANEL_INFO_FONT = "EsoZh/fonts/univers57.otf|14|soft-shadow-thin", - }, - pl = { -- provided by EmiruTegryfon - PANEL_NAME = "Dodatki", - VERSION = "Wersja: <>", - WEBSITE = "Odwiedź stronę", - RELOAD_UI_WARNING = "Zmiany będą widoczne po ponownym załadowaniu UI.", - RELOAD_DIALOG_TITLE = "Wymagane przeładowanie UI", - RELOAD_DIALOG_TEXT = "Niektóre zmiany wymagają ponownego załadowania UI. Czy chcesz teraz ponownie załadować, czy porzucić zmiany?", - RELOAD_DIALOG_RELOAD_BUTTON = "Przeładuj", - RELOAD_DIALOG_DISCARD_BUTTON = "Porzuć", - }, -} - -util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")], localization["en"]) -util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead -util.GetStringFromValue = GetStringFromValue -util.GetDefaultValue = GetDefaultValue -util.CreateBaseControl = CreateBaseControl -util.CreateLabelAndContainerControl = CreateLabelAndContainerControl -util.RequestRefreshIfNeeded = RequestRefreshIfNeeded -util.RegisterForRefreshIfNeeded = RegisterForRefreshIfNeeded -util.RegisterForReloadIfNeeded = RegisterForReloadIfNeeded -util.GetTopPanel = GetTopPanel -util.ShowConfirmationDialog = ShowConfirmationDialog -util.UpdateWarning = UpdateWarning - -local ADDON_DATA_TYPE = 1 -local RESELECTING_DURING_REBUILD = true -local USER_REQUESTED_OPEN = true - - ---INTERNAL FUNCTION ---scrolls ZO_ScrollList `list` to move the row corresponding to `data` --- into view (does nothing if there is no such row in the list) ---unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for --- fading near the list's edges - it avoids the fading area by scrolling --- a little further than the ZO function -local function ScrollDataIntoView(list, data) - local targetIndex = data.sortIndex - if not targetIndex then return end - - local scrollMin, scrollMax = list.scrollbar:GetMinMax() - local scrollTop = list.scrollbar:GetValue() - local controlHeight = list.uniformControlHeight or list.controlHeight - local targetMin = controlHeight * (targetIndex - 1) - 64 - -- subtracting 64 ain't arbitrary, it's the maximum fading height - -- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade) - - if targetMin < scrollTop then - ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin)) - else - local listHeight = ZO_ScrollList_GetHeight(list) - local targetMax = controlHeight * targetIndex + 64 - listHeight - - if targetMax > scrollTop then - ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax)) - end - end -end - - ---INTERNAL FUNCTION ---constructs a string pattern from the text in `searchEdit` control --- * metacharacters are escaped, losing their special meaning --- * whitespace matches anything (including empty substring) ---if there is nothing but whitespace, returns nil ---otherwise returns a filter function, which takes a `data` table argument --- and returns true iff `data.filterText` matches the pattern -local function GetSearchFilterFunc(searchEdit) - local text = searchEdit:GetText():lower() - local pattern = text:match("(%S+.-)%s*$") - - if not pattern then -- nothing but whitespace - return nil - end - - -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de" - pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0") - - -- replace whitespace with "match shortest anything" - pattern = pattern:gsub("%s+", ".-") - - return function(data) - return data.filterText:lower():find(pattern) ~= nil - end -end - - ---INTERNAL FUNCTION ---populates `addonList` with entries from `addonsForList` --- addonList = ZO_ScrollList control --- filter = [optional] function(data) -local function PopulateAddonList(addonList, filter) - local entryList = ZO_ScrollList_GetDataList(addonList) - local numEntries = 0 - local selectedData = nil - local selectionIsFinal = false - - ZO_ScrollList_Clear(addonList) - - for i, data in ipairs(addonsForList) do - if not filter or filter(data) then - local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data) - numEntries = numEntries + 1 - data.sortIndex = numEntries - entryList[numEntries] = dataEntry - -- select the first panel passing the filter, or the currently - -- shown panel, but only if it passes the filter as well - if selectedData == nil or data.panel == lam.pendingAddonPanel or data.panel == lam.currentAddonPanel then - if not selectionIsFinal then - selectedData = data - end - if data.panel == lam.pendingAddonPanel then - lam.pendingAddonPanel = nil - selectionIsFinal = true - end - end - else - data.sortIndex = nil - end - end - - ZO_ScrollList_Commit(addonList) - - if selectedData then - if selectedData.panel == lam.currentAddonPanel then - ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD) - else - ZO_ScrollList_SelectData(addonList, selectedData, nil) - end - ScrollDataIntoView(addonList, selectedData) - end -end - - ---METHOD: REGISTER WIDGET-- ---each widget has its version checked before loading, ---so we only have the most recent one in memory ---Usage: --- widgetType = "string"; the type of widget being registered --- widgetVersion = integer; the widget's version number -LAMCreateControl = LAMCreateControl or {} -local lamcc = LAMCreateControl - -function lam:RegisterWidget(widgetType, widgetVersion) - if widgets[widgetType] and widgets[widgetType] >= widgetVersion then - return false - else - widgets[widgetType] = widgetVersion - return true - end -end - --- INTERNAL METHOD: hijacks the handlers for the actions in the OptionsWindow layer if not already done -local function InitKeybindActions() - if not lam.keybindsInitialized then - lam.keybindsInitialized = true - ZO_PreHook(KEYBOARD_OPTIONS, "ApplySettings", function() - if lam.currentPanelOpened then - if not lam.applyButton:IsHidden() then - HandleReloadUIPressed() - end - return true - end - end) - ZO_PreHook("ZO_Dialogs_ShowDialog", function(dialogName) - if lam.currentPanelOpened and dialogName == "OPTIONS_RESET_TO_DEFAULTS" then - if not lam.defaultButton:IsHidden() then - HandleLoadDefaultsPressed() - end - return true - end - end) - end -end - --- INTERNAL METHOD: fires the LAM-PanelOpened callback if not already done -local function OpenCurrentPanel() - if lam.currentAddonPanel and not lam.currentPanelOpened then - lam.currentPanelOpened = true - lam.defaultButton:SetHidden(not lam.currentAddonPanel.data.registerForDefaults) - cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel) - end -end - --- INTERNAL METHOD: fires the LAM-PanelClosed callback if not already done -local function CloseCurrentPanel() - if lam.currentAddonPanel and lam.currentPanelOpened then - lam.currentPanelOpened = false - cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel) - end -end - ---METHOD: OPEN TO ADDON PANEL-- ---opens to a specific addon's option panel ---Usage: --- panel = userdata; the panel returned by the :RegisterOptionsPanel method -local locSettings = GetString(SI_GAME_MENU_SETTINGS) -function lam:OpenToPanel(panel) - - -- find and select the panel's row in addon list - - local addonList = lam.addonList - local selectedData = nil - - for _, addonData in ipairs(addonsForList) do - if addonData.panel == panel then - selectedData = addonData - ScrollDataIntoView(addonList, selectedData) - lam.pendingAddonPanel = addonData.panel - break - end - end - - ZO_ScrollList_SelectData(addonList, selectedData) - ZO_ScrollList_RefreshVisible(addonList, selectedData) - - local srchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") - srchEdit:Clear() - - -- note that ZO_ScrollList doesn't require `selectedData` to be actually - -- present in the list, and that the list will only be populated once LAM - -- "Addon Settings" menu entry is selected for the first time - - local function openAddonSettingsMenu() - local gameMenu = ZO_GameMenu_InGame.gameMenu - local settingsMenu = gameMenu.headerControls[locSettings] - - if settingsMenu then -- an instance of ZO_TreeNode - local children = settingsMenu:GetChildren() - for i = 1, (children and #children or 0) do - local childNode = children[i] - local data = childNode:GetData() - if data and data.id == lam.panelId then - -- found LAM "Addon Settings" node, yay! - childNode:GetTree():SelectNode(childNode) - break - end - end - end - end - - if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then - openAddonSettingsMenu() - else - sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu) - sm:Show("gameMenuInGame") - end -end - -local TwinOptionsContainer_Index = 0 -local function TwinOptionsContainer(parent, leftWidget, rightWidget) - TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1 - local cParent = parent.scroll or parent - local panel = parent.panel or cParent - local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index), - cParent, CT_CONTROL) - container:SetResizeToFitDescendents(true) - container:SetAnchor(select(2, leftWidget:GetAnchor(0) )) - - leftWidget:ClearAnchors() - leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT) - rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0) - - leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls - rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 ) - - leftWidget:SetParent(container) - rightWidget:SetParent(container) - - container.data = {type = "container"} - container.panel = panel - return container -end - ---INTERNAL FUNCTION ---creates controls when options panel is first shown ---controls anchoring of these controls in the panel -local function CreateOptionsControls(panel) - local addonID = panel:GetName() - if(optionsState[addonID] == OPTIONS_CREATED) then - return false - elseif(optionsState[addonID] == OPTIONS_CREATION_RUNNING) then - return true - end - optionsState[addonID] = OPTIONS_CREATION_RUNNING - - local function CreationFinished() - optionsState[addonID] = OPTIONS_CREATED - cm:FireCallbacks("LAM-PanelControlsCreated", panel) - OpenCurrentPanel() - end - - local optionsTable = addonToOptionsMap[addonID] - if optionsTable then - local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf) - local widget - local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end) - if not status then - return err or true, offsetY, anchorTarget, wasHalf - else - local isHalf = (widgetData.width == "half") - if not anchorTarget then -- the first widget in a panel is just placed in the top left corner - widget:SetAnchor(TOPLEFT) - anchorTarget = widget - elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side - widget.lineControl = anchorTarget - isHalf = false - offsetY = 0 - anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget) - else -- otherwise we just put it below the previous one normally - widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15) - offsetY = 0 - anchorTarget = widget - end - return false, offsetY, anchorTarget, isHalf - end - end - - local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20 - local fifo = {} - local anchorOffset, lastAddedControl, wasHalf - local CreateWidgetsInPanel, err - - local function PrepareForNextPanel() - anchorOffset, lastAddedControl, wasHalf = 0, nil, false - end - - local function SetupCreationCalls(parent, widgetDataTable) - fifo[#fifo + 1] = PrepareForNextPanel - local count = #widgetDataTable - for i = 1, count, THROTTLE_COUNT do - fifo[#fifo + 1] = function() - CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count)) - end - end - return count ~= NonContiguousCount(widgetDataTable) - end - - CreateWidgetsInPanel = function(parent, widgetDataTable, startIndex, endIndex) - for i=startIndex,endIndex do - local widgetData = widgetDataTable[i] - if not widgetData then - PrintLater("Skipped creation of missing entry in the settings menu of " .. addonID .. ".") - else - local widgetType = widgetData.type - local offsetX = 0 - local isSubmenu = (widgetType == "submenu") - if isSubmenu then - wasHalf = false - offsetX = 5 - end - - err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) - if err then - PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) - end - - if isSubmenu then - if SetupCreationCalls(lastAddedControl, widgetData.controls) then - PrintLater(("The sub menu '%s' of %s is missing some entries."):format(GetStringFromValue(widgetData.name or "unnamed"), addonID)) - end - end - end - end - end - - local function DoCreateSettings() - if #fifo > 0 then - local nextCall = table.remove(fifo, 1) - nextCall() - if(nextCall == PrepareForNextPanel) then - DoCreateSettings() - else - zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT) - end - else - CreationFinished() - end - end - - if SetupCreationCalls(panel, optionsTable) then - PrintLater(("The settings menu of %s is missing some entries."):format(addonID)) - end - DoCreateSettings() - else - CreationFinished() - end - - return true -end - ---INTERNAL FUNCTION ---handles switching between panels -local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel - local currentlySelected = lam.currentAddonPanel - if currentlySelected and currentlySelected ~= panel then - currentlySelected:SetHidden(true) - CloseCurrentPanel() - end - lam.currentAddonPanel = panel - - -- refresh visible rows to reflect panel IsHidden status - ZO_ScrollList_RefreshVisible(lam.addonList) - - if not CreateOptionsControls(panel) then - OpenCurrentPanel() - end - - cm:FireCallbacks("LAM-RefreshPanel", panel) -end - -local CheckSafetyAndInitialize - ---METHOD: REGISTER ADDON PANEL ---registers your addon with LibAddonMenu and creates a panel ---Usage: --- addonID = "string"; unique ID which will be the global name of your panel --- panelData = table; data object for your panel - see controls\panel.lua -function lam:RegisterAddonPanel(addonID, panelData) - CheckSafetyAndInitialize(addonID) - local container = lam:GetAddonPanelContainer() - local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel - panel:SetHidden(true) - panel:SetAnchorFill(container) - panel:SetHandler("OnShow", ToggleAddonPanels) - - local function stripMarkup(str) - return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") - end - - local filterParts = {panelData.name, nil, nil} - -- append keywords and author separately, the may be nil - filterParts[#filterParts + 1] = panelData.keywords - filterParts[#filterParts + 1] = panelData.author - - local addonData = { - panel = panel, - name = stripMarkup(panelData.name), - filterText = stripMarkup(tconcat(filterParts, "\t")):lower(), - } - - tinsert(addonsForList, addonData) - - if panelData.slashCommand then - SLASH_COMMANDS[panelData.slashCommand] = function() - lam:OpenToPanel(panel) - end - end - - return panel --return for authors creating options manually -end - - ---METHOD: REGISTER OPTION CONTROLS ---registers the options you want shown for your addon ---these are stored in a table where each key-value pair is the order ---of the options in the panel and the data for that control, respectively ---see exampleoptions.lua for an example ---see controls\.lua for each widget type ---Usage: --- addonID = "string"; the same string passed to :RegisterAddonPanel --- optionsTable = table; the table containing all of the options controls and their data -function lam:RegisterOptionControls(addonID, optionsTable) --optionsTable = {sliderData, buttonData, etc} - addonToOptionsMap[addonID] = optionsTable -end - ---INTERNAL FUNCTION ---creates LAM's Addon Settings entry in ZO_GameMenu -local function CreateAddonSettingsMenuEntry() - local panelData = { - id = KEYBOARD_OPTIONS.currentPanelId, - name = util.L["PANEL_NAME"], - } - - KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1 - KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name - - lam.panelId = panelData.id - - local addonListSorted = false - - function panelData.callback() - sm:AddFragment(lam:GetAddonSettingsFragment()) - KEYBOARD_OPTIONS:ChangePanels(lam.panelId) - - local title = LAMAddonSettingsWindow:GetNamedChild("Title") - title:SetText(panelData.name) - - if not addonListSorted and #addonsForList > 0 then - local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") - --we're about to show our list for the first time - let's sort it - table.sort(addonsForList, function(a, b) return a.name < b.name end) - PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit)) - addonListSorted = true - end - end - - function panelData.unselectedCallback() - sm:RemoveFragment(lam:GetAddonSettingsFragment()) - if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011 - SetCameraOptionsPreviewModeEnabled(false) - end - end - - ZO_GameMenu_AddSettingPanel(panelData) -end - - ---INTERNAL FUNCTION ---creates the left-hand menu in LAM's window -local function CreateAddonList(name, parent) - local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList") - - local function addonListRow_OnMouseDown(control, button) - if button == 1 then - local data = ZO_ScrollList_GetData(control) - ZO_ScrollList_SelectData(addonList, data, control) - end - end - - local function addonListRow_OnMouseEnter(control) - ZO_ScrollList_MouseEnter(addonList, control) - end - - local function addonListRow_OnMouseExit(control) - ZO_ScrollList_MouseExit(addonList, control) - end - - local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild) - if not reselectingDuringRebuild then - if previouslySelectedData then - previouslySelectedData.panel:SetHidden(true) - end - if selectedData then - selectedData.panel:SetHidden(false) - PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION) - end - end - end - - local function addonListRow_Setup(control, data) - control:SetText(data.name) - control:SetSelected(not data.panel:IsHidden()) - end - - ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup) - -- I don't know how to make highlights clear properly; they often - -- get stuck and after a while the list is full of highlighted rows - --ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight") - ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select) - - local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE) - local addonListRow_CreateRaw = addonDataType.pool.m_Factory - - local function addonListRow_Create(pool) - local control = addonListRow_CreateRaw(pool) - control:SetHandler("OnMouseDown", addonListRow_OnMouseDown) - --control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter) - --control:SetHandler("OnMouseExit", addonListRow_OnMouseExit) - control:SetHeight(28) - control:SetFont("ZoFontHeader") - control:SetHorizontalAlignment(TEXT_ALIGN_LEFT) - control:SetVerticalAlignment(TEXT_ALIGN_CENTER) - control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - return control - end - - addonDataType.pool.m_Factory = addonListRow_Create - - return addonList -end - - ---INTERNAL FUNCTION -local function CreateSearchFilterBox(name, parent) - local boxControl = wm:CreateControl(name, parent, CT_CONTROL) - - local srchButton = wm:CreateControl("$(parent)Button", boxControl, CT_BUTTON) - srchButton:SetDimensions(32, 32) - srchButton:SetAnchor(LEFT, nil, LEFT, 2, 0) - srchButton:SetNormalTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_up.dds") - srchButton:SetPressedTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_down.dds") - srchButton:SetMouseOverTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_over.dds") - - local srchEdit = wm:CreateControlFromVirtual("$(parent)Edit", boxControl, "ZO_DefaultEdit") - srchEdit:SetAnchor(LEFT, srchButton, RIGHT, 4, 1) - srchEdit:SetAnchor(RIGHT, nil, RIGHT, -4, 1) - srchEdit:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) - - local srchBg = wm:CreateControl("$(parent)Bg", boxControl, CT_BACKDROP) - srchBg:SetAnchorFill() - srchBg:SetAlpha(0) - srchBg:SetCenterColor(0, 0, 0, 0.5) - srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) - srchBg:SetEdgeTexture("", 1, 1, 0, 0) - - -- search backdrop should appear whenever you hover over either - -- the magnifying glass button or the edit field (which is only - -- visible when it contains some text), and also while the edit - -- field has keyboard focus - - local srchActive = false - local srchHover = false - - local function srchBgUpdateAlpha() - if srchActive or srchEdit:HasFocus() then - srchBg:SetAlpha(srchHover and 0.8 or 0.6) - else - srchBg:SetAlpha(srchHover and 0.6 or 0.0) - end - end - - local function srchMouseEnter(control) - srchHover = true - srchBgUpdateAlpha() - end - - local function srchMouseExit(control) - srchHover = false - srchBgUpdateAlpha() - end - - boxControl:SetMouseEnabled(true) - boxControl:SetHitInsets(1, 1, -1, -1) - boxControl:SetHandler("OnMouseEnter", srchMouseEnter) - boxControl:SetHandler("OnMouseExit", srchMouseExit) - - srchButton:SetHandler("OnMouseEnter", srchMouseEnter) - srchButton:SetHandler("OnMouseExit", srchMouseExit) - - local focusLostTime = 0 - - srchButton:SetHandler("OnClicked", function(self) - srchEdit:Clear() - if GetFrameTimeMilliseconds() - focusLostTime < 100 then - -- re-focus the edit box if it lost focus due to this - -- button click (note that this handler may run a few - -- frames later) - srchEdit:TakeFocus() - end - end) - - srchEdit:SetHandler("OnMouseEnter", srchMouseEnter) - srchEdit:SetHandler("OnMouseExit", srchMouseExit) - srchEdit:SetHandler("OnFocusGained", srchBgUpdateAlpha) - - srchEdit:SetHandler("OnFocusLost", function() - focusLostTime = GetFrameTimeMilliseconds() - srchBgUpdateAlpha() - end) - - srchEdit:SetHandler("OnEscape", function(self) - self:Clear() - self:LoseFocus() - end) - - srchEdit:SetHandler("OnTextChanged", function(self) - local filterFunc = GetSearchFilterFunc(self) - if filterFunc then - srchActive = true - srchBg:SetEdgeColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA()) - srchButton:SetState(BSTATE_PRESSED) - else - srchActive = false - srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) - srchButton:SetState(BSTATE_NORMAL) - end - srchBgUpdateAlpha() - PopulateAddonList(lam.addonList, filterFunc) - PlaySound(SOUNDS.SPINNER_DOWN) - end) - - return boxControl -end - - ---INTERNAL FUNCTION ---creates LAM's Addon Settings top-level window -local function CreateAddonSettingsWindow() - local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow") - tlw:SetHidden(true) - tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow - - ZO_ReanchorControlForLeftSidePanel(tlw) - - -- create black background for the window (mimic ZO_RightFootPrintBackground) - - local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE) - bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds") - bgLeft:SetDimensions(1024, 1024) - bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT) - bgLeft:SetDrawLayer(DL_BACKGROUND) - bgLeft:SetExcludeFromResizeToFitExtents(true) - - local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE) - bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds") - bgRight:SetDimensions(64, 1024) - bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT) - bgRight:SetDrawLayer(DL_BACKGROUND) - bgRight:SetExcludeFromResizeToFitExtents(true) - - -- create gray background for addon list (mimic ZO_TreeUnderlay) - - local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE) - underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds") - underlayLeft:SetDimensions(256, 1024) - underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT) - underlayLeft:SetDrawLayer(DL_BACKGROUND) - underlayLeft:SetExcludeFromResizeToFitExtents(true) - - local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE) - underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds") - underlayRight:SetDimensions(128, 1024) - underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT) - underlayRight:SetDrawLayer(DL_BACKGROUND) - underlayRight:SetExcludeFromResizeToFitExtents(true) - - -- create title bar (mimic ZO_OptionsWindow) - - local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL) - title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70) - title:SetFont("ZoFontWinH1") - title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE) - - local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider") - divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108) - - -- create search filter box - - local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw) - srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120) - srchBox:SetDimensions(260, 30) - - -- create scrollable addon list - - local addonList = CreateAddonList("$(parent)AddonList", tlw) - addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160) - addonList:SetDimensions(285, 665) - - lam.addonList = addonList -- for easy access from elsewhere - - -- create container for option panels - - local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL) - panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120) - panelContainer:SetDimensions(645, 675) - - local defaultButton = wm:CreateControlFromVirtual("$(parent)ResetToDefaultButton", tlw, "ZO_DialogButton") - ZO_KeybindButtonTemplate_Setup(defaultButton, "OPTIONS_LOAD_DEFAULTS", HandleLoadDefaultsPressed, GetString(SI_OPTIONS_DEFAULTS)) - defaultButton:SetAnchor(TOPLEFT, panelContainer, BOTTOMLEFT, 0, 2) - lam.defaultButton = defaultButton - - local applyButton = wm:CreateControlFromVirtual("$(parent)ApplyButton", tlw, "ZO_DialogButton") - ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_ADDON_MANAGER_RELOAD)) - applyButton:SetAnchor(TOPRIGHT, panelContainer, BOTTOMRIGHT, 0, 2) - applyButton:SetHidden(true) - lam.applyButton = applyButton - - return tlw -end - - ---INITIALIZING -local safeToInitialize = false -local hasInitialized = false - -local eventHandle = table.concat({MAJOR, MINOR}, "r") -local function OnLoad(_, addonName) - -- wait for the first loaded event - em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED) - safeToInitialize = true -end -em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad) - -local function OnActivated(_, initial) - em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED) - FlushMessages() - - local reopenPanel = RetrievePanelForReopening() - if not initial and reopenPanel then - lam:OpenToPanel(reopenPanel) - end -end -em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated) - -function CheckSafetyAndInitialize(addonID) - if not safeToInitialize then - local msg = string.format("The panel with id '%s' was registered before addon loading has completed. This might break the AddOn Settings menu.", addonID) - PrintLater(msg) - end - if not hasInitialized then - hasInitialized = true - end -end - - ---TODO documentation -function lam:GetAddonPanelContainer() - local fragment = lam:GetAddonSettingsFragment() - local window = fragment:GetControl() - return window:GetNamedChild("PanelContainer") -end - - ---TODO documentation -function lam:GetAddonSettingsFragment() - assert(hasInitialized or safeToInitialize) - if not LAMAddonSettingsFragment then - local window = CreateAddonSettingsWindow() - LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100) - LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState) - if(newState == SCENE_FRAGMENT_SHOWN) then - InitKeybindActions() - PushActionLayerByName("OptionsWindow") - OpenCurrentPanel() - elseif(newState == SCENE_FRAGMENT_HIDDEN) then - CloseCurrentPanel() - RemoveActionLayerByName("OptionsWindow") - ShowReloadDialogIfNeeded() - end - end) - CreateAddonSettingsMenuEntry() - end - return LAMAddonSettingsFragment -end diff --git a/C615_LED_Off.reg b/C615_LED_Off.reg new file mode 100644 index 0000000..0124b9b Binary files /dev/null and b/C615_LED_Off.reg differ diff --git a/Gumroad Scanner.py b/Data Scrapers/Gumroad Scanner.py similarity index 73% rename from Gumroad Scanner.py rename to Data Scrapers/Gumroad Scanner.py index 8cf7234..33846d9 100644 --- a/Gumroad Scanner.py +++ b/Data Scrapers/Gumroad Scanner.py @@ -1,6 +1,13 @@ import requests from urllib.parse import quote -import time, codecs, re, random, signal, sys + +import time +# import codecs +import re +import random +import signal +# import sys +import os DEBUG = 0 @@ -9,13 +16,18 @@ # Ctrl+C stops page fetching loop, # while saving results. interrupted = False + + def signal_handler(sig, frame): global interrupted print('Interrupted! Finishing...') interrupted = True + + signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) + # Get user settings. query = '' while not query: @@ -27,21 +39,23 @@ def signal_handler(sig, frame): maxPrice = input('Max price per item [0]: ') maxPrice = float(maxPrice) if maxPrice != '' else 0 + # Log results to a new file. def log(text, f='txt'): t = time.strftime("%Y%m%d_%H%M%S") - with open('gumroad_results_'+t+'.'+f, 'w', encoding='utf-8') as file: + with open(f'gumroad_results_{t}.{f}', 'w', encoding='utf-8') as file: file.write(text) + # Return [(uniqueID str, price float), ..] from gumroad search results page. def scrape(page): try: r = requests.get(domain + page) except Exception as err: - DEBUG and print('Failed to connect: '+str(err)) + DEBUG and print(f'Failed to connect: {err}') return [] - + source = r.text # print(source) @@ -49,64 +63,72 @@ def scrape(page): n = 'data-unique-permalink=\\"' # itemprop=\"price\"\u003e$149+\u003c p = 'itemprop=\\"price\\"\\u003e' - # class=\"discover-product__information\"\u003e\n\u003ch2\u003e\nvoxel plugin™ PRO\n\u003c/h2 - t = 'class=\\"discover-product__information\\"\\u003e\\n\\u003ch2\\u003e\\n' + # \n\u003cstrong\u003e\nvoxel plugin™ PRO\n\u003c/strong\u003e\n + t = '\\u003cstrong\\u003e\\n' res = [] lastIndex = 0 for i in range(8): # Get item id for linking. a = source.find(n, lastIndex) + # No more items to list, so finish. if a == -1: break - b = source.find('\\"', a+len(n)) - name = source[a+len(n):b] + b = source.find('\\"', a + len(n)) + name = source[a + len(n):b] DEBUG and print(name) + # Get item price. - a = source.find(p, lastIndex) - b = source.find('\\u003c', a+len(p)) - price = source[a+len(p):b] + a = source.find(p, lastIndex) # Start from the last result's index. + b = source.find('\\u003c', a + len(p)) + price = source[a + len(p):b] DEBUG and print(price) # Extract number only. price = re.findall(r'\d+', price) + # BUG: No price available. if not price: break price = price[0] + # Get item title. a = source.find(t, lastIndex) - b = source.find('\\n', a+len(t)) - title = source[a+len(t):b] + b = source.find('\\n', a + len(t)) + title = source[a + len(t):b] DEBUG and print(title) + # Add item as tuple. res.append((name, float(price), title)) lastIndex = b return res + # Main loop. results = [] pageCount = '1' + + def run(): global pageCount - print() # Skip a line. + print() # Skip a line. for i in range(maxResults): # Signal interruption from system or user. if interrupted: break - - not DEBUG and print('Searching...'+('.'*i), end='\r', flush=True) + + not DEBUG and print(f'Searching...{("."*i)}', end="\r", flush=True) # Increments of 8, so 1, 9,.. and so on. v = i * 9 if i > 1 else 1 - link = '/discover_search?from=' + str(v) + '&query=' + quote(query) + link = f'/discover_search?from={v}&query={quote(query)}' # Imitate human delay. if i > 1: # 1-3 seconds. z = random.randrange(10, 30) / 10 - DEBUG and print('Page '+str(i)+' - Sleeping for '+str(z)+' seconds...') + DEBUG and print(f'Page {i} - Sleeping for {z} seconds...') time.sleep(z) res = scrape(link) @@ -128,26 +150,31 @@ def run(): 'price': price, 'title': title, } + # NOTE: Slow check, but keeps order. if x not in results: results.append(x) + def finish(): global pageCount - + DEBUG and print(results) # Log to file. if not results: - text = 'No results for '+query+'.' + text = f'No results for {query}.' else: text = '' for item in results: s = domain + '/l/' + item['id'] - text += ''+item['title']+'
' + text += f'
{item["title"]}
' + log(text, 'html') - input('Got '+str(len(results))+' matches saved from '+pageCount+' pages. Press Enter To Quit...') + print(f'Got {len(results)} matches saved from {pageCount} pages.') + os.system('pause') + # Calls. run() -finish() \ No newline at end of file +finish() diff --git a/Data Scrapers/HDRIHavenDownloader.py b/Data Scrapers/HDRIHavenDownloader.py new file mode 100644 index 0000000..21b8bd4 --- /dev/null +++ b/Data Scrapers/HDRIHavenDownloader.py @@ -0,0 +1,48 @@ +import scrapy +from scrapy.http import Request + + +class Spider(scrapy.Spider): + name = "spider" + start_urls = ['https://hdrihaven.com/hdris/category/?c=all'] + + custom_settings = { + 'DOWNLOAD_WARNSIZE': 0, + 'CONCURRENT_REQUESTS': 1, + 'CONCURRENT_ITEMS': 1, + 'LOG_LEVEL': 'INFO', + 'EXTENSIONS': { + 'scrapy.extensions.logstats.LogStats': None, + }, + } + + count = 0 + + def parse(self, response): + for href in response.css('div#hdri-grid > a::attr(href)').extract(): + yield Request( + url=response.urljoin(href), + callback=self.parse_link + ) + + def parse_link(self, response): + self.logger.info('Crawling... %s', response.request.url) + for href in response.css('div#hdri-info a[href$="&r=4k"]::attr(href)').extract(): + yield Request( + url=response.urljoin(href), + callback=self.parse_redirect + ) + + def parse_redirect(self, response): + for href in response.css('div#page-wrapper a[href$="4k.hdr"]::attr(href)').extract(): + yield Request( + url=response.urljoin(href), + callback=self.save_link + ) + + def save_link(self, response): + path = response.url.split('/')[-1] + self.count += 1 + self.logger.info('Saving #%d HDR %s', self.count, path) + with open(path, 'wb') as f: + f.write(response.body) diff --git a/Data Scrapers/TextureHavenDownloader.py b/Data Scrapers/TextureHavenDownloader.py new file mode 100644 index 0000000..e511a30 --- /dev/null +++ b/Data Scrapers/TextureHavenDownloader.py @@ -0,0 +1,41 @@ +import scrapy +from scrapy.http import Request + + +class Spider(scrapy.Spider): + name = "spider" + start_urls = ['https://texturehaven.com/textures/'] + + custom_settings = { + 'DOWNLOAD_WARNSIZE': 0, + 'CONCURRENT_REQUESTS': 1, + 'CONCURRENT_ITEMS': 1, + 'LOG_LEVEL': 'INFO', + 'EXTENSIONS': { + 'scrapy.extensions.logstats.LogStats': None, + }, + } + + count = 0 + + def parse(self, response): + for href in response.css('div#item-grid > a::attr(href)').extract(): + yield Request( + url=response.urljoin(href), + callback=self.parse_link + ) + + def parse_link(self, response): + self.logger.info('Crawling... %s', response.request.url) + for href in response.css('div.res-item a[href$="_4k_png.zip"]::attr(href)').extract(): + yield Request( + url=response.urljoin(href), + callback=self.save_link + ) + + def save_link(self, response): + path = response.url.split('/')[-1] + self.count += 1 + self.logger.info('Saving #%d ZIP %s', self.count, path) + with open(path, 'wb') as f: + f.write(response.body) diff --git a/DealFinder.py b/DealFinder.py new file mode 100644 index 0000000..ad3f6e9 --- /dev/null +++ b/DealFinder.py @@ -0,0 +1,1428 @@ +""" + Scrapes data from TTC, calculates the value of recent listings in the search, + and prints out filtered results to console. +""" + +from twisted.internet import reactor +import scrapy +from scrapy.crawler import CrawlerRunner +from scrapy.utils.log import configure_logging +from scrapy.http.request import Request + +from datetime import datetime +from time import sleep +from json import loads +from statistics import mean +from random import shuffle, uniform +from math import ceil + +import ctypes +import os +import winsound +import signal + + +DEBUG = 0 + + +# Let user force quit, if needed. +def ForceQuit(signum=None, frame=None, msg=''): + DEBUG and msg and print(f'\n\n{GetTimestamp()} - Forced quitting: {msg}\n') + + if not OPTIONS['TRIED_QUITTING']: + reactor.stop() + OPTIONS['TRIED_QUITTING'] = True + else: + os._exit(1) # Kill it! + + +OPTIONS = { + # System settings. # + 'TRIED_QUITTING': False, # Track CTRL-C. Twice forces quitting. + 'PRINTOUT': False, # Track whether any items were printed since last crawl. + # Track total listings printed out. + 'LISTING_COUNTER': 0, + # Track total listing printed out, including skipped items. + 'TOTAL_LISTING_COUNTER': 0, + # Track total skipped listings. + 'TOTAL_SKIPPED': 0, + # -------------------------------------------------------------------------------- # + + # NOTE The two highest will give a notification when matched. + 'SALES': { + 0: 'NOPE', + 5000: 'SALE', + 10000: 'GOOD SALE', + 20000: 'SPICY SALE', + 30000: 'HOT SALE', + 50000: 'FLAMING SALE', + }, + + # Hash table. + 'ITEM_TRAITS': { + None: '', + 'powered': 0, + 'charged': 1, + 'precise': 2, + 'infused': 3, + 'defending': 4, + 'training': 5, + 'sharpened': 6, + 'decisive': 7, + 'sturdy': 8, + 'impenetrable': 9, + 'reinforced': 10, + 'well fitted': 11, + 'invigorating': 12, + 'divines': 13, + 'nirnhoned': 14, + 'intricate': 15, + 'ornate': 16, + 'arcane': 17, + 'healthy': 18, + 'robust': 19, + 'special': 20, + 'bloodthirsty': 21, + 'harmony': 22, + 'protective': 23, + 'swift': 24, + 'triune': 25, + }, + + # Hash table. + 'ITEM_QUALITIES': { + None: '', + 'any quality': '', + 'normal': 0, + 'fine': 1, + 'superior': 2, + 'epic': 3, + 'legendary': 4, + }, + + # The BUY is too expensive for the potential PROFIT. + # Spending 100k to sell at 105k is too much investment for a 5k profit. + # RISK_REWARD_RATIO = 2 means that the purchase cost isn't more than double the profit estimate. + # Profit * Ratio >= Price + # 0 to disable. + 'RISK_REWARD_RATIO': 3, + + # Nearest SALES[] value below which a listing is not displayed to the user. + # 0 to disable. + 'IGNORE_SALES_UNDER': 5000, + + # Limit the listing purchase price. + # If you only have 20k to spend, then no sense in listing anything over that. + # 0 to disable. + 'IGNORE_BUYS_OVER': 0, + + # Ignore sales older than this, in minutes. + # 0 to disable. + # NOTE Only applies to ITEMS list crawling. + 'IGNORE_SALES_OLDER': 60, + + # How long to wait between refreshes of the spider from the start. + 'SPIDER_REFRESH_WAIT': 60 * 5, + + # How long to wait between each request for item data. + 'ITEM_WAIT': 1, + + # How long to wait before calling the connection bad. + 'CONNECTION_TIMEOUT': 10, + + # Connection retries. Proxies can have a bunch, it's normal. + 'CONNECTION_RETRIES': 2, + + # How many pages of recently listed items to crawl through. + 'URLS_PAGES': 3, + + # How many pages of each item listings to crawl through. + 'ITEM_PAGES': 3, + + # Excluded keywords in search. + 'EXCLUDE_KEYWORDS': [], + + # Required keywords in search. + 'REQUIRED_KEYWORDS': [], + + # How many units of an item must be for sale in a listing. + 'MINIMUM_UNITS': None, + + # Must not have more than this amount of units in a listing. (Game maximum stack is 200.) + 'MAXIMUM_UNITS': None, +} + +# Load proxies from file. +PROXY_COUNTER = 0 +PROXIES_FILE = 'proxies.txt' +PROXIES = None +try: + with open(PROXIES_FILE) as f: + # Not empty. Starts as a URL. + PROXIES = [line.strip() for line in f if line.strip().startswith('http')] + assert PROXIES # Not empty. + # Shuffle for when script is restarted often. + shuffle(PROXIES) + # Proxies are pop()ed, so reload the list from a copy. + PROXIES_COPY = PROXIES.copy() +except Exception: + print(f'\nFailed to load proxies from local file "{PROXIES_FILE}". Quitting...') + os.system('pause') + os._exit(1) + + +# Load items to search for from file. +ITEMS_FILE = 'items.txt' +ITEMS = None +try: + with open(ITEMS_FILE) as f: + # Not empty. Starts as a URL. + ITEMS = [line.strip() for line in f if line.strip().startswith('http')] + assert ITEMS # Not empty. +except Exception: + pass + + +def MakeBeep(): + """ Make a reasonably nice beep. Used for good sales. """ + winsound.Beep(200, 300) # Frequency in Hertz. Duration in ms. + + +def FlashTaskbar(): + """ Flash the taskbar. Used for great sales. """ + ctypes.windll.user32.FlashWindow(ctypes.windll.kernel32.GetConsoleWindow(), True) + + +def GetTimestamp(): + """ Return a formatted timestamp. """ + return str(datetime.now().strftime('%H:%M:%S')) + + +# Handle both success and failure callbacks from the spider. +def sleeper(error=None): + # Print out errors. + error and print(f'\n\nSpider error: {str(error)}\n') + + # Sleep, but allow interruption. + counter = 0 + while counter <= OPTIONS['SPIDER_REFRESH_WAIT'] and not OPTIONS['TRIED_QUITTING']: + print(f'Finished a scrape, waiting {OPTIONS["SPIDER_REFRESH_WAIT"] - counter} seconds for refresh...', end='\r', flush=True) + sleep(1) + counter += 1 + + OPTIONS['PRINTOUT'] = False + + +def crawl(runner): + """ Loop with a delay. """ + d = runner.crawl(Spider) + d.addBoth(sleeper) + d.addBoth(lambda _: crawl(runner)) + return d + + +# Ask the user for input about bot options. +def GetOptions(): + global ITEMS + + # Override crawler for item list mode. + if ITEMS: + answer = input( + '\n' + + f'Items list detected! Would you like to scan only for the listed {len(ITEMS)} items [y]: ' + ) + # Let user ignore the item list. + if answer and answer != 'y': + ITEMS = None + + if not ITEMS: + # Deal evaluation options: + opts = { + 'RISK_REWARD_RATIO': + '\n' + + '(A value of 2 means the expected profit is at least half the buy price.)' + + '\n' + + 'Risk ratio of BUY/PROFIT [3]: ', + + 'IGNORE_SALES_UNDER': + '\n' + + '(Profit values closer to 0, than they are closer to this value, will not be listed.)' + + '\n' + + 'Ignore sales under [5000]: ', + } + + for k, v in opts.items(): + input_value = input(v) + + try: + input_value_check = int(float(input_value)) + OPTIONS[k] = input_value_check + except Exception: + pass + + # Listing options: + opts = { + 'IGNORE_BUYS_OVER': + '\n' + + '(Skip listings that cost more than this amount to buy.)' + + '\n' + + 'Ignore buys over [0]: ', + + 'MINIMUM_UNITS': + '\n' + + 'Minimum amount of units [1]: ', + + 'MAXIMUM_UNITS': + '\n' + + 'Maximum amount of units [200]: ', + } + + for k, v in opts.items(): + input_value = input(v) + + try: + input_value_check = int(float(input_value)) + OPTIONS[k] = input_value_check + except Exception: + pass + + input_value = input( + '\n' + + '(Includes partial matches. Example: style, vanus)' + + '\n' + + 'Exclude keywords: ' + ) + try: + input_value_check = [ + x.strip().lower() + for x in input_value.split(',') + if x.strip() != '' + ] + OPTIONS['EXCLUDE_KEYWORDS'] = input_value_check + except Exception: + pass + + input_value = input( + '\n' + + '(Includes partial matches. Example: dagger, plati)' + + '\n' + + 'Require keywords: ' + ) + try: + input_value_check = [ + x.strip().lower() + for x in input_value.split(',') + if x.strip() != '' + ] + OPTIONS['REQUIRED_KEYWORDS'] = input_value_check + except Exception: + pass + else: + # Listing options. + opts = { + 'IGNORE_SALES_OLDER': + '\n' + + '(Skip listings that are older than this many minutes.)' + + '\n' + + 'Ignore older than [60]: ', + } + + for k, v in opts.items(): + input_value = input(v) + + try: + input_value_check = int(float(input_value)) + OPTIONS[k] = input_value_check + except Exception: + pass + + # Scanning options. + opts = { + 'SPIDER_REFRESH_WAIT': + '\n' + + '(How long to wait after completion to start the entire crawl over, in seconds.)' + + '\n' + + 'Spider delay [300]: ', + + # More pages puts a loads on the TTC website, + # but less pages is less listings and more waiting. + 'URLS_PAGES': + '\n' + + '(More pages means more recent listings every full scan interval.)' + + '\n' + + 'Search result pages to scan [3]: ', + } + + for k, v in opts.items(): + input_value = input(v) + + try: + input_value_check = int(float(input_value)) + OPTIONS[k] = input_value_check + except Exception: + pass + + +def StartCrawler(): + # Configure. + configure_logging({'LOG_FORMAT': '\n%(levelname)s: %(message)s\n'}) + runner = CrawlerRunner() + # Execute. + crawl(runner) + reactor.run() + + +class Item(): + """ + A TTC item with all its data. + """ + + def __init__(self, name, level, champion, quality, trait, vouchers, location, guild, + price_per_piece, units_count, buy_price, last_seen, ItemID=None, index=None): + self.name = name # str + self.level = level # 'true' or 'false'. + self.champion = champion + self.quality = quality + self.trait = trait # Optional + self.vouchers = vouchers # Optional, for writs. + self.trader = '' # TODO 'Community' for guild trader, otherwise @player. + self.location = location # '' if private sale not ignored! + self.guild = guild # '' if private sale not ignored! + self.ppp = price_per_piece # int + self.units = units_count # int + self.total = buy_price # int - Total price of listing. + self.lastSeen = last_seen # int - Last seen in minutes (Seen! not listed.) + self.values = [] # Added later. + self.seens = [] # ... + self.itemID = ItemID + # Tracking. + self.value = None # Estimated worth. + self.index = index # By order of adding. + + DEBUG and print(f'\n\n- Done parsing item: {name}\n') + + +class Spider(scrapy.Spider): + """ + Crawl TTC with a new proxy for each Request(). Fetch listings from latest search results, + and calculate their value (as resale) for print-out in console. + """ + name = "spider" + + # Count for printing. + counter = 0 + # Visual for printing. + skipped = 0 + + # Holds all found items. + ITEMS = {} + + # Scrape the general search for latest listings. + urls = [ + 'https://us.tamrieltradecentre.com/pc/Trade/SearchResult?' + + 'ItemID=' + + '&SearchType=Sell' + + '&ItemNamePattern=' + + '&ItemCategory1ID=' + + '&ItemCategory2ID=' + + '&ItemCategory3ID=' + + '&ItemTraitID=' + + '&ItemQualityID=' + + '&IsChampionPoint=false' + + '&LevelMin=' + + '&LevelMax=' + + '&MasterWritVoucherMin=' + + '&MasterWritVoucherMax=' + + '&AmountMin=' + + '&AmountMax=' + + '&PriceMin=' + + '&PriceMax=' + + '&page=' + ] + + item_autocomplete_url = 'https://us.tamrieltradecentre.com/api/pc/Trade/GetItemAutoComplete?term=' + + custom_settings = { + 'DOWNLOAD_WARNSIZE': 0, + 'CONCURRENT_REQUESTS': 1, + 'CONCURRENT_ITEMS': 1, + 'LOG_LEVEL': 'ERROR', # WARNING + 'EXTENSIONS': { + 'scrapy.extensions.logstats.LogStats': None, + }, + + 'DNS_TIMEOUT': OPTIONS['CONNECTION_TIMEOUT'], + 'DOWNLOAD_TIMEOUT': OPTIONS['CONNECTION_TIMEOUT'], + 'DOWNLOAD_DELAY': OPTIONS['ITEM_WAIT'], + + 'RETRY_TIMES': OPTIONS['CONNECTION_RETRIES'], + 'RETRY_HTTP_CODES': [500, 503, 504, 400, 403, 404, 408], + + 'ROBOTSTXT_OBEY': 'False', + + 'DOWNLOADER_MIDDLEWARES': { + 'scrapy.downloadermiddlewares.retry.RetryMiddleware': 90, + 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110, + # 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, + # 'scrapy_useragents.downloadermiddlewares.useragents.UserAgentsMiddleware': 500, + }, + } + + # TODO Move instatiated values to here! Above are shared for all instances! + def __init__(self): + pass + + # Track and printout item skipping. + def SkipItem(self): + self.skipped += 1 + OPTIONS['TOTAL_SKIPPED'] += 1 + + if not OPTIONS['PRINTOUT']: + print('\n') + OPTIONS['PRINTOUT'] = True + + print(f'{GetTimestamp()} Skipped {self.skipped} ({OPTIONS["TOTAL_SKIPPED"]}) items...', end='\r', flush=True) + + # Estimate the value of an item from its listings. + # Return the smart average, its digits category, and the values kept in the analysis. + def GetAverageValue(self, values): + # Number of digits in price. No fractions in the game. + categories = { + '1': 0, + '2': 0, + '3': 0, # Hundreds. + '4': 0, # Thousands. + '5': 0, + '6': 0, + '7': 0, # Millions. + '8': 0, + '9': 0, + } + + # Number of digits in the number is its category. + for v in values: + categories[(str(len(str(v))))] += 1 + + # Get the biggest one. If more than one, get the bigger category. + category = max(reversed(sorted(categories.keys())), key=(lambda k: categories[k])) + + # Keep only the values in the category. + kept = [] + for v in values: + cat = str(len(str(v))) + if cat == category: + # Round to category less two digit. (1,553 -> 1,600) + r = round(v, -int(category) + 2) + kept.append(r) + + # Add values from another category if it has a meaningful amount of listings. + for v in values: + cat = str(len(str(v))) + # Skip main category. + if cat == category: + continue + # NOTE Hard to say what number makes sense. Ratios don't make sense in any format. + if categories[cat] >= 10: + # Round to category less two digit. (1,553 -> 1,600) + r = round(v, -int(category) + 2) + kept.append(r) + + return mean(kept), category, kept + + # Figure out what is an expected sale price. + # Saves and returns the resulting value calculations. + # Sorts the Values at the end. + # Ignored listings return None. + def CalcItemValue(self, item): + ''' + p = [15000, 15000, 14500, 22500, 33000, 9999, 27000, 35500, 150000, 200000] + + 1. Count how many digits are in each number: Singles, Doubles, Hundreds, Thousands, Tens of, Hundreds of, Millions. + (8 Tens of, 2 Hundreds of.) + + 2. Select the most used digits state. (Tens of.) [15000, 15000, 14500, 22500, 33000, 9999, 27000, 35500] + + 3. Round all up or down (by nearness to middle) to one digit under category. + [15000, 15000, 15000, 23000, 33000, 10000, 27000, 36000] + + 4. Get the mean(). (21750) + + 5. Get the nearest sale prices below and over the mean. (15000, 33000) + + Return all 3 last results rounded. ("22,000 [15,000, 33,000]") + ''' + + values = item.values + len_values = len(values) + units = item.units + ppp = item.ppp + last_seens = item.seens + + # Get estimates. + avrg, category, kept = self.GetAverageValue(values) + # No fractions. + avrg = int(avrg) + # Round to category. + avrg = round(avrg, -int(category) + 2) + + # Save estimated average price. + item.value = avrg + + # Separate prices around the mean. + underMean = [p for p in kept if p < avrg] + overMean = [p for p in kept if p > avrg] + + # Get range. + nearestUnder = underMean and min(underMean, key=lambda x: abs(x - avrg)) or 0 + nearestOver = overMean and min(overMean, key=lambda x: abs(x - avrg)) or 0 + # Round to category. + nearestUnder = round(nearestUnder, -int(category) + 2) + nearestOver = round(nearestOver, -int(category) + 2) + + # Find my potential profit. Stacks calculate selling the whole stack. + # Example: 120g * 37 - 35g * 37 = 4440 - 1295 = 3,145g EARNINGS + profit = (avrg * units) - (ppp * units) + # Round to category. + profit = round(profit, -int(category) + 2) + + # Find nearest sale category value. + # Example: profit = 3,145g matches category [5000]. 1,232g would match [0]. + nearestCategory = min(list(OPTIONS['SALES']), key=lambda x: abs(x - profit)) + + # Under profit threshold. + # NOTE replace nearestCategory with profit, for accuracy? + if OPTIONS['IGNORE_SALES_UNDER'] and nearestCategory < OPTIONS['IGNORE_SALES_UNDER']: + DEBUG and print(f'\n\n- Skipping listing from calc nearestCategory {nearestCategory} < {OPTIONS["IGNORE_SALES_UNDER"]}: {item.name}\n') + return + + # For the same profit, the smaller the purchase the better. + # Example: 3,145g * 1 >= 1,295g + if not profit: + # All values are the same. IGNORE_SALES_UNDER normally filters this out. + risk = 0 + else: + risk = (ppp * units) / profit + + # print(f'\n\nRisk: {risk}') + + # The advanced cost is too high for the potential profit. + # Example: BUY 100k, SELL 105k, PROFIT 5k. risk = 100 / 5 = 20 + # NOTE add < 0 case? + if OPTIONS['RISK_REWARD_RATIO'] and risk > OPTIONS['RISK_REWARD_RATIO']: + DEBUG and print(f'\n\n- Skipping listing from calc risk {risk} > {OPTIONS["RISK_REWARD_RATIO"]}: {item.name}\n') + return + + limited_supply = False + if len_values < 10: + # Limited supply items don't even have 10 results in TTC. + limited_supply = True + + # Trends. Recognize when an item is being sold a lot (more than twice an hour?) + # and the price is dropping daily (in the last 3 days?) + hourly_sales = 0 + prices_today = [] + prices_yesterday = [] + prices_ereyesterday = [] + i = 0 # Index. + for m in last_seens: + # Count sales in last hour. + if m <= 60: + hourly_sales += 1 + + if m <= 1440: + prices_today.append(values[i]) + elif m <= 2880: + prices_yesterday.append(values[i]) + elif m <= 4320: + prices_ereyesterday.append(values[i]) + + i += 1 + + # Figure out if there's a trend in daily pricing. + a = b = c = 0 + + if prices_today: + a = self.GetAverageValue(prices_today)[0] + if prices_yesterday: + b = self.GetAverageValue(prices_yesterday)[0] + if prices_ereyesterday: + c = self.GetAverageValue(prices_ereyesterday)[0] + + if a > b and b > c: + # Price is rising daily. + trend = mean([a - b, b - c]) + elif a < b and b < c: + # Price is dropping daily. + trend = mean([b - a, c - b]) + else: + # Price has no simple trend. + trend = 0 + + return avrg, nearestUnder, nearestOver, nearestCategory, profit, limited_supply, hourly_sales, trend + + # Extracts item values in TTC from a .css() selector result. + # nameOnly - Optionally only return the name. Helps validity checks. + # Return None on failure. + def ExtractItem(self, item, nameOnly=None, exceptions=True): + # Item name. + name = item.css('td:nth-child(1) > div:nth-of-type(1)::text').get() + # Remove whitespaces. + name = name.strip() + + if nameOnly: + return name + + try: + champion = item.css('td:nth-child(1) > div:nth-of-type(3) > img::attr(src)').get() + if champion is None: + raise Exception() + except Exception: + # In third div. + champion = item.css('td:nth-child(1) > div:nth-of-type(2) > img::attr(src)').get() + + # /Content/icons/nonvet.png or /Content/icons/championPoint.png + if 'championPoint' in champion: + champion = 'true' + else: + champion = 'false' + + try: + level = item.css('td:nth-child(1) > div:nth-of-type(3)::text').getall()[1] + if level is None: + raise Exception() + except Exception: + # In third div. + level = item.css('td:nth-child(1) > div:nth-of-type(2)::text').getall()[1] + + quality = item.css('td:nth-child(1) > img::attr(class)').get() + quality = quality.strip().split()[1].split('-')[-1] + + trait = item.css('td:nth-child(1) > img::attr(data-trait)').get() + + try: + v = item.css('td:nth-child(1) > div:nth-of-type(2)::text').get() + vouchers = int(v.split()[1]) + except Exception: + # Not a writ. + vouchers = '' + pass + + location = '' + guild = '' + try: + place = item.css('td:nth-child(3) > div::text').getall() + location = place[0] + guild = place[1] + except Exception: + # Some listings are from a user, not a trader, so ignore those. + DEBUG and print(f'\n\n- Skipping listing from user sale: {name}\n') + if exceptions: + return + + pricings = item.css('td:nth-child(4)::text').getall() + + price_per_piece = pricings[1] + units_count = pricings[3] + buy_price = pricings[5] + + last_seen = item.css('td:nth-child(5)::attr(data-mins-elapsed)').get() + + # Remove whitespaces. + level = level.strip() + quality = quality.strip() + location = location.strip() + guild = guild.strip() + price_per_piece = price_per_piece.strip() + units_count = units_count.strip() + last_seen = last_seen.strip() + + # Remove commas. + price_per_piece = price_per_piece.replace(',', '') + units_count = units_count.replace(',', '') + buy_price = buy_price.replace(',', '') + last_seen = last_seen.replace(',', '') + # Remove decimal point. Rounds down! + price_per_piece = int(float(price_per_piece)) + units_count = int(float(units_count)) + buy_price = int(float(buy_price)) + last_seen = int(float(last_seen)) + + # Lowercase for dict and url matching. + quality = quality.lower() + if trait is not None: + trait = trait.lower() + + return Item(name, level, champion, quality, trait, vouchers, location, guild, + price_per_piece, units_count, buy_price, last_seen) + + # Yielded bad proxy. Remove it from list, and yield same request with new proxy. + def BadProxy(self, failure=None): + global PROXIES_COPY + + # Pass original request data for reuse: Search page, ItemID, or item search page. + r = failure.request + + # Remove bad proxies from safe list. + PROXIES_COPY.remove(r.meta['proxy']) + + # Copy all optional meta properties. Use new proxy. + meta = {} + + if 'name' in r.meta: + meta['name'] = r.meta['name'] + if 'item' in r.meta: + meta['item'] = r.meta['item'] + if 'page' in r.meta: + meta['page'] = r.meta['page'] + if 'index' in r.meta: + meta['index'] = r.meta['index'] + if 'retries' in meta: + meta['retries'] = r.meta['retries'] + + meta['proxy'] = self.GetProxy() + meta['retry'] = 'bad connection' + + # If no connection or blocked by captcha, try another proxy. + yield Request( + url=r.url, + callback=r.callback, + meta=meta, + headers=r.headers, + errback=self.BadProxy, + dont_filter=True, + ) + + # Gets the current proxy and moves to the next, for next request. + def GetProxy(self): + global PROXY_COUNTER, PROXIES + + try: + p = PROXIES.pop(0) # Avoid async getting the same item. + except Exception: + DEBUG and print(f'\n\n- Restarting proxy list...\n') + # Emptied the list, so reload it to start over. + PROXIES = PROXIES_COPY.copy() + p = PROXIES.pop(0) + PROXY_COUNTER = 0 + + # Next request will get the next proxy. + PROXY_COUNTER += 1 + + return p + + # First call. + def start_requests(self): + global ITEMS + + DEBUG and print(f'\n\n- Starting crawler...\n') + + if not ITEMS: + for i in range(OPTIONS['URLS_PAGES']): + yield Request( + url=f'{self.urls[0]}{i+1}', + callback=self.parse, + meta={'proxy': self.GetProxy(), 'page': i + 1}, + errback=self.BadProxy, + dont_filter=True + ) + else: + i = 0 + for url in ITEMS: + # Scan the item's recent listings. + yield Request( + url=url, + callback=self.parse_get_item_value, + meta={'proxy': self.GetProxy(), 'page': 1, 'index': i}, + errback=self.BadProxy, + dont_filter=True + ) + # Track indexing. + i += 1 + + def parse(self, response): + """ + Gets items from search results page. + Sends to parse_set_item(). + """ + + selector = response.css('tr.cursor-pointer') + count = len(selector) + noneSelector = response.xpath("//h4[contains(., 'No trade matches your constraint')]") + + # Blocked by captcha! + if not selector and not noneSelector: + # Call page again with new proxy. + yield Request( + url = response.url, + callback = response.request.callback, + meta = {'proxy': self.GetProxy(), 'page': response.meta['page'], 'retry': 'blocked by captcha'}, + errback=self.BadProxy, + dont_filter=True, + ) + return + + DEBUG and print(f'\n\n-- Started parsing TTC page #{response.meta["page"]} - {count} items.\n') + + # Get recently listed items and their data. + for item in selector: + name = self.ExtractItem(item, True) + + # Skip unmatched item names. TODO Abstract to function. + try: + for word in OPTIONS['EXCLUDE_KEYWORDS']: + if word in name.lower(): + raise Exception(f'skipping {name} excluded word {word}') + for word in OPTIONS['REQUIRED_KEYWORDS']: + if word not in name.lower(): + raise Exception(f'skipping {name} required word {word}') + except Exception as e: + # Skip listing. + DEBUG and print(f'\n\n- Skipping listing from name: {name}\nReason: {e}\n') + self.SkipItem() + continue + + # REQUIRED. Get ItemID for accurate TTC searching. + yield Request( + url = scrapy.utils.url.safe_url_string(self.item_autocomplete_url + name), + callback = self.parse_set_item, + meta = {'proxy': self.GetProxy(), 'name': name, 'item': item}, + headers={'content-type': "application/json", + 'accept': "text/plain, */*; q=0.01"}, + errback=self.BadProxy, + dont_filter=True, + ) + + def parse_set_item(self, response): + """ + Gets ItemID for item. + Sends to parse_get_value(). + """ + + OPTIONS['TOTAL_LISTING_COUNTER'] += 1 + + try: + j = loads(response.body) + ItemID = j[0]['ItemID'] + except Exception: + print(f'\n\n- Failed to get ItemID for {response.meta["name"]}. Probably bad proxy. Dropping listing.\n') + return + + name = response.meta['name'] + item = response.meta['item'] + proxy = response.meta['proxy'] + + if DEBUG: + if 'retry' in response.meta: + print(f'\n\n- Parsing item (after {response.meta["retry"]}): {name}\tProxies left: {len(PROXIES)}\n') + else: + print(f'\n\n- Parsing item: {name}\n') + + item = self.ExtractItem(item) + + # Any failure from extraction, such as listing from player - not guild trader. + if not item: + self.SkipItem() + return + + # Skip listings outside of limits. TODO Abstract to function. + if OPTIONS['IGNORE_BUYS_OVER'] and item.total > OPTIONS['IGNORE_BUYS_OVER']: + DEBUG and print(f'\n\n- Skipping listing buy_price {item.total} > {OPTIONS["IGNORE_BUYS_OVER"]}: {name}\n') + self.SkipItem() + return + if OPTIONS['MINIMUM_UNITS'] and item.units < OPTIONS['MINIMUM_UNITS']: + DEBUG and print(f'\n\n- Skipping listing units_count {item.units} < {OPTIONS["MINIMUM_UNITS"]}: {name}\n') + self.SkipItem() + return + if OPTIONS['MAXIMUM_UNITS'] and item.units > OPTIONS['MAXIMUM_UNITS']: + DEBUG and print(f'\n\n- Skipping listing units_count {item.units} > {OPTIONS["MAXIMUM_UNITS"]}: {name}\n') + self.SkipItem() + return + + # Add to collection. + # TODO or update existing item. + index = len(self.ITEMS) + 1 + self.ITEMS[index] = item + + # Add parse values to item. + item.itemID = ItemID + item.index = index + + # Get listing pages for the item, to aggregate its market value. + # NOTE Must get to the last page of OPTIONS['ITEM_PAGES'], or no printout! + page = 1 + yield Request( + f'https://us.tamrieltradecentre.com/pc/Trade/SearchResult?ItemID={item.itemID}&SearchType=Sell' + + f'&ItemNamePattern=&ItemCategory1ID=&ItemCategory2ID=&ItemCategory3ID=' + + f'&ItemTraitID={OPTIONS["ITEM_TRAITS"][item.trait]}&ItemQualityID={OPTIONS["ITEM_QUALITIES"][item.quality]}' + + f'&IsChampionPoint={item.champion}&LevelMin={item.level}&LevelMax={item.level}' + + f'&MasterWritVoucherMin={item.vouchers}&MasterWritVoucherMax={item.vouchers}' + + f'&AmountMin=&AmountMax=&PriceMin=&PriceMax=&page={page}', + callback = self.parse_get_value, + meta = {'proxy': proxy, 'item': item, 'page': page, 'name': name}, + errback=self.BadProxy, + dont_filter=True, + ) + + def parse_get_value(self, response): + """ + Gets recent listing values for item, and calculate worth of original item listing. + TODO Merge item by ItemID, so they all share values, + but each has its own PPP and Location. + """ + r = response + meta = r.meta + + item = meta['item'] + page = meta['page'] + proxy = meta['proxy'] + name = item.name + + # Limit retries. NOTE Bug that causes unending failures? Bad proxy list? + retries = 1 + if 'retries' in meta: + retries = meta['retries'] + if retries > 7: + # Skips listing. TODO Unwanted! + DEBUG and print(f'\n\n- Dropping item page #{page} (after {meta["retry"]}) ({retries}): {name}\tProxies left: {len(PROXIES)}\n') + self.SkipItem() + return + + if DEBUG: + if 'retry' in meta: + print(f'\n\n- Parsing item page #{page} (after {meta["retry"]}) ({retries}): {name}\tProxies left: {len(PROXIES)}\n') + else: + print(f'\n\n- Parsing item page #{page}: {name}\n') + + selector = r.css('tr.cursor-pointer') + noneSelector = r.xpath("//h4[contains(., 'No trade matches your constraint')]") + + # Blocked by captcha! + if not selector and not noneSelector: + # Call page again with new proxy. + yield Request( + url = r.url, + callback = r.request.callback, + meta = {'proxy': self.GetProxy(), 'item': item, 'page': page, + 'name': name, 'retry': 'blocked by captcha', 'retries': retries + 1}, + errback=self.BadProxy, + dont_filter=True, + ) + return + + # Get all of this item's prices per piece (unit) recently listed. + for i in r.css('tr.cursor-pointer'): + price_per_piece = i.css('td:nth-child(4)::text').getall()[1] + last_seen = i.css('td:nth-child(5)::attr(data-mins-elapsed)').get() + + # Remove whitespaces. + price_per_piece = price_per_piece.strip() + last_seen = last_seen.strip() + # Remove decimals and points. + price_per_piece = price_per_piece.replace(',', '') + last_seen = last_seen.replace(',', '') + # Remove decimal point. Rounds down! + price_per_piece = int(float(price_per_piece)) + last_seen = int(float(last_seen)) + + item.values.append(price_per_piece) + item.seens.append(last_seen) + + DEBUG and print(f'\n\n- Finished page #{page}: {name}\n') + + # If not last page of search. + if page < OPTIONS['ITEM_PAGES']: + # Wait between every page, like a human would. + sleep(uniform(10.5, 15.5)) + # Next page. + page = page + 1 + # Callback next page. + yield Request( + url = f'https://us.tamrieltradecentre.com/pc/Trade/SearchResult?ItemID={item.itemID}&SearchType=Sell' + + f'&ItemNamePattern=&ItemCategory1ID=&ItemCategory2ID=&ItemCategory3ID=' + + f'&ItemTraitID={OPTIONS["ITEM_TRAITS"][item.trait]}&ItemQualityID={OPTIONS["ITEM_QUALITIES"][item.quality]}' + + f'&IsChampionPoint={item.champion}&LevelMin={item.level}&LevelMax={item.level}' + + f'&MasterWritVoucherMin={item.vouchers}&MasterWritVoucherMax={item.vouchers}' + + f'&AmountMin=&AmountMax=&PriceMin=&PriceMax=&page={page}', + callback = r.request.callback, + meta = {'proxy': proxy, 'item': item, 'page': page, 'name': name}, + errback=self.BadProxy, + dont_filter=True, + ) + return + + # Calculate value after last page, if there are any values. + if item.values: + avrg, nearestUnder, nearestOver, nearest, profit, limited_supply, hourly_sales, trend = \ + self.CalcItemValue(item) or [None for x in range(8)] + + # Item ignored in calc. + if not avrg: + DEBUG and print(f'\n\n- Skipping listing from calc: {name}\n') + self.SkipItem() + return + + # DEBUG track proxy changes + # p = r.request.meta["proxy"] + # msg += f'\nproxy #{PROXIES.index(p)}' + + # Values range to meaningful text. + value_range = '' + if nearestUnder: + value_range = str(nearestUnder) + if nearestOver: + # Inbetween sign. + if nearestUnder: + value_range += ' < ' + value_range += str(nearestOver) + + values_len = len(item.values) + values = sorted(item.values) + if values_len > 15: + # Split into lines of 15 values max. + v = [] + for i in range(ceil(values_len / 15)): + start = i * 15 + end = (i + 1) * 15 + v.append(str(values[start:end])) + # Add a newline between parts. + values = '\n'.join(v) + + # Buy price. + buyTotal = item.total + buyPPP = '' + + # Sell price, for same batch. + sellTotal = avrg * item.units + sellPPP = '' + + # Item quality. + quality = '(' + item.quality.capitalize() + ') ' + + # Optionals. + trait = '' + units = '' + vouchers = '' + + if item.trait is not None: + trait = '(' + item.trait.capitalize() + ') ' + + # More than 1 unit. + if item.units > 1: + units = str(item.units) + ' x ' + # Print out, as well. + buyPPP = f'({item.ppp:,}g)' + sellPPP = f'({avrg:,}g)' + + if item.vouchers: + vouchers = '(' + str(item.vouchers) + ' Vouchers) ' + + if limited_supply: + limited_supply = 'Limited supply!' + else: + limited_supply = '' + + # Attention on amazing sales! Last two values. + if nearest >= sorted(OPTIONS['SALES'])[-2]: + MakeBeep() + FlashTaskbar() + + # Blueprint: High Elf Bookcase, Winged (Epic) | Deshaan: Mournhold by "Ethereal Traders Union II" + # BUY 16,311g | SELL 28,000g [18,000g < 30,000g] | HOT SALE - EARNINGS 11689g + # [15000, 16311, 18000, 30000, 30000, 30000, 30000, 33300] Limited supply! + msg = (f'{units}{item.name} {quality}{trait}{vouchers}| {item.location} by "{item.guild}"\n' + + f'BUY {buyTotal:,}g {buyPPP}| SELL {sellTotal:,}g [{value_range}] {sellPPP}| {OPTIONS["SALES"][nearest]} | ' + + f'PROFIT {profit:,}g | HOURLY: {hourly_sales}\n' + # | PRICE TREND {trend:,}g\n' + + f'{"-"*80}\n' + + f'{values} {limited_supply}') + + self.print_value(msg) + + # In tandem with ScanItems() only. + def parse_get_item_value(self, response): + """ + Make the Item() and find new listings (as filtered by the url.) + """ + + OPTIONS['TOTAL_LISTING_COUNTER'] += 1 + + r = response + meta = r.meta + url = r.url + + DEBUG and print(f'url: {url}') + + page = meta['page'] + index = meta['index'] + proxy = meta['proxy'] + + item = None + if 'item' in meta: + item = meta['item'] + + newItems = [] + if 'newItems' in meta: + newItems = meta['newItems'] + + # Limit retries. NOTE Bug that causes unending failures? Bad proxy list? + retries = 1 + if 'retries' in meta: + retries = meta['retries'] + if retries > 7: + # Skips listing. TODO Unwanted! + DEBUG and print(f'\n\n- Dropping item page #{page} (after {meta["retry"]}) ({retries}): {url}\tProxies left: {len(PROXIES)}\n') + self.SkipItem() + return + + if DEBUG: + if 'retry' in meta: + print(f'\n- Parsing item page #{page} (after {meta["retry"]}) ({retries}): {url}\tProxies left: {len(PROXIES)}\n') + else: + print(f'\n- Parsing item page #{page}: {url}\n') + + selector = r.css('tr.cursor-pointer') + count = len(selector) + noneSelector = r.xpath("//h4[contains(., 'No trade matches your constraint')]") + + DEBUG and print(f'\n\n - Nothing in selector: {not selector} | Nothing in noneSelector: {not noneSelector}\n') + + # Blocked by captcha! + if not selector and not noneSelector: + # Call page again with new proxy. + yield Request( + url = url, + callback = r.request.callback, + meta = {'proxy': self.GetProxy(), 'item': item, 'page': page, + 'index': index, 'retry': 'blocked by captcha', 'retries': retries + 1}, + errback=self.BadProxy, + dont_filter=True, + ) + return + + # No results for search url, at the time. + if page == 1 and not selector: + DEBUG and print(f'\nNo results for: {url}\n') + return + + # Set up the item object from first listing. + if not item: + if index in self.ITEMS: + item = self.ITEMS[index] + else: + item = self.ExtractItem(selector[0], exceptions=False) + + item.index = index + + # Extract ItemID from url. + # TODO Optional get ItemID from API with link. + try: + s = 'ItemID=' + start = url.find(s) + assert start >= 0 + start += len(s) + end = url.find('&', start) + + ItemID = url[start:end] + assert ItemID and int(ItemID) + except Exception: + print(f'\nItem link without ItemID! Skipping: {url}\n') + return + + item.itemID = ItemID + # Reset lastSeen to start tracking. + item.lastSeen = 0 + + # Add to list. + self.ITEMS[index] = item + + # Get all of this item's prices per piece (unit) recently listed. + allFurtherOld = False + for i in selector: + o = self.ExtractItem(i) + + # Private sale. + if not o: + continue + + # An estimate of whether the listing is the same as an existing one. + known = False + for j in item.values: + if ( + j.location == o.location and j.guild == o.guild and + j.ppp == o.ppp and j.units == o.units + ): + DEBUG and print(f'\nSkipping known - {j.location} == {o.location}, {j.guild} == {o.guild}, ' + + f'{j.ppp} == {o.ppp}, {j.units} == {o.units}\n') + known = j + break + if known: + # Remove a known listing if it got too old. + if o.lastSeen > OPTIONS['IGNORE_SALES_OLDER']: + DEBUG and print(f'\n - Removing {o.name} {o.lastSeen}m from item.values: ' + + f'{o.lastSeen} > {OPTIONS["IGNORE_SALES_OLDER"]}.\n') + item.values.remove(known) + continue + + # Ignore old listings. Further listings will not be newer! + if o.lastSeen > OPTIONS['IGNORE_SALES_OLDER']: + allFurtherOld = True + break + + # Track listings to avoid repetition. + item.values.append(o) + + # Keep between crawls, for printout. + newItems.append(o) + + DEBUG and print(f'\n\n- Finished page #{page}: {item.name}\n') + + # Go to next page, if: + # not last page of search, + # and page had a full page of 10 items, + # and further listings aren't too old. + if page < OPTIONS['ITEM_PAGES'] and count == 10 and not allFurtherOld: + page = page + 1 + + # Update page number. + if '&page=' not in url: + # url might not have the page part. + url += f'&page={page}' + else: + # Replace page number. + s = 'page=' + start = url.find(s) + start += len(s) + + url = f'{url[:start]}{page}' + # print(f'url page #{page} -> {url}') + + # Wait between every page, like a human would. + sleep(uniform(10.5, 15.5)) + + # Callback next page. + yield Request( + url = url, + callback = response.request.callback, + meta = {'proxy': proxy, 'item': item, 'page': page, + 'index': index, 'newItems': newItems}, + errback=self.BadProxy, + dont_filter=True, + ) + return + + # Print all new results. + for newItem in newItems: + # Buy price. + buyTotal = newItem.total + buyPPP = '' + + # Item quality. + quality = '(' + newItem.quality.capitalize() + ') ' + + # Optionals. + trait = '' + units = '' + vouchers = '' + + if newItem.trait is not None: + trait = '(' + newItem.trait.capitalize() + ') ' + + if newItem.vouchers: + vouchers = '(' + str(newItem.vouchers) + ' Vouchers) ' + + lastSeen = newItem.lastSeen + if lastSeen >= 60: + # Days. + days = int(lastSeen / 60 / 24) + if not days: + days = '' + else: + days = f'{days} day{(days>1 and "s") or ""}, ' + # Hours. + hours = int(lastSeen / 60) + if not hours: + hours = '' + else: + hours = f'{hours} hour{(hours>1 and "s") or ""}, ' + # Minutes. + mins = lastSeen % 60 + if not mins: + mins = '' + else: + mins = f'{mins} minute{(mins>1 and "s") or ""}.' + + lastSeen = days + hours + mins + else: + lastSeen = f'{lastSeen} minutes.' + + # Attention on amazing sales! Half max value, if set. + priceMax = 0 + if 'PriceMax=' in url: + start = url.find('PriceMax=') + start += len('PriceMax=') + end = url.find('&', start) + if end == -1: + end = None + + priceMax = int(url[start:end]) + if not priceMax: + priceMax = 0 + + # print(newItem.ppp, priceMax) + if newItem.ppp <= item.ppp / 2: + FlashTaskbar() + + priceMax = f'<= {priceMax:,}g ' + + # More than 1 unit. + if newItem.units > 1: + units = str(newItem.units) + ' x ' + # Print out. + if priceMax: + buyPPP = f'- {newItem.ppp:,}g ' + + MakeBeep() + + # Blueprint: High Elf Bookcase, Winged (Epic) | Deshaan: Mournhold by "Ethereal Traders Union II" + # BUY 16,311g | 7 hours, 41 minutes. + msg = (f'{units}{newItem.name} {quality}{trait}{vouchers}| {newItem.location} by "{newItem.guild}"\n' + + f'BUY {buyTotal:,}g {buyPPP}{priceMax}| {lastSeen}') + + self.print_value(msg) + + def print_value(self, msg): + """ + Print out the item's value and details. + Optional: Ignore low value deals. + """ + + OPTIONS['LISTING_COUNTER'] += 1 + + self.counter += 1 # DEBUG + + # Reset skipped counter on every print. + self.skipped = 0 + + if not OPTIONS['PRINTOUT']: + print('\n') + OPTIONS['PRINTOUT'] = True + + print(f'{GetTimestamp()} ({self.counter}) ({OPTIONS["LISTING_COUNTER"]}) ({OPTIONS["TOTAL_LISTING_COUNTER"]})\n{msg}\n') + + +# TODO: +# - Option at the end to print to html file for easy viewing. +# - After the digits group, there's which leading number is the most common. +# e.g. [32550, 32550, 35550, 35550, 50000, 69999, 69999, 70000, 85000] +# It's all 5 digits, but 3 is the most common leading number. + +if __name__ == "__main__": + # Catch CTRL-C. + signal.signal(signal.SIGINT, ForceQuit) + + GetOptions() + StartCrawler() + + # Quitting... + print(f'\n\n{GetTimestamp()} - Quitting...\n') + os.system('pause') + os.system('pause') diff --git a/DealFinderSimple.py b/DealFinderSimple.py new file mode 100644 index 0000000..a6faf22 --- /dev/null +++ b/DealFinderSimple.py @@ -0,0 +1,983 @@ +""" + Finds good deals for resale from TTC and prints them to an HTML page. + + - Uses proxies, if provided in a local file named "proxies.txt" in the format "http://123.123.123.123:123" per line. + - Only checks a given list of items, if provided in a local file named "items.txt" in their search-results page URL format per line. +""" + +import signal +import os +from traceback import format_exc + +from datetime import datetime +from random import shuffle, uniform +from time import sleep +from math import ceil +from statistics import mean + +from lxml import html +import requests + +DEBUG = True + + +# Let user force quit, if needed. +def ForceQuit(signum=None, frame=None, msg='', graceful=True): + global CRAWLER, DEBUG + + DEBUG and print(f'\n\n{GetTimestamp()} - Quitting...\n') + + try: + if graceful and not CRAWLER.tracker.attemptedQuit: + CRAWLER.options.attemptedQuit += 1 + else: + raise Exception() + except Exception: + os._exit(1) + + +def GetTimestamp(file=False): + """ Return a formatted timestamp. """ + if file: + d = str(datetime.now().strftime(f'%m_%d_%y %H_%M_%S')) + else: + d = str(datetime.now().strftime(f'%H:%M:%S')) + + return d + + +class Options(): + """ Handle all global options and trackers. """ + + def __init__(self, crawler): + i = crawler.input + self.attemptedQuit = False + itemized = crawler.links.itemized + + # Default values. + self.age = 60 # Itemized list only. + self.pages = 5 + self.risk = 3 + self.profit = 5000 + self.buy = 0 + self.minUnits = 1 + self.maxUnits = 200 + self.exclude = [] + self.require = [] + # Applies to either scan. + self.accuracy = 3 + self.interval = 5 + + # Use itemized list or not. + if itemized: + r = i(f'Scan {len(crawler.links)} listed items [y]: ') + if r and r != 'y': + crawler.links.itemized = False + + # Some options are only relevant for an itemized links list, and others only for a global search. + if crawler.links.itemized: + try: + self.age = int(i('Maximum age of listing in minutes [60]: ')) + except Exception: + pass + else: + try: + self.pages = int(i('Search result pages to scan every round [5]: ')) + except Exception: + pass + + try: + self.risk = int(i('Maximum Price / Profit risk ratio [3]: ')) + except Exception: + pass + + try: + self.profit = int(i('Minimum profit-category in gold [5000]: ')) + except Exception: + pass + + try: + self.buy = int(i('Maximum price per listing: ')) + except Exception: + pass + + try: + self.minUnits = int(i('Minimum amount of units per listing: ')) + except Exception: + pass + + try: + self.maxUnits = int(i('Maximum amount of units per listing [200]: ')) + except Exception: + pass + + self.exclude = i('Exclude all substrings from results (Example: key, writ): ') + self.exclude = [x.strip().lower() for x in self.exclude.split(',') if x.strip()] + + self.require = i('Require any of substrings in results (Example: of power, necro): ') + self.require = [x.strip().lower() for x in self.require.split(',') if x.strip()] + + # Display further options. + try: + self.accuracy = int(i('Item price-estimation accuracy by search pages [3]: ')) + except Exception: + pass + + try: + self.interval = int(i('Delay between each round in minutes [5]: ')) + except Exception: + pass + + +class Proxies(): + """ Load proxies from file and handle proxy rotation. """ + + def __init__(self, crawler): + self.crawler = crawler + self.list = [] # Empty. Defaults to no proxy. + self.index = 0 # Current proxy index. + + try: + with open('proxies.txt') as f: + # Not empty. Starts as a URL. + self.list = [line.strip() for line in f if line.strip().startswith('http')] + + # Not empty. + if not self.list: + raise Exception() + + # Shuffle for when script is restarted often. + shuffle(self.list) + except Exception: + x = input('Failed to load proxies from file! Continue without a proxy? [n]: ') + if not x: + ForceQuit(graceful=False) + + def GetProxy(self): + """" Return the next proxy, or '' for no proxy used - but then sleep() too. """ + + if not self.list: + # Insert a delay without proxies. + sleep(10) + return '' + + try: + p = self.list[self.index] + except Exception: + # Start over. + self.index = 0 + p = self.list[self.index] + finally: + proxy = p + self.index += 1 + + # Crawler tracking. + self.crawler.tracker.proxyFailed += 1 + self.crawler.proxy = proxy + + return proxy + + +class Links(): + """ Either load items to scan from file, or use generic recent search results. """ + + searchURL = ('https://us.tamrieltradecentre.com/pc/Trade/SearchResult?ItemID=&SearchType=Sell&ItemNamePattern=' + '&ItemCategory1ID=&ItemCategory2ID=&ItemCategory3ID=&ItemTraitID=&ItemQualityID=&IsChampionPoint=false' + '&LevelMin=&LevelMax=&MasterWritVoucherMin=&MasterWritVoucherMax=&AmountMin=&AmountMax=&PriceMin=&PriceMax=') + + def __init__(self, crawler): + self.itemized = False # Item list has loaded. + self.crawler = crawler + + # Set finally after Options() finished. + self.list = [] + + try: + with open('items.txt') as f: + # Not empty. Starts as a URL. + self.list = [line.strip() for line in f if line.strip().startswith('http')] + + # Empty. + if not self.list: + raise Exception() + + self.itemized = True + except Exception: + x = input('Failed to load items from file! Continue with a general scan? [y]: ') + if x and x != 'y': + ForceQuit(graceful=False) + + def __iter__(self): + """ Yield all links. """ + for i in self.list: + yield i + + def __len__(self): + """ Length of links list. """ + return len(self.list) + + def UpdateList(self): + """ Override the links list according to the user choice. """ + if not self.itemized: + self.list = [self.searchURL] # Mimic website url pattern. + for i in range(2, self.crawler.options.pages + 1): + self.list.append(f'{self.searchURL}&page={i}') + + +class Tracker(): + """ Track all crawler activities. """ + + def __init__(self): + self.attemptedQuit = 0 + + self.proxyFailed = 0 + + self.matches = 0 # Successful listing matches. + self.listings = 0 # All listings scanned through. + + +class Item(): + """ + A TTC item with all its data. + + id + name + level str + champion str - 'true' or 'false' + quality + trait Optional. + vouchers Optional. For writs. + + trader 'Community' for guild trader, otherwise @player. + location + guild + + ppp int + units int + buy int - Total price of listing. + lastSeen int - Last seen in minutes (Seen! not listed.) + + values [int, ...] - Most recent listings prices. + sell int - Estimated worth. + sellppp int - Estimated worth per unit. + risk float - Higher number means higher risk of investment. + profit int - Estimated profit made by reselling the item. + + limited bool - Has under 10 listings available. + recentSales int - How many recent sales of the item were made. + + digitCategory int - How many digits are in the estimated sale-value of the item. + profitBracket int - The nearest profit bracket to the estimated profit-value of the item. + + indexAll int - All listings counted. + index int - Only successful matches counted. + """ + + IdUrl = 'https://us.tamrieltradecentre.com/api/pc/Trade/GetItemAutoComplete?term=' + + sales = { + 0: 'NOPE', + 5000: 'SALE', + 10000: 'GOOD SALE', + 20000: 'SPICY SALE', + 30000: 'HOT SALE', + 50000: 'FLAMING SALE', + } + + traits = { + '': '', # Traits are optional. + 'powered': 0, + 'charged': 1, + 'precise': 2, + 'infused': 3, + 'defending': 4, + 'training': 5, + 'sharpened': 6, + 'decisive': 7, + 'sturdy': 8, + 'impenetrable': 9, + 'reinforced': 10, + 'well fitted': 11, + 'invigorating': 12, + 'divines': 13, + 'nirnhoned': 14, + 'intricate': 15, + 'ornate': 16, + 'arcane': 17, + 'healthy': 18, + 'robust': 19, + 'special': 20, + 'bloodthirsty': 21, + 'harmony': 22, + 'protective': 23, + 'swift': 24, + 'triune': 25, + } + + qualities = { + '': '', + 'any quality': '', + 'normal': 0, + 'fine': 1, + 'superior': 2, + 'epic': 3, + 'legendary': 4, + } + + profit_categories = { + # Number of digits in price. No fractions in the game. + 1: 0, + 2: 0, + 3: 0, # Hundreds. + 4: 0, # Thousands. + 5: 0, + 6: 0, + 7: 0, # Millions. + 8: 0, + 9: 0, + 10: 0, + } + + def __init__(self, e, crawler): + """ Use the Element() e to extract the item data. """ + + self.crawler = crawler + + self.time = GetTimestamp() + self.indexAll = crawler.tracker.listings + + cols = e.xpath('td') + c = cols[0] + + path = 'div[1]/text()' + self.name = c.xpath(f'string({path})').strip() + + self.SetId() + + self.SetChamp(c) + + self.SetLevel(c) + + self.SetQuality(c) + + path = 'img/@data-trait' + self.trait = c.xpath(f'string({path})').strip() + + self.SetVouchers(c) + + c = cols[1] + + # "Community" or user name. + path = 'div/text()' + self.trader = c.xpath(f'string({path})').strip() + + c = cols[2] + + self.SetLocation(c) + + c = cols[3] + + self.SetPrice(c) + + c = cols[4] + + path = './@data-mins-elapsed' + self.lastSeen = int(float(c.xpath(f'string({path})').replace(',', ''))) + + # Assigned later. + self.values = [] + self.sell = 0 + self.sellppp = 0 + self.index = 0 + self.risk = 0 + self.profit = 0 + self.digitCategory = 0 + self.profitBracket = 0 + self.limited = False + self.recentSales = 0 + + def SetId(self, retry=False): + """ Retry a failed connection until success, and set the item's id. """ + c = self.crawler + name = self.name + link = self.IdUrl + name + + if retry: + # New proxy. Handles tracking. + proxy = c.proxies.GetProxy() + else: + # Use last proxy. + proxy = c.proxy + + try: + r = requests.get(link, headers={'https': proxy}) + except Exception: + raise + + if r.status_code != requests.codes.ok: + self.SetId(True) + return + + try: + j = r.json() + self.id = int(j[0]['ItemID']) + except Exception: + # Any unexpected error. + self.SetId(True) + return + + def SetChamp(self, c): + try: + path = 'div[3]/img/@src' + champion = c.xpath(f'string({path})').strip() + if not champion: + raise Exception() + except Exception: + path = 'div[2]/img/@src' + champion = c.xpath(f'string({path})').strip() + + # /Content/icons/nonvet.png or /Content/icons/championPoint.png + if 'championPoint' in champion: + self.champion = 'true' + else: + self.champion = 'false' + + def SetLevel(self, c): + try: + path = 'div[3]' + level = c.xpath(f'string({path})').split()[-1] + # Verify value. + int(level) + except Exception: + path = 'div[2]' + level = c.xpath(f'string({path})').split()[-1] + + self.level = level + + def SetQuality(self, c): + path = 'img/@class' + parts = c.xpath(f'string({path})').split() + part = [x for x in parts if 'quality' in x][0] + self.quality = part.split('-')[-1] + + def SetVouchers(self, c): + try: + path = 'div[2]/text()' + v = c.xpath(f'string({path})') + p = v.split()[1] + self.vouchers = int(p) + except Exception: + # Not a writ. + self.vouchers = '' + pass + + def SetLocation(self, c): + try: + self.location = c.xpath(f'string(div[1]/text())').strip() + self.guild = c.xpath(f'string(div[2]/text())').strip() + except Exception: + # No details for some private user trades. + self.location = '' + self.guild = '' + + def SetPrice(self, c): + parts = c.xpath(f'string()').split() + + self.ppp = int(float(parts[0].replace(',', ''))) + self.units = int(float(parts[2].replace(',', ''))) + self.buy = int(float(parts[4].replace(',', ''))) + + def GetSale(self, n): + return self.sales[n] + + def GetTrait(self, s): + return str(self.traits[s.lower()]) + + def GetQuality(self, s): + return str(self.qualities[s.lower()]) + + def SetValue(self): + """ + As part of Evaluate(), calculates the item's value per unit. + + Method: + + p = [15000, 15000, 14500, 22500, 33000, 9999, 27000, 35500, 150000, 200000] + + 1. Count how many digits are in each number: Singles, Doubles, Hundreds, Thousands, Tens of, Hundreds of, Millions. + (8 Tens of, 2 Hundreds of.) + + 2. Select the most used digits state. (Tens of.) [15000, 15000, 14500, 22500, 33000, 9999, 27000, 35500] + + 3. Round all up or down (by nearness to middle) to one digit under category. + [15000, 15000, 15000, 23000, 33000, 10000, 27000, 36000] + + 4. Get the mean(). (21750) + + 5. Get the nearest sale prices below and over the mean. (15000, 33000) + + Return all 3 last results rounded. ("22,000 [15,000, 33,000]") + """ + + categories = self.profit_categories.copy() + + # Count the digits for every value, to find the most common. + for v in self.values: + categories[len(str(v))] += 1 + + # Get the biggest one. If more than one, get the bigger category. + self.digitCategory = max(reversed(sorted(categories.keys())), key=(lambda k: categories[k])) + + # Keep only the values from that category. + kept = [] + for v in self.values: + cat = len(str(v)) + if cat == self.digitCategory: + # Round to two digits under category. (1,553 -> 1,550) + r = round(v, -self.digitCategory + 3) + kept.append(r) + + # Add values from another category if it has a meaningful amount of listings. + for v in self.values: + cat = len(str(v)) + # Skip main category. + if cat == self.digitCategory: + continue + # NOTE Hard to say what number makes sense. Ratios don't make sense in any format. + if categories[cat] >= 10: + # Round to two digits under category. + r = round(v, -self.digitCategory + 3) + kept.append(r) + + # Statistical mean(). + v = mean(kept) + # No fractions. + v = int(v) + # Round to two digits under category. + v = round(v, -int(self.digitCategory) + 3) + + self.sellppp = v + self.sell = self.sellppp * self.units + + def Evaluate(self): + """ + Estimate the item's value from the values of further recent listings. + + Return the item if it passes all the filters, or None. + """ + + opts = self.crawler.options + + self.SetValue() + + # Find my potential profit. Stacks calculate selling the whole stack. + # Example: 120g * 37 - 35g * 37 = 4440 - 1295 = 3,145g EARNINGS + self.profit = self.sell - self.buy + # Round to two digits under category. + self.profit = round(self.profit, -int(self.category) + 3) + + # Find nearest sale category value. + # Example: profit = 3,145g matches category [5000]. 1,232g would match [0]. + self.profitBracket = min(list(self.sales), key=lambda x: abs(x - self.profit)) + + # For the same profit, the smaller the purchase the better. + # If buy and sell values are equal, then there's no assumed risk. NOTE Or is there? + # Example: buy 1,000g / sell 2,000g = 0.5 risk + if self.profit: + self.risk = self.buy / self.profit + + # The advanced cost is too high for the potential profit. + # Example: BUY 100k, SELL 105k, PROFIT 5k. risk = 100 / 5 = 20 + # NOTE add < 0 case? + if opts.risk and self.risk > opts.risk: + return + + # Limited supply items don't even have 10 results in TTC. + if len(self.values) < 10: + self.limited = True + + return self + + def CompareItems(self, item): + """ Returns True if two items are estimated to be the same listing. """ + return (self.location == item.location and + self.guild == item.guild and + self.ppp == item.ppp and + self.units == item.units) + + +class Crawler(): + """ + Handles crawling webpages, one at a time (not async.) + - Load all other classes. + - Print results as a webpage file. + """ + + # The format of the html page where all the results are saved, live. + html = ( + "\n" + "\n" + "\n" + " \n" + " \n" + " Deal Finder\n" + " \n" + "\n" + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ) + row = ( + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ) + close = ( + "
- #UnitsNameQualityTraitVouchersLocationGuildTotal PricePiece PriceSell ValuePiece ValueSale CategoryProfitRecent SalesAll ValuesLimited Supply
{0}{1}\n" + " {2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}{16}{17}
\n" + "\n" + "\n" + ) + + def __init__(self): + # Track the currently used proxy for reuse. + self.proxy = None + # Track saved (filtered) listings. + self.matches = [] + + # Load item links from file or setup a general scan. + self.links = Links(self) + + # Load options. Get user input. + self.options = Options(self) + + # Update the links list per user choice. + self.links.UpdateList() + + # Track all activites. + self.tracker = Tracker() + + # Used in the save() filename. + self.time = GetTimestamp(True) + + # Load proxies. + self.proxies = Proxies(self) + + self.print(f'Crawler intialized. Scanning {len(self.links)} links...', True) + + # Start the scan. + while not self.tracker.attemptedQuit: + for link in self.links: + # Analyze page. + try: + self.scan(link) + except (KeyboardInterrupt, SystemExit): + ForceQuit() + + i = 0 + while not self.tracker.attemptedQuit and i < self.options.interval * 60: + self.print(f'Finished a scrape, waiting {(self.options.interval * 60) - i} seconds for next round...', flush=True) + sleep(1) + i += 1 + + def print(self, s, debug=False, flush=False): + """ Pretty print. """ + global DEBUG + # Only print debugs if enabled. + if debug and not DEBUG: + return + + # Prefix. + pre = '' + if debug: + pre = '- ' + + end = '\n' + timestamp = f'{GetTimestamp()} ' + if flush: + end = '\r' + timestamp = '' + + print(f'{timestamp}{pre}{s}', end=end, flush=flush) + + if not flush: + print() + + def input(self, s): + """ Pretty input. """ + result = input(s) + print() # Newline. + return result + + def save(self, items): + """ Create or add to the save file with formatting. """ + # Format into html. + content = '' + for item in items: + values = '' + vlen = len(item.values) + ivalues = sorted(item.values) + if vlen > 10: + # Split into lines. + v = [] + for i in range(ceil(vlen / 10)): + start = i * 10 + end = (i + 1) * 10 + v.append(str(ivalues[start:end])) + # Add a newline between parts. + values = '\n'.join(v) + + content += self.row.format(item.time, item.index, item.units, item.name, item.quality, item.trait, item.vouchers, item.location, + item.guild, item.buy, item.ppp, item.sell, item.sellppp, item.profitBracket, + item.profit, item.recentSales, values, item.limited) + + self.print(f'Saving {len(items)} items to file...', True) + + filename = f'DealFinder_{self.time}.html' + + # Create file on first call. + if not os.path.isfile(filename): + with open(filename, 'w') as f: + f.write(self.html + self.close) + + # TODO: Split files to 1,000 items each? + + if content: + # Get old content, remove ending, add new content, add ending. + with open(filename, 'r+') as f: + lines = f.readlines() + # Remove ending. + old = lines[:-3] + # Recompose. + old = '\n'.join(old) + # Add and reclose. + new = old + content + self.close + # Save from start. + f.seek(0) # TODO Seek before self.close and only add to file, instead of full rewrite. + f.write(new) + + def connect(self, link, retry=False): + """ + Connect until success, and return the items Element() list. + + retry - Identify the call as a retry attempt, for logging. + """ + # TODO Implement retries? Not critical as all proxies rotate anyways. + + # if retry: + # New proxy. Handles tracking. + + # self.print(f'Retrying connection with proxy #{self.proxies.index}...', True, True) + # else: + # # Use last proxy. + # proxy = self.proxy + + # Always switch proxy. + proxy = self.proxies.GetProxy() + + try: + r = requests.get(link, headers={'https': proxy}) + except Exception: + self.print(f'Failed proxy #{self.proxies.index}: {format_exc()}', True) + raise # TODO Not raise? Kills script for no reason? + + try: + root = html.fromstring(r.content) + + items = root.xpath('//tr[@class="cursor-pointer"]') + + # NOTE Figuring out if captcha is blocking this or what. + # noMatches = root.xpath("//h4[contains(., 'No trade matches your constraint')]") + completeCaptcha = root.xpath("//h5[contains(., 'complete the captcha')]") + + # Blocked by captcha! + # not items and not noMatches + if completeCaptcha: + raise Exception() + except Exception: + items = self.connect(link, True) + + return items + + def scan(self, link): + """ Handles all link operations. """ + items = self.connect(link) + + # Make an Item() object for each listing. + setupItems = [] + for i in items: + self.tracker.listings += 1 + + self.print(f'Scanning item #{self.tracker.listings}...', True, True) + + try: + item = Item(i, self) + except Exception: + # Any errors on the website. + self.print(f'Failed item #{self.tracker.listings} creation: {format_exc()}', True) + continue + + not item and self.print(f'Failed item #{self.tracker.listings} in creation.', True) + + # Track setup items. + if item: + setupItems.append(item) + + # Populate values and estimates for items. Filter. + matches = [] + for i in setupItems: + try: + item = self.analyze(i) + except Exception: + # Connection impasses or website issues. + self.print(f'Failed item #{self.tracker.listings} in analyze: {format_exc()}', True) + continue + + not item and self.print(f'Failed item #{self.tracker.listings} in analyze.', True) + + # Track filtered items. + if item: + self.tracker.matches += 1 + item.index = self.tracker.matches + # Add. + matches.append(item) + + if matches: + # Track. + self.matches += matches + + # Save to file. + self.save(matches) + + def analyze(self, item): + """ + Get the item's listed values and estimate its value. + Return only an item that passes all filters. + """ + + opts = self.options + links = self.links + + if links.itemized: + # Too old. + if item.lastSeen > opts.age: + return + + # Item already listed before. + for i in self.matches: + if item.CompareItems(i): + # Also, remove a listing that next round gets too old. + if item.lastSeen + (opts.interval * 60) > opts.age: + self.matches.remove(i) + return + + # Acceptable. + return item + else: + # Purchase is too expensive. + if opts.buy and item.buy > opts.buy: + self.print(f'Failed item #{self.tracker.listings} in analyze for opts.buy.', True) + return + + # Too few or too many units. + if opts.minUnits and item.units < opts.minUnits: + self.print(f'Failed item #{self.tracker.listings} in analyze for opts.minUnits.', True) + return + if opts.maxUnits and item.units > opts.maxUnits: + self.print(f'Failed item #{self.tracker.listings} in analyze for opts.maxUnits.', True) + return + + # Exclude substrings from name. Case insensitive. + for s in opts.exclude: + if s in item.name.lower(): + self.print(f'Failed item #{self.tracker.listings} in analyze for opts.exclude.', True) + return + + # Require at least one substring match in name. Case insensitive. + if opts.require: + m = False + for s in opts.require: + if s in item.name.lower(): + m = True + if not m: + self.print(f'Failed item #{self.tracker.listings} in analyze for opts.require.', True) + return + + end = opts.accuracy + 1 + for page in range(1, end): + sleep(uniform(1.5, 2.5)) # Delay between pages. + + self.print(f'Scanning values page #{page} of {opts.accuracy} for {item.name}...', True, True) + + link = (f'https://us.tamrieltradecentre.com/pc/Trade/SearchResult?ItemID={item.id}&SearchType=Sell' + f'&ItemNamePattern=&ItemCategory1ID=&ItemCategory2ID=&ItemCategory3ID=' + f'&ItemTraitID={item.GetTrait(item.trait)}&ItemQualityID={item.GetQuality(item.quality)}' + f'&IsChampionPoint={item.champion}&LevelMin={item.level}&LevelMax={item.level}' + f'&MasterWritVoucherMin={item.vouchers}&MasterWritVoucherMax={item.vouchers}' + f'&AmountMin=&AmountMax=&PriceMin=&PriceMax=&page={page}') + + items = self.connect(link) + # NOTE Should I assume I'll always get at least 1 item in the result? Infinite loop possible in connect(). + for i in items: + # NOTE Uses the same operations from Item(). + cols = i.xpath('td') + c = cols[3] + parts = c.xpath(f'string()').split() + ppp = int(float(parts[0].replace(',', ''))) + + item.values.append(ppp) + + # Count recent sales. + if item.lastSeen <= 60: + item.recentSales += 1 + + # Set value estimates. + if not item.Evaluate(): + return + + # Acceptable. + return item + + +# Not designed for modulation. +if __name__ == "__main__": + # Catch interruptions. + signal.signal(signal.SIGINT, ForceQuit) + + # Crawl links. + CRAWLER = Crawler() diff --git a/DisplayFusion_UpdateWindowPositionProfile.dfscript b/DisplayFusion_UpdateWindowPositionProfile.dfscript new file mode 100644 index 0000000..22f7fff --- /dev/null +++ b/DisplayFusion_UpdateWindowPositionProfile.dfscript @@ -0,0 +1,58 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using System.Management; +using System.Threading; + +// Automatically changes Window Position Profile, if not loaded previously, +// according to screen width. +// by Phuein +// +// The 'windowHandle' parameter will contain the window handle for the: +// - Active window when run by hotkey +// - Window Location target when run by a Window Location rule +// - TitleBar Button owner when run by a TitleBar Button +// - Jump List owner when run from a Taskbar Jump List +// - Currently focused window if none of these match +public static class DisplayFusionFunction +{ + const int screenWidth1 = 3440; + const string profile1 = "3440x1440"; + + const int screenWidth2 = 1720; + const string profile2 = "1720x1440"; + + public static void Run(IntPtr windowHandle) + { + string lastProfileLoaded = ""; + try { + lastProfileLoaded = BFS.ScriptSettings.ReadValue("lastProfileLoaded"); + } catch { + BFS.ScriptSettings.WriteValue("lastProfileLoaded", ""); + lastProfileLoaded = BFS.ScriptSettings.ReadValue("lastProfileLoaded"); + } + + int screenWidth = Screen.PrimaryScreen.Bounds.Width; + + //BFS.Dialog.ShowMessageInfo(screenWidth.ToString()); + //BFS.Dialog.ShowMessageInfo(lastProfileLoaded); + + // Full screen + if (screenWidth == screenWidth1 && lastProfileLoaded != profile1) + { + BFS.ScriptSettings.WriteValue("lastProfileLoaded", profile1); + BFS.DisplayFusion.LoadWindowPositionProfile(profile1); + + //BFS.Dialog.ShowMessageInfo("Full screen!"); + } + + // Split screen + else if (screenWidth == screenWidth2 && lastProfileLoaded != profile2) + { + BFS.ScriptSettings.WriteValue("lastProfileLoaded", profile2); + BFS.DisplayFusion.LoadWindowPositionProfile(profile2); + + //BFS.Dialog.ShowMessageInfo("Split screen!"); + } + } +} \ No newline at end of file diff --git a/ESOLauncherKiller.py b/ESOLauncherKiller.py new file mode 100644 index 0000000..0d787cb --- /dev/null +++ b/ESOLauncherKiller.py @@ -0,0 +1,25 @@ +import os +from time import sleep + +while True: + foundGame = os.popen('tasklist /FI "IMAGENAME eq eso64.exe" 2>NUL | \ + find /I /N "eso64.exe"').read() + + foundLauncher = os.popen('tasklist /FI "IMAGENAME eq Bethesda.net_Launcher.exe" 2>NUL | \ + find /I /N "Bethesda.net_Launcher.exe"').read() + + if foundGame and foundLauncher: + # k = os.popen('taskkill /IM Bethesda.net_Launcher.exe').read() + os.popen('taskkill /IM Bethesda.net_Launcher.exe') + + # Verify kill! + sleep(10) + + foundLauncher = None + foundLauncher = os.popen('tasklist /FI "IMAGENAME eq Bethesda.net_Launcher.exe" 2>NUL | \ + find /I /N "Bethesda.net_Launcher.exe"').read() + + if foundLauncher: + os.popen('taskkill /F /IM Bethesda.net_Launcher.exe') + + sleep(60 * 1) # Minutes. diff --git a/BestFriends2018/BestFriends.lua b/Elder Scrolls Online Addons/BestFriends2018/BestFriends.lua similarity index 100% rename from BestFriends2018/BestFriends.lua rename to Elder Scrolls Online Addons/BestFriends2018/BestFriends.lua diff --git a/BestFriends2018/BestFriends2018.txt b/Elder Scrolls Online Addons/BestFriends2018/BestFriends2018.txt similarity index 100% rename from BestFriends2018/BestFriends2018.txt rename to Elder Scrolls Online Addons/BestFriends2018/BestFriends2018.txt diff --git a/NewAddon/LibAddonMenu-2.0/LICENSE b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/LICENSE similarity index 100% rename from NewAddon/LibAddonMenu-2.0/LICENSE rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/LICENSE diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua similarity index 93% rename from Notebook2018/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua index 7a88896..20ffe3a 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -4,9 +4,10 @@ --Register LAM with LibStub -local MAJOR, MINOR = "LibAddonMenu-2.0", 26 +local MAJOR, MINOR = "LibAddonMenu-2.0", 29 local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) if not lam then return end --the same or newer version of this lib is already loaded into memory +LibAddonMenu2 = lam local messages = {} local MESSAGE_PREFIX = "[LAM2] " @@ -25,6 +26,11 @@ local function FlushMessages() messages = {} end +local logger +if LibDebugLogger then + logger = LibDebugLogger(MAJOR) +end + if LAMSettingsPanelCreated and not LAMCompatibilityWarning then PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") LAMCompatibilityWarning = true @@ -72,6 +78,10 @@ local function GetStringFromValue(value) return value end +local function GetColorForState(disabled) + return disabled and ZO_DEFAULT_DISABLED_COLOR or ZO_DEFAULT_ENABLED_COLOR +end + local function CreateBaseControl(parent, controlData, controlName) local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent @@ -144,12 +154,14 @@ local function RefreshReloadUIButton() end end - lam.applyButton:SetHidden(not lam.requiresReload) + if lam.applyButton then + lam.applyButton:SetHidden(not lam.requiresReload) + end end local function RequestRefreshIfNeeded(control) -- if our parent window wants to refresh controls, then fire the callback - local panel = GetTopPanel(control.panel) + local panel = GetTopPanel(control) local panelData = panel.data if panelData.registerForRefresh then cm:FireCallbacks("LAM-RefreshPanel", control) @@ -313,9 +325,9 @@ local function UpdateWarning(control) if control.data.requiresReload then if not warning then - warning = string.format("|cff0000%s", util.L["RELOAD_UI_WARNING"]) + warning = string.format("%s", util.L["RELOAD_UI_WARNING"]) else - warning = string.format("%s\n\n|cff0000%s", warning, util.L["RELOAD_UI_WARNING"]) + warning = string.format("%s\n\n%s", warning, util.L["RELOAD_UI_WARNING"]) end end @@ -333,10 +345,13 @@ local localization = { AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" VERSION = "Version: <>", WEBSITE = "Visit Website", + FEEDBACK = "Feedback", + TRANSLATION = "Translation", + DONATION = "Donate", PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", - RELOAD_UI_WARNING = "Changes to this setting require an UI reload in order to take effect.", - RELOAD_DIALOG_TITLE = "UI Reload required", - RELOAD_DIALOG_TEXT = "Some changes require an UI reload in order to take effect. Do you want to reload now or discard the changes?", + RELOAD_UI_WARNING = "Changes to this setting require a UI reload in order to take effect.", + RELOAD_DIALOG_TITLE = "UI Reload Required", + RELOAD_DIALOG_TEXT = "Some changes require a UI reload in order to take effect. Do you want to reload now or discard the changes?", RELOAD_DIALOG_RELOAD_BUTTON = "Reload", RELOAD_DIALOG_DISCARD_BUTTON = "Discard", }, @@ -344,6 +359,9 @@ local localization = { PANEL_NAME = "Addon", VERSION = "Versione: <>", WEBSITE = "Visita il Sitoweb", + FEEDBACK = "Feedback", + TRANSLATION = "Traduzione", + DONATION = "Donare", RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", @@ -353,6 +371,9 @@ local localization = { fr = { -- provided by Ayantir PANEL_NAME = "Extensions", WEBSITE = "Visiter le site Web", + FEEDBACK = "Réaction", + TRANSLATION = "Traduction", + DONATION = "Donner", RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", RELOAD_DIALOG_TITLE = "Reload UI requis", RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", @@ -362,6 +383,9 @@ local localization = { de = { -- provided by sirinsidiator PANEL_NAME = "Erweiterungen", WEBSITE = "Webseite besuchen", + FEEDBACK = "Feedback", + TRANSLATION = "Übersetzung", + DONATION = "Spende", RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", RELOAD_DIALOG_TITLE = "Neuladen benötigt", RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", @@ -372,6 +396,9 @@ local localization = { PANEL_NAME = "Дополнения", VERSION = "Версия: <>", WEBSITE = "Посетить сайт", + FEEDBACK = "отзыв", + TRANSLATION = "Перевод", + DONATION = "жертвовать", PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", @@ -383,6 +410,9 @@ local localization = { PANEL_NAME = "Configuración", VERSION = "Versión: <>", WEBSITE = "Visita la página web", + FEEDBACK = "Reaccion", + TRANSLATION = "Traducción", + DONATION = "Donar", RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", @@ -392,6 +422,9 @@ local localization = { jp = { -- provided by k0ta0uchi PANEL_NAME = "アドオン設定", WEBSITE = "ウェブサイトを見る", + FEEDBACK = "フィードバック", + TRANSLATION = "訳書", + DONATION = "寄贈する", }, zh = { -- provided by bssthu PANEL_NAME = "插件", @@ -420,16 +453,19 @@ local localization = { RELOAD_DIALOG_RELOAD_BUTTON = "苈穜滠遨", RELOAD_DIALOG_DISCARD_BUTTON = "绀溽迨莌", }, - br = { -- provided by mlsevero + br = { -- provided by mlsevero & FelipeS11 PANEL_NAME = "Addons", AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Autor: <>" VERSION = "Versão: <>", WEBSITE = "Visite o Website", - RELOAD_UI_WARNING = "Mudanças nessa configuração requer a releitura da UI para ter efeito.", - RELOAD_DIALOG_TITLE = "Releitura da UI requerida", - RELOAD_DIALOG_TEXT = "Algumas mudanças requerem a releitura da UI para ter efeito. Você deseja reler agora ou descartar as mudanças?", - RELOAD_DIALOG_RELOAD_BUTTON = "Relê", - RELOAD_DIALOG_DISCARD_BUTTON = "Descarta", + FEEDBACK = "Feedback", + TRANSLATION = "Tradução", + DONATION = "Doação", + RELOAD_UI_WARNING = "Mudanças nessa configuração requerem o recarregamento da UI para ter efeito.", + RELOAD_DIALOG_TITLE = "Recarregamento da UI requerida", + RELOAD_DIALOG_TEXT = "Algumas mudanças requerem o recarregamento da UI para ter efeito. Você deseja recarregar agora ou descartar as mudanças?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recarregar", + RELOAD_DIALOG_DISCARD_BUTTON = "Descartar", }, } @@ -437,6 +473,7 @@ util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")] or {}, localiza util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead util.GetStringFromValue = GetStringFromValue util.GetDefaultValue = GetDefaultValue +util.GetColorForState = GetColorForState util.CreateBaseControl = CreateBaseControl util.CreateLabelAndContainerControl = CreateLabelAndContainerControl util.RequestRefreshIfNeeded = RequestRefreshIfNeeded @@ -776,6 +813,9 @@ local function CreateOptionsControls(panel) err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) if err then PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) + if logger then + logger:Error(err) + end end if isSubmenu then @@ -833,6 +873,22 @@ local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel end local CheckSafetyAndInitialize +local function ShowSetHandlerWarning(panel, handler) + local hint + if(handler == "OnShow" or handler == "OnEffectivelyShown") then + hint = "'LAM-PanelControlsCreated' or 'LAM-PanelOpened'" + elseif(handler == "OnHide" or handler == "OnEffectivelyHidden") then + hint = "'LAM-PanelClosed'" + end + + if hint then + local message = ("Setting a handler on a panel is not recommended. Use the global callback %s instead. (%s on %s)"):format(hint, handler, panel.data.name) + PrintLater(message) + if logger then + logger:Warn(message) + end + end +end --METHOD: REGISTER ADDON PANEL --registers your addon with LibAddonMenu and creates a panel @@ -845,7 +901,8 @@ function lam:RegisterAddonPanel(addonID, panelData) local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel panel:SetHidden(true) panel:SetAnchorFill(container) - panel:SetHandler("OnShow", ToggleAddonPanels) + panel:SetHandler("OnEffectivelyShown", ToggleAddonPanels) + ZO_PreHook(panel, "SetHandler", ShowSetHandlerWarning) local function stripMarkup(str) return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") diff --git a/Junkee2018/LibAddonMenu-2.0/controls/button.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/button.lua similarity index 93% rename from Junkee2018/LibAddonMenu-2.0/controls/button.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/button.lua index 82b5032..17ecfef 100644 --- a/Junkee2018/LibAddonMenu-2.0/controls/button.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/button.lua @@ -3,11 +3,11 @@ name = "My Button", -- string id or function returning a string func = function() end, tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - icon = "icon\\path.dds", --(optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + icon = "icon\\path.dds", -- (optional) isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) - warning = "Will need to reload the UI.", --(optional) + warning = "Will need to reload the UI.", -- (optional) reference = "MyAddonButton", -- unique global reference to control (optional) } ]] diff --git a/NewAddon/LibAddonMenu-2.0/controls/checkbox.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/checkbox.lua similarity index 98% rename from NewAddon/LibAddonMenu-2.0/controls/checkbox.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/checkbox.lua index 6696dd7..8f48b63 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/checkbox.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/checkbox.lua @@ -5,7 +5,7 @@ setFunc = function(value) db.var = value doStuff() end, tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) width = "full", -- or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- a boolean or function that returns a boolean (optional) diff --git a/Junkee2018/LibAddonMenu-2.0/controls/colorpicker.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/colorpicker.lua similarity index 85% rename from Junkee2018/LibAddonMenu-2.0/controls/colorpicker.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/colorpicker.lua index db21260..b62cfba 100644 --- a/Junkee2018/LibAddonMenu-2.0/controls/colorpicker.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/colorpicker.lua @@ -1,106 +1,110 @@ ---[[colorpickerData = { - type = "colorpicker", - name = "My Color Picker", -- or string id or function returning a string - getFunc = function() return db.r, db.g, db.b, db.a end, --(alpha is optional) - setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, --(alpha is optional) - tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, --(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color - reference = "MyAddonColorpicker" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 13 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end - - control.isDisabled = disable -end - -local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) - if forceDefault then --if we are forcing defaults - local color = LAM.util.GetDefaultValue(control.data.default) - valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a - control.data.setFunc(valueR, valueG, valueB, valueA) - elseif valueR and valueG and valueB then - control.data.setFunc(valueR, valueG, valueB, valueA or 1) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - valueR, valueG, valueB, valueA = control.data.getFunc() - end - - control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) -end - -function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName) - - control.color = control.container - local color = control.color - - control.thumb = wm:CreateControl(nil, color, CT_TEXTURE) - local thumb = control.thumb - thumb:SetDimensions(36, 18) - thumb:SetAnchor(LEFT, color, LEFT, 4, 0) - - color.border = wm:CreateControl(nil, color, CT_TEXTURE) - local border = color.border - border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds") - border:SetTextureCoords(0, .625, 0, .8125) - border:SetDimensions(40, 22) - border:SetAnchor(CENTER, thumb, CENTER, 0, 0) - - local function ColorPickerCallback(r, g, b, a) - control:UpdateValue(false, r, g, b, a) - end - - control:SetHandler("OnMouseUp", function(self, btn, upInside) - if self.isDisabled then return end - - if upInside then - local r, g, b, a = colorpickerData.getFunc() - COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, LAM.util.GetStringFromValue(colorpickerData.name)) - end - end) - - if colorpickerData.warning ~= nil or colorpickerData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) - - control.UpdateValue = UpdateValue - control:UpdateValue() - if colorpickerData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end +--[[colorpickerData = { + type = "colorpicker", + name = "My Color Picker", -- or string id or function returning a string + getFunc = function() return db.r, db.g, db.b, db.a end, -- (alpha is optional) + setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, -- (alpha is optional) + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, -- (optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color + reference = "MyAddonColorpicker" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end + + control.isDisabled = disable +end + +local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) + if forceDefault then --if we are forcing defaults + local color = LAM.util.GetDefaultValue(control.data.default) + valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a + control.data.setFunc(valueR, valueG, valueB, valueA) + elseif valueR and valueG and valueB then + control.data.setFunc(valueR, valueG, valueB, valueA or 1) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + valueR, valueG, valueB, valueA = control.data.getFunc() + end + + control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) +end + +function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName) + + control.color = control.container + local color = control.color + + control.thumb = wm:CreateControl(nil, color, CT_TEXTURE) + local thumb = control.thumb + thumb:SetDimensions(36, 18) + thumb:SetAnchor(LEFT, color, LEFT, 4, 0) + + color.border = wm:CreateControl(nil, color, CT_TEXTURE) + local border = color.border + border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds") + border:SetTextureCoords(0, .625, 0, .8125) + border:SetDimensions(40, 22) + border:SetAnchor(CENTER, thumb, CENTER, 0, 0) + + local function ColorPickerCallback(r, g, b, a) + control:UpdateValue(false, r, g, b, a) + end + + control:SetHandler("OnMouseUp", function(self, btn, upInside) + if self.isDisabled then return end + + if upInside then + local r, g, b, a = colorpickerData.getFunc() + if IsInGamepadPreferredMode() then + COLOR_PICKER_GAMEPAD:Show(ColorPickerCallback, r, g, b, a) + else + COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a) + end + end + end) + + if colorpickerData.warning ~= nil or colorpickerData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if colorpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/custom.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/custom.lua similarity index 78% rename from BestFriends2018/LibAddonMenu-2.0/controls/custom.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/custom.lua index 40a7c42..eb6f26c 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/custom.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/custom.lua @@ -1,8 +1,8 @@ --[[customData = { type = "custom", - reference = "MyAddonCustomControl", --(optional) unique name for your control to use as reference - refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh - width = "full", --or "half" (optional) + reference = "MyAddonCustomControl", -- unique name for your control to use as reference (optional) + refreshFunc = function(customControl) end, -- function to call when panel/controls refresh (optional) + width = "full", -- or "half" (optional) } ]] local widgetVersion = 7 diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/description.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/description.lua similarity index 72% rename from BestFriends2018/LibAddonMenu-2.0/controls/description.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/description.lua index da207a0..a53c5b1 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/description.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/description.lua @@ -2,17 +2,33 @@ type = "description", text = "My description text to display.", -- or string id or function returning a string title = "My Title", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) reference = "MyAddonDescription" -- unique global reference to control (optional) } ]] -local widgetVersion = 8 +local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("description", widgetVersion) then return end local wm = WINDOW_MANAGER +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + control.desc:SetColor(color:UnpackRGBA()) + if control.title then + control.title:SetColor(color:UnpackRGBA()) + end + control.disabled = disable + end +end + local function UpdateValue(control) if control.title then control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) @@ -52,6 +68,10 @@ function LAMCreateControl.description(parent, descriptionData, controlName) end control.UpdateValue = UpdateValue + if descriptionData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end LAM.util.RegisterForRefreshIfNeeded(control) diff --git a/NewAddon/LibAddonMenu-2.0/controls/divider.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/divider.lua similarity index 92% rename from NewAddon/LibAddonMenu-2.0/controls/divider.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/divider.lua index 8089539..90ed6e8 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/divider.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/divider.lua @@ -1,8 +1,8 @@ --[[dividerData = { type = "divider", - width = "full", --or "half" (optional) - height = 10, (optional) - alpha = 0.25, (optional) + width = "full", -- or "half" (optional) + height = 10, -- (optional) + alpha = 0.25, -- (optional) reference = "MyAddonDivider" -- unique global reference to control (optional) } ]] diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/dropdown.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/dropdown.lua similarity index 81% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/dropdown.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/dropdown.lua index 70e23bb..2f554cc 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/dropdown.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/dropdown.lua @@ -7,10 +7,10 @@ setFunc = function(var) db.var = var doStuff() end, tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) - sort = "name-up", --or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted - width = "full", --or "half" (optional) + sort = "name-up", -- or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted + width = "full", -- or "half" (optional) scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- default value or function that returns the default value (optional) @@ -18,12 +18,13 @@ } ]] -local widgetVersion = 18 +local widgetVersion = 20 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("dropdown", widgetVersion) then return end local wm = WINDOW_MANAGER -local SORT_BY_VALUE = { ["value"] = {} } +local cm = CALLBACK_MANAGER +local SORT_BY_VALUE = { ["value"] = {} } local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } local SORT_TYPES = { name = ZO_SORT_BY_NAME, @@ -155,11 +156,16 @@ local function GrabSortingInfo(sortInfo) return t end +local ENTRY_ID = 1 +local LAST_ENTRY_ID = 2 +local OFFSET_X_INDEX = 4 local DEFAULT_VISIBLE_ROWS = 10 -local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = 25 -- same as in zo_combobox.lua -local CONTENT_PADDING = 24 -local SCROLLBAR_PADDING = 16 -local PADDING = GetMenuPadding() / 2 -- half the amount looks closer to the regular dropdown +local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = ZO_SCROLLABLE_ENTRY_TEMPLATE_HEIGHT +local SCROLLBAR_PADDING = ZO_SCROLL_BAR_WIDTH +local PADDING_X = GetMenuPadding() +local PADDING_Y = ZO_SCROLLABLE_COMBO_BOX_LIST_PADDING_Y +local LABEL_OFFSET_X = 2 +local CONTENT_PADDING = PADDING_X * 4 local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed local ScrollableDropdownHelper = ZO_Object:Subclass() @@ -169,10 +175,10 @@ function ScrollableDropdownHelper:New(...) return object end -function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) +function ScrollableDropdownHelper:Initialize(panel, control, visibleRows) local combobox = control.combobox local dropdown = control.dropdown - self.parent = parent + self.panel = panel self.control = control self.combobox = combobox self.dropdown = dropdown @@ -183,14 +189,16 @@ function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) -- handle dropdown or settingsmenu opening/closing - local function onShow() self:OnShow() end + local function onShow() return self:OnShow() end local function onHide() self:OnHide() end - local function doHide() self:DoHide() end + local function doHide(closedPanel) + if closedPanel == panel then self:DoHide() end + end ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) ZO_PreHook(dropdown, "HideDropdownInternal", onHide) combobox:SetHandler("OnEffectivelyHidden", onHide) - parent:SetHandler("OnEffectivelyHidden", doHide) + cm:RegisterCallback("LAM-PanelClosed", doHide) -- dont fade entries near the edges local scrollList = dropdown.m_scroll @@ -202,32 +210,32 @@ function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) -- adjust scroll content anchor to mimic menu padding local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") - local anchor1 = {scroll:GetAnchor(0)} - local anchor2 = {scroll:GetAnchor(1)} + local anchor1 = {select(2, scroll:GetAnchor(0))} + local anchor2 = {select(2, scroll:GetAnchor(1))} + anchor1[OFFSET_X_INDEX] = PADDING_X - LABEL_OFFSET_X + anchor2[OFFSET_X_INDEX] = -anchor1[OFFSET_X_INDEX] scroll:ClearAnchors() - scroll:SetAnchor(anchor1[2], anchor1[3], anchor1[4], anchor1[5] + PADDING, anchor1[6] + PADDING) - scroll:SetAnchor(anchor2[2], anchor2[3], anchor2[4], anchor2[5] - PADDING, anchor2[6] - PADDING) + scroll:SetAnchor(unpack(anchor1)) + scroll:SetAnchor(unpack(anchor2)) ZO_ScrollList_Commit(scrollList) - + -- hook mouse enter/exit local function onMouseEnter(control) self:OnMouseEnter(control) end local function onMouseExit(control) self:OnMouseExit(control) end -- adjust row setup to mimic the highlight padding - local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) - local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 2) + local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, ENTRY_ID) + local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, LAST_ENTRY_ID) local oSetup = dataType1.setupCallback -- both types have the same setup function local function SetupEntry(control, data, list) oSetup(control, data, list) - control.m_label:SetAnchor(LEFT, nil, nil, 2) + control.m_label:SetAnchor(LEFT, nil, nil, LABEL_OFFSET_X) + control.m_label:SetAnchor(RIGHT, nil, nil, -LABEL_OFFSET_X) -- no need to store old ones since we have full ownership of our dropdown controls if not control.hookedMouseHandlers then --only do it once per control control.hookedMouseHandlers = true ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) - -- we could also just replace the handlers - --control:SetHandler("OnMouseEnter", onMouseEnter) - --control:SetHandler("OnMouseExit", onMouseExit) end end dataType1.setupCallback = SetupEntry @@ -235,24 +243,61 @@ function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) -- adjust dimensions based on entries local scrollContent = scroll:GetNamedChild("Contents") - ZO_PreHook(dropdown, "AddMenuItems", function() - local width = PADDING * 2 + zo_max(self:GetMaxWidth(), combobox:GetWidth()) + dropdown.AddMenuItems = ScrollableDropdownHelper.AddMenuItems + + dropdown.AdjustDimensions = function() local numItems = #dropdown.m_sortedItems + local contentWidth = self:CalculateContentWidth() + CONTENT_PADDING local anchorOffset = 0 if(numItems > self.visibleRows) then - width = width + CONTENT_PADDING + SCROLLBAR_PADDING - anchorOffset = -SCROLLBAR_PADDING numItems = self.visibleRows + contentWidth = contentWidth + SCROLLBAR_PADDING + anchorOffset = -SCROLLBAR_PADDING end - scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) - local height = PADDING * 2 + numItems * (SCROLLABLE_ENTRY_TEMPLATE_HEIGHT + dropdown.m_spacing) - dropdown.m_spacing + ROUNDING_MARGIN + + local width = zo_max(contentWidth, dropdown.m_container:GetWidth()) + local height = dropdown:GetEntryTemplateHeightWithSpacing() * numItems - dropdown.m_spacing + (PADDING_Y * 2) + ROUNDING_MARGIN + dropdown.m_dropdown:SetWidth(width) dropdown.m_dropdown:SetHeight(height) - end) + ZO_ScrollList_SetHeight(dropdown.m_scroll, height) + + scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) + end +end + +local function CreateScrollableComboBoxEntry(self, item, index, isLast) + item.m_index = index + item.m_owner = self + local entryType = isLast and LAST_ENTRY_ID or ENTRY_ID + local entry = ZO_ScrollList_CreateDataEntry(entryType, item) + + return entry +end + +function ScrollableDropdownHelper.AddMenuItems(self) -- self refers to the ZO_ScrollableComboBox here + ZO_ScrollList_Clear(self.m_scroll) + + local numItems = #self.m_sortedItems + local dataList = ZO_ScrollList_GetDataList(self.m_scroll) + + for i = 1, numItems do + local item = self.m_sortedItems[i] + local entry = CreateScrollableComboBoxEntry(self, item, i, i == numItems) + table.insert(dataList, entry) + end + + self:AdjustDimensions() + + ZO_ScrollList_Commit(self.m_scroll) end function ScrollableDropdownHelper:OnShow() local dropdown = self.dropdown + + -- don't show if there are no entries + if #dropdown.m_sortedItems == 0 then return true end + if dropdown.m_lastParent ~= ZO_Menus then dropdown.m_lastParent = dropdown.m_dropdown:GetParent() dropdown.m_dropdown:SetParent(ZO_Menus) @@ -262,7 +307,7 @@ end function ScrollableDropdownHelper:OnHide() local dropdown = self.dropdown - if dropdown.m_lastParent then + if dropdown.m_lastParent then dropdown.m_dropdown:SetParent(dropdown.m_lastParent) dropdown.m_lastParent = nil end @@ -275,9 +320,9 @@ function ScrollableDropdownHelper:DoHide() end end -function ScrollableDropdownHelper:GetMaxWidth() +function ScrollableDropdownHelper:CalculateContentWidth() local dropdown = self.dropdown - local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) + local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) local dummy = dataType.pool:AcquireObject() dataType.setupCallback(dummy, { @@ -344,8 +389,8 @@ function LAMCreateControl.dropdown(parent, dropdownData, controlName) dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value if dropdownData.scrollable then - local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS - control.scrollHelper = ScrollableDropdownHelper:New(parent, control, visibleRows) + local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS + control.scrollHelper = ScrollableDropdownHelper:New(LAM.util.GetTopPanel(parent), control, visibleRows) end ZO_PreHook(dropdown, "UpdateItems", function(self) diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/editbox.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/editbox.lua similarity index 96% rename from BestFriends2018/LibAddonMenu-2.0/controls/editbox.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/editbox.lua index d6baf11..f9f79ad 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/editbox.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/editbox.lua @@ -4,10 +4,10 @@ getFunc = function() return db.text end, setFunc = function(text) db.text = text doStuff() end, tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) - isMultiline = true, --boolean (optional) - isExtraWide = true, --boolean (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + isMultiline = true, -- boolean (optional) + isExtraWide = true, -- boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.text, -- default value or function that returns the default value (optional) diff --git a/NewAddon/LibAddonMenu-2.0/controls/header.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/header.lua similarity index 96% rename from NewAddon/LibAddonMenu-2.0/controls/header.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/header.lua index eadff38..3eda1d7 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/header.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/header.lua @@ -1,7 +1,7 @@ --[[headerData = { type = "header", name = "My Header", -- or string id or function returning a string - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) reference = "MyAddonHeader" -- unique global reference to control (optional) } ]] diff --git a/NewAddon/LibAddonMenu-2.0/controls/iconpicker.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/iconpicker.lua similarity index 99% rename from NewAddon/LibAddonMenu-2.0/controls/iconpicker.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/iconpicker.lua index 65c7782..2cca460 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/iconpicker.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/iconpicker.lua @@ -11,8 +11,8 @@ iconSize = 28, -- size of the icons (optional) defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) width = "full", --or "half" (optional) - beforeShow = function(control, iconPicker) return preventShow end, --(optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + beforeShow = function(control, iconPicker) return preventShow end, -- (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- default value or function that returns the default value (optional) diff --git a/Junkee2018/LibAddonMenu-2.0/controls/panel.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/panel.lua similarity index 55% rename from Junkee2018/LibAddonMenu-2.0/controls/panel.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/panel.lua index d6956d8..75bb904 100644 --- a/Junkee2018/LibAddonMenu-2.0/controls/panel.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/panel.lua @@ -1,126 +1,168 @@ ---[[panelData = { - type = "panel", - name = "Window Title", -- or string id or function returning a string - displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) - author = "Seerah", -- or string id or function returning a string (optional) - version = "2.0", -- or string id or function returning a string (optional) - website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated (optional) - keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) - slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) - registerForRefresh = true, --boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown) - registerForDefaults = true, --boolean (optional) (will set all options controls back to default values) - resetFunc = function() print("defaults reset") end, --(optional) custom function to run after settings are reset to defaults -} ]] - - -local widgetVersion = 13 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("panel", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local cm = CALLBACK_MANAGER - -local function RefreshPanel(control) - local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu - local panelControls = panel.controlsToRefresh - - for i = 1, #panelControls do - local updateControl = panelControls[i] - if updateControl ~= control and updateControl.UpdateValue then - updateControl:UpdateValue() - end - if updateControl.UpdateDisabled then - updateControl:UpdateDisabled() - end - if updateControl.UpdateWarning then - updateControl:UpdateWarning() - end - end -end - -local function ForceDefaults(panel) - local panelControls = panel.controlsToRefresh - - for i = 1, #panelControls do - local updateControl = panelControls[i] - if updateControl.UpdateValue and updateControl.data.default ~= nil then - updateControl:UpdateValue(true) - end - end - - if panel.data.resetFunc then - panel.data.resetFunc() - end - - cm:FireCallbacks("LAM-RefreshPanel", panel) -end - -local callbackRegistered = false -LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 -local SEPARATOR = " - " -local LINK_COLOR = ZO_ColorDef:New("5959D5") -local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") - -function LAMCreateControl.panel(parent, panelData, controlName) - local control = wm:CreateControl(controlName, parent, CT_CONTROL) - - control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") - local label = control.label - label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) - label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) - - if panelData.author or panelData.version then - control.info = wm:CreateControl(nil, control, CT_LABEL) - local info = control.info - info:SetFont(LAM.util.L["PANEL_INFO_FONT"]) - info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) - - local output = {} - if panelData.author then - output[#output + 1] = zo_strformat(LAM.util.L["AUTHOR"], LAM.util.GetStringFromValue(panelData.author)) - end - if panelData.version then - output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) - end - info:SetText(table.concat(output, SEPARATOR)) - end - - if panelData.website then - control.website = wm:CreateControl(nil, control, CT_BUTTON) - local website = control.website - website:SetClickSound("Click") - website:SetFont(LAM.util.L["PANEL_INFO_FONT"]) - website:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) - website:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) - if(control.info) then - website:SetAnchor(TOPLEFT, control.info, TOPRIGHT, 0, 0) - website:SetText(string.format("|cffffff%s|r%s", SEPARATOR, LAM.util.L["WEBSITE"])) - else - website:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) - website:SetText(LAM.util.L["WEBSITE"]) - end - website:SetDimensions(website:GetLabelControl():GetTextDimensions()) - website:SetHandler("OnClicked", function() - RequestOpenUnsafeURL(panelData.website) - end) - end - - control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") - LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1 - local container = control.container - container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20) - container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3) - control.scroll = GetControl(control.container, "ScrollChild") - control.scroll:SetResizeToFitPadding(0, 20) - - if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once - cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel) - callbackRegistered = true - end - - control.ForceDefaults = ForceDefaults - control.data = panelData - control.controlsToRefresh = {} - - return control -end +--[[panelData = { + type = "panel", + name = "Window Title", -- or string id or function returning a string + displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) + author = "Seerah", -- or string id or function returning a string (optional) + version = "2.0", -- or string id or function returning a string (optional) + website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated or function (optional) + feedback = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where feedback/feature requests/bugs can be reported for the addon or function (optional) + translation = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where translation texts of the addon can be helped with or function (optional) + donation = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where a donation for the addon author can be raised or function (optional) + keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) + slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) + registerForRefresh = true, -- boolean will refresh all options controls when a setting is changed and when the panel is shown (optional) + registerForDefaults = true, -- boolean will set all options controls back to default values (optional) + resetFunc = function() print("defaults reset") end, -- custom function to run after settings are reset to defaults (optional) +} ]] + + +local widgetVersion = 15 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("panel", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER + +local function RefreshPanel(control) + local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu + if LAM.currentAddonPanel ~= panel or not LAM.currentPanelOpened then return end -- we refresh it later when the panel is opened + + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl ~= control and updateControl.UpdateValue then + updateControl:UpdateValue() + end + if updateControl.UpdateDisabled then + updateControl:UpdateDisabled() + end + if updateControl.UpdateWarning then + updateControl:UpdateWarning() + end + end +end + +local function ForceDefaults(panel) + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl.UpdateValue and updateControl.data.default ~= nil then + updateControl:UpdateValue(true) + end + end + + if panel.data.resetFunc then + panel.data.resetFunc() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) +end + +local callbackRegistered = false +LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 +local SEPARATOR = " - " +local COLORED_SEPARATOR = ZO_WHITE:Colorize(SEPARATOR) +local LINK_COLOR = ZO_ColorDef:New("5959D5") +local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") +local LINK_COLOR_DONATE = ZO_ColorDef:New("FFD700") -- golden +local LINK_MOUSE_OVER_COLOR_DONATE = ZO_ColorDef:New("FFF6CC") + +local function CreateButtonControl(control, label, clickAction, relativeTo) + local button = wm:CreateControl(nil, control, CT_BUTTON) + button:SetClickSound("Click") + button:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + button:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) + button:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) + + local OnClicked + local actionType = type(clickAction) + if actionType == "string" then + OnClicked = function() RequestOpenUnsafeURL(clickAction) end + elseif actionType == "function" then + OnClicked = clickAction + end + button:SetHandler("OnClicked", OnClicked) + + if relativeTo then + button:SetAnchor(TOPLEFT, relativeTo, TOPRIGHT, 0, 0) + button:SetText(COLORED_SEPARATOR .. label) + else + button:SetAnchor(TOPLEFT, control.label, BOTTOMLEFT, 0, -2) + button:SetText(label) + end + button:SetDimensions(button:GetLabelControl():GetTextDimensions()) + + return button +end + +function LAMCreateControl.panel(parent, panelData, controlName) + local control = wm:CreateControl(controlName, parent, CT_CONTROL) + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) + label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) + + local previousInfoControl + if panelData.author or panelData.version then + control.info = wm:CreateControl(nil, control, CT_LABEL) + local info = control.info + info:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) + + local output = {} + if panelData.author then + output[#output + 1] = zo_strformat(LAM.util.L["AUTHOR"], LAM.util.GetStringFromValue(panelData.author)) + end + if panelData.version then + output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) + end + info:SetText(table.concat(output, SEPARATOR)) + previousInfoControl = info + end + + if panelData.website then + control.website = CreateButtonControl(control, LAM.util.L["WEBSITE"], panelData.website, previousInfoControl) + previousInfoControl = control.website + end + + if panelData.feedback then + control.feedback = CreateButtonControl(control, LAM.util.L["FEEDBACK"], panelData.feedback, previousInfoControl) + previousInfoControl = control.feedback + end + + if panelData.translation then + control.translation = CreateButtonControl(control, LAM.util.L["TRANSLATION"], panelData.translation, previousInfoControl) + previousInfoControl = control.translation + end + + if panelData.donation then + control.donation = CreateButtonControl(control, LAM.util.L["DONATION"], panelData.donation, previousInfoControl) + local donation = control.donation + previousInfoControl = donation + donation:SetNormalFontColor(LINK_COLOR_DONATE:UnpackRGBA()) + donation:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR_DONATE:UnpackRGBA()) + end + + control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") + LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1 + local container = control.container + container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3) + control.scroll = GetControl(control.container, "ScrollChild") + control.scroll:SetResizeToFitPadding(0, 20) + + if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once + cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel) + callbackRegistered = true + end + + control.ForceDefaults = ForceDefaults + control.RefreshPanel = LAM.util.RequestRefreshIfNeeded + control.data = panelData + control.controlsToRefresh = {} + + return control +end diff --git a/NewAddon/LibAddonMenu-2.0/controls/slider.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/slider.lua similarity index 93% rename from NewAddon/LibAddonMenu-2.0/controls/slider.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/slider.lua index bd721c5..6c80968 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/slider.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/slider.lua @@ -5,13 +5,14 @@ setFunc = function(value) db.var = value doStuff() end, min = 0, max = 20, - step = 1, --(optional) + step = 1, -- (optional) clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) + clampFunction = function(value, min, max) return math.max(math.min(value, max), min) end, -- function that is called to clamp the value (optional) decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) disabled = function() return db.someBooleanSetting end, --or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) @@ -19,7 +20,7 @@ reference = "MyAddonSlider" -- unique global reference to control (optional) } ]] -local widgetVersion = 12 +local widgetVersion = 13 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("slider", widgetVersion) then return end @@ -30,6 +31,10 @@ local function RoundDecimalToPlace(d, place) return tonumber(strformat("%." .. tostring(place) .. "f", d)) end +local function ClampValue(value, min, max) + return math.max(math.min(value, max), min) +end + local function UpdateDisabled(control) local disable if type(control.data.disabled) == "function" then @@ -62,7 +67,8 @@ local function UpdateValue(control, forceDefault, value) value = RoundDecimalToPlace(value, control.data.decimals) end if control.data.clampInput ~= false then - value = math.max(math.min(value, control.data.max), control.data.min) + local clamp = control.data.clampFunction or ClampValue + value = clamp(value, control.data.min, control.data.max) end control.data.setFunc(value) --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed @@ -182,7 +188,9 @@ function LAMCreateControl.slider(parent, sliderData, controlName) HandleValueChanged(value) end) slider:SetHandler("OnSliderReleased", function(self, value) - control:UpdateValue(false, value) + if self:GetEnabled() then + control:UpdateValue(false, value) + end end) slider:SetHandler("OnMouseWheel", function(self, value) if(not self:GetEnabled()) then return end diff --git a/NewAddon/LibAddonMenu-2.0/controls/submenu.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/submenu.lua similarity index 51% rename from NewAddon/LibAddonMenu-2.0/controls/submenu.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/submenu.lua index 1766a1f..d7bc8bf 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/submenu.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/submenu.lua @@ -1,20 +1,61 @@ --[[submenuData = { type = "submenu", name = "Submenu Title", -- or string id or function returning a string - tooltip = "My submenu tooltip", -- -- or string id or function returning a string (optional) - controls = {sliderData, buttonData} --(optional) used by LAM - reference = "MyAddonSubmenu" --(optional) unique global reference to control + icon = "path/to/my/icon.dds", -- or function returning a string (optional) + iconTextureCoords = {left, right, top, bottom}, -- or function returning a table (optional) + tooltip = "My submenu tooltip", -- or string id or function returning a string (optional) + controls = {sliderData, buttonData} -- used by LAM (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + disabledLabel = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonSubmenu" -- unique global reference to control (optional) } ]] -local widgetVersion = 11 +local widgetVersion = 13 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("submenu", widgetVersion) then return end local wm = WINDOW_MANAGER local am = ANIMATION_MANAGER +local ICON_SIZE = 32 + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + if disable and control.open then + control.open = false + control.animation:PlayFromStart() + end + + control.arrow:SetColor(color:UnpackRGBA()) + control.disabled = disable + end + + local disableLabel = control.disabled or GetDefaultValue(control.data.disabledLabel) + if disableLabel ~= control.disabledLabel then + local color = GetColorForState(disableLabel) + control.label:SetColor(color:UnpackRGBA()) + if(control.icon) then + control.icon:SetDesaturation(disableLabel and 1 or 0) + end + control.disabledLabel = disableLabel + end +end local function UpdateValue(control) control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) + + if control.icon then + control.icon:SetTexture(GetDefaultValue(control.data.icon)) + if(control.data.iconTextureCoords) then + local coords = GetDefaultValue(control.data.iconTextureCoords) + control.icon:SetTextureCoords(unpack(coords)) + end + end + if control.data.tooltip then control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) end @@ -22,8 +63,9 @@ end local function AnimateSubmenu(clicked) local control = clicked:GetParent() - control.open = not control.open + if control.disabled then return end + control.open = not control.open if control.open then control.animation:PlayFromStart() else @@ -39,30 +81,55 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") local label = control.label - label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) - label:SetDimensions(width, 30) label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) label:SetText(LAM.util.GetStringFromValue(submenuData.name)) label:SetMouseEnabled(true) + + if submenuData.icon then + control.icon = wm:CreateControl(nil, control, CT_TEXTURE) + local icon = control.icon + icon:SetTexture(GetDefaultValue(submenuData.icon)) + if(submenuData.iconTextureCoords) then + local coords = GetDefaultValue(submenuData.iconTextureCoords) + icon:SetTextureCoords(unpack(coords)) + end + icon:SetDimensions(ICON_SIZE, ICON_SIZE) + icon:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + icon:SetMouseEnabled(true) + icon:SetDrawLayer(DL_CONTROLS) + label:SetAnchor(TOP, control, TOP, 0, 5, ANCHOR_CONSTRAINS_Y) + label:SetAnchor(LEFT, icon, RIGHT, 10, 0, ANCHOR_CONSTRAINS_X) + label:SetDimensions(width - ICON_SIZE - 5, 30) + else + label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + label:SetDimensions(width, 30) + end + if submenuData.tooltip then label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + if control.icon then + control.icon.data = label.data + control.icon:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control.icon:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end end control.scroll = wm:CreateControl(nil, control, CT_SCROLL) local scroll = control.scroll scroll:SetParent(control) - scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10) + scroll:SetAnchor(TOPLEFT, control.icon or label, BOTTOMLEFT, 0, 10) scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) - control.bg = wm:CreateControl(nil, label, CT_BACKDROP) + control.bg = wm:CreateControl(nil, control.icon or label, CT_BACKDROP) local bg = control.bg - bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5) + bg:SetAnchor(TOPLEFT, control.icon or label, TOPLEFT, -5, -5) bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") bg:SetInsets(16, 16, -16, -16) + bg:SetDrawLayer(DL_BACKGROUND) control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) local arrow = control.arrow @@ -78,6 +145,9 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) control:SetResizeToFitDescendents(true) control.open = false label:SetHandler("OnMouseUp", AnimateSubmenu) + if(control.icon) then + control.icon:SetHandler("OnMouseUp", AnimateSubmenu) + end animation:SetHandler("OnStop", function(self, completedPlaying) scroll:SetResizeToFitDescendents(control.open) if control.open then @@ -101,6 +171,10 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) control.UpdateValue = UpdateValue + if submenuData.disabled ~= nil or submenuData.disabledLabel ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end LAM.util.RegisterForRefreshIfNeeded(control) diff --git a/NewAddon/LibAddonMenu-2.0/controls/texture.lua b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/texture.lua similarity index 84% rename from NewAddon/LibAddonMenu-2.0/controls/texture.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/texture.lua index 29dda7c..6862ac2 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/texture.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibAddonMenu-2.0/controls/texture.lua @@ -1,14 +1,14 @@ --[[textureData = { type = "texture", image = "file/path.dds", - imageWidth = 64, --max of 250 for half width, 510 for full - imageHeight = 32, --max of 100 + imageWidth = 64, -- max of 250 for half width, 510 for full + imageHeight = 32, -- max of 100 tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonTexture" --(optional) unique global reference to control + width = "full", -- or "half" (optional) + reference = "MyAddonTexture" -- unique global reference to control (optional) } ]] ---add texture coords support? +-- TODO: add texture coords support? local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") diff --git a/Junkee2018/LibStub/LibStub.lua b/Elder Scrolls Online Addons/BestFriends2018/LibStub/LibStub.lua similarity index 96% rename from Junkee2018/LibStub/LibStub.lua rename to Elder Scrolls Online Addons/BestFriends2018/LibStub/LibStub.lua index 0e6bf67..e6b8997 100644 --- a/Junkee2018/LibStub/LibStub.lua +++ b/Elder Scrolls Online Addons/BestFriends2018/LibStub/LibStub.lua @@ -3,7 +3,7 @@ -- LibStub developed for World of Warcraft by above members of the WowAce community. -- Ported to Elder Scrolls Online by Seerah -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 4 +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 5 local LibStub = _G[LIBSTUB_MAJOR] local strformat = string.format diff --git a/Elder Scrolls Online Addons/DataExtractor/DataExtractor.lua b/Elder Scrolls Online Addons/DataExtractor/DataExtractor.lua new file mode 100644 index 0000000..ba76cb7 --- /dev/null +++ b/Elder Scrolls Online Addons/DataExtractor/DataExtractor.lua @@ -0,0 +1,568 @@ +--[[ + Scan for game data and save to savedvars, on demand. + Data available: Skills, Item Sets, Furniture Items, Recipes. + Uses layered callbacks to reduce CPU usage (freezes or crashes.) +--]] + +DataExtractor = { + name = "DataExtractor", -- Matches folder and Manifest file names. + author = "phuein", + color = "DDFFEE", -- Used in menu titles and so on. + menuName = "Data Extractor", -- A UNIQUE identifier for menu object. + -- Default settings. + savedVariables = { + FirstLoad = true, -- First time the addon is loaded ever. + -- Scraping categories. TODO + scrapeSkills = true, + scrapeItems = true, + -- Scraping sub-categories. TODO + scrapeSets = true, + scrapeFurniture = true, + scrapeRecipes = true, + -- Saved data. NOTE Content length may be long! + dataSkills = {}, + dataItems = { + Sets = {}, + Furniture = {}, + Recipes = {}, + }, + }, + -- Options. + itemScanLimit = 500000, -- How many itemIDs to scan through. NOTE Max is probably around 200k. + -- Data. + dataSkills = {}, -- ... skills. + dataSets = {}, -- Holds references to all item sets. + dataFurniture = {}, -- ... furniture. + dataRecipes = {}, -- ... recipes. + -- Counters. + dataSkillLinesCounter = 0, + dataSkillsCounter = 0, + dataSetsCounter = 0, + dataFurnitureCounter = 0, + dataRecipesCounter = 0, + -- Tracking. + scrapingSkills = false, -- Avoid running a scraper more than once at a time. + scrapingItems = false, + -- Track skills async. + currentType = nil, + currentLine = nil, + currentSkill = nil, + -- Slash commands. Lowercase! Slash! + slashSkills = '/scrapeskills', + slashItems = '/scrapeitems', + slashSave = '/scrapesave', +} + +-- Wraps text with a color. +function DataExtractor.Colorize(text, color) + -- Default to addon's .color. + if not color then color = DataExtractor.color end + + text = string.format('|c%s%s|r', color, text) + + return text +end + +-- Adds items to the database from given item id that applies to a link object. +-- i - (int) item id. +-- Returns true on success. +local function AddItemFromID(i) + -- Textless link. + -- 364, 50 for max lvl. + -- 10000 for fully repaired. (2nd from last, might not be necessary.) + local link = ZO_LinkHandler_CreateLink('', nil, ITEM_LINK_TYPE, i, 364, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + + local itemName = GetItemLinkName(link) + + -- No match, skip. + if itemName == '' then return end + + -- Only matching for: Sets, Furniture, and Recipes. + -- Vars will be used below! + local hasSet, setName, setNumBonuses, setNumEquipped, setMaxEquipped, setID = GetItemLinkSetInfo(link) + local itemType = GetItemLinkItemType(link) + + -- Format. + itemName = zo_strformat(SI_TOOLTIP_ITEM_NAME, itemName) + + -- Sets. + if hasSet then + local data = DataExtractor.dataSets + + -- Set already listed. + if data[setID] then return end + + data[setID] = {} + local item = data[setID] -- Reference. + + item.id = setID + item.name = setName + + -- Get bonuses info. + for j = 1, setNumBonuses do + local numRequired, bonusDescription = GetItemLinkSetBonusInfo(link, nil, j) + item[j+1] = bonusDescription + end + + DataExtractor.dataSetsCounter = DataExtractor.dataSetsCounter + 1 + + return true + end + + -- Furniture. + if itemType == ITEMTYPE_FURNISHING then + local data = DataExtractor.dataFurniture + + data[i] = {} + local item = data[i] -- Reference. + + item.id = i + item.name = itemName + + local quality = GetItemLinkQuality(link) + quality = GetString("SI_ITEMQUALITY", quality) + item.quality = quality + + local flavor = GetItemLinkFlavorText(link) + if flavor ~= '' then + item.description = flavor + end + + local icon = GetItemLinkIcon(link) + item.icon = icon + + -- Category. + local dataId = GetItemLinkFurnitureDataId(link) + -- item.dataId = dataId + local categoryId, subcategoryId = GetFurnitureDataCategoryInfo(dataId) + item.category = GetFurnitureCategoryName(categoryId) + + -- Tags. "Furnishing Behavior". + local numTags = GetItemLinkNumItemTags(link) + local tagStrings = {} + for j = 1, numTags do + local tagDescription, tagCategory = GetItemLinkItemTagInfo(link, j) + + if tagDescription ~= '' then + table.insert(tagStrings, zo_strformat(SI_TOOLTIP_ITEM_TAG_FORMATER, tagDescription)) + end + end + if #tagStrings > 0 then + item.tags = table.concat(tagStrings, ', ') + end + + DataExtractor.dataFurnitureCounter = DataExtractor.dataFurnitureCounter +1 + + return true + end + + -- Recipes. + if itemType == ITEMTYPE_RECIPE then + local data = DataExtractor.dataRecipes + + data[i] = {} + local item = data[i] -- Reference. + + item.id = i + item.name = itemName + + local quality = GetItemLinkQuality(link) + quality = GetString("SI_ITEMQUALITY", quality) + item.quality = quality + + local recipeType = GetItemLinkRecipeCraftingSkillType(link) + recipeType = GetCraftingSkillName(recipeType) + item.type = recipeType + + local recipeItemLink = GetItemLinkRecipeResultItemLink(link) + local hasAbility, abilityHeader, abilityDescription, cooldown, hasScaling, minLevel, maxLevel, isChampionPoints, remainingCooldown = GetItemLinkOnUseAbilityInfo(recipeItemLink) + if hasAbility then + item.description = abilityDescription + + if hasScaling then + local champ = '' + if isChampionPoints then champ = 'cp' end + item.scales = string.format('Scales from level %s%s to %s%s.', champ, minLevel, champ, maxLevel) + end + end + + -- Ingredients. + local ingredients = {} + local numIngredients = GetItemLinkRecipeNumIngredients(link) + for j = 1, numIngredients do + local ingredientName, numOwned, numRequired = GetItemLinkRecipeIngredientInfo(link, j) + table.insert(ingredients, string.format('%s (%s)', ingredientName, numRequired)) + end + item.ingredients = table.concat(ingredients, ', ') + + -- Skills required. + skills = {} + local numSkillsReq = GetItemLinkRecipeNumTradeskillRequirements(link) + for j = 1, numSkillsReq do + local skill, lvl = GetItemLinkRecipeTradeskillRequirement(link, j) + + local skillid = GetTradeskillLevelPassiveAbilityId(skill) + local skillName = GetAbilityName(skillid) + + table.insert(skills, string.format('%s %s', skillName, lvl)) + end + item.skills = table.concat(skills, ', ') + + DataExtractor.dataRecipesCounter = DataExtractor.dataRecipesCounter + 1 + + return true + end +end + +-- Updates the callbacks to the next: skill, line, type, or done. +local function UpdateSkillsPosition(i, j, line, k, skillsLimit, linesLimit) + -- Finished all skills for this line! Catches empty lines. + if k == skillsLimit or k == -1 then + -- Finished all skills of all lines of type! Next type. Catches empty types. + if j == linesLimit or j == -1 then + -- Finished all skills of all lines of all types! Complete. + if i == SKILL_TYPE_MAX_VALUE then + -- Print summary. + d( + string.format( + '|cFFFFFFDataExtractor:|r Finished! Types: %s Lines: %s Skills: %s. (Use %s to save the data!)', + SKILL_TYPE_MAX_VALUE, DataExtractor.dataSkillLinesCounter, DataExtractor.dataSkillsCounter, + DataExtractor.slashSave + ) + ) + -- Update tracker. + DataExtractor.scrapingSkills = false + else + -- d('finished type ' .. DataExtractor['currentType']) + DataExtractor.currentType = DataExtractor.currentType + 1 + end + else + -- Next line. + -- d('finished line ' .. DataExtractor['currentLine']) + DataExtractor.currentLine = DataExtractor.currentLine + 1 + end + else + DataExtractor.currentSkill = DataExtractor.currentSkill + 1 + end +end + +-- Get a skill. +local function AddSkill(i, j, line, k, skillsLimit, linesLimit) + -- Delay until ready for call. + if DataExtractor.currentSkill ~= k then + -- Don't keep waiting if moved to next type or line. + if DataExtractor.currentType == i and DataExtractor.currentLine == j then + zo_callLater(function() AddSkill(i, j, line, k, skillsLimit, linesLimit) end, 50) + end + return + end + + -- d('adding skill ' .. k) + + local skills = line.skills -- Reference + skills[k] = {} + local skill = skills[k] -- Reference + + -- Base skill, only. Below has passive upgrades and active morphs. + local name, icon, earnedRank, passive, ultimate, purchased, progressionIndex, rank = GetSkillAbilityInfo(i, j, k) + + -- Only skills with morphs have this. + local pid = GetProgressionSkillProgressionId(i, j, k) + + if pid == 0 then + -- No morphs, such as passive skills. + local abilityId = GetSkillAbilityId(i, j, k, false) + + skill.name = zo_strformat(SI_ABILITY_NAME, name) + + skill.id = abilityId + local aid = skill.id -- Reference. + + skill.description = GetAbilityDescription(aid, MAX_RANKS_PER_ABILITY) + + skill.icon = icon + skill.passive = passive + skill.ultimate = ultimate + + -- Same property name for consistency. With passives this means the Skill Level to unlock. + skill.earnedRank = earnedRank + + skill.cost, skill.resource = GetAbilityCost(aid, MAX_RANKS_PER_ABILITY) + skill.duration = GetAbilityDuration(aid, MAX_RANKS_PER_ABILITY) + skill.radius = GetAbilityRadius(aid, MAX_RANKS_PER_ABILITY) + skill.minRange, skill.maxRange = GetAbilityRange(aid, MAX_RANKS_PER_ABILITY) + skill.isChanneled, skill.castTime, skill.channelTime = GetAbilityCastInfo(aid, MAX_RANKS_PER_ABILITY) + skill.isTank, skill.isHealer, skill.isDamage = GetAbilityRoles(aid) + skill.target = GetAbilityTargetDescription(aid, MAX_RANKS_PER_ABILITY) + + -- Get upgrades for passives. + if passive then + local mapped = SKILLS_DATA_MANAGER.abilityIdToProgressionDataMap[aid] + local skillData = mapped.skillData + -- Holds all the skill levels. + local skillProgressions = skillData.skillProgressions + + local upgrades = GetNumPassiveSkillRanks(i, j, k) + -- Get all further upgrades. + for x = 2, upgrades do + skill[x] = {} + local s = skill[x] -- Reference. + + s.id = skillProgressions[x].abilityId + s.name = zo_strformat(SI_ABILITY_NAME, GetAbilityName(s.id)) + + s.description = GetAbilityDescription(s.id) + + -- Same property name for consistency. With passives this means the Skill Level to unlock. + s.earnedRank = skillProgressions[x].lineRankNeededToUnlock + + s.cost, s.resource = GetAbilityCost(aid, MAX_RANKS_PER_ABILITY) + s.duration = GetAbilityDuration(aid, MAX_RANKS_PER_ABILITY) + s.radius = GetAbilityRadius(aid, MAX_RANKS_PER_ABILITY) + s.minRange, s.maxRange = GetAbilityRange(aid, MAX_RANKS_PER_ABILITY) + s.isChanneled, s.castTime, s.channelTime = GetAbilityCastInfo(aid, MAX_RANKS_PER_ABILITY) + s.isTank, s.isHealer, s.isDamage = GetAbilityRoles(aid) + s.target = GetAbilityTargetDescription(aid, MAX_RANKS_PER_ABILITY) + + s.parentAbilityId = skill.id + end + end + else + -- Skills with morphs. Ultimates and fighting skills. + -- Base and two morphs: 0, 1, 2. + for x = MORPH_SLOT_MIN_VALUE, MORPH_SLOT_MAX_VALUE do + if x == MORPH_SLOT_MIN_VALUE then + -- Base keeps data in skill table. + s = skill + else + -- Morphs keep data in sub-tables. + skill[x] = {} + s = skill[x] + end + + s.id = GetProgressionSkillMorphSlotAbilityId(pid, x) + local aid = s.id -- Reference. + + s.name = zo_strformat(SI_ABILITY_NAME, GetAbilityName(aid)) + + s.description = GetAbilityDescription(aid, MAX_RANKS_PER_ABILITY) + + s.icon = GetAbilityIcon(aid) + s.passive = false + s.ultimate = ultimate + + s.earnedRank = earnedRank -- Only applies to base. + s.cost, s.resource = GetAbilityCost(aid, MAX_RANKS_PER_ABILITY) + s.duration = GetAbilityDuration(aid, MAX_RANKS_PER_ABILITY) + s.radius = GetAbilityRadius(aid, MAX_RANKS_PER_ABILITY) + s.minRange, s.maxRange = GetAbilityRange(aid, MAX_RANKS_PER_ABILITY) + s.isChanneled, s.castTime, s.channelTime = GetAbilityCastInfo(aid, MAX_RANKS_PER_ABILITY) + s.isTank, s.isHealer, s.isDamage = GetAbilityRoles(aid) + s.target = GetAbilityTargetDescription(aid, MAX_RANKS_PER_ABILITY) + + if x > MORPH_SLOT_MIN_VALUE then + -- For morphs. + s.parentAbilityId = skill.id + s.newEffect = GetAbilityNewEffectLines(aid) + end + end + end + + DataExtractor.dataSkillsCounter = DataExtractor.dataSkillsCounter + 1 + + UpdateSkillsPosition(i, j, line, k, skillsLimit, linesLimit) +end + +-- Get a skill line, and continue to get its skills. +local function AddLine(data, i, j, linesLimit) + -- Delay until ready for call. + if DataExtractor.currentLine ~= j then + -- Don't keep waiting if moved to next type. + if DataExtractor.currentType == i then + zo_callLater(function() AddLine(data, i, j, linesLimit) end, 200) + end + return + end + + -- d('adding line ' .. j) + + local name, rank, unlocked, notid, a, unlock, b, c = GetSkillLineInfo(i, j) + + data[j] = {} + line = data[j] -- Reference. + + line.skills = {} -- Will hold all skills in line. + + line.name = name + -- line.rank = rank + -- line.unlocked = unlocked + line.id = notid + -- line.unlock = unlock + -- line.a = a + -- line.b = b + -- line.c = b + + DataExtractor.dataSkillLinesCounter = DataExtractor.dataSkillLinesCounter + 1 + + -- Get all skills for line. + local skillsLimit = GetNumSkillAbilities(i, j) + DataExtractor.currentSkill = 1 + + -- No skills in line. + if skillsLimit == 0 then + -- Make it finish the iteration. + UpdateSkillsPosition(i, j, line, -1) + return + end + + for k = 1, skillsLimit do + AddSkill(i, j, line, k, skillsLimit, linesLimit) + end +end + +-- Get all skill lines for line type. +-- Continues to getting skills for each line. +local function AddType(i) + -- Delay until ready for call. + if DataExtractor.currentType ~= i then + zo_callLater(function() AddType(i) end, 500) + return + end + + -- d('doing type ' .. i) + + local typeName = GetString("SI_SKILLTYPE", i) + -- Empty type. Next! + if typeName == '' then + DataExtractor.currentType = DataExtractor.currentType + 1 + return + end + + DataExtractor.dataSkills[i] = {} + local data = DataExtractor.dataSkills[i] + + data.name = typeName + + -- Get me all skill lines for type. + local linesLimit = GetNumSkillLines(i) + local delay = 10 + DataExtractor.currentLine = 1 + + -- No lines in type. + if linesLimit == 0 then + -- Make it finish the iteration. + UpdateSkillsPosition(i, -1, nil, -1) + return + end + + for j = 1, linesLimit do + AddLine(data, i, j, linesLimit) + end +end + +-- Scrapes all the skills in the game. +local function GetAllSkills() + -- Don't run twice. + if DataExtractor.scrapingSkills == true then + d('|cFFFFFFDataExtractor:|r Skill scraper is already running!') + return + end + -- Track. + DataExtractor.scrapingSkills = true + + d('|cFFFFFFDataExtractor:|r Gathering skills data, please wait...') + + -- Gets all types. Each type gets all lines. Each line gets all skills. + DataExtractor.currentType = SKILL_TYPE_MIN_VALUE + for i = SKILL_TYPE_MIN_VALUE, SKILL_TYPE_MAX_VALUE do + AddType(i) + end +end + +-- Scrapes all the items in the game. +local function GetAllItems() + -- Don't run twice. + if DataExtractor.scrapingItems == true then + d('|cFFFFFFDataExtractor:|r Item scraper is already running!') + return + end + -- Track. + DataExtractor.scrapingItems = true + + -- Iterate over all items in-game. + local limit = DataExtractor.itemScanLimit + + local chunk = 100 -- Split the load to avoid crashing the game. + local chunks = limit / chunk -- How many chunks to process. + local delay = 20 -- ms delay between chunks. + + local addedDelay = 0 + for t = 1, chunks do + zo_callLater(function() + local x = 1 + (chunk * (t-1)) -- Start. + local y = chunk * t -- End. + + for i = x, y do + AddItemFromID(i) + end + + -- FINISHED. Last chunk prints summary. + if t == chunks then + d( + string.format( + '|cFFFFFFDataExtractor:|r Finished! Total IDs: %s Sets: %s Furniture: %s Recipes: %s. (Use %s to save the data!)', + limit, DataExtractor.dataSetsCounter, DataExtractor.dataFurnitureCounter, DataExtractor.dataRecipesCounter, + DataExtractor.slashSave + ) + ) + -- Update tracker. + DataExtractor.scrapingItems = false + end + end, delay * t) + end + + d(string.format('|cFFFFFFDataExtractor:|r Gathering item data, please wait for %s seconds...', math.floor((chunks * delay) / 1000))) +end + +-- Saved the scraped data from all tables into savedvars, +-- and commits a /reloadui to force save to file. +local function SaveData() + -- Update savedvars. + DataExtractor.savedVariables.dataSkills = DataExtractor.dataSkills + + DataExtractor.savedVariables.dataItems.Sets = DataExtractor.dataSets + DataExtractor.savedVariables.dataItems.Furniture = DataExtractor.dataFurniture + DataExtractor.savedVariables.dataItems.Recipes = DataExtractor.dataRecipes + + ReloadUI("ingame") +end + +-- Only show the loading message on first load ever. +function DataExtractor.Activated(e) + EVENT_MANAGER:UnregisterForEvent(DataExtractor.name, EVENT_PLAYER_ACTIVATED) + + if DataExtractor.savedVariables.FirstLoad then + DataExtractor.savedVariables.FirstLoad = false + end +end +-- When player is ready, after everything has been loaded. +EVENT_MANAGER:RegisterForEvent(DataExtractor.name, EVENT_PLAYER_ACTIVATED, DataExtractor.Activated) + +function DataExtractor.OnAddOnLoaded(event, addonName) + if addonName ~= DataExtractor.name then return end + EVENT_MANAGER:UnregisterForEvent(DataExtractor.name, EVENT_ADD_ON_LOADED) + + DataExtractor.savedVariables = ZO_SavedVars:NewAccountWide("DataExtractorSavedVariables", 1, nil, DataExtractor.savedVariables) + + -- Settings menu in Settings.lua. TODO + -- DataExtractor.LoadSettings() + + SLASH_COMMANDS[DataExtractor.slashSkills] = GetAllSkills + SLASH_COMMANDS[DataExtractor.slashItems] = GetAllItems + SLASH_COMMANDS[DataExtractor.slashSave] = SaveData + + -- Reset autocomplete cache to update it. + SLASH_COMMAND_AUTO_COMPLETE:InvalidateSlashCommandCache() +end +-- When any addon is loaded, but before UI (Chat) is loaded. +EVENT_MANAGER:RegisterForEvent(DataExtractor.name, EVENT_ADD_ON_LOADED, DataExtractor.OnAddOnLoaded) \ No newline at end of file diff --git a/Elder Scrolls Online Addons/DataExtractor/DataExtractor.txt b/Elder Scrolls Online Addons/DataExtractor/DataExtractor.txt new file mode 100644 index 0000000..ae6d6f0 --- /dev/null +++ b/Elder Scrolls Online Addons/DataExtractor/DataExtractor.txt @@ -0,0 +1,32 @@ +## APIVersion: 100027 +## Title: DataExtractor +## Version: 1.11 +## Author: phuein +## Description: Exctract data about items and skills. +## SavedVariables: DataExtractorSavedVariables +## OptionalDependsOn: LibAddonMenu-2.0 + +Languages\en.lua +Languages\$(language).lua + +LibStub\LibStub.lua + +LibAddonMenu-2.0\LibAddonMenu-2.0.lua + +LibAddonMenu-2.0\controls\button.lua +LibAddonMenu-2.0\controls\checkbox.lua +LibAddonMenu-2.0\controls\colorpicker.lua +LibAddonMenu-2.0\controls\custom.lua +LibAddonMenu-2.0\controls\description.lua +LibAddonMenu-2.0\controls\divider.lua +LibAddonMenu-2.0\controls\dropdown.lua +LibAddonMenu-2.0\controls\editbox.lua +LibAddonMenu-2.0\controls\header.lua +LibAddonMenu-2.0\controls\iconpicker.lua +LibAddonMenu-2.0\controls\panel.lua +LibAddonMenu-2.0\controls\slider.lua +LibAddonMenu-2.0\controls\submenu.lua +LibAddonMenu-2.0\controls\texture.lua + +DataExtractor.lua +Settings.lua \ No newline at end of file diff --git a/NewAddon/Languages/de.lua b/Elder Scrolls Online Addons/DataExtractor/Languages/de.lua similarity index 100% rename from NewAddon/Languages/de.lua rename to Elder Scrolls Online Addons/DataExtractor/Languages/de.lua diff --git a/NewAddon/Languages/en.lua b/Elder Scrolls Online Addons/DataExtractor/Languages/en.lua similarity index 100% rename from NewAddon/Languages/en.lua rename to Elder Scrolls Online Addons/DataExtractor/Languages/en.lua diff --git a/NewAddon/Languages/fr.lua b/Elder Scrolls Online Addons/DataExtractor/Languages/fr.lua similarity index 100% rename from NewAddon/Languages/fr.lua rename to Elder Scrolls Online Addons/DataExtractor/Languages/fr.lua diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/LICENSE b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/LICENSE similarity index 100% rename from Notebook2018/Libs/LibAddonMenu-2.0/LICENSE rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/LICENSE diff --git a/ShowMount/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/LibAddonMenu-2.0.lua similarity index 94% rename from ShowMount/LibAddonMenu-2.0/LibAddonMenu-2.0.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/LibAddonMenu-2.0.lua index 7a88896..afd87ed 100644 --- a/ShowMount/LibAddonMenu-2.0/LibAddonMenu-2.0.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -4,9 +4,10 @@ --Register LAM with LibStub -local MAJOR, MINOR = "LibAddonMenu-2.0", 26 +local MAJOR, MINOR = "LibAddonMenu-2.0", 28 local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) if not lam then return end --the same or newer version of this lib is already loaded into memory +LibAddonMenu2 = lam local messages = {} local MESSAGE_PREFIX = "[LAM2] " @@ -25,6 +26,11 @@ local function FlushMessages() messages = {} end +local logger +if LibDebugLogger then + logger = LibDebugLogger(MAJOR) +end + if LAMSettingsPanelCreated and not LAMCompatibilityWarning then PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") LAMCompatibilityWarning = true @@ -72,6 +78,10 @@ local function GetStringFromValue(value) return value end +local function GetColorForState(disabled) + return disabled and ZO_DEFAULT_DISABLED_COLOR or ZO_DEFAULT_ENABLED_COLOR +end + local function CreateBaseControl(parent, controlData, controlName) local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent @@ -149,7 +159,7 @@ end local function RequestRefreshIfNeeded(control) -- if our parent window wants to refresh controls, then fire the callback - local panel = GetTopPanel(control.panel) + local panel = GetTopPanel(control) local panelData = panel.data if panelData.registerForRefresh then cm:FireCallbacks("LAM-RefreshPanel", control) @@ -313,9 +323,9 @@ local function UpdateWarning(control) if control.data.requiresReload then if not warning then - warning = string.format("|cff0000%s", util.L["RELOAD_UI_WARNING"]) + warning = string.format("%s", util.L["RELOAD_UI_WARNING"]) else - warning = string.format("%s\n\n|cff0000%s", warning, util.L["RELOAD_UI_WARNING"]) + warning = string.format("%s\n\n%s", warning, util.L["RELOAD_UI_WARNING"]) end end @@ -333,10 +343,13 @@ local localization = { AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" VERSION = "Version: <>", WEBSITE = "Visit Website", + FEEDBACK = "Feedback", + TRANSLATION = "Translation", + DONATION = "Donate", PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", - RELOAD_UI_WARNING = "Changes to this setting require an UI reload in order to take effect.", - RELOAD_DIALOG_TITLE = "UI Reload required", - RELOAD_DIALOG_TEXT = "Some changes require an UI reload in order to take effect. Do you want to reload now or discard the changes?", + RELOAD_UI_WARNING = GetString(SI_OPTIONS_APPLY_WARNING), + RELOAD_DIALOG_TITLE = GetString(SI_ADDON_MANAGER_RELOAD), + RELOAD_DIALOG_TEXT = "Some changes require a UI reload in order to take effect. Do you want to reload now or discard the changes?", RELOAD_DIALOG_RELOAD_BUTTON = "Reload", RELOAD_DIALOG_DISCARD_BUTTON = "Discard", }, @@ -344,6 +357,9 @@ local localization = { PANEL_NAME = "Addon", VERSION = "Versione: <>", WEBSITE = "Visita il Sitoweb", + FEEDBACK = "Feedback", + TRANSLATION = "Traduzione", + DONATION = "Donare", RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", @@ -353,6 +369,9 @@ local localization = { fr = { -- provided by Ayantir PANEL_NAME = "Extensions", WEBSITE = "Visiter le site Web", + FEEDBACK = "Réaction", + TRANSLATION = "Traduction", + DONATION = "Donner", RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", RELOAD_DIALOG_TITLE = "Reload UI requis", RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", @@ -362,6 +381,9 @@ local localization = { de = { -- provided by sirinsidiator PANEL_NAME = "Erweiterungen", WEBSITE = "Webseite besuchen", + FEEDBACK = "Feedback", + TRANSLATION = "Übersetzung", + DONATION = "Spende", RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", RELOAD_DIALOG_TITLE = "Neuladen benötigt", RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", @@ -372,6 +394,9 @@ local localization = { PANEL_NAME = "Дополнения", VERSION = "Версия: <>", WEBSITE = "Посетить сайт", + FEEDBACK = "отзыв", + TRANSLATION = "Перевод", + DONATION = "жертвовать", PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", @@ -383,6 +408,9 @@ local localization = { PANEL_NAME = "Configuración", VERSION = "Versión: <>", WEBSITE = "Visita la página web", + FEEDBACK = "Reaccion", + TRANSLATION = "Traducción", + DONATION = "Donar", RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", @@ -392,6 +420,9 @@ local localization = { jp = { -- provided by k0ta0uchi PANEL_NAME = "アドオン設定", WEBSITE = "ウェブサイトを見る", + FEEDBACK = "フィードバック", + TRANSLATION = "訳書", + DONATION = "寄贈する", }, zh = { -- provided by bssthu PANEL_NAME = "插件", @@ -420,16 +451,19 @@ local localization = { RELOAD_DIALOG_RELOAD_BUTTON = "苈穜滠遨", RELOAD_DIALOG_DISCARD_BUTTON = "绀溽迨莌", }, - br = { -- provided by mlsevero + br = { -- provided by mlsevero & FelipeS11 PANEL_NAME = "Addons", AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Autor: <>" VERSION = "Versão: <>", WEBSITE = "Visite o Website", - RELOAD_UI_WARNING = "Mudanças nessa configuração requer a releitura da UI para ter efeito.", - RELOAD_DIALOG_TITLE = "Releitura da UI requerida", - RELOAD_DIALOG_TEXT = "Algumas mudanças requerem a releitura da UI para ter efeito. Você deseja reler agora ou descartar as mudanças?", - RELOAD_DIALOG_RELOAD_BUTTON = "Relê", - RELOAD_DIALOG_DISCARD_BUTTON = "Descarta", + FEEDBACK = "Feedback", + TRANSLATION = "Tradução", + DONATION = "Doação", + RELOAD_UI_WARNING = "Mudanças nessa configuração requerem o recarregamento da UI para ter efeito.", + RELOAD_DIALOG_TITLE = "Recarregamento da UI requerida", + RELOAD_DIALOG_TEXT = "Algumas mudanças requerem o recarregamento da UI para ter efeito. Você deseja recarregar agora ou descartar as mudanças?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recarregar", + RELOAD_DIALOG_DISCARD_BUTTON = "Descartar", }, } @@ -437,6 +471,7 @@ util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")] or {}, localiza util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead util.GetStringFromValue = GetStringFromValue util.GetDefaultValue = GetDefaultValue +util.GetColorForState = GetColorForState util.CreateBaseControl = CreateBaseControl util.CreateLabelAndContainerControl = CreateLabelAndContainerControl util.RequestRefreshIfNeeded = RequestRefreshIfNeeded @@ -776,6 +811,9 @@ local function CreateOptionsControls(panel) err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) if err then PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) + if logger then + logger:Error(err) + end end if isSubmenu then @@ -833,6 +871,15 @@ local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel end local CheckSafetyAndInitialize +local function ShowSetHandlerWarning(panel, handler) + bob = panel + mike = handler + if(handler == "OnShow" or handler == "OnEffectivelyShown") then + PrintLater(("Setting a handler on a panel is not recommended. Use the global callback 'LAM-PanelControlsCreated' or 'LAM-PanelOpened' instead. (%s on %s)"):format(handler, panel:GetName())) + elseif(handler == "OnHide" or handler == "OnEffectivelyHidden") then + PrintLater(("Setting a handler on a panel is not recommended. Use the global callback 'LAM-PanelClosed' instead. (%s on %s)"):format(handler, panel:GetName())) + end +end --METHOD: REGISTER ADDON PANEL --registers your addon with LibAddonMenu and creates a panel @@ -845,7 +892,8 @@ function lam:RegisterAddonPanel(addonID, panelData) local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel panel:SetHidden(true) panel:SetAnchorFill(container) - panel:SetHandler("OnShow", ToggleAddonPanels) + panel:SetHandler("OnEffectivelyShown", ToggleAddonPanels) + ZO_PreHook(panel, "SetHandler", ShowSetHandlerWarning) local function stripMarkup(str) return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") @@ -1174,7 +1222,7 @@ local function CreateAddonSettingsWindow() lam.defaultButton = defaultButton local applyButton = wm:CreateControlFromVirtual("$(parent)ApplyButton", tlw, "ZO_DialogButton") - ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_ADDON_MANAGER_RELOAD)) + ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_APPLY)) applyButton:SetAnchor(TOPRIGHT, panelContainer, BOTTOMRIGHT, 0, 2) applyButton:SetHidden(true) lam.applyButton = applyButton diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/button.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/button.lua similarity index 93% rename from BestFriends2018/LibAddonMenu-2.0/controls/button.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/button.lua index 82b5032..17ecfef 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/button.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/button.lua @@ -3,11 +3,11 @@ name = "My Button", -- string id or function returning a string func = function() end, tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - icon = "icon\\path.dds", --(optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + icon = "icon\\path.dds", -- (optional) isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) - warning = "Will need to reload the UI.", --(optional) + warning = "Will need to reload the UI.", -- (optional) reference = "MyAddonButton", -- unique global reference to control (optional) } ]] diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/checkbox.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/checkbox.lua similarity index 98% rename from PvPFPS2018/LibAddonMenu-2.0/controls/checkbox.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/checkbox.lua index 6696dd7..8f48b63 100644 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/checkbox.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/checkbox.lua @@ -5,7 +5,7 @@ setFunc = function(value) db.var = value doStuff() end, tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) width = "full", -- or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- a boolean or function that returns a boolean (optional) diff --git a/NewAddon/LibAddonMenu-2.0/controls/colorpicker.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/colorpicker.lua similarity index 85% rename from NewAddon/LibAddonMenu-2.0/controls/colorpicker.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/colorpicker.lua index a57aab0..b62cfba 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/colorpicker.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/colorpicker.lua @@ -1,19 +1,19 @@ --[[colorpickerData = { type = "colorpicker", name = "My Color Picker", -- or string id or function returning a string - getFunc = function() return db.r, db.g, db.b, db.a end, --(alpha is optional) - setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, --(alpha is optional) + getFunc = function() return db.r, db.g, db.b, db.a end, -- (alpha is optional) + setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, -- (alpha is optional) tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, --(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color + default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, -- (optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color reference = "MyAddonColorpicker" -- unique global reference to control (optional) } ]] -local widgetVersion = 13 +local widgetVersion = 14 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end @@ -79,7 +79,11 @@ function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) if upInside then local r, g, b, a = colorpickerData.getFunc() - COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, LAM.util.GetStringFromValue(colorpickerData.name)) + if IsInGamepadPreferredMode() then + COLOR_PICKER_GAMEPAD:Show(ColorPickerCallback, r, g, b, a) + else + COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a) + end end end) diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/custom.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/custom.lua similarity index 78% rename from PvPFPS2018/LibAddonMenu-2.0/controls/custom.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/custom.lua index 40a7c42..eb6f26c 100644 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/custom.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/custom.lua @@ -1,8 +1,8 @@ --[[customData = { type = "custom", - reference = "MyAddonCustomControl", --(optional) unique name for your control to use as reference - refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh - width = "full", --or "half" (optional) + reference = "MyAddonCustomControl", -- unique name for your control to use as reference (optional) + refreshFunc = function(customControl) end, -- function to call when panel/controls refresh (optional) + width = "full", -- or "half" (optional) } ]] local widgetVersion = 7 diff --git a/Junkee2018/LibAddonMenu-2.0/controls/description.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/description.lua similarity index 72% rename from Junkee2018/LibAddonMenu-2.0/controls/description.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/description.lua index 27c7192..a53c5b1 100644 --- a/Junkee2018/LibAddonMenu-2.0/controls/description.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/description.lua @@ -1,60 +1,80 @@ ---[[descriptionData = { - type = "description", - text = "My description text to display.", -- or string id or function returning a string - title = "My Title", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonDescription" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 8 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("description", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateValue(control) - if control.title then - control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) - end - control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) -end - -function LAMCreateControl.description(parent, descriptionData, controlName) - local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName) - local isHalfWidth = control.isHalfWidth - local width = control:GetWidth() - control:SetResizeToFitDescendents(true) - - if isHalfWidth then - control:SetDimensionConstraints(width / 2, 0, width / 2, 0) - else - control:SetDimensionConstraints(width, 0, width, 0) - end - - control.desc = wm:CreateControl(nil, control, CT_LABEL) - local desc = control.desc - desc:SetVerticalAlignment(TEXT_ALIGN_TOP) - desc:SetFont("ZoFontGame") - desc:SetText(LAM.util.GetStringFromValue(descriptionData.text)) - desc:SetWidth(isHalfWidth and width / 2 or width) - - if descriptionData.title then - control.title = wm:CreateControl(nil, control, CT_LABEL) - local title = control.title - title:SetWidth(isHalfWidth and width / 2 or width) - title:SetAnchor(TOPLEFT, control, TOPLEFT) - title:SetFont("ZoFontWinH4") - title:SetText(LAM.util.GetStringFromValue(descriptionData.title)) - desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT) - else - desc:SetAnchor(TOPLEFT) - end - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control - -end +--[[descriptionData = { + type = "description", + text = "My description text to display.", -- or string id or function returning a string + title = "My Title", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonDescription" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 9 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("description", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + control.desc:SetColor(color:UnpackRGBA()) + if control.title then + control.title:SetColor(color:UnpackRGBA()) + end + control.disabled = disable + end +end + +local function UpdateValue(control) + if control.title then + control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) + end + control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) +end + +function LAMCreateControl.description(parent, descriptionData, controlName) + local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if isHalfWidth then + control:SetDimensionConstraints(width / 2, 0, width / 2, 0) + else + control:SetDimensionConstraints(width, 0, width, 0) + end + + control.desc = wm:CreateControl(nil, control, CT_LABEL) + local desc = control.desc + desc:SetVerticalAlignment(TEXT_ALIGN_TOP) + desc:SetFont("ZoFontGame") + desc:SetText(LAM.util.GetStringFromValue(descriptionData.text)) + desc:SetWidth(isHalfWidth and width / 2 or width) + + if descriptionData.title then + control.title = wm:CreateControl(nil, control, CT_LABEL) + local title = control.title + title:SetWidth(isHalfWidth and width / 2 or width) + title:SetAnchor(TOPLEFT, control, TOPLEFT) + title:SetFont("ZoFontWinH4") + title:SetText(LAM.util.GetStringFromValue(descriptionData.title)) + desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT) + else + desc:SetAnchor(TOPLEFT) + end + + control.UpdateValue = UpdateValue + if descriptionData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control + +end diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/divider.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/divider.lua similarity index 92% rename from PvPFPS2018/LibAddonMenu-2.0/controls/divider.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/divider.lua index 8089539..90ed6e8 100644 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/divider.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/divider.lua @@ -1,8 +1,8 @@ --[[dividerData = { type = "divider", - width = "full", --or "half" (optional) - height = 10, (optional) - alpha = 0.25, (optional) + width = "full", -- or "half" (optional) + height = 10, -- (optional) + alpha = 0.25, -- (optional) reference = "MyAddonDivider" -- unique global reference to control (optional) } ]] diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/dropdown.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/dropdown.lua similarity index 83% rename from BestFriends2018/LibAddonMenu-2.0/controls/dropdown.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/dropdown.lua index 70e23bb..a5450e5 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/dropdown.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/dropdown.lua @@ -7,10 +7,10 @@ setFunc = function(var) db.var = var doStuff() end, tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) - sort = "name-up", --or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted - width = "full", --or "half" (optional) + sort = "name-up", -- or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted + width = "full", -- or "half" (optional) scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- default value or function that returns the default value (optional) @@ -18,12 +18,13 @@ } ]] -local widgetVersion = 18 +local widgetVersion = 19 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("dropdown", widgetVersion) then return end local wm = WINDOW_MANAGER -local SORT_BY_VALUE = { ["value"] = {} } +local cm = CALLBACK_MANAGER +local SORT_BY_VALUE = { ["value"] = {} } local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } local SORT_TYPES = { name = ZO_SORT_BY_NAME, @@ -155,11 +156,16 @@ local function GrabSortingInfo(sortInfo) return t end +local ENTRY_ID = 1 +local LAST_ENTRY_ID = 2 +local OFFSET_X_INDEX = 4 local DEFAULT_VISIBLE_ROWS = 10 -local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = 25 -- same as in zo_combobox.lua -local CONTENT_PADDING = 24 -local SCROLLBAR_PADDING = 16 -local PADDING = GetMenuPadding() / 2 -- half the amount looks closer to the regular dropdown +local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = ZO_SCROLLABLE_ENTRY_TEMPLATE_HEIGHT +local SCROLLBAR_PADDING = ZO_SCROLL_BAR_WIDTH +local PADDING_X = GetMenuPadding() +local PADDING_Y = ZO_SCROLLABLE_COMBO_BOX_LIST_PADDING_Y +local LABEL_OFFSET_X = 2 +local CONTENT_PADDING = PADDING_X * 4 local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed local ScrollableDropdownHelper = ZO_Object:Subclass() @@ -183,14 +189,14 @@ function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) -- handle dropdown or settingsmenu opening/closing - local function onShow() self:OnShow() end + local function onShow() return self:OnShow() end local function onHide() self:OnHide() end local function doHide() self:DoHide() end ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) ZO_PreHook(dropdown, "HideDropdownInternal", onHide) combobox:SetHandler("OnEffectivelyHidden", onHide) - parent:SetHandler("OnEffectivelyHidden", doHide) + cm:RegisterCallback("LAM-PanelClosed", doHide) -- dont fade entries near the edges local scrollList = dropdown.m_scroll @@ -202,32 +208,32 @@ function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) -- adjust scroll content anchor to mimic menu padding local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") - local anchor1 = {scroll:GetAnchor(0)} - local anchor2 = {scroll:GetAnchor(1)} + local anchor1 = {select(2, scroll:GetAnchor(0))} + local anchor2 = {select(2, scroll:GetAnchor(1))} + anchor1[OFFSET_X_INDEX] = PADDING_X - LABEL_OFFSET_X + anchor2[OFFSET_X_INDEX] = -anchor1[OFFSET_X_INDEX] scroll:ClearAnchors() - scroll:SetAnchor(anchor1[2], anchor1[3], anchor1[4], anchor1[5] + PADDING, anchor1[6] + PADDING) - scroll:SetAnchor(anchor2[2], anchor2[3], anchor2[4], anchor2[5] - PADDING, anchor2[6] - PADDING) + scroll:SetAnchor(unpack(anchor1)) + scroll:SetAnchor(unpack(anchor2)) ZO_ScrollList_Commit(scrollList) - + -- hook mouse enter/exit local function onMouseEnter(control) self:OnMouseEnter(control) end local function onMouseExit(control) self:OnMouseExit(control) end -- adjust row setup to mimic the highlight padding - local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) - local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 2) + local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, ENTRY_ID) + local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, LAST_ENTRY_ID) local oSetup = dataType1.setupCallback -- both types have the same setup function local function SetupEntry(control, data, list) oSetup(control, data, list) - control.m_label:SetAnchor(LEFT, nil, nil, 2) + control.m_label:SetAnchor(LEFT, nil, nil, LABEL_OFFSET_X) + control.m_label:SetAnchor(RIGHT, nil, nil, -LABEL_OFFSET_X) -- no need to store old ones since we have full ownership of our dropdown controls if not control.hookedMouseHandlers then --only do it once per control control.hookedMouseHandlers = true ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) - -- we could also just replace the handlers - --control:SetHandler("OnMouseEnter", onMouseEnter) - --control:SetHandler("OnMouseExit", onMouseExit) end end dataType1.setupCallback = SetupEntry @@ -235,24 +241,61 @@ function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) -- adjust dimensions based on entries local scrollContent = scroll:GetNamedChild("Contents") - ZO_PreHook(dropdown, "AddMenuItems", function() - local width = PADDING * 2 + zo_max(self:GetMaxWidth(), combobox:GetWidth()) + dropdown.AddMenuItems = ScrollableDropdownHelper.AddMenuItems + + dropdown.AdjustDimensions = function() local numItems = #dropdown.m_sortedItems + local contentWidth = self:CalculateContentWidth() + CONTENT_PADDING local anchorOffset = 0 if(numItems > self.visibleRows) then - width = width + CONTENT_PADDING + SCROLLBAR_PADDING - anchorOffset = -SCROLLBAR_PADDING numItems = self.visibleRows + contentWidth = contentWidth + SCROLLBAR_PADDING + anchorOffset = -SCROLLBAR_PADDING end - scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) - local height = PADDING * 2 + numItems * (SCROLLABLE_ENTRY_TEMPLATE_HEIGHT + dropdown.m_spacing) - dropdown.m_spacing + ROUNDING_MARGIN + + local width = zo_max(contentWidth, dropdown.m_container:GetWidth()) + local height = dropdown:GetEntryTemplateHeightWithSpacing() * numItems - dropdown.m_spacing + (PADDING_Y * 2) + ROUNDING_MARGIN + dropdown.m_dropdown:SetWidth(width) dropdown.m_dropdown:SetHeight(height) - end) + ZO_ScrollList_SetHeight(dropdown.m_scroll, height) + + scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) + end +end + +local function CreateScrollableComboBoxEntry(self, item, index, isLast) + item.m_index = index + item.m_owner = self + local entryType = isLast and LAST_ENTRY_ID or ENTRY_ID + local entry = ZO_ScrollList_CreateDataEntry(entryType, item) + + return entry +end + +function ScrollableDropdownHelper.AddMenuItems(self) -- self refers to the ZO_ScrollableComboBox here + ZO_ScrollList_Clear(self.m_scroll) + + local numItems = #self.m_sortedItems + local dataList = ZO_ScrollList_GetDataList(self.m_scroll) + + for i = 1, numItems do + local item = self.m_sortedItems[i] + local entry = CreateScrollableComboBoxEntry(self, item, i, i == numItems) + table.insert(dataList, entry) + end + + self:AdjustDimensions() + + ZO_ScrollList_Commit(self.m_scroll) end function ScrollableDropdownHelper:OnShow() local dropdown = self.dropdown + + -- don't show if there are no entries + if #dropdown.m_sortedItems == 0 then return true end + if dropdown.m_lastParent ~= ZO_Menus then dropdown.m_lastParent = dropdown.m_dropdown:GetParent() dropdown.m_dropdown:SetParent(ZO_Menus) @@ -262,7 +305,7 @@ end function ScrollableDropdownHelper:OnHide() local dropdown = self.dropdown - if dropdown.m_lastParent then + if dropdown.m_lastParent then dropdown.m_dropdown:SetParent(dropdown.m_lastParent) dropdown.m_lastParent = nil end @@ -275,9 +318,9 @@ function ScrollableDropdownHelper:DoHide() end end -function ScrollableDropdownHelper:GetMaxWidth() +function ScrollableDropdownHelper:CalculateContentWidth() local dropdown = self.dropdown - local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) + local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) local dummy = dataType.pool:AcquireObject() dataType.setupCallback(dummy, { @@ -344,7 +387,7 @@ function LAMCreateControl.dropdown(parent, dropdownData, controlName) dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value if dropdownData.scrollable then - local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS + local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS control.scrollHelper = ScrollableDropdownHelper:New(parent, control, visibleRows) end diff --git a/NewAddon/LibAddonMenu-2.0/controls/editbox.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/editbox.lua similarity index 96% rename from NewAddon/LibAddonMenu-2.0/controls/editbox.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/editbox.lua index d6baf11..f9f79ad 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/editbox.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/editbox.lua @@ -4,10 +4,10 @@ getFunc = function() return db.text end, setFunc = function(text) db.text = text doStuff() end, tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) - isMultiline = true, --boolean (optional) - isExtraWide = true, --boolean (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + isMultiline = true, -- boolean (optional) + isExtraWide = true, -- boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.text, -- default value or function that returns the default value (optional) diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/header.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/header.lua similarity index 96% rename from PvPFPS2018/LibAddonMenu-2.0/controls/header.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/header.lua index eadff38..3eda1d7 100644 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/header.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/header.lua @@ -1,7 +1,7 @@ --[[headerData = { type = "header", name = "My Header", -- or string id or function returning a string - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) reference = "MyAddonHeader" -- unique global reference to control (optional) } ]] diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/iconpicker.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/iconpicker.lua similarity index 99% rename from BestFriends2018/LibAddonMenu-2.0/controls/iconpicker.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/iconpicker.lua index 65c7782..2cca460 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/iconpicker.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/iconpicker.lua @@ -11,8 +11,8 @@ iconSize = 28, -- size of the icons (optional) defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) width = "full", --or "half" (optional) - beforeShow = function(control, iconPicker) return preventShow end, --(optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + beforeShow = function(control, iconPicker) return preventShow end, -- (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- default value or function that returns the default value (optional) diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/panel.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/panel.lua similarity index 55% rename from BestFriends2018/LibAddonMenu-2.0/controls/panel.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/panel.lua index 1404686..75bb904 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/panel.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/panel.lua @@ -4,16 +4,19 @@ displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) author = "Seerah", -- or string id or function returning a string (optional) version = "2.0", -- or string id or function returning a string (optional) - website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated (optional) + website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated or function (optional) + feedback = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where feedback/feature requests/bugs can be reported for the addon or function (optional) + translation = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where translation texts of the addon can be helped with or function (optional) + donation = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where a donation for the addon author can be raised or function (optional) keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) - registerForRefresh = true, --boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown) - registerForDefaults = true, --boolean (optional) (will set all options controls back to default values) - resetFunc = function() print("defaults reset") end, --(optional) custom function to run after settings are reset to defaults + registerForRefresh = true, -- boolean will refresh all options controls when a setting is changed and when the panel is shown (optional) + registerForDefaults = true, -- boolean will set all options controls back to default values (optional) + resetFunc = function() print("defaults reset") end, -- custom function to run after settings are reset to defaults (optional) } ]] -local widgetVersion = 13 +local widgetVersion = 15 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("panel", widgetVersion) then return end @@ -22,6 +25,8 @@ local cm = CALLBACK_MANAGER local function RefreshPanel(control) local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu + if LAM.currentAddonPanel ~= panel or not LAM.currentPanelOpened then return end -- we refresh it later when the panel is opened + local panelControls = panel.controlsToRefresh for i = 1, #panelControls do @@ -58,8 +63,39 @@ end local callbackRegistered = false LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 local SEPARATOR = " - " +local COLORED_SEPARATOR = ZO_WHITE:Colorize(SEPARATOR) local LINK_COLOR = ZO_ColorDef:New("5959D5") local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") +local LINK_COLOR_DONATE = ZO_ColorDef:New("FFD700") -- golden +local LINK_MOUSE_OVER_COLOR_DONATE = ZO_ColorDef:New("FFF6CC") + +local function CreateButtonControl(control, label, clickAction, relativeTo) + local button = wm:CreateControl(nil, control, CT_BUTTON) + button:SetClickSound("Click") + button:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + button:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) + button:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) + + local OnClicked + local actionType = type(clickAction) + if actionType == "string" then + OnClicked = function() RequestOpenUnsafeURL(clickAction) end + elseif actionType == "function" then + OnClicked = clickAction + end + button:SetHandler("OnClicked", OnClicked) + + if relativeTo then + button:SetAnchor(TOPLEFT, relativeTo, TOPRIGHT, 0, 0) + button:SetText(COLORED_SEPARATOR .. label) + else + button:SetAnchor(TOPLEFT, control.label, BOTTOMLEFT, 0, -2) + button:SetText(label) + end + button:SetDimensions(button:GetLabelControl():GetTextDimensions()) + + return button +end function LAMCreateControl.panel(parent, panelData, controlName) local control = wm:CreateControl(controlName, parent, CT_CONTROL) @@ -69,6 +105,7 @@ function LAMCreateControl.panel(parent, panelData, controlName) label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) + local previousInfoControl if panelData.author or panelData.version then control.info = wm:CreateControl(nil, control, CT_LABEL) local info = control.info @@ -83,26 +120,30 @@ function LAMCreateControl.panel(parent, panelData, controlName) output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) end info:SetText(table.concat(output, SEPARATOR)) + previousInfoControl = info end if panelData.website then - control.website = wm:CreateControl(nil, control, CT_BUTTON) - local website = control.website - website:SetClickSound("Click") - website:SetFont(LAM.util.L["PANEL_INFO_FONT"]) - website:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) - website:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) - if(control.info) then - website:SetAnchor(TOPLEFT, control.info, TOPRIGHT, 0, 0) - website:SetText(string.format("|cffffff%s|r%s", SEPARATOR, LAM.util.L["WEBSITE"])) - else - website:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) - website:SetText(LAM.util.L["WEBSITE"]) - end - website:SetDimensions(website:GetLabelControl():GetTextDimensions()) - website:SetHandler("OnClicked", function() - RequestOpenUnsafeURL(panelData.website) - end) + control.website = CreateButtonControl(control, LAM.util.L["WEBSITE"], panelData.website, previousInfoControl) + previousInfoControl = control.website + end + + if panelData.feedback then + control.feedback = CreateButtonControl(control, LAM.util.L["FEEDBACK"], panelData.feedback, previousInfoControl) + previousInfoControl = control.feedback + end + + if panelData.translation then + control.translation = CreateButtonControl(control, LAM.util.L["TRANSLATION"], panelData.translation, previousInfoControl) + previousInfoControl = control.translation + end + + if panelData.donation then + control.donation = CreateButtonControl(control, LAM.util.L["DONATION"], panelData.donation, previousInfoControl) + local donation = control.donation + previousInfoControl = donation + donation:SetNormalFontColor(LINK_COLOR_DONATE:UnpackRGBA()) + donation:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR_DONATE:UnpackRGBA()) end control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") @@ -119,6 +160,7 @@ function LAMCreateControl.panel(parent, panelData, controlName) end control.ForceDefaults = ForceDefaults + control.RefreshPanel = LAM.util.RequestRefreshIfNeeded control.data = panelData control.controlsToRefresh = {} diff --git a/Junkee2018/LibAddonMenu-2.0/controls/slider.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/slider.lua similarity index 93% rename from Junkee2018/LibAddonMenu-2.0/controls/slider.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/slider.lua index 7a85d57..6c80968 100644 --- a/Junkee2018/LibAddonMenu-2.0/controls/slider.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/slider.lua @@ -1,212 +1,220 @@ ---[[sliderData = { - type = "slider", - name = "My Slider", -- or string id or function returning a string - getFunc = function() return db.var end, - setFunc = function(value) db.var = value doStuff() end, - min = 0, - max = 20, - step = 1, --(optional) - clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) - decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) - autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) - inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) - tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonSlider" -- unique global reference to control (optional) -} ]] - -local widgetVersion = 12 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("slider", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local strformat = string.format - -local function RoundDecimalToPlace(d, place) - return tonumber(strformat("%." .. tostring(place) .. "f", d)) -end - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - control.slider:SetEnabled(not disable) - control.slidervalue:SetEditEnabled(not disable) - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - elseif value then - if control.data.decimals then - value = RoundDecimalToPlace(value, control.data.decimals) - end - if control.data.clampInput ~= false then - value = math.max(math.min(value, control.data.max), control.data.min) - end - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - end - - control.slider:SetValue(value) - control.slidervalue:SetText(value) -end - -function LAMCreateControl.slider(parent, sliderData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) - local isInputOnRight = sliderData.inputLocation == "right" - - --skipping creating the backdrop... Is this the actual slider texture? - control.slider = wm:CreateControl(nil, control.container, CT_SLIDER) - local slider = control.slider - slider:SetAnchor(TOPLEFT) - slider:SetHeight(14) - if(isInputOnRight) then - slider:SetAnchor(TOPRIGHT, nil, nil, -60) - else - slider:SetAnchor(TOPRIGHT) - end - slider:SetMouseEnabled(true) - slider:SetOrientation(ORIENTATION_HORIZONTAL) - --put nil for highlighted texture file path, and what look to be texture coords - slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16) - local minValue = sliderData.min - local maxValue = sliderData.max - slider:SetMinMax(minValue, maxValue) - slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - slider:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - - slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP) - local bg = slider.bg - bg:SetCenterColor(0, 0, 0) - bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4) - bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4) - bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4) - - control.minText = wm:CreateControl(nil, slider, CT_LABEL) - local minText = control.minText - minText:SetFont("ZoFontGameSmall") - minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT) - minText:SetText(sliderData.min) - - control.maxText = wm:CreateControl(nil, slider, CT_LABEL) - local maxText = control.maxText - maxText:SetFont("ZoFontGameSmall") - maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT) - maxText:SetText(sliderData.max) - - control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop") - if(isInputOnRight) then - control.slidervalueBG:SetDimensions(60, 26) - control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0) - else - control.slidervalueBG:SetDimensions(50, 16) - control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0) - end - control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop") - local slidervalue = control.slidervalue - slidervalue:ClearAnchors() - slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1) - slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1) - slidervalue:SetTextType(TEXT_TYPE_NUMERIC) - if(isInputOnRight) then - slidervalue:SetFont("ZoFontGameLarge") - else - slidervalue:SetFont("ZoFontGameSmall") - end - - local isHandlingChange = false - local function HandleValueChanged(value) - if isHandlingChange then return end - if sliderData.decimals then - value = RoundDecimalToPlace(value, sliderData.decimals) - end - isHandlingChange = true - slider:SetValue(value) - slidervalue:SetText(value) - isHandlingChange = false - end - - slidervalue:SetHandler("OnEscape", function(self) - HandleValueChanged(sliderData.getFunc()) - self:LoseFocus() - end) - slidervalue:SetHandler("OnEnter", function(self) - self:LoseFocus() - end) - slidervalue:SetHandler("OnFocusLost", function(self) - local value = tonumber(self:GetText()) - control:UpdateValue(false, value) - end) - slidervalue:SetHandler("OnTextChanged", function(self) - local input = self:GetText() - if(#input > 1 and not input:sub(-1):match("[0-9]")) then return end - local value = tonumber(input) - if(value) then - HandleValueChanged(value) - end - end) - if(sliderData.autoSelect) then - ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self) - self:SelectAll() - end) - end - - local range = maxValue - minValue - slider:SetValueStep(sliderData.step or 1) - slider:SetHandler("OnValueChanged", function(self, value, eventReason) - if eventReason == EVENT_REASON_SOFTWARE then return end - HandleValueChanged(value) - end) - slider:SetHandler("OnSliderReleased", function(self, value) - control:UpdateValue(false, value) - end) - slider:SetHandler("OnMouseWheel", function(self, value) - if(not self:GetEnabled()) then return end - local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) - control:UpdateValue(false, new_value) - end) - - if sliderData.warning ~= nil or sliderData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateValue = UpdateValue - control:UpdateValue() - - if sliderData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end +--[[sliderData = { + type = "slider", + name = "My Slider", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + min = 0, + max = 20, + step = 1, -- (optional) + clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) + clampFunction = function(value, min, max) return math.max(math.min(value, max), min) end, -- function that is called to clamp the value (optional) + decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) + autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) + inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) + tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonSlider" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("slider", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local strformat = string.format + +local function RoundDecimalToPlace(d, place) + return tonumber(strformat("%." .. tostring(place) .. "f", d)) +end + +local function ClampValue(value, min, max) + return math.max(math.min(value, max), min) +end + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.slider:SetEnabled(not disable) + control.slidervalue:SetEditEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value then + if control.data.decimals then + value = RoundDecimalToPlace(value, control.data.decimals) + end + if control.data.clampInput ~= false then + local clamp = control.data.clampFunction or ClampValue + value = clamp(value, control.data.min, control.data.max) + end + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + + control.slider:SetValue(value) + control.slidervalue:SetText(value) +end + +function LAMCreateControl.slider(parent, sliderData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) + local isInputOnRight = sliderData.inputLocation == "right" + + --skipping creating the backdrop... Is this the actual slider texture? + control.slider = wm:CreateControl(nil, control.container, CT_SLIDER) + local slider = control.slider + slider:SetAnchor(TOPLEFT) + slider:SetHeight(14) + if(isInputOnRight) then + slider:SetAnchor(TOPRIGHT, nil, nil, -60) + else + slider:SetAnchor(TOPRIGHT) + end + slider:SetMouseEnabled(true) + slider:SetOrientation(ORIENTATION_HORIZONTAL) + --put nil for highlighted texture file path, and what look to be texture coords + slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16) + local minValue = sliderData.min + local maxValue = sliderData.max + slider:SetMinMax(minValue, maxValue) + slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + slider:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP) + local bg = slider.bg + bg:SetCenterColor(0, 0, 0) + bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4) + bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4) + + control.minText = wm:CreateControl(nil, slider, CT_LABEL) + local minText = control.minText + minText:SetFont("ZoFontGameSmall") + minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT) + minText:SetText(sliderData.min) + + control.maxText = wm:CreateControl(nil, slider, CT_LABEL) + local maxText = control.maxText + maxText:SetFont("ZoFontGameSmall") + maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT) + maxText:SetText(sliderData.max) + + control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop") + if(isInputOnRight) then + control.slidervalueBG:SetDimensions(60, 26) + control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0) + else + control.slidervalueBG:SetDimensions(50, 16) + control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0) + end + control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop") + local slidervalue = control.slidervalue + slidervalue:ClearAnchors() + slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1) + slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1) + slidervalue:SetTextType(TEXT_TYPE_NUMERIC) + if(isInputOnRight) then + slidervalue:SetFont("ZoFontGameLarge") + else + slidervalue:SetFont("ZoFontGameSmall") + end + + local isHandlingChange = false + local function HandleValueChanged(value) + if isHandlingChange then return end + if sliderData.decimals then + value = RoundDecimalToPlace(value, sliderData.decimals) + end + isHandlingChange = true + slider:SetValue(value) + slidervalue:SetText(value) + isHandlingChange = false + end + + slidervalue:SetHandler("OnEscape", function(self) + HandleValueChanged(sliderData.getFunc()) + self:LoseFocus() + end) + slidervalue:SetHandler("OnEnter", function(self) + self:LoseFocus() + end) + slidervalue:SetHandler("OnFocusLost", function(self) + local value = tonumber(self:GetText()) + control:UpdateValue(false, value) + end) + slidervalue:SetHandler("OnTextChanged", function(self) + local input = self:GetText() + if(#input > 1 and not input:sub(-1):match("[0-9]")) then return end + local value = tonumber(input) + if(value) then + HandleValueChanged(value) + end + end) + if(sliderData.autoSelect) then + ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self) + self:SelectAll() + end) + end + + local range = maxValue - minValue + slider:SetValueStep(sliderData.step or 1) + slider:SetHandler("OnValueChanged", function(self, value, eventReason) + if eventReason == EVENT_REASON_SOFTWARE then return end + HandleValueChanged(value) + end) + slider:SetHandler("OnSliderReleased", function(self, value) + if self:GetEnabled() then + control:UpdateValue(false, value) + end + end) + slider:SetHandler("OnMouseWheel", function(self, value) + if(not self:GetEnabled()) then return end + local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) + control:UpdateValue(false, new_value) + end) + + if sliderData.warning ~= nil or sliderData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + + if sliderData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/submenu.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/submenu.lua similarity index 51% rename from BestFriends2018/LibAddonMenu-2.0/controls/submenu.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/submenu.lua index 1766a1f..d7bc8bf 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/submenu.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/submenu.lua @@ -1,20 +1,61 @@ --[[submenuData = { type = "submenu", name = "Submenu Title", -- or string id or function returning a string - tooltip = "My submenu tooltip", -- -- or string id or function returning a string (optional) - controls = {sliderData, buttonData} --(optional) used by LAM - reference = "MyAddonSubmenu" --(optional) unique global reference to control + icon = "path/to/my/icon.dds", -- or function returning a string (optional) + iconTextureCoords = {left, right, top, bottom}, -- or function returning a table (optional) + tooltip = "My submenu tooltip", -- or string id or function returning a string (optional) + controls = {sliderData, buttonData} -- used by LAM (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + disabledLabel = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonSubmenu" -- unique global reference to control (optional) } ]] -local widgetVersion = 11 +local widgetVersion = 13 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("submenu", widgetVersion) then return end local wm = WINDOW_MANAGER local am = ANIMATION_MANAGER +local ICON_SIZE = 32 + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + if disable and control.open then + control.open = false + control.animation:PlayFromStart() + end + + control.arrow:SetColor(color:UnpackRGBA()) + control.disabled = disable + end + + local disableLabel = control.disabled or GetDefaultValue(control.data.disabledLabel) + if disableLabel ~= control.disabledLabel then + local color = GetColorForState(disableLabel) + control.label:SetColor(color:UnpackRGBA()) + if(control.icon) then + control.icon:SetDesaturation(disableLabel and 1 or 0) + end + control.disabledLabel = disableLabel + end +end local function UpdateValue(control) control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) + + if control.icon then + control.icon:SetTexture(GetDefaultValue(control.data.icon)) + if(control.data.iconTextureCoords) then + local coords = GetDefaultValue(control.data.iconTextureCoords) + control.icon:SetTextureCoords(unpack(coords)) + end + end + if control.data.tooltip then control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) end @@ -22,8 +63,9 @@ end local function AnimateSubmenu(clicked) local control = clicked:GetParent() - control.open = not control.open + if control.disabled then return end + control.open = not control.open if control.open then control.animation:PlayFromStart() else @@ -39,30 +81,55 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") local label = control.label - label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) - label:SetDimensions(width, 30) label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) label:SetText(LAM.util.GetStringFromValue(submenuData.name)) label:SetMouseEnabled(true) + + if submenuData.icon then + control.icon = wm:CreateControl(nil, control, CT_TEXTURE) + local icon = control.icon + icon:SetTexture(GetDefaultValue(submenuData.icon)) + if(submenuData.iconTextureCoords) then + local coords = GetDefaultValue(submenuData.iconTextureCoords) + icon:SetTextureCoords(unpack(coords)) + end + icon:SetDimensions(ICON_SIZE, ICON_SIZE) + icon:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + icon:SetMouseEnabled(true) + icon:SetDrawLayer(DL_CONTROLS) + label:SetAnchor(TOP, control, TOP, 0, 5, ANCHOR_CONSTRAINS_Y) + label:SetAnchor(LEFT, icon, RIGHT, 10, 0, ANCHOR_CONSTRAINS_X) + label:SetDimensions(width - ICON_SIZE - 5, 30) + else + label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + label:SetDimensions(width, 30) + end + if submenuData.tooltip then label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + if control.icon then + control.icon.data = label.data + control.icon:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control.icon:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end end control.scroll = wm:CreateControl(nil, control, CT_SCROLL) local scroll = control.scroll scroll:SetParent(control) - scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10) + scroll:SetAnchor(TOPLEFT, control.icon or label, BOTTOMLEFT, 0, 10) scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) - control.bg = wm:CreateControl(nil, label, CT_BACKDROP) + control.bg = wm:CreateControl(nil, control.icon or label, CT_BACKDROP) local bg = control.bg - bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5) + bg:SetAnchor(TOPLEFT, control.icon or label, TOPLEFT, -5, -5) bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") bg:SetInsets(16, 16, -16, -16) + bg:SetDrawLayer(DL_BACKGROUND) control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) local arrow = control.arrow @@ -78,6 +145,9 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) control:SetResizeToFitDescendents(true) control.open = false label:SetHandler("OnMouseUp", AnimateSubmenu) + if(control.icon) then + control.icon:SetHandler("OnMouseUp", AnimateSubmenu) + end animation:SetHandler("OnStop", function(self, completedPlaying) scroll:SetResizeToFitDescendents(control.open) if control.open then @@ -101,6 +171,10 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) control.UpdateValue = UpdateValue + if submenuData.disabled ~= nil or submenuData.disabledLabel ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end LAM.util.RegisterForRefreshIfNeeded(control) diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/texture.lua b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/texture.lua similarity index 84% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/texture.lua rename to Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/texture.lua index 29dda7c..6862ac2 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/texture.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibAddonMenu-2.0/controls/texture.lua @@ -1,14 +1,14 @@ --[[textureData = { type = "texture", image = "file/path.dds", - imageWidth = 64, --max of 250 for half width, 510 for full - imageHeight = 32, --max of 100 + imageWidth = 64, -- max of 250 for half width, 510 for full + imageHeight = 32, -- max of 100 tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonTexture" --(optional) unique global reference to control + width = "full", -- or "half" (optional) + reference = "MyAddonTexture" -- unique global reference to control (optional) } ]] ---add texture coords support? +-- TODO: add texture coords support? local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") diff --git a/BestFriends2018/LibStub/LibStub.lua b/Elder Scrolls Online Addons/DataExtractor/LibStub/LibStub.lua similarity index 96% rename from BestFriends2018/LibStub/LibStub.lua rename to Elder Scrolls Online Addons/DataExtractor/LibStub/LibStub.lua index 0e6bf67..e6b8997 100644 --- a/BestFriends2018/LibStub/LibStub.lua +++ b/Elder Scrolls Online Addons/DataExtractor/LibStub/LibStub.lua @@ -3,7 +3,7 @@ -- LibStub developed for World of Warcraft by above members of the WowAce community. -- Ported to Elder Scrolls Online by Seerah -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 4 +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 5 local LibStub = _G[LIBSTUB_MAJOR] local strformat = string.format diff --git a/Elder Scrolls Online Addons/DataExtractor/Settings.lua b/Elder Scrolls Online Addons/DataExtractor/Settings.lua new file mode 100644 index 0000000..75c1233 --- /dev/null +++ b/Elder Scrolls Online Addons/DataExtractor/Settings.lua @@ -0,0 +1,132 @@ +-- Settings menu. +function DataExtractor.LoadSettings() + local LAM = LibStub("LibAddonMenu-2.0") + + local panelData = { + type = "panel", + name = DataExtractor.menuName, + displayName = DataExtractor.Colorize(DataExtractor.menuName), + author = DataExtractor.Colorize(DataExtractor.author, "AAF0BB"), + -- version = DataExtractor.Colorize(DataExtractor.version, "AA00FF"), + -- slashCommand = "/dataextractor", + registerForRefresh = true, + registerForDefaults = true, + } + LAM:RegisterAddonPanel(DataExtractor.menuName, panelData) + + local optionsTable = {} + + -- Category. -- + table.insert(optionsTable, { + type = "header", + name = ZO_HIGHLIGHT_TEXT:Colorize("My Header"), + width = "full", --or "half" (optional) + }) + + table.insert(optionsTable, { + type = "description", + --title = "My Title", --(optional) + title = nil, --(optional) + text = "My description text to display.", + width = "full", --or "half" (optional) + }) + + table.insert(optionsTable, { + type = "dropdown", + name = "My Dropdown", + tooltip = "Dropdown's tooltip text.", + choices = {"table", "of", "choices"}, + getFunc = function() return "of" end, + setFunc = function(var) print(var) end, + width = "half", --or "half" (optional) + warning = "Will need to reload the UI.", --(optional) + }) + + table.insert(optionsTable, { + type = "dropdown", + name = "My Dropdown", + tooltip = "Dropdown's tooltip text.", + choices = {"table", "of", "choices"}, + getFunc = function() return "of" end, + setFunc = function(var) print(var) end, + width = "half", --or "half" (optional) + warning = "Will need to reload the UI.", --(optional) + }) + + table.insert(optionsTable, { + type = "slider", + name = "My Slider", + tooltip = "Slider's tooltip text.", + min = 0, + max = 20, + step = 1, --(optional) + getFunc = function() return 3 end, + setFunc = function(value) d(value) end, + width = "half", --or "half" (optional) + default = 5, --(optional) + }) + + table.insert(optionsTable, { + type = "button", + name = "My Button", + tooltip = "Button's tooltip text.", + func = function() d("button pressed!") end, + width = "half", --or "half" (optional) + warning = "Will need to reload the UI.", --(optional) + }) + + table.insert(optionsTable, { + type = "submenu", + name = "Submenu Title", + tooltip = "My submenu tooltip", --(optional) + controls = { + [1] = { + type = "checkbox", + name = "My Checkbox", + tooltip = "Checkbox's tooltip text.", + getFunc = function() return true end, + setFunc = function(value) d(value) end, + width = "half", --or "half" (optional) + warning = "Will need to reload the UI.", --(optional) + }, + [2] = { + type = "colorpicker", + name = "My Color Picker", + tooltip = "Color Picker's tooltip text.", + getFunc = function() return 1, 0, 0, 1 end, --(alpha is optional) + setFunc = function(r,g,b,a) print(r, g, b, a) end, --(alpha is optional) + width = "half", --or "half" (optional) + warning = "warning text", + }, + [3] = { + type = "editbox", + name = "My Editbox", + tooltip = "Editbox's tooltip text.", + getFunc = function() return "this is some text" end, + setFunc = function(text) print(text) end, + isMultiline = false, --boolean + width = "half", --or "half" (optional) + warning = "Will need to reload the UI.", --(optional) + default = "", --(optional) + }, + }, + }) + + table.insert(optionsTable, { + type = "custom", + reference = "MyAddonCustomControl", --unique name for your control to use as reference + refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh + width = "half", --or "half" (optional) + }) + + table.insert(optionsTable, { + type = "texture", + image = "EsoUI\\Art\\ActionBar\\abilityframe64_up.dds", + imageWidth = 64, --max of 250 for half width, 510 for full + imageHeight = 64, --max of 100 + tooltip = "Image's tooltip text.", --(optional) + width = "half", --or "half" (optional) + }) + + LAM:RegisterOptionControls(DataExtractor.menuName, optionsTable) +end \ No newline at end of file diff --git a/Elder Scrolls Online Addons/Junkee2018/Junkee.lua b/Elder Scrolls Online Addons/Junkee2018/Junkee.lua new file mode 100644 index 0000000..e29c01b --- /dev/null +++ b/Elder Scrolls Online Addons/Junkee2018/Junkee.lua @@ -0,0 +1,763 @@ +Junkee = Junkee or {} +Junkee.__index = Junkee +Junkee.name = "Junkee2018" + +local LAM = LibStub("LibAddonMenu-2.0") + +local EM = EVENT_MANAGER + +local INVENTORIES_TO_HOOK = {INVENTORY_BACKPACK, INVENTORY_BANK} + +Junkee.firstActivation = true -- First time activation event runs. +Junkee.slotControl = nil -- Reference for misc' properties. +Junkee.bagId = nil +Junkee.slotId = nil +Junkee.isJunk = false +Junkee.zoneName = nil -- Track zone name changes. +Junkee.hadZoneChat = nil -- And if there was any zone chat since, to avoid spam. + +-- Defaults. +Junkee.savedVars = { + visible = true, -- All items visible. + DestroyVisible = true, + LinkVisible = true, + LockVisible = true, + firstRun = true, + copyName = false, + hideMainQuest = false, + trackZone = false, + shortGuildNames = false, + startInZoneChat = false, + blockAutoinvites = false, + playerLinkSendMail = false, + playerLinkJumpTo = false, + playerLinkToHouse = false, + -- Each command name will have "/" prepended to it automatically. + slashCmds = { + GroupLeave = { + cmd = "/gl", + active = false, + f = function() + if IsUnitGrouped("player") then + GroupLeave() + end + end + }, + GroupDisband = { + cmd = "/gd", + active = false, + f = function() + if IsUnitGrouped("player") and IsUnitGroupLeader("player") then + GroupDisband() + end + end + }, + d = { + cmd = "/d", + active = false, + f = function(text) + CHAT_SYSTEM:StartTextEntry("/script d(" .. text .. ")") + end + }, + } +} + +Junkee.OnMouseEnter = function(control) + Junkee.slotControl = control + Junkee.bagId = control.dataEntry.data.bagId + Junkee.slotId = control.dataEntry.data.slotIndex + Junkee.isJunk = control.dataEntry.data.isJunk + if Junkee.savedVars.visible then + Junkee.AddJunkAction() + end +end + +Junkee.OnMouseExit = function(control) + Junkee.slotControl = nil + Junkee.bagId = nil + Junkee.slotId = nil + Junkee.isJunk = false + if Junkee.savedVars.visible then + Junkee.RemoveJunkAction() + end +end + +local function registerHook(inventory) + local listView = inventory.listView + if listView and listView.dataTypes and listView.dataTypes[1] then + local originalCallback = listView.dataTypes[1].setupCallback + listView.dataTypes[1].setupCallback = function(rowControl, slot) + originalCallback(rowControl, slot) + ZO_PreHookHandler(rowControl, "OnMouseEnter", Junkee.OnMouseEnter) + ZO_PreHookHandler(rowControl, "OnMouseExit", Junkee.OnMouseExit) + end + end +end + +local function registerHooks() + for _, index in pairs(INVENTORIES_TO_HOOK) do + registerHook(PLAYER_INVENTORY.inventories[index]) + end +end + +-- Add menu with options. +local panelData = { + type = "panel", + name = "Junkee 2018", + displayName = "Junkee Settings", + registerForRefresh = true, + registerForDefaults = true, +} + +local optionsTable = { + [1] = { + type = "checkbox", + name = "Display Keybindings", + tooltip = "Display the addon's keybindings when opening the Inventory. " .. + "They appear on the bottom left.", + getFunc = function() return Junkee.savedVars.visible end, + setFunc = function(v) Junkee.savedVars.visible = v end, + width = "full", --or "half", + }, + [2] = { + type = "checkbox", + name = "Display the Destroy Keybinding", + tooltip = "Display the addon's keybinding for Destroy when opening the Inventory.", + getFunc = function() + return Junkee.savedVars.visible and Junkee.savedVars.DestroyVisible + end, + setFunc = function(v) Junkee.savedVars.DestroyVisible = v end, + width = "full", --or "half", + }, + [3] = { + type = "checkbox", + name = "Display the Link Keybinding", + tooltip = "Display the addon's keybinding for Link when opening the Inventory.", + getFunc = function() + return Junkee.savedVars.visible and Junkee.savedVars.LinkVisible + end, + setFunc = function(v) Junkee.savedVars.LinkVisible = v end, + width = "full", --or "half", + }, + [4] = { + type = "checkbox", + name = "Display the Lock Keybinding", + tooltip = "Display the addon's keybinding for Lock when opening the Inventory.", + getFunc = function() + return Junkee.savedVars.visible and Junkee.savedVars.LockVisible + end, + setFunc = function(v) Junkee.savedVars.LockVisible = v end, + width = "full", --or "half", + }, + [5] = { + type = "checkbox", + name = Junkee.savedVars.slashCmds["GroupLeave"].cmd, + tooltip = "Chat command to leave your group.", + getFunc = function() + return Junkee.savedVars.slashCmds["GroupLeave"].active + end, + setFunc = function(v) + local cmd = Junkee.savedVars.slashCmds["GroupLeave"].cmd + + Junkee.savedVars.slashCmds["GroupLeave"].active = v + if v then + SLASH_COMMANDS[cmd] = Junkee.savedVars.slashCmds["GroupLeave"].f + else + SLASH_COMMANDS[cmd] = nil + end + -- Reset autocomplete cache to update it. + SLASH_COMMAND_AUTO_COMPLETE:InvalidateSlashCommandCache() + end, + width = "full", --or "half", + }, + [6] = { + type = "checkbox", + name = Junkee.savedVars.slashCmds["GroupDisband"].cmd, + tooltip = "Chat command to disband your group.", + getFunc = function() + return Junkee.savedVars.slashCmds["GroupDisband"].active + end, + setFunc = function(v) + local cmd = Junkee.savedVars.slashCmds["GroupDisband"].cmd + + Junkee.savedVars.slashCmds["GroupDisband"].active = v + if v then + SLASH_COMMANDS[cmd] = Junkee.savedVars.slashCmds["GroupDisband"].f + else + SLASH_COMMANDS[cmd] = nil + end + -- Reset autocomplete cache to update it. + SLASH_COMMAND_AUTO_COMPLETE:InvalidateSlashCommandCache() + end, + width = "full", --or "half", + }, + [7] = { + type = "checkbox", + name = Junkee.savedVars.slashCmds["d"].cmd, + tooltip = "Chat command to automatically replace /d CMD with /script d(CMD).", + getFunc = function() + return Junkee.savedVars.slashCmds["d"].active + end, + setFunc = function(v) + local cmd = Junkee.savedVars.slashCmds["d"].cmd + + Junkee.savedVars.slashCmds["d"].active = v + if v then + SLASH_COMMANDS[cmd] = Junkee.savedVars.slashCmds["d"].f + else + SLASH_COMMANDS[cmd] = nil + end + -- Reset autocomplete cache to update it. + SLASH_COMMAND_AUTO_COMPLETE:InvalidateSlashCommandCache() + end, + width = "full", + }, + [8] = { + type = "checkbox", + name = "Name in Chat", + tooltip = "Middle-Mouse clicking an item in your inventory, mail, or a chat link, ".. + "will copy its name into the chat and select it - for a quick copy/paste.", + getFunc = function() + return Junkee.savedVars.copyName + end, + setFunc = function(v) + Junkee.savedVars.copyName = v + end, + width = "full", + }, + [9] = { + type = "checkbox", + name = "Hide Main Quest", + tooltip = "Hides the Main Quest from the Journal.", + getFunc = function() + return Junkee.savedVars.hideMainQuest + end, + setFunc = function(v) + Junkee.savedVars.hideMainQuest = v + -- Apply change now. Reload all quests, in case we're adding them back. + QUEST_JOURNAL_KEYBOARD:RefreshQuestMasterList() + QUEST_JOURNAL_KEYBOARD:RefreshQuestList() + end, + width = "full", + }, + [10] = { + type = "checkbox", + name = "Track Zone Changes", + tooltip = "Informs the player when the zone chat has changed.", + getFunc = function() + return Junkee.savedVars.trackZone + end, + setFunc = function(v) + Junkee.savedVars.trackZone = v + end, + width = "full", + }, + [11] = { + type = "checkbox", + name = "Short Guild Names", + tooltip = "Shortens the guild names in your chat into their abbreviations.", + getFunc = function() + return Junkee.savedVars.shortGuildNames + end, + setFunc = function(v) + Junkee.savedVars.shortGuildNames = v + end, + width = "full", + }, + [12] = { + type = "checkbox", + name = "Start in Zone Chat", + tooltip = "After logging in, the chat will start in /zone chat instead of the default /say.", + getFunc = function() + return Junkee.savedVars.startInZoneChat + end, + setFunc = function(v) + Junkee.savedVars.startInZoneChat = v + end, + width = "full", + }, + [13] = { + type = "checkbox", + name = "Block AutoInvites in Zone Chat", + tooltip = "Zone messages that are one (1) character long, such as 'x' or 'y'. (Disabled if AutoInvite is Enabled!)", + getFunc = function() + return Junkee.savedVars.blockAutoinvites + end, + setFunc = function(v) + Junkee.savedVars.blockAutoinvites = v + end, + width = "full", + }, + [14] = { + type = "checkbox", + name = GetString(SI_SOCIAL_MENU_SEND_MAIL), + tooltip = "When right-clicking a player link in the chat, adds an option to mail them.", + getFunc = function() + return Junkee.savedVars.playerLinkSendMail + end, + setFunc = function(v) + Junkee.savedVars.playerLinkSendMail = v + end, + width = "full", + }, + [15] = { + type = "checkbox", + name = GetString(SI_SOCIAL_MENU_JUMP_TO_PLAYER), + tooltip = "When right-clicking a player link in the chat, adds an option to travel to them.", + getFunc = function() + return Junkee.savedVars.playerLinkJumpTo + end, + setFunc = function(v) + Junkee.savedVars.playerLinkJumpTo = v + end, + width = "full", + }, + [16] = { + type = "checkbox", + name = GetString(SI_SOCIAL_MENU_VISIT_HOUSE), + tooltip = "When right-clicking a player link in the chat, adds an option to visit their primary house.", + getFunc = function() + return Junkee.savedVars.playerLinkToHouse + end, + setFunc = function(v) + Junkee.savedVars.playerLinkToHouse = v + end, + width = "full", + }, +} + +local function LoadMenu() + LAM:RegisterAddonPanel("Junkee 2018", panelData) + LAM:RegisterOptionControls("Junkee 2018", optionsTable) +end + +Junkee.JunkIt = function() + if Junkee.bagId == nil then return end + local isJunk = IsItemJunk(Junkee.bagId, Junkee.slotId) + SetItemIsJunk(Junkee.bagId, Junkee.slotId, not isJunk) + if isJunk then + PlaySound(SOUNDS.INVENTORY_ITEM_UNJUNKED) + else + PlaySound(SOUNDS.INVENTORY_ITEM_JUNKED) + end +end + +Junkee.DeleteIt = function() + if Junkee.bagId == nil then return end + DestroyItem(Junkee.bagId, Junkee.slotId) +end + +local function createJunkStripDescriptor(name) + return JunkeeKeyStrip:New(name, "JUNKEE_JUNK_IT", Junkee.JunkIt) +end + +local junkStripDescriptor = createJunkStripDescriptor(Junkee.tr("JunkLabel")) +local unjunkStripDescriptor = createJunkStripDescriptor(Junkee.tr("UnjunkLabel")) +local deleteStripDescriptor = JunkeeKeyStrip:New(Junkee.tr("DeleteLabel"), "JUNKEE_DELETE_IT", Junkee.DeleteIt) +local linkStripDescriptor = JunkeeKeyStrip:New(Junkee.tr("LinkLabel"), "JUNKEE_LINK_IT", Junkee.LinkIt) +local lockStripDescriptor = JunkeeKeyStrip:New(Junkee.tr("LockLabel"), "JUNKEE_LOCK_IT", Junkee.LockIt) + +Junkee.AddJunkAction = function() + if (Junkee.isJunk) then + junkStripDescriptor:Remove() + unjunkStripDescriptor:Add(true) + else + unjunkStripDescriptor:Remove() + junkStripDescriptor:Add(true) + end + + if Junkee.savedVars.DestroyVisible then deleteStripDescriptor:Add(true) end + if Junkee.savedVars.LinkVisible then linkStripDescriptor:Add(true) end + if Junkee.savedVars.LockVisible then lockStripDescriptor:Add(true) end +end + +Junkee.RemoveJunkAction = function() + unjunkStripDescriptor:Remove() + junkStripDescriptor:Remove() + + deleteStripDescriptor:Remove() + linkStripDescriptor:Remove() + lockStripDescriptor:Remove() +end + +-- Link item in chat. +Junkee.LinkIt = function() + if Junkee.bagId == nil then return end + + local link = GetItemLink(Junkee.bagId, Junkee.slotId, 1) + ZO_LinkHandler_InsertLink(link) +end + +-- Un/Lock item. +Junkee.LockIt = function() + if Junkee.bagId == nil then return end + + local bag, index = Junkee.bagId, Junkee.slotId + local locking = not IsItemPlayerLocked(bag, index) -- The locking state to apply. + if CanItemBePlayerLocked(bag, index) then + SetItemIsPlayerLocked(bag, index, locking) + PlaySound(not locking and SOUNDS.INVENTORY_ITEM_LOCKED or SOUNDS.INVENTORY_ITEM_UNLOCKED) + end + + -- Below is taken from the game code for locking. + -- IsItemAlreadySlottedToCraft() errors, + -- so until that's solved I use the above code. Reference: + -- http://www.esoui.com/forums/showthread.php?p=34500 + + -- local inventorySlot = Junkee.slotControl + -- local bag, index = Junkee.bagId, Junkee.slotId -- ZO_Inventory_GetBagAndIndex(inventorySlot) + -- local locking = not IsItemPlayerLocked(bag, index) -- The locking state to apply. + -- local action + + -- if locking then + -- action = SI_ITEM_ACTION_MARK_AS_LOCKED + -- -- Can't lock these. + -- if IsItemAlreadySlottedToCraft(inventorySlot) then return end + -- else + -- action = SI_ITEM_ACTION_UNMARK_AS_LOCKED + -- end + + -- if CanItemBePlayerLocked(bag, index) and + -- not QUICKSLOT_WINDOW:AreQuickSlotsShowing() then + -- slotActions:AddSlotAction(action, + -- function() MarkAsPlayerLockedHelper(bag, index, locking) end, + -- "secondary") + -- end +end + +-- Needed to bind CTRL/Shift+KEY. +function KEYBINDING_MANAGER:IsChordingAlwaysEnabled() + return true +end + +ZO_CreateStringId("SI_BINDING_NAME_JUNKEE_JUNK_IT", Junkee.tr("JunkBindingName")) +ZO_CreateStringId("SI_BINDING_NAME_JUNKEE_DELETE_IT", Junkee.tr("DeleteBindingName")) +ZO_CreateStringId("SI_BINDING_NAME_JUNKEE_LINK_IT", Junkee.tr("LinkBindingName")) +ZO_CreateStringId("SI_BINDING_NAME_JUNKEE_LOCK_IT", Junkee.tr("LockBindingName")) + +ZO_CreateStringId("SI_BINDING_NAME_JUNKEE_COPY_NAME", "Name in Chat") + +-- Copies text to chat inputbox and selects it, for quick copying. +local function CopyToChatInput(text) + CHAT_SYSTEM:StartTextEntry(text) + ZO_ChatWindowTextEntryEditBox:SelectAll() +end + +-- Get formatted item name from slot. +local function SlotToName(inventorySlot) + local bag, index = ZO_Inventory_GetBagAndIndex(inventorySlot) + + if index and bag then + -- Some slot items require formatting. Taking this from game code: + -- https://esodata.uesp.net/100017/src/ingame/crafting/craftinginventory.lua.html#192 + return GetItemName(bag, index) + end +end + +-- Some cases return the row, so get the name from that. +local function RowToName(inventorySlot) + if inventorySlot.dataEntry then + return inventorySlot.dataEntry.data.name + end +end + +-- Find the matching slot index in list. +local function AttachmentToName(inventorySlot) + local link = GetAttachedItemLink(MAIL_INBOX:GetOpenMailId(), ZO_Inventory_GetSlotIndex(inventorySlot), LINK_STYLE_DEFAULT) + if link then + return GetItemLinkName(link) + end +end + +-- Add middle-mouse button to click listener. +local function AddMiddleMouseButton(slotControl, stackCount, iconFile, meetsUsageRequirement, locked) + -- Patch for mail items, or any Control really. + slotControl:EnableMouseButton(MOUSE_BUTTON_INDEX_MIDDLE, true) +end + +-- Middle mouse copies item name to chat. +local function MiddleMouseCopiesNameToChat(inventorySlot, button) + -- Disabled. + if not Junkee.savedVars.copyName then return end + + -- Middle mouse button. + if button == MOUSE_BUTTON_INDEX_MIDDLE then + -- Rows. + local name = RowToName(inventorySlot) + -- Slots. + if not name then name = SlotToName(inventorySlot) end + -- Mail attachments. + if not name then name = AttachmentToName(inventorySlot) end + + -- Silent failure. + if name then + name = zo_strformat(SI_TOOLTIP_ITEM_NAME, name) + CopyToChatInput(name) + + -- DEBUG open link in TTC? + -- GetItemLinkQuality() + -- GetItemLinkInfo() + -- GetItemLinkItemId() + -- GetItemLinkItemStyle() + -- GetItemLinkRequiredLevel() + -- ... + + -- RequestOpenUnsafeURL() + end + end +end + +-- Hides the Main Quest category from the Journal. +local function HideMainQuest() + -- Disabled. + if not Junkee.savedVars.hideMainQuest then return end + + -- Quests. + local remove = {} + + for i= 1, #QUEST_JOURNAL_KEYBOARD.questMasterList.quests do + if QUEST_JOURNAL_KEYBOARD.questMasterList.quests[i].categoryName == "Main Quest" then + table.insert(remove, i) + end + end + -- Remove matches. + for i = 1, #remove do + table.remove(QUEST_JOURNAL_KEYBOARD.questMasterList.quests, remove[i]) + end + + -- Quest Categories. + remove = {} + + for i= 1, #QUEST_JOURNAL_KEYBOARD.questMasterList.categories do + if QUEST_JOURNAL_KEYBOARD.questMasterList.categories[i].name == "Main Quest" then + table.insert(remove, i) + end + end + -- Remove matches. + for i = 1, #remove do + table.remove(QUEST_JOURNAL_KEYBOARD.questMasterList.categories, remove[i]) + end +end + +-- Pre-hook main quest from journal. +local function PreHookMainQuest() + ZO_PreHook(QUEST_JOURNAL_KEYBOARD, "RefreshQuestList", HideMainQuest) + -- Apply. + QUEST_JOURNAL_KEYBOARD:RefreshQuestList() +end + +-- Track zone chat messages. +local function TrackChat(messageType, fromName, text, isFromCustomerService, fromDisplayName) + -- Zone chat tracker. + if not Junkee.hadZoneChat and messageType == CHAT_CHANNEL_ZONE then + Junkee.hadZoneChat = true + end + + -- Ignore Autoinvite posts in zone. It's usually "x" or "y", so that's close enough. + -- NOTE Try to avoid this if AutoInvite is detected and active! + if AutoInvite and AutoInvite.enabled then + -- Do nothing. + elseif Junkee.savedVars.blockAutoinvites and messageType == CHAT_CHANNEL_ZONE and #text:gsub("%s+", "") == 1 then + return true + end +end + +local function LinkHandler_OnLinkMouseUp(link, button, _, _, linkType, ...) + -- Disabled. + if not Junkee.savedVars.copyName then return end + + if button == MOUSE_BUTTON_INDEX_MIDDLE and linkType == ITEM_LINK_TYPE and type(link) == 'string' and #link > 0 and link ~= '' then + CopyToChatInput(GetItemLinkName(link)) + end +end + +-- Overrides the game function, for guild channels. +-- TODO don't repeat this every time, but just update a table with abbreviations on guild changes and load. +local OriginalCreateChannelLink = _G["ZO_LinkHandler_CreateChannelLink"] +local GuildNameAbbreviations = {} +local function CreateChannelLink(channelName) + -- Disabled. + if not Junkee.savedVars.shortGuildNames then return OriginalCreateChannelLink(channelName) end + + local name = channelName + + -- 12 to 16. + for i = CHAT_CHANNEL_GUILD_1, CHAT_CHANNEL_GUILD_5 do + if GetChannelName(i) == channelName then + if GuildNameAbbreviations[i] then + -- Already made an abbr for it. + name = GuildNameAbbreviations[i] + else + -- Get only the intials and special characters. Remove the spaces. + name = name:gsub('(%w)%w+', '%1'):gsub('%s', '') + -- Save it. + GuildNameAbbreviations[i] = name + end + end + end + + -- Only change the appearance, not the data. + return ZO_LinkHandler_CreateLink(name, nil, CHANNEL_LINK_TYPE, channelName) +end + +local function ClearGuildNameAbbreviations() + GuildNameAbbreviations = {} +end + +EM:RegisterForEvent("GuildRoster", EVENT_GUILD_SELF_JOINED_GUILD, function() ClearGuildNameAbbreviations() end) +EM:RegisterForEvent("GuildRoster", EVENT_GUILD_SELF_LEFT_GUILD, function() ClearGuildNameAbbreviations() end) + +local function TrackZone() + local zone = GetUnitZone("player") + if zone ~= Junkee.zoneName then + if not Junkee.zoneName then + -- First load. No verbose. + Junkee.zoneName = zone + else + -- Avoid spamming the chatbox, + -- so only verbose if any zone chat activity found. + if Junkee.hadZoneChat then + -- Print system message with the color of /zone chat. + local r, g, b = GetChatCategoryColor(CHAT_CATEGORY_ZONE) + local itemColor = ZO_ColorDef:New(r, g, b) + local msg = '|t16:16:esoui/art/buttons/large_leftarrow_up.dds|t' .. + itemColor:Colorize(zone) .. + '|t16:16:esoui/art/buttons/large_rightarrow_up.dds|t' + msg = itemColor:Colorize(msg) + d(msg) + end + + -- Update zone tracker. + Junkee.zoneName = zone + Junkee.hadZoneChat = nil + end + end +end + +local OriginalShowPlayerContextMenu = CHAT_SYSTEM.ShowPlayerContextMenu +local function ShowPlayerContextMenu(playerName, rawName) + -- Run the original function. + OriginalShowPlayerContextMenu(playerName, rawName) + + if Junkee.savedVars.playerLinkSendMail then + AddMenuItem(GetString(SI_SOCIAL_MENU_SEND_MAIL), function() + MAIN_MENU_KEYBOARD:Hide() -- In case it's open. Necessary! + MAIN_MENU_KEYBOARD:ShowScene("mailSend") + + SCENE_MANAGER:CallWhen("mailSend", SCENE_SHOWN, function() + MAIL_SEND.to:SetText(rawName) + MAIL_SEND.subject:TakeFocus() + end) + end) + + -- Update menu dimensions. + ZO_Menu:SetDimensions((ZO_Menu.menuPad * 2) + ZO_Menu.width, (ZO_Menu.menuPad * 2) + ZO_Menu.height + ZO_Menu.spacing * (#ZO_Menu.items - 1)) + + -- Update item dimensions. + local item = ZO_Menu.items[#ZO_Menu.items].item + item:SetDimensions(ZO_Menu.width, item.storedHeight) + end + + if Junkee.savedVars.playerLinkJumpTo then + AddMenuItem(GetString(SI_SOCIAL_MENU_JUMP_TO_PLAYER), function() + JumpToFriend(rawName) + end) + + -- Update menu dimensions. + ZO_Menu:SetDimensions((ZO_Menu.menuPad * 2) + ZO_Menu.width, (ZO_Menu.menuPad * 2) + ZO_Menu.height + ZO_Menu.spacing * (#ZO_Menu.items - 1)) + + -- Update item dimensions. + local item = ZO_Menu.items[#ZO_Menu.items].item + item:SetDimensions(ZO_Menu.width, item.storedHeight) + end + + if Junkee.savedVars.playerLinkToHouse then + AddMenuItem(GetString(SI_SOCIAL_MENU_VISIT_HOUSE), function() + JumpToHouse(rawName) + end) + + -- Update menu dimensions. + ZO_Menu:SetDimensions((ZO_Menu.menuPad * 2) + ZO_Menu.width, (ZO_Menu.menuPad * 2) + ZO_Menu.height + ZO_Menu.spacing * (#ZO_Menu.items - 1)) + + -- Update item dimensions. + local item = ZO_Menu.items[#ZO_Menu.items].item + item:SetDimensions(ZO_Menu.width, item.storedHeight) + end +end + +-- Do once after activation. +local function OnActivatedOnce() + -- Do on first run of addon. + if Junkee.savedVars.firstRun then + Junkee.savedVars.firstRun = false + d("Junkee recommends these keybindings:\n" .. + "Junk/UnJunk = Z, Destroy = Shift+Z, Link = F2, Lock = Tab.") + end + + -- Add copy name to chat item links. + LINK_HANDLER:RegisterCallback(LINK_HANDLER.LINK_MOUSE_UP_EVENT, LinkHandler_OnLinkMouseUp) + + -- Pre-hook enabling middle-mouse button for all slots (mail, inventory, etc.) + ZO_PreHook("ZO_Inventory_SetupSlot", AddMiddleMouseButton) + + -- Pre-hook adding name copying with middle-mouse click. + ZO_PreHook("ZO_InventorySlot_OnSlotClicked", MiddleMouseCopiesNameToChat) + + -- Remove Main Quests from quests list, so they're hidden. + PreHookMainQuest() + + -- Listen to chat events. + ZO_PreHook(ZO_ChatSystem_GetEventHandlers(), EVENT_CHAT_MESSAGE_CHANNEL, TrackChat) + + -- Override guild names in chat. + _G["ZO_LinkHandler_CreateChannelLink"] = CreateChannelLink + + -- Start in /zone chat. + if Junkee.savedVars.startInZoneChat then CHAT_SYSTEM:SetChannel(CHAT_CHANNEL_ZONE) end + + -- Override right-click menu for player links in chat. + CHAT_SYSTEM.ShowPlayerContextMenu = ShowPlayerContextMenu +end + +-- Do when player and UI are ready. +Junkee.OnActivated = function(eventCode, initial) + if Junkee.firstActivation then + Junkee.firstActivation = false + OnActivatedOnce() + end + + -- Repeat whenever player is loaded (after loading screens, usually.) + -- NOTE Maybe use EVENT_ZONE_CHANNEL_CHANGED? + if Junkee.savedVars.trackZone then TrackZone() end +end + +EM:RegisterForEvent(Junkee.name, EVENT_PLAYER_ACTIVATED, Junkee.OnActivated) + +Junkee.Loaded = function(eventCode, addonName) + if (Junkee.name == addonName) then + EM:UnregisterForEvent(Junkee.name, EVENT_ADD_ON_LOADED) + + registerHooks() + + -- Load saved variables. + Junkee.savedVars = ZO_SavedVars:New("JunkeeAddonSavedVars", 2, nil, Junkee.savedVars) + + -- Settings menu. + LoadMenu() + + -- Chat /slash commands. + local newCmds + for name, item in pairs(Junkee.savedVars.slashCmds) do + if item.active then + newCmds = true + SLASH_COMMANDS[item.cmd] = item.f + end + end + -- Reset autocomplete cache to update it. + if newCmds then + SLASH_COMMAND_AUTO_COMPLETE:InvalidateSlashCommandCache() + end + end +end + +EM:RegisterForEvent(Junkee.name, EVENT_ADD_ON_LOADED, Junkee.Loaded) \ No newline at end of file diff --git a/Junkee2018/Junkee2018.txt b/Elder Scrolls Online Addons/Junkee2018/Junkee2018.txt similarity index 88% rename from Junkee2018/Junkee2018.txt rename to Elder Scrolls Online Addons/Junkee2018/Junkee2018.txt index 2e7b246..709a3dc 100644 --- a/Junkee2018/Junkee2018.txt +++ b/Elder Scrolls Online Addons/Junkee2018/Junkee2018.txt @@ -1,31 +1,31 @@ -## Title: |cf4ad42Junkee 2018|cffffff -## APIVersion: 100023 -## Version: 1.41 -## Author: Thenedus & Denidil & phuein -## Description: Provides a keybinding to quickly mark an item as junk or destroy it. -## SavedVariables: JunkeeAddonSavedVars -## OptionalDependsOn: LibAddonMenu-2.0 - -bindings.xml -keystrip.lua -localizations.lua - -LibStub\LibStub.lua - -LibAddonMenu-2.0\LibAddonMenu-2.0.lua -LibAddonMenu-2.0\controls\panel.lua -LibAddonMenu-2.0\controls\submenu.lua -LibAddonMenu-2.0\controls\button.lua -LibAddonMenu-2.0\controls\checkbox.lua -LibAddonMenu-2.0\controls\colorpicker.lua -LibAddonMenu-2.0\controls\custom.lua -LibAddonMenu-2.0\controls\description.lua -LibAddonMenu-2.0\controls\dropdown.lua -LibAddonMenu-2.0\controls\editbox.lua -LibAddonMenu-2.0\controls\header.lua -LibAddonMenu-2.0\controls\slider.lua -LibAddonMenu-2.0\controls\texture.lua -LibAddonMenu-2.0\controls\iconpicker.lua -LibAddonMenu-2.0\controls\divider.lua - -Junkee.lua +## Title: |cf4ad42Junkee 2018|cffffff +## APIVersion: 100027 +## Version: 1.58 +## Author: phuein & Thenedus & Denidil +## Description: Provides a keybinding to quickly mark an item as junk or destroy it. +## SavedVariables: JunkeeAddonSavedVars +## OptionalDependsOn: LibAddonMenu-2.0 + +bindings.xml +keystrip.lua +localizations.lua + +LibStub\LibStub.lua + +LibAddonMenu-2.0\LibAddonMenu-2.0.lua +LibAddonMenu-2.0\controls\panel.lua +LibAddonMenu-2.0\controls\submenu.lua +LibAddonMenu-2.0\controls\button.lua +LibAddonMenu-2.0\controls\checkbox.lua +LibAddonMenu-2.0\controls\colorpicker.lua +LibAddonMenu-2.0\controls\custom.lua +LibAddonMenu-2.0\controls\description.lua +LibAddonMenu-2.0\controls\dropdown.lua +LibAddonMenu-2.0\controls\editbox.lua +LibAddonMenu-2.0\controls\header.lua +LibAddonMenu-2.0\controls\slider.lua +LibAddonMenu-2.0\controls\texture.lua +LibAddonMenu-2.0\controls\iconpicker.lua +LibAddonMenu-2.0\controls\divider.lua + +Junkee.lua diff --git a/ShowMount/LibAddonMenu-2.0/LICENSE b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/LICENSE similarity index 100% rename from ShowMount/LibAddonMenu-2.0/LICENSE rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/LICENSE diff --git a/Junkee2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua similarity index 91% rename from Junkee2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua index 50696f4..20ffe3a 100644 --- a/Junkee2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -4,9 +4,10 @@ --Register LAM with LibStub -local MAJOR, MINOR = "LibAddonMenu-2.0", _LAM2_VERSION_NUMBER or -1 +local MAJOR, MINOR = "LibAddonMenu-2.0", 29 local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) if not lam then return end --the same or newer version of this lib is already loaded into memory +LibAddonMenu2 = lam local messages = {} local MESSAGE_PREFIX = "[LAM2] " @@ -25,6 +26,11 @@ local function FlushMessages() messages = {} end +local logger +if LibDebugLogger then + logger = LibDebugLogger(MAJOR) +end + if LAMSettingsPanelCreated and not LAMCompatibilityWarning then PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") LAMCompatibilityWarning = true @@ -72,6 +78,10 @@ local function GetStringFromValue(value) return value end +local function GetColorForState(disabled) + return disabled and ZO_DEFAULT_DISABLED_COLOR or ZO_DEFAULT_ENABLED_COLOR +end + local function CreateBaseControl(parent, controlData, controlName) local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent @@ -144,12 +154,14 @@ local function RefreshReloadUIButton() end end - lam.applyButton:SetHidden(not lam.requiresReload) + if lam.applyButton then + lam.applyButton:SetHidden(not lam.requiresReload) + end end local function RequestRefreshIfNeeded(control) -- if our parent window wants to refresh controls, then fire the callback - local panel = GetTopPanel(control.panel) + local panel = GetTopPanel(control) local panelData = panel.data if panelData.registerForRefresh then cm:FireCallbacks("LAM-RefreshPanel", control) @@ -313,9 +325,9 @@ local function UpdateWarning(control) if control.data.requiresReload then if not warning then - warning = string.format("|cff0000%s", util.L["RELOAD_UI_WARNING"]) + warning = string.format("%s", util.L["RELOAD_UI_WARNING"]) else - warning = string.format("%s\n\n|cff0000%s", warning, util.L["RELOAD_UI_WARNING"]) + warning = string.format("%s\n\n%s", warning, util.L["RELOAD_UI_WARNING"]) end end @@ -333,10 +345,13 @@ local localization = { AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" VERSION = "Version: <>", WEBSITE = "Visit Website", + FEEDBACK = "Feedback", + TRANSLATION = "Translation", + DONATION = "Donate", PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", - RELOAD_UI_WARNING = "Changes to this setting require an UI reload in order to take effect.", - RELOAD_DIALOG_TITLE = "UI Reload required", - RELOAD_DIALOG_TEXT = "Some changes require an UI reload in order to take effect. Do you want to reload now or discard the changes?", + RELOAD_UI_WARNING = "Changes to this setting require a UI reload in order to take effect.", + RELOAD_DIALOG_TITLE = "UI Reload Required", + RELOAD_DIALOG_TEXT = "Some changes require a UI reload in order to take effect. Do you want to reload now or discard the changes?", RELOAD_DIALOG_RELOAD_BUTTON = "Reload", RELOAD_DIALOG_DISCARD_BUTTON = "Discard", }, @@ -344,6 +359,9 @@ local localization = { PANEL_NAME = "Addon", VERSION = "Versione: <>", WEBSITE = "Visita il Sitoweb", + FEEDBACK = "Feedback", + TRANSLATION = "Traduzione", + DONATION = "Donare", RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", @@ -353,6 +371,9 @@ local localization = { fr = { -- provided by Ayantir PANEL_NAME = "Extensions", WEBSITE = "Visiter le site Web", + FEEDBACK = "Réaction", + TRANSLATION = "Traduction", + DONATION = "Donner", RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", RELOAD_DIALOG_TITLE = "Reload UI requis", RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", @@ -362,6 +383,9 @@ local localization = { de = { -- provided by sirinsidiator PANEL_NAME = "Erweiterungen", WEBSITE = "Webseite besuchen", + FEEDBACK = "Feedback", + TRANSLATION = "Übersetzung", + DONATION = "Spende", RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", RELOAD_DIALOG_TITLE = "Neuladen benötigt", RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", @@ -372,6 +396,9 @@ local localization = { PANEL_NAME = "Дополнения", VERSION = "Версия: <>", WEBSITE = "Посетить сайт", + FEEDBACK = "отзыв", + TRANSLATION = "Перевод", + DONATION = "жертвовать", PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", @@ -383,6 +410,9 @@ local localization = { PANEL_NAME = "Configuración", VERSION = "Versión: <>", WEBSITE = "Visita la página web", + FEEDBACK = "Reaccion", + TRANSLATION = "Traducción", + DONATION = "Donar", RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", @@ -392,6 +422,9 @@ local localization = { jp = { -- provided by k0ta0uchi PANEL_NAME = "アドオン設定", WEBSITE = "ウェブサイトを見る", + FEEDBACK = "フィードバック", + TRANSLATION = "訳書", + DONATION = "寄贈する", }, zh = { -- provided by bssthu PANEL_NAME = "插件", @@ -409,12 +442,38 @@ local localization = { RELOAD_DIALOG_RELOAD_BUTTON = "Przeładuj", RELOAD_DIALOG_DISCARD_BUTTON = "Porzuć", }, + kr = { -- provided by p.walker + PANEL_NAME = "蝠盜蠨", + VERSION = "纄訄: <>", + WEBSITE = "裹芬襴钸 縩紸", + PANEL_INFO_FONT = "EsoKR/fonts/Univers57.otf|14|soft-shadow-thin", + RELOAD_UI_WARNING = "襴 茤訕襄 绀溽靘籴 風滼筼 訁袩靘瀰褄靴 UI 苈穜滠遨襴 靄袔革瓈瓤.", + RELOAD_DIALOG_TITLE = "UI 苈穜滠遨 靄袔", + RELOAD_DIALOG_TEXT = "绀溽瘜 茤訕 謑 UI 苈穜滠遨襄 靄袔穜靘璔 芬靭襴 覈蒵瓈瓤. 诀瀈 苈穜滠遨靘蓜溠蒵瓈灌? 蝄瓈籴 绀溽襄 迨莌靘蓜溠蒵瓈灌?", + RELOAD_DIALOG_RELOAD_BUTTON = "苈穜滠遨", + RELOAD_DIALOG_DISCARD_BUTTON = "绀溽迨莌", + }, + br = { -- provided by mlsevero & FelipeS11 + PANEL_NAME = "Addons", + AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Autor: <>" + VERSION = "Versão: <>", + WEBSITE = "Visite o Website", + FEEDBACK = "Feedback", + TRANSLATION = "Tradução", + DONATION = "Doação", + RELOAD_UI_WARNING = "Mudanças nessa configuração requerem o recarregamento da UI para ter efeito.", + RELOAD_DIALOG_TITLE = "Recarregamento da UI requerida", + RELOAD_DIALOG_TEXT = "Algumas mudanças requerem o recarregamento da UI para ter efeito. Você deseja recarregar agora ou descartar as mudanças?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recarregar", + RELOAD_DIALOG_DISCARD_BUTTON = "Descartar", + }, } -util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")], localization["en"]) +util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")] or {}, localization["en"]) util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead util.GetStringFromValue = GetStringFromValue util.GetDefaultValue = GetDefaultValue +util.GetColorForState = GetColorForState util.CreateBaseControl = CreateBaseControl util.CreateLabelAndContainerControl = CreateLabelAndContainerControl util.RequestRefreshIfNeeded = RequestRefreshIfNeeded @@ -754,6 +813,9 @@ local function CreateOptionsControls(panel) err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) if err then PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) + if logger then + logger:Error(err) + end end if isSubmenu then @@ -811,6 +873,22 @@ local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel end local CheckSafetyAndInitialize +local function ShowSetHandlerWarning(panel, handler) + local hint + if(handler == "OnShow" or handler == "OnEffectivelyShown") then + hint = "'LAM-PanelControlsCreated' or 'LAM-PanelOpened'" + elseif(handler == "OnHide" or handler == "OnEffectivelyHidden") then + hint = "'LAM-PanelClosed'" + end + + if hint then + local message = ("Setting a handler on a panel is not recommended. Use the global callback %s instead. (%s on %s)"):format(hint, handler, panel.data.name) + PrintLater(message) + if logger then + logger:Warn(message) + end + end +end --METHOD: REGISTER ADDON PANEL --registers your addon with LibAddonMenu and creates a panel @@ -823,7 +901,8 @@ function lam:RegisterAddonPanel(addonID, panelData) local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel panel:SetHidden(true) panel:SetAnchorFill(container) - panel:SetHandler("OnShow", ToggleAddonPanels) + panel:SetHandler("OnEffectivelyShown", ToggleAddonPanels) + ZO_PreHook(panel, "SetHandler", ShowSetHandlerWarning) local function stripMarkup(str) return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") diff --git a/NewAddon/LibAddonMenu-2.0/controls/button.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/button.lua similarity index 93% rename from NewAddon/LibAddonMenu-2.0/controls/button.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/button.lua index 82b5032..17ecfef 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/button.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/button.lua @@ -3,11 +3,11 @@ name = "My Button", -- string id or function returning a string func = function() end, tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - icon = "icon\\path.dds", --(optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + icon = "icon\\path.dds", -- (optional) isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) - warning = "Will need to reload the UI.", --(optional) + warning = "Will need to reload the UI.", -- (optional) reference = "MyAddonButton", -- unique global reference to control (optional) } ]] diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/checkbox.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/checkbox.lua similarity index 98% rename from BestFriends2018/LibAddonMenu-2.0/controls/checkbox.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/checkbox.lua index 6696dd7..8f48b63 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/checkbox.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/checkbox.lua @@ -5,7 +5,7 @@ setFunc = function(value) db.var = value doStuff() end, tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) width = "full", -- or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- a boolean or function that returns a boolean (optional) diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/colorpicker.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/colorpicker.lua similarity index 85% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/colorpicker.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/colorpicker.lua index a57aab0..b62cfba 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/colorpicker.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/colorpicker.lua @@ -1,19 +1,19 @@ --[[colorpickerData = { type = "colorpicker", name = "My Color Picker", -- or string id or function returning a string - getFunc = function() return db.r, db.g, db.b, db.a end, --(alpha is optional) - setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, --(alpha is optional) + getFunc = function() return db.r, db.g, db.b, db.a end, -- (alpha is optional) + setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, -- (alpha is optional) tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, --(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color + default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, -- (optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color reference = "MyAddonColorpicker" -- unique global reference to control (optional) } ]] -local widgetVersion = 13 +local widgetVersion = 14 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end @@ -79,7 +79,11 @@ function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) if upInside then local r, g, b, a = colorpickerData.getFunc() - COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, LAM.util.GetStringFromValue(colorpickerData.name)) + if IsInGamepadPreferredMode() then + COLOR_PICKER_GAMEPAD:Show(ColorPickerCallback, r, g, b, a) + else + COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a) + end end end) diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/custom.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/custom.lua similarity index 78% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/custom.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/custom.lua index 40a7c42..eb6f26c 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/custom.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/custom.lua @@ -1,8 +1,8 @@ --[[customData = { type = "custom", - reference = "MyAddonCustomControl", --(optional) unique name for your control to use as reference - refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh - width = "full", --or "half" (optional) + reference = "MyAddonCustomControl", -- unique name for your control to use as reference (optional) + refreshFunc = function(customControl) end, -- function to call when panel/controls refresh (optional) + width = "full", -- or "half" (optional) } ]] local widgetVersion = 7 diff --git a/NewAddon/LibAddonMenu-2.0/controls/description.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/description.lua similarity index 72% rename from NewAddon/LibAddonMenu-2.0/controls/description.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/description.lua index da207a0..a53c5b1 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/description.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/description.lua @@ -2,17 +2,33 @@ type = "description", text = "My description text to display.", -- or string id or function returning a string title = "My Title", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) reference = "MyAddonDescription" -- unique global reference to control (optional) } ]] -local widgetVersion = 8 +local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("description", widgetVersion) then return end local wm = WINDOW_MANAGER +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + control.desc:SetColor(color:UnpackRGBA()) + if control.title then + control.title:SetColor(color:UnpackRGBA()) + end + control.disabled = disable + end +end + local function UpdateValue(control) if control.title then control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) @@ -52,6 +68,10 @@ function LAMCreateControl.description(parent, descriptionData, controlName) end control.UpdateValue = UpdateValue + if descriptionData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end LAM.util.RegisterForRefreshIfNeeded(control) diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/divider.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/divider.lua similarity index 92% rename from BestFriends2018/LibAddonMenu-2.0/controls/divider.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/divider.lua index 8089539..90ed6e8 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/divider.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/divider.lua @@ -1,8 +1,8 @@ --[[dividerData = { type = "divider", - width = "full", --or "half" (optional) - height = 10, (optional) - alpha = 0.25, (optional) + width = "full", -- or "half" (optional) + height = 10, -- (optional) + alpha = 0.25, -- (optional) reference = "MyAddonDivider" -- unique global reference to control (optional) } ]] diff --git a/Junkee2018/LibAddonMenu-2.0/controls/dropdown.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/dropdown.lua similarity index 81% rename from Junkee2018/LibAddonMenu-2.0/controls/dropdown.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/dropdown.lua index c67624a..2f554cc 100644 --- a/Junkee2018/LibAddonMenu-2.0/controls/dropdown.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/dropdown.lua @@ -1,387 +1,432 @@ ---[[dropdownData = { - type = "dropdown", - name = "My Dropdown", -- or string id or function returning a string - choices = {"table", "of", "choices"}, - choicesValues = {"foo", 2, "three"}, -- if specified, these values will get passed to setFunc instead (optional) - getFunc = function() return db.var end, - setFunc = function(var) db.var = var doStuff() end, - tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) - choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) - sort = "name-up", --or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted - width = "full", --or "half" (optional) - scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonDropdown" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 18 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("dropdown", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local SORT_BY_VALUE = { ["value"] = {} } -local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } -local SORT_TYPES = { - name = ZO_SORT_BY_NAME, - numeric = ZO_SORT_BY_NAME_NUMERIC, - value = SORT_BY_VALUE, - numericvalue = SORT_BY_VALUE_NUMERIC, -} -local SORT_ORDERS = { - up = ZO_SORT_ORDER_UP, - down = ZO_SORT_ORDER_DOWN, -} - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - control.dropdown:SetEnabled(not disable) - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - control.dropdown:SetSelectedItem(control.choices[value]) - elseif value then - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - control.dropdown:SetSelectedItem(control.choices[value]) - end -end - -local function DropdownCallback(control, choiceText, choice) - choice.control:UpdateValue(false, choice.value or choiceText) -end - -local function SetupTooltips(comboBox, choicesTooltips) - local function ShowTooltip(control) - InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) - SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.tooltip)) - InformationTooltipTopLevel:BringWindowToTop() - end - local function HideTooltip(control) - ClearTooltip(InformationTooltip) - end - - -- allow for tooltips on the drop down entries - local originalShow = comboBox.ShowDropdownInternal - comboBox.ShowDropdownInternal = function(comboBox) - originalShow(comboBox) - local entries = ZO_Menu.items - for i = 1, #entries do - local entry = entries[i] - local control = entries[i].item - control.tooltip = choicesTooltips[i] - entry.onMouseEnter = control:GetHandler("OnMouseEnter") - entry.onMouseExit = control:GetHandler("OnMouseExit") - ZO_PreHookHandler(control, "OnMouseEnter", ShowTooltip) - ZO_PreHookHandler(control, "OnMouseExit", HideTooltip) - end - end - - local originalHide = comboBox.HideDropdownInternal - comboBox.HideDropdownInternal = function(self) - local entries = ZO_Menu.items - for i = 1, #entries do - local entry = entries[i] - local control = entries[i].item - control:SetHandler("OnMouseEnter", entry.onMouseEnter) - control:SetHandler("OnMouseExit", entry.onMouseExit) - control.tooltip = nil - end - originalHide(self) - end -end - -local function UpdateChoices(control, choices, choicesValues, choicesTooltips) - control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?) - ZO_ClearTable(control.choices) - - --build new list of choices - local choices = choices or control.data.choices - local choicesValues = choicesValues or control.data.choicesValues - local choicesTooltips = choicesTooltips or control.data.choicesTooltips - - if choicesValues then - assert(#choices == #choicesValues, "choices and choicesValues need to have the same size") - end - - if choicesTooltips then - assert(#choices == #choicesTooltips, "choices and choicesTooltips need to have the same size") - if not control.scrollHelper then -- only do this for non-scrollable - SetupTooltips(control.dropdown, choicesTooltips) - end - end - - for i = 1, #choices do - local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback) - entry.control = control - if choicesValues then - entry.value = choicesValues[i] - end - if choicesTooltips and control.scrollHelper then - entry.tooltip = choicesTooltips[i] - end - control.choices[entry.value or entry.name] = entry.name - control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort - end -end - -local function GrabSortingInfo(sortInfo) - local t, i = {}, 1 - for info in string.gmatch(sortInfo, "([^%-]+)") do - t[i] = info - i = i + 1 - end - - return t -end - -local DEFAULT_VISIBLE_ROWS = 10 -local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = 25 -- same as in zo_combobox.lua -local CONTENT_PADDING = 24 -local SCROLLBAR_PADDING = 16 -local PADDING = GetMenuPadding() / 2 -- half the amount looks closer to the regular dropdown -local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed -local ScrollableDropdownHelper = ZO_Object:Subclass() - -function ScrollableDropdownHelper:New(...) - local object = ZO_Object.New(self) - object:Initialize(...) - return object -end - -function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) - local combobox = control.combobox - local dropdown = control.dropdown - self.parent = parent - self.control = control - self.combobox = combobox - self.dropdown = dropdown - self.visibleRows = visibleRows - - -- clear anchors so we can adjust the width dynamically - dropdown.m_dropdown:ClearAnchors() - dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) - - -- handle dropdown or settingsmenu opening/closing - local function onShow() self:OnShow() end - local function onHide() self:OnHide() end - local function doHide() self:DoHide() end - - ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) - ZO_PreHook(dropdown, "HideDropdownInternal", onHide) - combobox:SetHandler("OnEffectivelyHidden", onHide) - parent:SetHandler("OnEffectivelyHidden", doHide) - - -- dont fade entries near the edges - local scrollList = dropdown.m_scroll - scrollList.selectionTemplate = nil - scrollList.highlightTemplate = nil - ZO_ScrollList_EnableSelection(scrollList, "ZO_SelectionHighlight") - ZO_ScrollList_EnableHighlight(scrollList, "ZO_SelectionHighlight") - ZO_Scroll_SetUseFadeGradient(scrollList, false) - - -- adjust scroll content anchor to mimic menu padding - local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") - local anchor1 = {scroll:GetAnchor(0)} - local anchor2 = {scroll:GetAnchor(1)} - scroll:ClearAnchors() - scroll:SetAnchor(anchor1[2], anchor1[3], anchor1[4], anchor1[5] + PADDING, anchor1[6] + PADDING) - scroll:SetAnchor(anchor2[2], anchor2[3], anchor2[4], anchor2[5] - PADDING, anchor2[6] - PADDING) - ZO_ScrollList_Commit(scrollList) - - -- hook mouse enter/exit - local function onMouseEnter(control) self:OnMouseEnter(control) end - local function onMouseExit(control) self:OnMouseExit(control) end - - -- adjust row setup to mimic the highlight padding - local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) - local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 2) - local oSetup = dataType1.setupCallback -- both types have the same setup function - local function SetupEntry(control, data, list) - oSetup(control, data, list) - control.m_label:SetAnchor(LEFT, nil, nil, 2) - -- no need to store old ones since we have full ownership of our dropdown controls - if not control.hookedMouseHandlers then --only do it once per control - control.hookedMouseHandlers = true - ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) - ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) - -- we could also just replace the handlers - --control:SetHandler("OnMouseEnter", onMouseEnter) - --control:SetHandler("OnMouseExit", onMouseExit) - end - end - dataType1.setupCallback = SetupEntry - dataType2.setupCallback = SetupEntry - - -- adjust dimensions based on entries - local scrollContent = scroll:GetNamedChild("Contents") - ZO_PreHook(dropdown, "AddMenuItems", function() - local width = PADDING * 2 + zo_max(self:GetMaxWidth(), combobox:GetWidth()) - local numItems = #dropdown.m_sortedItems - local anchorOffset = 0 - if(numItems > self.visibleRows) then - width = width + CONTENT_PADDING + SCROLLBAR_PADDING - anchorOffset = -SCROLLBAR_PADDING - numItems = self.visibleRows - end - scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) - local height = PADDING * 2 + numItems * (SCROLLABLE_ENTRY_TEMPLATE_HEIGHT + dropdown.m_spacing) - dropdown.m_spacing + ROUNDING_MARGIN - dropdown.m_dropdown:SetWidth(width) - dropdown.m_dropdown:SetHeight(height) - end) -end - -function ScrollableDropdownHelper:OnShow() - local dropdown = self.dropdown - if dropdown.m_lastParent ~= ZO_Menus then - dropdown.m_lastParent = dropdown.m_dropdown:GetParent() - dropdown.m_dropdown:SetParent(ZO_Menus) - ZO_Menus:BringWindowToTop() - end -end - -function ScrollableDropdownHelper:OnHide() - local dropdown = self.dropdown - if dropdown.m_lastParent then - dropdown.m_dropdown:SetParent(dropdown.m_lastParent) - dropdown.m_lastParent = nil - end -end - -function ScrollableDropdownHelper:DoHide() - local dropdown = self.dropdown - if dropdown:IsDropdownVisible() then - dropdown:HideDropdown() - end -end - -function ScrollableDropdownHelper:GetMaxWidth() - local dropdown = self.dropdown - local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) - - local dummy = dataType.pool:AcquireObject() - dataType.setupCallback(dummy, { - m_owner = dropdown, - name = "Dummy" - }, dropdown) - - local maxWidth = 0 - local label = dummy.m_label - local entries = dropdown.m_sortedItems - local numItems = #entries - for index = 1, numItems do - label:SetText(entries[index].name) - local width = label:GetTextWidth() - if (width > maxWidth) then - maxWidth = width - end - end - - dataType.pool:ReleaseObject(dummy.key) - return maxWidth -end - -function ScrollableDropdownHelper:OnMouseEnter(control) - -- call original code if we replace instead of hook the handler - --ZO_ScrollableComboBox_Entry_OnMouseEnter(control) - -- show tooltip - if control.m_data.tooltip then - InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) - SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.m_data.tooltip)) - InformationTooltipTopLevel:BringWindowToTop() - end -end -function ScrollableDropdownHelper:OnMouseExit(control) - -- call original code if we replace instead of hook the handler - --ZO_ScrollableComboBox_Entry_OnMouseExit(control) - -- hide tooltip - if control.m_data.tooltip then - ClearTooltip(InformationTooltip) - end -end - -function LAMCreateControl.dropdown(parent, dropdownData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName) - control.choices = {} - - local countControl = parent - local name = parent:GetName() - if not name or #name == 0 then - countControl = LAMCreateControl - name = "LAM" - end - local comboboxCount = (countControl.comboboxCount or 0) + 1 - countControl.comboboxCount = comboboxCount - control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, dropdownData.scrollable and "ZO_ScrollableComboBox" or "ZO_ComboBox") - - local combobox = control.combobox - combobox:SetAnchor(TOPLEFT) - combobox:SetDimensions(control.container:GetDimensions()) - combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox) - local dropdown = control.dropdown - dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value - - if dropdownData.scrollable then - local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS - control.scrollHelper = ScrollableDropdownHelper:New(parent, control, visibleRows) - end - - ZO_PreHook(dropdown, "UpdateItems", function(self) - assert(not self.m_sortsItems, "built-in dropdown sorting was reactivated, sorting is handled by LAM") - if control.m_sortOrder ~= nil and control.m_sortType then - local sortKey = next(control.m_sortType) - local sortFunc = function(item1, item2) return ZO_TableOrderingFunction(item1, item2, sortKey, control.m_sortType, control.m_sortOrder) end - table.sort(self.m_sortedItems, sortFunc) - end - end) - - if dropdownData.sort then - local sortInfo = GrabSortingInfo(dropdownData.sort) - control.m_sortType, control.m_sortOrder = SORT_TYPES[sortInfo[1]], SORT_ORDERS[sortInfo[2]] - elseif dropdownData.choicesValues then - control.m_sortType, control.m_sortOrder = ZO_SORT_ORDER_UP, SORT_BY_VALUE - end - - if dropdownData.warning ~= nil or dropdownData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateChoices = UpdateChoices - control:UpdateChoices(dropdownData.choices, dropdownData.choicesValues) - control.UpdateValue = UpdateValue - control:UpdateValue() - if dropdownData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end +--[[dropdownData = { + type = "dropdown", + name = "My Dropdown", -- or string id or function returning a string + choices = {"table", "of", "choices"}, + choicesValues = {"foo", 2, "three"}, -- if specified, these values will get passed to setFunc instead (optional) + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + sort = "name-up", -- or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted + width = "full", -- or "half" (optional) + scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonDropdown" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 20 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("dropdown", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER +local SORT_BY_VALUE = { ["value"] = {} } +local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } +local SORT_TYPES = { + name = ZO_SORT_BY_NAME, + numeric = ZO_SORT_BY_NAME_NUMERIC, + value = SORT_BY_VALUE, + numericvalue = SORT_BY_VALUE_NUMERIC, +} +local SORT_ORDERS = { + up = ZO_SORT_ORDER_UP, + down = ZO_SORT_ORDER_DOWN, +} + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.dropdown:SetEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.dropdown:SetSelectedItem(control.choices[value]) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.dropdown:SetSelectedItem(control.choices[value]) + end +end + +local function DropdownCallback(control, choiceText, choice) + choice.control:UpdateValue(false, choice.value or choiceText) +end + +local function SetupTooltips(comboBox, choicesTooltips) + local function ShowTooltip(control) + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end + local function HideTooltip(control) + ClearTooltip(InformationTooltip) + end + + -- allow for tooltips on the drop down entries + local originalShow = comboBox.ShowDropdownInternal + comboBox.ShowDropdownInternal = function(comboBox) + originalShow(comboBox) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control.tooltip = choicesTooltips[i] + entry.onMouseEnter = control:GetHandler("OnMouseEnter") + entry.onMouseExit = control:GetHandler("OnMouseExit") + ZO_PreHookHandler(control, "OnMouseEnter", ShowTooltip) + ZO_PreHookHandler(control, "OnMouseExit", HideTooltip) + end + end + + local originalHide = comboBox.HideDropdownInternal + comboBox.HideDropdownInternal = function(self) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control:SetHandler("OnMouseEnter", entry.onMouseEnter) + control:SetHandler("OnMouseExit", entry.onMouseExit) + control.tooltip = nil + end + originalHide(self) + end +end + +local function UpdateChoices(control, choices, choicesValues, choicesTooltips) + control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?) + ZO_ClearTable(control.choices) + + --build new list of choices + local choices = choices or control.data.choices + local choicesValues = choicesValues or control.data.choicesValues + local choicesTooltips = choicesTooltips or control.data.choicesTooltips + + if choicesValues then + assert(#choices == #choicesValues, "choices and choicesValues need to have the same size") + end + + if choicesTooltips then + assert(#choices == #choicesTooltips, "choices and choicesTooltips need to have the same size") + if not control.scrollHelper then -- only do this for non-scrollable + SetupTooltips(control.dropdown, choicesTooltips) + end + end + + for i = 1, #choices do + local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback) + entry.control = control + if choicesValues then + entry.value = choicesValues[i] + end + if choicesTooltips and control.scrollHelper then + entry.tooltip = choicesTooltips[i] + end + control.choices[entry.value or entry.name] = entry.name + control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort + end +end + +local function GrabSortingInfo(sortInfo) + local t, i = {}, 1 + for info in string.gmatch(sortInfo, "([^%-]+)") do + t[i] = info + i = i + 1 + end + + return t +end + +local ENTRY_ID = 1 +local LAST_ENTRY_ID = 2 +local OFFSET_X_INDEX = 4 +local DEFAULT_VISIBLE_ROWS = 10 +local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = ZO_SCROLLABLE_ENTRY_TEMPLATE_HEIGHT +local SCROLLBAR_PADDING = ZO_SCROLL_BAR_WIDTH +local PADDING_X = GetMenuPadding() +local PADDING_Y = ZO_SCROLLABLE_COMBO_BOX_LIST_PADDING_Y +local LABEL_OFFSET_X = 2 +local CONTENT_PADDING = PADDING_X * 4 +local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed +local ScrollableDropdownHelper = ZO_Object:Subclass() + +function ScrollableDropdownHelper:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function ScrollableDropdownHelper:Initialize(panel, control, visibleRows) + local combobox = control.combobox + local dropdown = control.dropdown + self.panel = panel + self.control = control + self.combobox = combobox + self.dropdown = dropdown + self.visibleRows = visibleRows + + -- clear anchors so we can adjust the width dynamically + dropdown.m_dropdown:ClearAnchors() + dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) + + -- handle dropdown or settingsmenu opening/closing + local function onShow() return self:OnShow() end + local function onHide() self:OnHide() end + local function doHide(closedPanel) + if closedPanel == panel then self:DoHide() end + end + + ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) + ZO_PreHook(dropdown, "HideDropdownInternal", onHide) + combobox:SetHandler("OnEffectivelyHidden", onHide) + cm:RegisterCallback("LAM-PanelClosed", doHide) + + -- dont fade entries near the edges + local scrollList = dropdown.m_scroll + scrollList.selectionTemplate = nil + scrollList.highlightTemplate = nil + ZO_ScrollList_EnableSelection(scrollList, "ZO_SelectionHighlight") + ZO_ScrollList_EnableHighlight(scrollList, "ZO_SelectionHighlight") + ZO_Scroll_SetUseFadeGradient(scrollList, false) + + -- adjust scroll content anchor to mimic menu padding + local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") + local anchor1 = {select(2, scroll:GetAnchor(0))} + local anchor2 = {select(2, scroll:GetAnchor(1))} + anchor1[OFFSET_X_INDEX] = PADDING_X - LABEL_OFFSET_X + anchor2[OFFSET_X_INDEX] = -anchor1[OFFSET_X_INDEX] + scroll:ClearAnchors() + scroll:SetAnchor(unpack(anchor1)) + scroll:SetAnchor(unpack(anchor2)) + ZO_ScrollList_Commit(scrollList) + + -- hook mouse enter/exit + local function onMouseEnter(control) self:OnMouseEnter(control) end + local function onMouseExit(control) self:OnMouseExit(control) end + + -- adjust row setup to mimic the highlight padding + local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, ENTRY_ID) + local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, LAST_ENTRY_ID) + local oSetup = dataType1.setupCallback -- both types have the same setup function + local function SetupEntry(control, data, list) + oSetup(control, data, list) + control.m_label:SetAnchor(LEFT, nil, nil, LABEL_OFFSET_X) + control.m_label:SetAnchor(RIGHT, nil, nil, -LABEL_OFFSET_X) + -- no need to store old ones since we have full ownership of our dropdown controls + if not control.hookedMouseHandlers then --only do it once per control + control.hookedMouseHandlers = true + ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) + ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) + end + end + dataType1.setupCallback = SetupEntry + dataType2.setupCallback = SetupEntry + + -- adjust dimensions based on entries + local scrollContent = scroll:GetNamedChild("Contents") + dropdown.AddMenuItems = ScrollableDropdownHelper.AddMenuItems + + dropdown.AdjustDimensions = function() + local numItems = #dropdown.m_sortedItems + local contentWidth = self:CalculateContentWidth() + CONTENT_PADDING + local anchorOffset = 0 + if(numItems > self.visibleRows) then + numItems = self.visibleRows + contentWidth = contentWidth + SCROLLBAR_PADDING + anchorOffset = -SCROLLBAR_PADDING + end + + local width = zo_max(contentWidth, dropdown.m_container:GetWidth()) + local height = dropdown:GetEntryTemplateHeightWithSpacing() * numItems - dropdown.m_spacing + (PADDING_Y * 2) + ROUNDING_MARGIN + + dropdown.m_dropdown:SetWidth(width) + dropdown.m_dropdown:SetHeight(height) + ZO_ScrollList_SetHeight(dropdown.m_scroll, height) + + scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) + end +end + +local function CreateScrollableComboBoxEntry(self, item, index, isLast) + item.m_index = index + item.m_owner = self + local entryType = isLast and LAST_ENTRY_ID or ENTRY_ID + local entry = ZO_ScrollList_CreateDataEntry(entryType, item) + + return entry +end + +function ScrollableDropdownHelper.AddMenuItems(self) -- self refers to the ZO_ScrollableComboBox here + ZO_ScrollList_Clear(self.m_scroll) + + local numItems = #self.m_sortedItems + local dataList = ZO_ScrollList_GetDataList(self.m_scroll) + + for i = 1, numItems do + local item = self.m_sortedItems[i] + local entry = CreateScrollableComboBoxEntry(self, item, i, i == numItems) + table.insert(dataList, entry) + end + + self:AdjustDimensions() + + ZO_ScrollList_Commit(self.m_scroll) +end + +function ScrollableDropdownHelper:OnShow() + local dropdown = self.dropdown + + -- don't show if there are no entries + if #dropdown.m_sortedItems == 0 then return true end + + if dropdown.m_lastParent ~= ZO_Menus then + dropdown.m_lastParent = dropdown.m_dropdown:GetParent() + dropdown.m_dropdown:SetParent(ZO_Menus) + ZO_Menus:BringWindowToTop() + end +end + +function ScrollableDropdownHelper:OnHide() + local dropdown = self.dropdown + if dropdown.m_lastParent then + dropdown.m_dropdown:SetParent(dropdown.m_lastParent) + dropdown.m_lastParent = nil + end +end + +function ScrollableDropdownHelper:DoHide() + local dropdown = self.dropdown + if dropdown:IsDropdownVisible() then + dropdown:HideDropdown() + end +end + +function ScrollableDropdownHelper:CalculateContentWidth() + local dropdown = self.dropdown + local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) + + local dummy = dataType.pool:AcquireObject() + dataType.setupCallback(dummy, { + m_owner = dropdown, + name = "Dummy" + }, dropdown) + + local maxWidth = 0 + local label = dummy.m_label + local entries = dropdown.m_sortedItems + local numItems = #entries + for index = 1, numItems do + label:SetText(entries[index].name) + local width = label:GetTextWidth() + if (width > maxWidth) then + maxWidth = width + end + end + + dataType.pool:ReleaseObject(dummy.key) + return maxWidth +end + +function ScrollableDropdownHelper:OnMouseEnter(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseEnter(control) + -- show tooltip + if control.m_data.tooltip then + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.m_data.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end +end +function ScrollableDropdownHelper:OnMouseExit(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseExit(control) + -- hide tooltip + if control.m_data.tooltip then + ClearTooltip(InformationTooltip) + end +end + +function LAMCreateControl.dropdown(parent, dropdownData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName) + control.choices = {} + + local countControl = parent + local name = parent:GetName() + if not name or #name == 0 then + countControl = LAMCreateControl + name = "LAM" + end + local comboboxCount = (countControl.comboboxCount or 0) + 1 + countControl.comboboxCount = comboboxCount + control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, dropdownData.scrollable and "ZO_ScrollableComboBox" or "ZO_ComboBox") + + local combobox = control.combobox + combobox:SetAnchor(TOPLEFT) + combobox:SetDimensions(control.container:GetDimensions()) + combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox) + local dropdown = control.dropdown + dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value + + if dropdownData.scrollable then + local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS + control.scrollHelper = ScrollableDropdownHelper:New(LAM.util.GetTopPanel(parent), control, visibleRows) + end + + ZO_PreHook(dropdown, "UpdateItems", function(self) + assert(not self.m_sortsItems, "built-in dropdown sorting was reactivated, sorting is handled by LAM") + if control.m_sortOrder ~= nil and control.m_sortType then + local sortKey = next(control.m_sortType) + local sortFunc = function(item1, item2) return ZO_TableOrderingFunction(item1, item2, sortKey, control.m_sortType, control.m_sortOrder) end + table.sort(self.m_sortedItems, sortFunc) + end + end) + + if dropdownData.sort then + local sortInfo = GrabSortingInfo(dropdownData.sort) + control.m_sortType, control.m_sortOrder = SORT_TYPES[sortInfo[1]], SORT_ORDERS[sortInfo[2]] + elseif dropdownData.choicesValues then + control.m_sortType, control.m_sortOrder = ZO_SORT_ORDER_UP, SORT_BY_VALUE + end + + if dropdownData.warning ~= nil or dropdownData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateChoices = UpdateChoices + control:UpdateChoices(dropdownData.choices, dropdownData.choicesValues) + control.UpdateValue = UpdateValue + control:UpdateValue() + if dropdownData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/editbox.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/editbox.lua similarity index 96% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/editbox.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/editbox.lua index d6baf11..f9f79ad 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/editbox.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/editbox.lua @@ -4,10 +4,10 @@ getFunc = function() return db.text end, setFunc = function(text) db.text = text doStuff() end, tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) - isMultiline = true, --boolean (optional) - isExtraWide = true, --boolean (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + isMultiline = true, -- boolean (optional) + isExtraWide = true, -- boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.text, -- default value or function that returns the default value (optional) diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/header.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/header.lua similarity index 96% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/header.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/header.lua index eadff38..3eda1d7 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/header.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/header.lua @@ -1,7 +1,7 @@ --[[headerData = { type = "header", name = "My Header", -- or string id or function returning a string - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) reference = "MyAddonHeader" -- unique global reference to control (optional) } ]] diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/iconpicker.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/iconpicker.lua similarity index 99% rename from PvPFPS2018/LibAddonMenu-2.0/controls/iconpicker.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/iconpicker.lua index 65c7782..2cca460 100644 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/iconpicker.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/iconpicker.lua @@ -11,8 +11,8 @@ iconSize = 28, -- size of the icons (optional) defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) width = "full", --or "half" (optional) - beforeShow = function(control, iconPicker) return preventShow end, --(optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + beforeShow = function(control, iconPicker) return preventShow end, -- (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- default value or function that returns the default value (optional) diff --git a/NewAddon/LibAddonMenu-2.0/controls/panel.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/panel.lua similarity index 55% rename from NewAddon/LibAddonMenu-2.0/controls/panel.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/panel.lua index 1404686..75bb904 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/panel.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/panel.lua @@ -4,16 +4,19 @@ displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) author = "Seerah", -- or string id or function returning a string (optional) version = "2.0", -- or string id or function returning a string (optional) - website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated (optional) + website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated or function (optional) + feedback = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where feedback/feature requests/bugs can be reported for the addon or function (optional) + translation = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where translation texts of the addon can be helped with or function (optional) + donation = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where a donation for the addon author can be raised or function (optional) keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) - registerForRefresh = true, --boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown) - registerForDefaults = true, --boolean (optional) (will set all options controls back to default values) - resetFunc = function() print("defaults reset") end, --(optional) custom function to run after settings are reset to defaults + registerForRefresh = true, -- boolean will refresh all options controls when a setting is changed and when the panel is shown (optional) + registerForDefaults = true, -- boolean will set all options controls back to default values (optional) + resetFunc = function() print("defaults reset") end, -- custom function to run after settings are reset to defaults (optional) } ]] -local widgetVersion = 13 +local widgetVersion = 15 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("panel", widgetVersion) then return end @@ -22,6 +25,8 @@ local cm = CALLBACK_MANAGER local function RefreshPanel(control) local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu + if LAM.currentAddonPanel ~= panel or not LAM.currentPanelOpened then return end -- we refresh it later when the panel is opened + local panelControls = panel.controlsToRefresh for i = 1, #panelControls do @@ -58,8 +63,39 @@ end local callbackRegistered = false LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 local SEPARATOR = " - " +local COLORED_SEPARATOR = ZO_WHITE:Colorize(SEPARATOR) local LINK_COLOR = ZO_ColorDef:New("5959D5") local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") +local LINK_COLOR_DONATE = ZO_ColorDef:New("FFD700") -- golden +local LINK_MOUSE_OVER_COLOR_DONATE = ZO_ColorDef:New("FFF6CC") + +local function CreateButtonControl(control, label, clickAction, relativeTo) + local button = wm:CreateControl(nil, control, CT_BUTTON) + button:SetClickSound("Click") + button:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + button:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) + button:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) + + local OnClicked + local actionType = type(clickAction) + if actionType == "string" then + OnClicked = function() RequestOpenUnsafeURL(clickAction) end + elseif actionType == "function" then + OnClicked = clickAction + end + button:SetHandler("OnClicked", OnClicked) + + if relativeTo then + button:SetAnchor(TOPLEFT, relativeTo, TOPRIGHT, 0, 0) + button:SetText(COLORED_SEPARATOR .. label) + else + button:SetAnchor(TOPLEFT, control.label, BOTTOMLEFT, 0, -2) + button:SetText(label) + end + button:SetDimensions(button:GetLabelControl():GetTextDimensions()) + + return button +end function LAMCreateControl.panel(parent, panelData, controlName) local control = wm:CreateControl(controlName, parent, CT_CONTROL) @@ -69,6 +105,7 @@ function LAMCreateControl.panel(parent, panelData, controlName) label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) + local previousInfoControl if panelData.author or panelData.version then control.info = wm:CreateControl(nil, control, CT_LABEL) local info = control.info @@ -83,26 +120,30 @@ function LAMCreateControl.panel(parent, panelData, controlName) output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) end info:SetText(table.concat(output, SEPARATOR)) + previousInfoControl = info end if panelData.website then - control.website = wm:CreateControl(nil, control, CT_BUTTON) - local website = control.website - website:SetClickSound("Click") - website:SetFont(LAM.util.L["PANEL_INFO_FONT"]) - website:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) - website:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) - if(control.info) then - website:SetAnchor(TOPLEFT, control.info, TOPRIGHT, 0, 0) - website:SetText(string.format("|cffffff%s|r%s", SEPARATOR, LAM.util.L["WEBSITE"])) - else - website:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) - website:SetText(LAM.util.L["WEBSITE"]) - end - website:SetDimensions(website:GetLabelControl():GetTextDimensions()) - website:SetHandler("OnClicked", function() - RequestOpenUnsafeURL(panelData.website) - end) + control.website = CreateButtonControl(control, LAM.util.L["WEBSITE"], panelData.website, previousInfoControl) + previousInfoControl = control.website + end + + if panelData.feedback then + control.feedback = CreateButtonControl(control, LAM.util.L["FEEDBACK"], panelData.feedback, previousInfoControl) + previousInfoControl = control.feedback + end + + if panelData.translation then + control.translation = CreateButtonControl(control, LAM.util.L["TRANSLATION"], panelData.translation, previousInfoControl) + previousInfoControl = control.translation + end + + if panelData.donation then + control.donation = CreateButtonControl(control, LAM.util.L["DONATION"], panelData.donation, previousInfoControl) + local donation = control.donation + previousInfoControl = donation + donation:SetNormalFontColor(LINK_COLOR_DONATE:UnpackRGBA()) + donation:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR_DONATE:UnpackRGBA()) end control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") @@ -119,6 +160,7 @@ function LAMCreateControl.panel(parent, panelData, controlName) end control.ForceDefaults = ForceDefaults + control.RefreshPanel = LAM.util.RequestRefreshIfNeeded control.data = panelData control.controlsToRefresh = {} diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/slider.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/slider.lua similarity index 93% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/slider.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/slider.lua index bd721c5..6c80968 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/slider.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/slider.lua @@ -5,13 +5,14 @@ setFunc = function(value) db.var = value doStuff() end, min = 0, max = 20, - step = 1, --(optional) + step = 1, -- (optional) clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) + clampFunction = function(value, min, max) return math.max(math.min(value, max), min) end, -- function that is called to clamp the value (optional) decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) disabled = function() return db.someBooleanSetting end, --or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) @@ -19,7 +20,7 @@ reference = "MyAddonSlider" -- unique global reference to control (optional) } ]] -local widgetVersion = 12 +local widgetVersion = 13 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("slider", widgetVersion) then return end @@ -30,6 +31,10 @@ local function RoundDecimalToPlace(d, place) return tonumber(strformat("%." .. tostring(place) .. "f", d)) end +local function ClampValue(value, min, max) + return math.max(math.min(value, max), min) +end + local function UpdateDisabled(control) local disable if type(control.data.disabled) == "function" then @@ -62,7 +67,8 @@ local function UpdateValue(control, forceDefault, value) value = RoundDecimalToPlace(value, control.data.decimals) end if control.data.clampInput ~= false then - value = math.max(math.min(value, control.data.max), control.data.min) + local clamp = control.data.clampFunction or ClampValue + value = clamp(value, control.data.min, control.data.max) end control.data.setFunc(value) --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed @@ -182,7 +188,9 @@ function LAMCreateControl.slider(parent, sliderData, controlName) HandleValueChanged(value) end) slider:SetHandler("OnSliderReleased", function(self, value) - control:UpdateValue(false, value) + if self:GetEnabled() then + control:UpdateValue(false, value) + end end) slider:SetHandler("OnMouseWheel", function(self, value) if(not self:GetEnabled()) then return end diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/submenu.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/submenu.lua similarity index 51% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/submenu.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/submenu.lua index 1766a1f..d7bc8bf 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/submenu.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/submenu.lua @@ -1,20 +1,61 @@ --[[submenuData = { type = "submenu", name = "Submenu Title", -- or string id or function returning a string - tooltip = "My submenu tooltip", -- -- or string id or function returning a string (optional) - controls = {sliderData, buttonData} --(optional) used by LAM - reference = "MyAddonSubmenu" --(optional) unique global reference to control + icon = "path/to/my/icon.dds", -- or function returning a string (optional) + iconTextureCoords = {left, right, top, bottom}, -- or function returning a table (optional) + tooltip = "My submenu tooltip", -- or string id or function returning a string (optional) + controls = {sliderData, buttonData} -- used by LAM (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + disabledLabel = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonSubmenu" -- unique global reference to control (optional) } ]] -local widgetVersion = 11 +local widgetVersion = 13 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("submenu", widgetVersion) then return end local wm = WINDOW_MANAGER local am = ANIMATION_MANAGER +local ICON_SIZE = 32 + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + if disable and control.open then + control.open = false + control.animation:PlayFromStart() + end + + control.arrow:SetColor(color:UnpackRGBA()) + control.disabled = disable + end + + local disableLabel = control.disabled or GetDefaultValue(control.data.disabledLabel) + if disableLabel ~= control.disabledLabel then + local color = GetColorForState(disableLabel) + control.label:SetColor(color:UnpackRGBA()) + if(control.icon) then + control.icon:SetDesaturation(disableLabel and 1 or 0) + end + control.disabledLabel = disableLabel + end +end local function UpdateValue(control) control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) + + if control.icon then + control.icon:SetTexture(GetDefaultValue(control.data.icon)) + if(control.data.iconTextureCoords) then + local coords = GetDefaultValue(control.data.iconTextureCoords) + control.icon:SetTextureCoords(unpack(coords)) + end + end + if control.data.tooltip then control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) end @@ -22,8 +63,9 @@ end local function AnimateSubmenu(clicked) local control = clicked:GetParent() - control.open = not control.open + if control.disabled then return end + control.open = not control.open if control.open then control.animation:PlayFromStart() else @@ -39,30 +81,55 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") local label = control.label - label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) - label:SetDimensions(width, 30) label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) label:SetText(LAM.util.GetStringFromValue(submenuData.name)) label:SetMouseEnabled(true) + + if submenuData.icon then + control.icon = wm:CreateControl(nil, control, CT_TEXTURE) + local icon = control.icon + icon:SetTexture(GetDefaultValue(submenuData.icon)) + if(submenuData.iconTextureCoords) then + local coords = GetDefaultValue(submenuData.iconTextureCoords) + icon:SetTextureCoords(unpack(coords)) + end + icon:SetDimensions(ICON_SIZE, ICON_SIZE) + icon:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + icon:SetMouseEnabled(true) + icon:SetDrawLayer(DL_CONTROLS) + label:SetAnchor(TOP, control, TOP, 0, 5, ANCHOR_CONSTRAINS_Y) + label:SetAnchor(LEFT, icon, RIGHT, 10, 0, ANCHOR_CONSTRAINS_X) + label:SetDimensions(width - ICON_SIZE - 5, 30) + else + label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + label:SetDimensions(width, 30) + end + if submenuData.tooltip then label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + if control.icon then + control.icon.data = label.data + control.icon:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control.icon:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end end control.scroll = wm:CreateControl(nil, control, CT_SCROLL) local scroll = control.scroll scroll:SetParent(control) - scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10) + scroll:SetAnchor(TOPLEFT, control.icon or label, BOTTOMLEFT, 0, 10) scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) - control.bg = wm:CreateControl(nil, label, CT_BACKDROP) + control.bg = wm:CreateControl(nil, control.icon or label, CT_BACKDROP) local bg = control.bg - bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5) + bg:SetAnchor(TOPLEFT, control.icon or label, TOPLEFT, -5, -5) bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") bg:SetInsets(16, 16, -16, -16) + bg:SetDrawLayer(DL_BACKGROUND) control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) local arrow = control.arrow @@ -78,6 +145,9 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) control:SetResizeToFitDescendents(true) control.open = false label:SetHandler("OnMouseUp", AnimateSubmenu) + if(control.icon) then + control.icon:SetHandler("OnMouseUp", AnimateSubmenu) + end animation:SetHandler("OnStop", function(self, completedPlaying) scroll:SetResizeToFitDescendents(control.open) if control.open then @@ -101,6 +171,10 @@ function LAMCreateControl.submenu(parent, submenuData, controlName) btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) control.UpdateValue = UpdateValue + if submenuData.disabled ~= nil or submenuData.disabledLabel ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end LAM.util.RegisterForRefreshIfNeeded(control) diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/texture.lua b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/texture.lua similarity index 84% rename from PvPFPS2018/LibAddonMenu-2.0/controls/texture.lua rename to Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/texture.lua index 29dda7c..6862ac2 100644 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/texture.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibAddonMenu-2.0/controls/texture.lua @@ -1,14 +1,14 @@ --[[textureData = { type = "texture", image = "file/path.dds", - imageWidth = 64, --max of 250 for half width, 510 for full - imageHeight = 32, --max of 100 + imageWidth = 64, -- max of 250 for half width, 510 for full + imageHeight = 32, -- max of 100 tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonTexture" --(optional) unique global reference to control + width = "full", -- or "half" (optional) + reference = "MyAddonTexture" -- unique global reference to control (optional) } ]] ---add texture coords support? +-- TODO: add texture coords support? local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") diff --git a/NewAddon/LibStub/LibStub.lua b/Elder Scrolls Online Addons/Junkee2018/LibStub/LibStub.lua similarity index 96% rename from NewAddon/LibStub/LibStub.lua rename to Elder Scrolls Online Addons/Junkee2018/LibStub/LibStub.lua index 0e6bf67..e6b8997 100644 --- a/NewAddon/LibStub/LibStub.lua +++ b/Elder Scrolls Online Addons/Junkee2018/LibStub/LibStub.lua @@ -3,7 +3,7 @@ -- LibStub developed for World of Warcraft by above members of the WowAce community. -- Ported to Elder Scrolls Online by Seerah -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 4 +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 5 local LibStub = _G[LIBSTUB_MAJOR] local strformat = string.format diff --git a/Junkee2018/bindings.xml b/Elder Scrolls Online Addons/Junkee2018/bindings.xml similarity index 96% rename from Junkee2018/bindings.xml rename to Elder Scrolls Online Addons/Junkee2018/bindings.xml index 2d47c78..f0d4b96 100644 --- a/Junkee2018/bindings.xml +++ b/Elder Scrolls Online Addons/Junkee2018/bindings.xml @@ -1,18 +1,18 @@ - - - - - Junkee.JunkIt() - - - Junkee.DeleteIt() - - - Junkee.LinkIt() - - - Junkee.LockIt() - - - - + + + + + Junkee.JunkIt() + + + Junkee.DeleteIt() + + + Junkee.LinkIt() + + + Junkee.LockIt() + + + + diff --git a/Junkee2018/keystrip.lua b/Elder Scrolls Online Addons/Junkee2018/keystrip.lua similarity index 96% rename from Junkee2018/keystrip.lua rename to Elder Scrolls Online Addons/Junkee2018/keystrip.lua index 5303990..dad68f6 100644 --- a/Junkee2018/keystrip.lua +++ b/Elder Scrolls Online Addons/Junkee2018/keystrip.lua @@ -1,47 +1,47 @@ -JunkeeKeyStrip = ZO_Object:Subclass() - -function JunkeeKeyStrip:New(name, keybind, callback, alignment) - local obj = ZO_Object.New(self) - obj:Init(name, keybind, callback, alignment) - return obj -end - -local function createStripDescriptor(name, keybind, callback, alignment) - return {{ - alignment = alignment or KEYBIND_STRIP_ALIGN_LEFT, - name = name, - keybind = keybind, - callback = callback - }} -end - -function JunkeeKeyStrip:Init(name, keybind, callback, alignment) - self.stripDescriptor = createStripDescriptor(name, keybind, callback, alignment) - self.wasAdded = false -end - -function JunkeeKeyStrip:Add(onlyIfBound) - if (not onlyIfBound or self:IsBound()) then - KEYBIND_STRIP:AddKeybindButtonGroup(self.stripDescriptor) - self.wasAdded = true - end -end - -function JunkeeKeyStrip:Remove() - if (self.wasAdded) then - KEYBIND_STRIP:RemoveKeybindButtonGroup(self.stripDescriptor) - self.wasAdded = false - end -end - -function JunkeeKeyStrip:IsBound() - -- TODO: if this is too expensive, only call once in the construction and register for keybind events - local layer, category, action = GetActionIndicesFromName(self.stripDescriptor[1]["keybind"]) - for binding = 1, GetMaxBindingsPerAction() do - local keyCode,_,_,_,_ = GetActionBindingInfo(layer, category, action, binding) - if (keyCode > 0) then - return true - end - end - return false -end +JunkeeKeyStrip = ZO_Object:Subclass() + +function JunkeeKeyStrip:New(name, keybind, callback, alignment) + local obj = ZO_Object.New(self) + obj:Init(name, keybind, callback, alignment) + return obj +end + +local function createStripDescriptor(name, keybind, callback, alignment) + return {{ + alignment = alignment or KEYBIND_STRIP_ALIGN_LEFT, + name = name, + keybind = keybind, + callback = callback + }} +end + +function JunkeeKeyStrip:Init(name, keybind, callback, alignment) + self.stripDescriptor = createStripDescriptor(name, keybind, callback, alignment) + self.wasAdded = false +end + +function JunkeeKeyStrip:Add(onlyIfBound) + if (not onlyIfBound or self:IsBound()) then + KEYBIND_STRIP:AddKeybindButtonGroup(self.stripDescriptor) + self.wasAdded = true + end +end + +function JunkeeKeyStrip:Remove() + if (self.wasAdded) then + KEYBIND_STRIP:RemoveKeybindButtonGroup(self.stripDescriptor) + self.wasAdded = false + end +end + +function JunkeeKeyStrip:IsBound() + -- TODO: if this is too expensive, only call once in the construction and register for keybind events + local layer, category, action = GetActionIndicesFromName(self.stripDescriptor[1]["keybind"]) + for binding = 1, GetMaxBindingsPerAction() do + local keyCode,_,_,_,_ = GetActionBindingInfo(layer, category, action, binding) + if (keyCode > 0) then + return true + end + end + return false +end diff --git a/Junkee2018/localizations.lua b/Elder Scrolls Online Addons/Junkee2018/localizations.lua similarity index 97% rename from Junkee2018/localizations.lua rename to Elder Scrolls Online Addons/Junkee2018/localizations.lua index 1736c6e..5b20e42 100644 --- a/Junkee2018/localizations.lua +++ b/Elder Scrolls Online Addons/Junkee2018/localizations.lua @@ -1,56 +1,56 @@ -Junkee = Junkee or {} -Junkee.localizations = { - en = { - JunkBindingName = "Junk current item", - DeleteBindingName = "Destroy current item", - LinkBindingName = "Link in Chat current item", - LockBindingName = "Un/Lock current item", - VisibleBindingName = "Show bindings in Inventory", - JunkLabel = "Junk", - UnjunkLabel = "UnJunk", - LinkLabel = "Link", - LockLabel = "Lock", - DeleteLabel = "Destroy" - }, - de = { - JunkBindingName = "Aktuellen Gegenstand als Trödel markieren", - DeleteBindingName = "Aktuellen Gegenstand zerstören", - LinkBindingName = "Link im Chat aktuelles element", - LockBindingName = "Un / Sperrt das aktuelle objekt", - VisibleBindingName = "Bindungen in Inventar anzeigen", - JunkLabel = "Als Trödel markieren", - UnjunkLabel = "Nicht als Trödel markieren", - LinkLabel = "Link", - LockLabel = "Sperren", - DeleteLabel = "Zerstören" - }, - fr = { - JunkBindingName = "Mette aux rebuts", - DeleteBindingName = "Détruire", - LinkBindingName = "Lien dans Chat article en cours", - LockBindingName = "Un / Verrouiller l'élément actuel", - VisibleBindingName = "Afficher les liaisons dans l'inventaire", - JunkLabel = "Mette aux rebuts", - UnjunkLabel = "Ne mette pas aux rebuts", - LinkLabel = "Lien", - LockLabel = "Fermer à clé", - DeleteLabel = "Détruire" - }, - ru = { - JunkBindingName = "Отметить как хлам", - DeleteBindingName = "Уничтожить указанный предмет", - LinkBindingName = "Ссылка в текущем элементе чата", - LockBindingName = "Заблокировать текущий элемент", - VisibleBindingName = "Показать привязки в инвентаре", - JunkLabel = "Хлам", - UnjunkLabel = "Не хлам", - LinkLabel = "Ссылка", - LockLabel = "Замок", - DeleteLabel = "Уничтожить" - }, -} - -Junkee.language = GetCVar("language.2") or "en" -Junkee.tr = function(str) - return Junkee.localizations[Junkee.language][str] -end +Junkee = Junkee or {} +Junkee.localizations = { + en = { + JunkBindingName = "Junk current item", + DeleteBindingName = "Destroy current item", + LinkBindingName = "Link in Chat current item", + LockBindingName = "Un/Lock current item", + VisibleBindingName = "Show bindings in Inventory", + JunkLabel = "Junk", + UnjunkLabel = "UnJunk", + LinkLabel = "Link", + LockLabel = "Lock", + DeleteLabel = "Destroy" + }, + de = { + JunkBindingName = "Aktuellen Gegenstand als Trödel markieren", + DeleteBindingName = "Aktuellen Gegenstand zerstören", + LinkBindingName = "Link im Chat aktuelles element", + LockBindingName = "Un / Sperrt das aktuelle objekt", + VisibleBindingName = "Bindungen in Inventar anzeigen", + JunkLabel = "Als Trödel markieren", + UnjunkLabel = "Nicht als Trödel markieren", + LinkLabel = "Link", + LockLabel = "Sperren", + DeleteLabel = "Zerstören" + }, + fr = { + JunkBindingName = "Mette aux rebuts", + DeleteBindingName = "Détruire", + LinkBindingName = "Lien dans Chat article en cours", + LockBindingName = "Un / Verrouiller l'élément actuel", + VisibleBindingName = "Afficher les liaisons dans l'inventaire", + JunkLabel = "Mette aux rebuts", + UnjunkLabel = "Ne mette pas aux rebuts", + LinkLabel = "Lien", + LockLabel = "Fermer à clé", + DeleteLabel = "Détruire" + }, + ru = { + JunkBindingName = "Отметить как хлам", + DeleteBindingName = "Уничтожить указанный предмет", + LinkBindingName = "Ссылка в текущем элементе чата", + LockBindingName = "Заблокировать текущий элемент", + VisibleBindingName = "Показать привязки в инвентаре", + JunkLabel = "Хлам", + UnjunkLabel = "Не хлам", + LinkLabel = "Ссылка", + LockLabel = "Замок", + DeleteLabel = "Уничтожить" + }, +} + +Junkee.language = GetCVar("language.2") or "en" +Junkee.tr = function(str) + return Junkee.localizations[Junkee.language][str] +end diff --git a/Junkee2018/readme.txt b/Elder Scrolls Online Addons/Junkee2018/readme.txt similarity index 97% rename from Junkee2018/readme.txt rename to Elder Scrolls Online Addons/Junkee2018/readme.txt index 108fe82..cceec91 100644 --- a/Junkee2018/readme.txt +++ b/Elder Scrolls Online Addons/Junkee2018/readme.txt @@ -1,76 +1,76 @@ -Junkee -====== - -Provides a keybinding to quickly mark an item as junk and additional keybindings to delete or link an item. - -Installation and Setup ----------------------- - -- Copy complete folder to - %USERPROFILE%\Documents\Elder Scrolls Online\\AddOns - where is "live" for North America and "liveeu" for Europe - (or use Minion) -- Go to Controls -> Keybindings -> User Interface Shortcuts -> Junkee and bind a key to "Junk current item." - -Version history ---------------- -## 1.4 -- [FIX] Visual fixes. -- [FIX] Got an error about duplicate bindings. Added removal before adding by case. -- [MOD] Toggle displaying which keybindings in Inventory. -- [MOD] Changed slash commands groupleave and groupdisband to /gl and /gd accordingly. -- [MOD] Add Lock toggle keybinding. - -## 1.3 -- [FIX] Text fixes. -- [MOD] Added /cmd mechanism + /groupleave. Disabled by default. - -## 1.2 -- [FIX] The addon's keybindings now show on the bottom-left in Inventory to save space. -- [MOD] Settings option for addon to Show/Hide the keybindings in Inventory screen. -- [MOD] Add keybinding for Link in Chat. - -## 1.1 -- [MOD] Keybindings allow key combinations, such as Shift + Z. - -## 1.0b -- [MOD] Adjusted APIVersion for Thieves Guild DLC - -## 1.0 -- [MOD] Adjusted APIVersion to the Current API, renamed mod - -## 0.9 -- [MOD] Adjusted APIVersion to the current API -## 0.8 -- [MOD] Adjusted APIVersion to the current one, added ZeniMax disclaimer -- [FIX] Pressing the key bound to delete in another view (e.g. map) destroyed the - helmet (Thanks Karmik) -## 0.7 -- [FIX] Pressing either bound key in another view (e.g. map) junked/destroyed the - last item the mouse was over (Thanks McGuffin) -## 0.6 -- [FIX] Inventory slots that were not present on login were missing the Junk action -- [FIX] Destroy action was missing completely -- [FIX] Actions were missing from bank -## 0.5 (Thanks Iyanga) -- [MOD] Plays sound when junking or unjunking an item -- [FIX] Adding the junk keybind is more robust, should fix the "unsecure code" error -## 0.4 -- [MOD] Adjusted APIVersion to the current one. -## 0.3 -- [NEW] Second action to delete an item. -- [MOD] Only show actions when they are bound. -- [NEW] Localization for German and French. -## 0.2a -- [FIX] Error when interacting with a vendor (Thanks ThadOptimus) -## 0.2 -- [MOD] Removed dependency on Wykkyd's Framework. -- [NEW] Toggle junk, i.e. unjunk a junked item. -- [NEW] Only display action for backpack and bank. -- [FIX] Renamed readme.txt to read.me (Thanks Tonyleila) -## 0.1 -- Initial release with basic functionality. - -This Add-on is not created by, affiliated with or sponsored by ZeniMax Media Inc. or its affiliates. -The Elder Scrolls and related logos are registered trademarks or trademarks of ZeniMax Media Inc. -in the United States and/or other countries. All rights reserved. +Junkee +====== + +Provides a keybinding to quickly mark an item as junk and additional keybindings to delete or link an item. + +Installation and Setup +---------------------- + +- Copy complete folder to + %USERPROFILE%\Documents\Elder Scrolls Online\\AddOns + where is "live" for North America and "liveeu" for Europe + (or use Minion) +- Go to Controls -> Keybindings -> User Interface Shortcuts -> Junkee and bind a key to "Junk current item." + +Version history +--------------- +## 1.4 +- [FIX] Visual fixes. +- [FIX] Got an error about duplicate bindings. Added removal before adding by case. +- [MOD] Toggle displaying which keybindings in Inventory. +- [MOD] Changed slash commands groupleave and groupdisband to /gl and /gd accordingly. +- [MOD] Add Lock toggle keybinding. + +## 1.3 +- [FIX] Text fixes. +- [MOD] Added /cmd mechanism + /groupleave. Disabled by default. + +## 1.2 +- [FIX] The addon's keybindings now show on the bottom-left in Inventory to save space. +- [MOD] Settings option for addon to Show/Hide the keybindings in Inventory screen. +- [MOD] Add keybinding for Link in Chat. + +## 1.1 +- [MOD] Keybindings allow key combinations, such as Shift + Z. + +## 1.0b +- [MOD] Adjusted APIVersion for Thieves Guild DLC + +## 1.0 +- [MOD] Adjusted APIVersion to the Current API, renamed mod + +## 0.9 +- [MOD] Adjusted APIVersion to the current API +## 0.8 +- [MOD] Adjusted APIVersion to the current one, added ZeniMax disclaimer +- [FIX] Pressing the key bound to delete in another view (e.g. map) destroyed the + helmet (Thanks Karmik) +## 0.7 +- [FIX] Pressing either bound key in another view (e.g. map) junked/destroyed the + last item the mouse was over (Thanks McGuffin) +## 0.6 +- [FIX] Inventory slots that were not present on login were missing the Junk action +- [FIX] Destroy action was missing completely +- [FIX] Actions were missing from bank +## 0.5 (Thanks Iyanga) +- [MOD] Plays sound when junking or unjunking an item +- [FIX] Adding the junk keybind is more robust, should fix the "unsecure code" error +## 0.4 +- [MOD] Adjusted APIVersion to the current one. +## 0.3 +- [NEW] Second action to delete an item. +- [MOD] Only show actions when they are bound. +- [NEW] Localization for German and French. +## 0.2a +- [FIX] Error when interacting with a vendor (Thanks ThadOptimus) +## 0.2 +- [MOD] Removed dependency on Wykkyd's Framework. +- [NEW] Toggle junk, i.e. unjunk a junked item. +- [NEW] Only display action for backpack and bank. +- [FIX] Renamed readme.txt to read.me (Thanks Tonyleila) +## 0.1 +- Initial release with basic functionality. + +This Add-on is not created by, affiliated with or sponsored by ZeniMax Media Inc. or its affiliates. +The Elder Scrolls and related logos are registered trademarks or trademarks of ZeniMax Media Inc. +in the United States and/or other countries. All rights reserved. diff --git a/NewAddon/Bindings.xml b/Elder Scrolls Online Addons/NewAddon/Bindings.xml similarity index 100% rename from NewAddon/Bindings.xml rename to Elder Scrolls Online Addons/NewAddon/Bindings.xml diff --git a/Elder Scrolls Online Addons/NewAddon/Languages/de.lua b/Elder Scrolls Online Addons/NewAddon/Languages/de.lua new file mode 100644 index 0000000..660c809 --- /dev/null +++ b/Elder Scrolls Online Addons/NewAddon/Languages/de.lua @@ -0,0 +1,11 @@ +-- Every variable must start with this addon's unique ID, as each is a global. +local localization_strings = { + SI_NEW_ADDON_MESSAGE = " ist aktiv!", + -- Keybindings. + SI_BINDING_NAME_NEWADDON_DISPLAY = "Zeigen Sie das NewAddon an", +} + +for stringId, stringValue in pairs(localization_strings) do + ZO_CreateStringId(stringId, stringValue) + SafeAddVersion(stringId, 1) +end \ No newline at end of file diff --git a/Elder Scrolls Online Addons/NewAddon/Languages/en.lua b/Elder Scrolls Online Addons/NewAddon/Languages/en.lua new file mode 100644 index 0000000..132a227 --- /dev/null +++ b/Elder Scrolls Online Addons/NewAddon/Languages/en.lua @@ -0,0 +1,11 @@ +-- Every variable must start with this addon's unique ID, as each is a global. +local localization_strings = { + SI_NEW_ADDON_MESSAGE = " is active!", + -- Keybindings. + SI_BINDING_NAME_NEWADDON_DISPLAY = "Display the NewAddon", +} + +for stringId, stringValue in pairs(localization_strings) do + ZO_CreateStringId(stringId, stringValue) + SafeAddVersion(stringId, 1) +end \ No newline at end of file diff --git a/Elder Scrolls Online Addons/NewAddon/Languages/fr.lua b/Elder Scrolls Online Addons/NewAddon/Languages/fr.lua new file mode 100644 index 0000000..af771c0 --- /dev/null +++ b/Elder Scrolls Online Addons/NewAddon/Languages/fr.lua @@ -0,0 +1,11 @@ +-- Every variable must start with this addon's unique ID, as each is a global. +local localization_strings = { + SI_NEW_ADDON_MESSAGE = " c'est actif!", + -- Keybindings. + SI_BINDING_NAME_NEWADDON_DISPLAY = "Afficher le NewAddon", +} + +for stringId, stringValue in pairs(localization_strings) do + ZO_CreateStringId(stringId, stringValue) + SafeAddVersion(stringId, 1) +end \ No newline at end of file diff --git a/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/LICENSE b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/LICENSE new file mode 100644 index 0000000..f69cbd4 --- /dev/null +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/LICENSE @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2016 Ryan Lakanen (Seerah) + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/NewAddon/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/LibAddonMenu-2.0.lua similarity index 94% rename from NewAddon/LibAddonMenu-2.0/LibAddonMenu-2.0.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/LibAddonMenu-2.0.lua index 7a88896..afd87ed 100644 --- a/NewAddon/LibAddonMenu-2.0/LibAddonMenu-2.0.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -4,9 +4,10 @@ --Register LAM with LibStub -local MAJOR, MINOR = "LibAddonMenu-2.0", 26 +local MAJOR, MINOR = "LibAddonMenu-2.0", 28 local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) if not lam then return end --the same or newer version of this lib is already loaded into memory +LibAddonMenu2 = lam local messages = {} local MESSAGE_PREFIX = "[LAM2] " @@ -25,6 +26,11 @@ local function FlushMessages() messages = {} end +local logger +if LibDebugLogger then + logger = LibDebugLogger(MAJOR) +end + if LAMSettingsPanelCreated and not LAMCompatibilityWarning then PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") LAMCompatibilityWarning = true @@ -72,6 +78,10 @@ local function GetStringFromValue(value) return value end +local function GetColorForState(disabled) + return disabled and ZO_DEFAULT_DISABLED_COLOR or ZO_DEFAULT_ENABLED_COLOR +end + local function CreateBaseControl(parent, controlData, controlName) local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent @@ -149,7 +159,7 @@ end local function RequestRefreshIfNeeded(control) -- if our parent window wants to refresh controls, then fire the callback - local panel = GetTopPanel(control.panel) + local panel = GetTopPanel(control) local panelData = panel.data if panelData.registerForRefresh then cm:FireCallbacks("LAM-RefreshPanel", control) @@ -313,9 +323,9 @@ local function UpdateWarning(control) if control.data.requiresReload then if not warning then - warning = string.format("|cff0000%s", util.L["RELOAD_UI_WARNING"]) + warning = string.format("%s", util.L["RELOAD_UI_WARNING"]) else - warning = string.format("%s\n\n|cff0000%s", warning, util.L["RELOAD_UI_WARNING"]) + warning = string.format("%s\n\n%s", warning, util.L["RELOAD_UI_WARNING"]) end end @@ -333,10 +343,13 @@ local localization = { AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" VERSION = "Version: <>", WEBSITE = "Visit Website", + FEEDBACK = "Feedback", + TRANSLATION = "Translation", + DONATION = "Donate", PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", - RELOAD_UI_WARNING = "Changes to this setting require an UI reload in order to take effect.", - RELOAD_DIALOG_TITLE = "UI Reload required", - RELOAD_DIALOG_TEXT = "Some changes require an UI reload in order to take effect. Do you want to reload now or discard the changes?", + RELOAD_UI_WARNING = GetString(SI_OPTIONS_APPLY_WARNING), + RELOAD_DIALOG_TITLE = GetString(SI_ADDON_MANAGER_RELOAD), + RELOAD_DIALOG_TEXT = "Some changes require a UI reload in order to take effect. Do you want to reload now or discard the changes?", RELOAD_DIALOG_RELOAD_BUTTON = "Reload", RELOAD_DIALOG_DISCARD_BUTTON = "Discard", }, @@ -344,6 +357,9 @@ local localization = { PANEL_NAME = "Addon", VERSION = "Versione: <>", WEBSITE = "Visita il Sitoweb", + FEEDBACK = "Feedback", + TRANSLATION = "Traduzione", + DONATION = "Donare", RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", @@ -353,6 +369,9 @@ local localization = { fr = { -- provided by Ayantir PANEL_NAME = "Extensions", WEBSITE = "Visiter le site Web", + FEEDBACK = "Réaction", + TRANSLATION = "Traduction", + DONATION = "Donner", RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", RELOAD_DIALOG_TITLE = "Reload UI requis", RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", @@ -362,6 +381,9 @@ local localization = { de = { -- provided by sirinsidiator PANEL_NAME = "Erweiterungen", WEBSITE = "Webseite besuchen", + FEEDBACK = "Feedback", + TRANSLATION = "Übersetzung", + DONATION = "Spende", RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", RELOAD_DIALOG_TITLE = "Neuladen benötigt", RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", @@ -372,6 +394,9 @@ local localization = { PANEL_NAME = "Дополнения", VERSION = "Версия: <>", WEBSITE = "Посетить сайт", + FEEDBACK = "отзыв", + TRANSLATION = "Перевод", + DONATION = "жертвовать", PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", @@ -383,6 +408,9 @@ local localization = { PANEL_NAME = "Configuración", VERSION = "Versión: <>", WEBSITE = "Visita la página web", + FEEDBACK = "Reaccion", + TRANSLATION = "Traducción", + DONATION = "Donar", RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", @@ -392,6 +420,9 @@ local localization = { jp = { -- provided by k0ta0uchi PANEL_NAME = "アドオン設定", WEBSITE = "ウェブサイトを見る", + FEEDBACK = "フィードバック", + TRANSLATION = "訳書", + DONATION = "寄贈する", }, zh = { -- provided by bssthu PANEL_NAME = "插件", @@ -420,16 +451,19 @@ local localization = { RELOAD_DIALOG_RELOAD_BUTTON = "苈穜滠遨", RELOAD_DIALOG_DISCARD_BUTTON = "绀溽迨莌", }, - br = { -- provided by mlsevero + br = { -- provided by mlsevero & FelipeS11 PANEL_NAME = "Addons", AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Autor: <>" VERSION = "Versão: <>", WEBSITE = "Visite o Website", - RELOAD_UI_WARNING = "Mudanças nessa configuração requer a releitura da UI para ter efeito.", - RELOAD_DIALOG_TITLE = "Releitura da UI requerida", - RELOAD_DIALOG_TEXT = "Algumas mudanças requerem a releitura da UI para ter efeito. Você deseja reler agora ou descartar as mudanças?", - RELOAD_DIALOG_RELOAD_BUTTON = "Relê", - RELOAD_DIALOG_DISCARD_BUTTON = "Descarta", + FEEDBACK = "Feedback", + TRANSLATION = "Tradução", + DONATION = "Doação", + RELOAD_UI_WARNING = "Mudanças nessa configuração requerem o recarregamento da UI para ter efeito.", + RELOAD_DIALOG_TITLE = "Recarregamento da UI requerida", + RELOAD_DIALOG_TEXT = "Algumas mudanças requerem o recarregamento da UI para ter efeito. Você deseja recarregar agora ou descartar as mudanças?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recarregar", + RELOAD_DIALOG_DISCARD_BUTTON = "Descartar", }, } @@ -437,6 +471,7 @@ util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")] or {}, localiza util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead util.GetStringFromValue = GetStringFromValue util.GetDefaultValue = GetDefaultValue +util.GetColorForState = GetColorForState util.CreateBaseControl = CreateBaseControl util.CreateLabelAndContainerControl = CreateLabelAndContainerControl util.RequestRefreshIfNeeded = RequestRefreshIfNeeded @@ -776,6 +811,9 @@ local function CreateOptionsControls(panel) err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) if err then PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) + if logger then + logger:Error(err) + end end if isSubmenu then @@ -833,6 +871,15 @@ local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel end local CheckSafetyAndInitialize +local function ShowSetHandlerWarning(panel, handler) + bob = panel + mike = handler + if(handler == "OnShow" or handler == "OnEffectivelyShown") then + PrintLater(("Setting a handler on a panel is not recommended. Use the global callback 'LAM-PanelControlsCreated' or 'LAM-PanelOpened' instead. (%s on %s)"):format(handler, panel:GetName())) + elseif(handler == "OnHide" or handler == "OnEffectivelyHidden") then + PrintLater(("Setting a handler on a panel is not recommended. Use the global callback 'LAM-PanelClosed' instead. (%s on %s)"):format(handler, panel:GetName())) + end +end --METHOD: REGISTER ADDON PANEL --registers your addon with LibAddonMenu and creates a panel @@ -845,7 +892,8 @@ function lam:RegisterAddonPanel(addonID, panelData) local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel panel:SetHidden(true) panel:SetAnchorFill(container) - panel:SetHandler("OnShow", ToggleAddonPanels) + panel:SetHandler("OnEffectivelyShown", ToggleAddonPanels) + ZO_PreHook(panel, "SetHandler", ShowSetHandlerWarning) local function stripMarkup(str) return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") @@ -1174,7 +1222,7 @@ local function CreateAddonSettingsWindow() lam.defaultButton = defaultButton local applyButton = wm:CreateControlFromVirtual("$(parent)ApplyButton", tlw, "ZO_DialogButton") - ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_ADDON_MANAGER_RELOAD)) + ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_APPLY)) applyButton:SetAnchor(TOPRIGHT, panelContainer, BOTTOMRIGHT, 0, 2) applyButton:SetHidden(true) lam.applyButton = applyButton diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/button.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/button.lua similarity index 93% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/button.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/button.lua index 82b5032..17ecfef 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/button.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/button.lua @@ -3,11 +3,11 @@ name = "My Button", -- string id or function returning a string func = function() end, tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - icon = "icon\\path.dds", --(optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + icon = "icon\\path.dds", -- (optional) isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) - warning = "Will need to reload the UI.", --(optional) + warning = "Will need to reload the UI.", -- (optional) reference = "MyAddonButton", -- unique global reference to control (optional) } ]] diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/checkbox.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/checkbox.lua similarity index 98% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/checkbox.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/checkbox.lua index 6696dd7..8f48b63 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/checkbox.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/checkbox.lua @@ -5,7 +5,7 @@ setFunc = function(value) db.var = value doStuff() end, tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) width = "full", -- or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- a boolean or function that returns a boolean (optional) diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/colorpicker.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/colorpicker.lua similarity index 85% rename from BestFriends2018/LibAddonMenu-2.0/controls/colorpicker.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/colorpicker.lua index a57aab0..b62cfba 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/colorpicker.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/colorpicker.lua @@ -1,19 +1,19 @@ --[[colorpickerData = { type = "colorpicker", name = "My Color Picker", -- or string id or function returning a string - getFunc = function() return db.r, db.g, db.b, db.a end, --(alpha is optional) - setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, --(alpha is optional) + getFunc = function() return db.r, db.g, db.b, db.a end, -- (alpha is optional) + setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, -- (alpha is optional) tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, --(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color + default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, -- (optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color reference = "MyAddonColorpicker" -- unique global reference to control (optional) } ]] -local widgetVersion = 13 +local widgetVersion = 14 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end @@ -79,7 +79,11 @@ function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) if upInside then local r, g, b, a = colorpickerData.getFunc() - COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, LAM.util.GetStringFromValue(colorpickerData.name)) + if IsInGamepadPreferredMode() then + COLOR_PICKER_GAMEPAD:Show(ColorPickerCallback, r, g, b, a) + else + COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a) + end end end) diff --git a/NewAddon/LibAddonMenu-2.0/controls/custom.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/custom.lua similarity index 78% rename from NewAddon/LibAddonMenu-2.0/controls/custom.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/custom.lua index 40a7c42..eb6f26c 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/custom.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/custom.lua @@ -1,8 +1,8 @@ --[[customData = { type = "custom", - reference = "MyAddonCustomControl", --(optional) unique name for your control to use as reference - refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh - width = "full", --or "half" (optional) + reference = "MyAddonCustomControl", -- unique name for your control to use as reference (optional) + refreshFunc = function(customControl) end, -- function to call when panel/controls refresh (optional) + width = "full", -- or "half" (optional) } ]] local widgetVersion = 7 diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/description.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/description.lua similarity index 72% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/description.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/description.lua index da207a0..a53c5b1 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/description.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/description.lua @@ -2,17 +2,33 @@ type = "description", text = "My description text to display.", -- or string id or function returning a string title = "My Title", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) reference = "MyAddonDescription" -- unique global reference to control (optional) } ]] -local widgetVersion = 8 +local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("description", widgetVersion) then return end local wm = WINDOW_MANAGER +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + control.desc:SetColor(color:UnpackRGBA()) + if control.title then + control.title:SetColor(color:UnpackRGBA()) + end + control.disabled = disable + end +end + local function UpdateValue(control) if control.title then control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) @@ -52,6 +68,10 @@ function LAMCreateControl.description(parent, descriptionData, controlName) end control.UpdateValue = UpdateValue + if descriptionData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end LAM.util.RegisterForRefreshIfNeeded(control) diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/divider.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/divider.lua similarity index 92% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/divider.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/divider.lua index 8089539..90ed6e8 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/divider.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/divider.lua @@ -1,8 +1,8 @@ --[[dividerData = { type = "divider", - width = "full", --or "half" (optional) - height = 10, (optional) - alpha = 0.25, (optional) + width = "full", -- or "half" (optional) + height = 10, -- (optional) + alpha = 0.25, -- (optional) reference = "MyAddonDivider" -- unique global reference to control (optional) } ]] diff --git a/NewAddon/LibAddonMenu-2.0/controls/dropdown.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/dropdown.lua similarity index 83% rename from NewAddon/LibAddonMenu-2.0/controls/dropdown.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/dropdown.lua index 70e23bb..a5450e5 100644 --- a/NewAddon/LibAddonMenu-2.0/controls/dropdown.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/dropdown.lua @@ -7,10 +7,10 @@ setFunc = function(var) db.var = var doStuff() end, tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) - sort = "name-up", --or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted - width = "full", --or "half" (optional) + sort = "name-up", -- or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted + width = "full", -- or "half" (optional) scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- default value or function that returns the default value (optional) @@ -18,12 +18,13 @@ } ]] -local widgetVersion = 18 +local widgetVersion = 19 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("dropdown", widgetVersion) then return end local wm = WINDOW_MANAGER -local SORT_BY_VALUE = { ["value"] = {} } +local cm = CALLBACK_MANAGER +local SORT_BY_VALUE = { ["value"] = {} } local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } local SORT_TYPES = { name = ZO_SORT_BY_NAME, @@ -155,11 +156,16 @@ local function GrabSortingInfo(sortInfo) return t end +local ENTRY_ID = 1 +local LAST_ENTRY_ID = 2 +local OFFSET_X_INDEX = 4 local DEFAULT_VISIBLE_ROWS = 10 -local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = 25 -- same as in zo_combobox.lua -local CONTENT_PADDING = 24 -local SCROLLBAR_PADDING = 16 -local PADDING = GetMenuPadding() / 2 -- half the amount looks closer to the regular dropdown +local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = ZO_SCROLLABLE_ENTRY_TEMPLATE_HEIGHT +local SCROLLBAR_PADDING = ZO_SCROLL_BAR_WIDTH +local PADDING_X = GetMenuPadding() +local PADDING_Y = ZO_SCROLLABLE_COMBO_BOX_LIST_PADDING_Y +local LABEL_OFFSET_X = 2 +local CONTENT_PADDING = PADDING_X * 4 local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed local ScrollableDropdownHelper = ZO_Object:Subclass() @@ -183,14 +189,14 @@ function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) -- handle dropdown or settingsmenu opening/closing - local function onShow() self:OnShow() end + local function onShow() return self:OnShow() end local function onHide() self:OnHide() end local function doHide() self:DoHide() end ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) ZO_PreHook(dropdown, "HideDropdownInternal", onHide) combobox:SetHandler("OnEffectivelyHidden", onHide) - parent:SetHandler("OnEffectivelyHidden", doHide) + cm:RegisterCallback("LAM-PanelClosed", doHide) -- dont fade entries near the edges local scrollList = dropdown.m_scroll @@ -202,32 +208,32 @@ function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) -- adjust scroll content anchor to mimic menu padding local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") - local anchor1 = {scroll:GetAnchor(0)} - local anchor2 = {scroll:GetAnchor(1)} + local anchor1 = {select(2, scroll:GetAnchor(0))} + local anchor2 = {select(2, scroll:GetAnchor(1))} + anchor1[OFFSET_X_INDEX] = PADDING_X - LABEL_OFFSET_X + anchor2[OFFSET_X_INDEX] = -anchor1[OFFSET_X_INDEX] scroll:ClearAnchors() - scroll:SetAnchor(anchor1[2], anchor1[3], anchor1[4], anchor1[5] + PADDING, anchor1[6] + PADDING) - scroll:SetAnchor(anchor2[2], anchor2[3], anchor2[4], anchor2[5] - PADDING, anchor2[6] - PADDING) + scroll:SetAnchor(unpack(anchor1)) + scroll:SetAnchor(unpack(anchor2)) ZO_ScrollList_Commit(scrollList) - + -- hook mouse enter/exit local function onMouseEnter(control) self:OnMouseEnter(control) end local function onMouseExit(control) self:OnMouseExit(control) end -- adjust row setup to mimic the highlight padding - local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) - local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 2) + local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, ENTRY_ID) + local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, LAST_ENTRY_ID) local oSetup = dataType1.setupCallback -- both types have the same setup function local function SetupEntry(control, data, list) oSetup(control, data, list) - control.m_label:SetAnchor(LEFT, nil, nil, 2) + control.m_label:SetAnchor(LEFT, nil, nil, LABEL_OFFSET_X) + control.m_label:SetAnchor(RIGHT, nil, nil, -LABEL_OFFSET_X) -- no need to store old ones since we have full ownership of our dropdown controls if not control.hookedMouseHandlers then --only do it once per control control.hookedMouseHandlers = true ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) - -- we could also just replace the handlers - --control:SetHandler("OnMouseEnter", onMouseEnter) - --control:SetHandler("OnMouseExit", onMouseExit) end end dataType1.setupCallback = SetupEntry @@ -235,24 +241,61 @@ function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) -- adjust dimensions based on entries local scrollContent = scroll:GetNamedChild("Contents") - ZO_PreHook(dropdown, "AddMenuItems", function() - local width = PADDING * 2 + zo_max(self:GetMaxWidth(), combobox:GetWidth()) + dropdown.AddMenuItems = ScrollableDropdownHelper.AddMenuItems + + dropdown.AdjustDimensions = function() local numItems = #dropdown.m_sortedItems + local contentWidth = self:CalculateContentWidth() + CONTENT_PADDING local anchorOffset = 0 if(numItems > self.visibleRows) then - width = width + CONTENT_PADDING + SCROLLBAR_PADDING - anchorOffset = -SCROLLBAR_PADDING numItems = self.visibleRows + contentWidth = contentWidth + SCROLLBAR_PADDING + anchorOffset = -SCROLLBAR_PADDING end - scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) - local height = PADDING * 2 + numItems * (SCROLLABLE_ENTRY_TEMPLATE_HEIGHT + dropdown.m_spacing) - dropdown.m_spacing + ROUNDING_MARGIN + + local width = zo_max(contentWidth, dropdown.m_container:GetWidth()) + local height = dropdown:GetEntryTemplateHeightWithSpacing() * numItems - dropdown.m_spacing + (PADDING_Y * 2) + ROUNDING_MARGIN + dropdown.m_dropdown:SetWidth(width) dropdown.m_dropdown:SetHeight(height) - end) + ZO_ScrollList_SetHeight(dropdown.m_scroll, height) + + scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) + end +end + +local function CreateScrollableComboBoxEntry(self, item, index, isLast) + item.m_index = index + item.m_owner = self + local entryType = isLast and LAST_ENTRY_ID or ENTRY_ID + local entry = ZO_ScrollList_CreateDataEntry(entryType, item) + + return entry +end + +function ScrollableDropdownHelper.AddMenuItems(self) -- self refers to the ZO_ScrollableComboBox here + ZO_ScrollList_Clear(self.m_scroll) + + local numItems = #self.m_sortedItems + local dataList = ZO_ScrollList_GetDataList(self.m_scroll) + + for i = 1, numItems do + local item = self.m_sortedItems[i] + local entry = CreateScrollableComboBoxEntry(self, item, i, i == numItems) + table.insert(dataList, entry) + end + + self:AdjustDimensions() + + ZO_ScrollList_Commit(self.m_scroll) end function ScrollableDropdownHelper:OnShow() local dropdown = self.dropdown + + -- don't show if there are no entries + if #dropdown.m_sortedItems == 0 then return true end + if dropdown.m_lastParent ~= ZO_Menus then dropdown.m_lastParent = dropdown.m_dropdown:GetParent() dropdown.m_dropdown:SetParent(ZO_Menus) @@ -262,7 +305,7 @@ end function ScrollableDropdownHelper:OnHide() local dropdown = self.dropdown - if dropdown.m_lastParent then + if dropdown.m_lastParent then dropdown.m_dropdown:SetParent(dropdown.m_lastParent) dropdown.m_lastParent = nil end @@ -275,9 +318,9 @@ function ScrollableDropdownHelper:DoHide() end end -function ScrollableDropdownHelper:GetMaxWidth() +function ScrollableDropdownHelper:CalculateContentWidth() local dropdown = self.dropdown - local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) + local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) local dummy = dataType.pool:AcquireObject() dataType.setupCallback(dummy, { @@ -344,7 +387,7 @@ function LAMCreateControl.dropdown(parent, dropdownData, controlName) dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value if dropdownData.scrollable then - local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS + local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS control.scrollHelper = ScrollableDropdownHelper:New(parent, control, visibleRows) end diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/editbox.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/editbox.lua similarity index 96% rename from PvPFPS2018/LibAddonMenu-2.0/controls/editbox.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/editbox.lua index d6baf11..f9f79ad 100644 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/editbox.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/editbox.lua @@ -4,10 +4,10 @@ getFunc = function() return db.text end, setFunc = function(text) db.text = text doStuff() end, tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) - isMultiline = true, --boolean (optional) - isExtraWide = true, --boolean (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + isMultiline = true, -- boolean (optional) + isExtraWide = true, -- boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.text, -- default value or function that returns the default value (optional) diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/header.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/header.lua similarity index 96% rename from BestFriends2018/LibAddonMenu-2.0/controls/header.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/header.lua index eadff38..3eda1d7 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/header.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/header.lua @@ -1,7 +1,7 @@ --[[headerData = { type = "header", name = "My Header", -- or string id or function returning a string - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) reference = "MyAddonHeader" -- unique global reference to control (optional) } ]] diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/iconpicker.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/iconpicker.lua similarity index 99% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/iconpicker.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/iconpicker.lua index 65c7782..2cca460 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/iconpicker.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/iconpicker.lua @@ -11,8 +11,8 @@ iconSize = 28, -- size of the icons (optional) defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) width = "full", --or "half" (optional) - beforeShow = function(control, iconPicker) return preventShow end, --(optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) + beforeShow = function(control, iconPicker) return preventShow end, -- (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) default = defaults.var, -- default value or function that returns the default value (optional) diff --git a/Notebook2018/Libs/LibAddonMenu-2.0/controls/panel.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/panel.lua similarity index 55% rename from Notebook2018/Libs/LibAddonMenu-2.0/controls/panel.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/panel.lua index 1404686..75bb904 100644 --- a/Notebook2018/Libs/LibAddonMenu-2.0/controls/panel.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/panel.lua @@ -4,16 +4,19 @@ displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) author = "Seerah", -- or string id or function returning a string (optional) version = "2.0", -- or string id or function returning a string (optional) - website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated (optional) + website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated or function (optional) + feedback = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where feedback/feature requests/bugs can be reported for the addon or function (optional) + translation = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where translation texts of the addon can be helped with or function (optional) + donation = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where a donation for the addon author can be raised or function (optional) keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) - registerForRefresh = true, --boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown) - registerForDefaults = true, --boolean (optional) (will set all options controls back to default values) - resetFunc = function() print("defaults reset") end, --(optional) custom function to run after settings are reset to defaults + registerForRefresh = true, -- boolean will refresh all options controls when a setting is changed and when the panel is shown (optional) + registerForDefaults = true, -- boolean will set all options controls back to default values (optional) + resetFunc = function() print("defaults reset") end, -- custom function to run after settings are reset to defaults (optional) } ]] -local widgetVersion = 13 +local widgetVersion = 15 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("panel", widgetVersion) then return end @@ -22,6 +25,8 @@ local cm = CALLBACK_MANAGER local function RefreshPanel(control) local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu + if LAM.currentAddonPanel ~= panel or not LAM.currentPanelOpened then return end -- we refresh it later when the panel is opened + local panelControls = panel.controlsToRefresh for i = 1, #panelControls do @@ -58,8 +63,39 @@ end local callbackRegistered = false LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 local SEPARATOR = " - " +local COLORED_SEPARATOR = ZO_WHITE:Colorize(SEPARATOR) local LINK_COLOR = ZO_ColorDef:New("5959D5") local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") +local LINK_COLOR_DONATE = ZO_ColorDef:New("FFD700") -- golden +local LINK_MOUSE_OVER_COLOR_DONATE = ZO_ColorDef:New("FFF6CC") + +local function CreateButtonControl(control, label, clickAction, relativeTo) + local button = wm:CreateControl(nil, control, CT_BUTTON) + button:SetClickSound("Click") + button:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + button:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) + button:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) + + local OnClicked + local actionType = type(clickAction) + if actionType == "string" then + OnClicked = function() RequestOpenUnsafeURL(clickAction) end + elseif actionType == "function" then + OnClicked = clickAction + end + button:SetHandler("OnClicked", OnClicked) + + if relativeTo then + button:SetAnchor(TOPLEFT, relativeTo, TOPRIGHT, 0, 0) + button:SetText(COLORED_SEPARATOR .. label) + else + button:SetAnchor(TOPLEFT, control.label, BOTTOMLEFT, 0, -2) + button:SetText(label) + end + button:SetDimensions(button:GetLabelControl():GetTextDimensions()) + + return button +end function LAMCreateControl.panel(parent, panelData, controlName) local control = wm:CreateControl(controlName, parent, CT_CONTROL) @@ -69,6 +105,7 @@ function LAMCreateControl.panel(parent, panelData, controlName) label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) + local previousInfoControl if panelData.author or panelData.version then control.info = wm:CreateControl(nil, control, CT_LABEL) local info = control.info @@ -83,26 +120,30 @@ function LAMCreateControl.panel(parent, panelData, controlName) output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) end info:SetText(table.concat(output, SEPARATOR)) + previousInfoControl = info end if panelData.website then - control.website = wm:CreateControl(nil, control, CT_BUTTON) - local website = control.website - website:SetClickSound("Click") - website:SetFont(LAM.util.L["PANEL_INFO_FONT"]) - website:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) - website:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) - if(control.info) then - website:SetAnchor(TOPLEFT, control.info, TOPRIGHT, 0, 0) - website:SetText(string.format("|cffffff%s|r%s", SEPARATOR, LAM.util.L["WEBSITE"])) - else - website:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) - website:SetText(LAM.util.L["WEBSITE"]) - end - website:SetDimensions(website:GetLabelControl():GetTextDimensions()) - website:SetHandler("OnClicked", function() - RequestOpenUnsafeURL(panelData.website) - end) + control.website = CreateButtonControl(control, LAM.util.L["WEBSITE"], panelData.website, previousInfoControl) + previousInfoControl = control.website + end + + if panelData.feedback then + control.feedback = CreateButtonControl(control, LAM.util.L["FEEDBACK"], panelData.feedback, previousInfoControl) + previousInfoControl = control.feedback + end + + if panelData.translation then + control.translation = CreateButtonControl(control, LAM.util.L["TRANSLATION"], panelData.translation, previousInfoControl) + previousInfoControl = control.translation + end + + if panelData.donation then + control.donation = CreateButtonControl(control, LAM.util.L["DONATION"], panelData.donation, previousInfoControl) + local donation = control.donation + previousInfoControl = donation + donation:SetNormalFontColor(LINK_COLOR_DONATE:UnpackRGBA()) + donation:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR_DONATE:UnpackRGBA()) end control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") @@ -119,6 +160,7 @@ function LAMCreateControl.panel(parent, panelData, controlName) end control.ForceDefaults = ForceDefaults + control.RefreshPanel = LAM.util.RequestRefreshIfNeeded control.data = panelData control.controlsToRefresh = {} diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/slider.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/slider.lua similarity index 93% rename from BestFriends2018/LibAddonMenu-2.0/controls/slider.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/slider.lua index bd721c5..6c80968 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/slider.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/slider.lua @@ -5,13 +5,14 @@ setFunc = function(value) db.var = value doStuff() end, min = 0, max = 20, - step = 1, --(optional) + step = 1, -- (optional) clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) + clampFunction = function(value, min, max) return math.max(math.min(value, max), min) end, -- function that is called to clamp the value (optional) decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) + width = "full", -- or "half" (optional) disabled = function() return db.someBooleanSetting end, --or boolean (optional) warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) @@ -19,7 +20,7 @@ reference = "MyAddonSlider" -- unique global reference to control (optional) } ]] -local widgetVersion = 12 +local widgetVersion = 13 local LAM = LibStub("LibAddonMenu-2.0") if not LAM:RegisterWidget("slider", widgetVersion) then return end @@ -30,6 +31,10 @@ local function RoundDecimalToPlace(d, place) return tonumber(strformat("%." .. tostring(place) .. "f", d)) end +local function ClampValue(value, min, max) + return math.max(math.min(value, max), min) +end + local function UpdateDisabled(control) local disable if type(control.data.disabled) == "function" then @@ -62,7 +67,8 @@ local function UpdateValue(control, forceDefault, value) value = RoundDecimalToPlace(value, control.data.decimals) end if control.data.clampInput ~= false then - value = math.max(math.min(value, control.data.max), control.data.min) + local clamp = control.data.clampFunction or ClampValue + value = clamp(value, control.data.min, control.data.max) end control.data.setFunc(value) --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed @@ -182,7 +188,9 @@ function LAMCreateControl.slider(parent, sliderData, controlName) HandleValueChanged(value) end) slider:SetHandler("OnSliderReleased", function(self, value) - control:UpdateValue(false, value) + if self:GetEnabled() then + control:UpdateValue(false, value) + end end) slider:SetHandler("OnMouseWheel", function(self, value) if(not self:GetEnabled()) then return end diff --git a/Junkee2018/LibAddonMenu-2.0/controls/submenu.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/submenu.lua similarity index 51% rename from Junkee2018/LibAddonMenu-2.0/controls/submenu.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/submenu.lua index 94087cb..d7bc8bf 100644 --- a/Junkee2018/LibAddonMenu-2.0/controls/submenu.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/submenu.lua @@ -1,108 +1,182 @@ ---[[submenuData = { - type = "submenu", - name = "Submenu Title", -- or string id or function returning a string - tooltip = "My submenu tooltip", -- -- or string id or function returning a string (optional) - controls = {sliderData, buttonData} --(optional) used by LAM - reference = "MyAddonSubmenu" --(optional) unique global reference to control -} ]] - -local widgetVersion = 11 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("submenu", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local am = ANIMATION_MANAGER - -local function UpdateValue(control) - control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) - if control.data.tooltip then - control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) - end -end - -local function AnimateSubmenu(clicked) - local control = clicked:GetParent() - control.open = not control.open - - if control.open then - control.animation:PlayFromStart() - else - control.animation:PlayFromEnd() - end -end - -function LAMCreateControl.submenu(parent, submenuData, controlName) - local width = parent:GetWidth() - 45 - local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL) - control.panel = parent - control.data = submenuData - - control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") - local label = control.label - label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) - label:SetDimensions(width, 30) - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetText(LAM.util.GetStringFromValue(submenuData.name)) - label:SetMouseEnabled(true) - if submenuData.tooltip then - label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} - label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - end - - control.scroll = wm:CreateControl(nil, control, CT_SCROLL) - local scroll = control.scroll - scroll:SetParent(control) - scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10) - scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) - - control.bg = wm:CreateControl(nil, label, CT_BACKDROP) - local bg = control.bg - bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5) - bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) - bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) - bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") - bg:SetInsets(16, 16, -16, -16) - - control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) - local arrow = control.arrow - arrow:SetDimensions(28, 28) - arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way - arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5) - - --figure out the cool animation later... - control.animation = am:CreateTimeline() - local animation = control.animation - animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count - - control:SetResizeToFitDescendents(true) - control.open = false - label:SetHandler("OnMouseUp", AnimateSubmenu) - animation:SetHandler("OnStop", function(self, completedPlaying) - scroll:SetResizeToFitDescendents(control.open) - if control.open then - control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds") - scroll:SetResizeToFitPadding(5, 20) - else - control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") - scroll:SetResizeToFitPadding(5, 0) - scroll:SetHeight(0) - end - end) - - --small strip at the bottom of the submenu that you can click to close it - control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE) - local btmToggle = control.btmToggle - btmToggle:SetMouseEnabled(true) - btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT) - btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT) - btmToggle:SetHeight(15) - btmToggle:SetAlpha(0) - btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control -end +--[[submenuData = { + type = "submenu", + name = "Submenu Title", -- or string id or function returning a string + icon = "path/to/my/icon.dds", -- or function returning a string (optional) + iconTextureCoords = {left, right, top, bottom}, -- or function returning a table (optional) + tooltip = "My submenu tooltip", -- or string id or function returning a string (optional) + controls = {sliderData, buttonData} -- used by LAM (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + disabledLabel = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonSubmenu" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("submenu", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local am = ANIMATION_MANAGER +local ICON_SIZE = 32 + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + if disable and control.open then + control.open = false + control.animation:PlayFromStart() + end + + control.arrow:SetColor(color:UnpackRGBA()) + control.disabled = disable + end + + local disableLabel = control.disabled or GetDefaultValue(control.data.disabledLabel) + if disableLabel ~= control.disabledLabel then + local color = GetColorForState(disableLabel) + control.label:SetColor(color:UnpackRGBA()) + if(control.icon) then + control.icon:SetDesaturation(disableLabel and 1 or 0) + end + control.disabledLabel = disableLabel + end +end + +local function UpdateValue(control) + control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) + + if control.icon then + control.icon:SetTexture(GetDefaultValue(control.data.icon)) + if(control.data.iconTextureCoords) then + local coords = GetDefaultValue(control.data.iconTextureCoords) + control.icon:SetTextureCoords(unpack(coords)) + end + end + + if control.data.tooltip then + control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) + end +end + +local function AnimateSubmenu(clicked) + local control = clicked:GetParent() + if control.disabled then return end + + control.open = not control.open + if control.open then + control.animation:PlayFromStart() + else + control.animation:PlayFromEnd() + end +end + +function LAMCreateControl.submenu(parent, submenuData, controlName) + local width = parent:GetWidth() - 45 + local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent + control.data = submenuData + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(LAM.util.GetStringFromValue(submenuData.name)) + label:SetMouseEnabled(true) + + if submenuData.icon then + control.icon = wm:CreateControl(nil, control, CT_TEXTURE) + local icon = control.icon + icon:SetTexture(GetDefaultValue(submenuData.icon)) + if(submenuData.iconTextureCoords) then + local coords = GetDefaultValue(submenuData.iconTextureCoords) + icon:SetTextureCoords(unpack(coords)) + end + icon:SetDimensions(ICON_SIZE, ICON_SIZE) + icon:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + icon:SetMouseEnabled(true) + icon:SetDrawLayer(DL_CONTROLS) + label:SetAnchor(TOP, control, TOP, 0, 5, ANCHOR_CONSTRAINS_Y) + label:SetAnchor(LEFT, icon, RIGHT, 10, 0, ANCHOR_CONSTRAINS_X) + label:SetDimensions(width - ICON_SIZE - 5, 30) + else + label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + label:SetDimensions(width, 30) + end + + if submenuData.tooltip then + label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} + label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + if control.icon then + control.icon.data = label.data + control.icon:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control.icon:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end + end + + control.scroll = wm:CreateControl(nil, control, CT_SCROLL) + local scroll = control.scroll + scroll:SetParent(control) + scroll:SetAnchor(TOPLEFT, control.icon or label, BOTTOMLEFT, 0, 10) + scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) + + control.bg = wm:CreateControl(nil, control.icon or label, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, control.icon or label, TOPLEFT, -5, -5) + bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + bg:SetDrawLayer(DL_BACKGROUND) + + control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) + local arrow = control.arrow + arrow:SetDimensions(28, 28) + arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way + arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5) + + --figure out the cool animation later... + control.animation = am:CreateTimeline() + local animation = control.animation + animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count + + control:SetResizeToFitDescendents(true) + control.open = false + label:SetHandler("OnMouseUp", AnimateSubmenu) + if(control.icon) then + control.icon:SetHandler("OnMouseUp", AnimateSubmenu) + end + animation:SetHandler("OnStop", function(self, completedPlaying) + scroll:SetResizeToFitDescendents(control.open) + if control.open then + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds") + scroll:SetResizeToFitPadding(5, 20) + else + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") + scroll:SetResizeToFitPadding(5, 0) + scroll:SetHeight(0) + end + end) + + --small strip at the bottom of the submenu that you can click to close it + control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE) + local btmToggle = control.btmToggle + btmToggle:SetMouseEnabled(true) + btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT) + btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT) + btmToggle:SetHeight(15) + btmToggle:SetAlpha(0) + btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) + + control.UpdateValue = UpdateValue + if submenuData.disabled ~= nil or submenuData.disabledLabel ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/BestFriends2018/LibAddonMenu-2.0/controls/texture.lua b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/texture.lua similarity index 84% rename from BestFriends2018/LibAddonMenu-2.0/controls/texture.lua rename to Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/texture.lua index 29dda7c..6862ac2 100644 --- a/BestFriends2018/LibAddonMenu-2.0/controls/texture.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibAddonMenu-2.0/controls/texture.lua @@ -1,14 +1,14 @@ --[[textureData = { type = "texture", image = "file/path.dds", - imageWidth = 64, --max of 250 for half width, 510 for full - imageHeight = 32, --max of 100 + imageWidth = 64, -- max of 250 for half width, 510 for full + imageHeight = 32, -- max of 100 tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonTexture" --(optional) unique global reference to control + width = "full", -- or "half" (optional) + reference = "MyAddonTexture" -- unique global reference to control (optional) } ]] ---add texture coords support? +-- TODO: add texture coords support? local widgetVersion = 9 local LAM = LibStub("LibAddonMenu-2.0") diff --git a/Notebook2018/Libs/LibStub/LibStub.lua b/Elder Scrolls Online Addons/NewAddon/LibStub/LibStub.lua similarity index 96% rename from Notebook2018/Libs/LibStub/LibStub.lua rename to Elder Scrolls Online Addons/NewAddon/LibStub/LibStub.lua index 0e6bf67..e6b8997 100644 --- a/Notebook2018/Libs/LibStub/LibStub.lua +++ b/Elder Scrolls Online Addons/NewAddon/LibStub/LibStub.lua @@ -3,7 +3,7 @@ -- LibStub developed for World of Warcraft by above members of the WowAce community. -- Ported to Elder Scrolls Online by Seerah -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 4 +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 5 local LibStub = _G[LIBSTUB_MAJOR] local strformat = string.format diff --git a/NewAddon/NewAddon.lua b/Elder Scrolls Online Addons/NewAddon/NewAddon.lua similarity index 94% rename from NewAddon/NewAddon.lua rename to Elder Scrolls Online Addons/NewAddon/NewAddon.lua index 437dd41..3718690 100644 --- a/NewAddon/NewAddon.lua +++ b/Elder Scrolls Online Addons/NewAddon/NewAddon.lua @@ -1,3 +1,8 @@ +--[[ + This addon is a template that helps developers create new addons. + Most parts can be removed or modified to need. +--]] + NewAddon = { name = "NewAddon", -- Matches folder and Manifest file names. -- version = "1.0", -- A nuisance to match to the Manifest. @@ -15,7 +20,7 @@ function NewAddon.Colorize(text, color) -- Default to addon's .color. if not color then color = NewAddon.color end - text = "|c" .. color .. text .. "|r" + text = string.format('|c%s%s|r', color, text) return text end diff --git a/NewAddon/NewAddon.txt b/Elder Scrolls Online Addons/NewAddon/NewAddon.txt similarity index 98% rename from NewAddon/NewAddon.txt rename to Elder Scrolls Online Addons/NewAddon/NewAddon.txt index 77b1a00..9a3b074 100644 --- a/NewAddon/NewAddon.txt +++ b/Elder Scrolls Online Addons/NewAddon/NewAddon.txt @@ -1,6 +1,6 @@ ## APIVersion: 100026 ## Title: NewAddon -## Version: 1.23 +## Version: 1.24 ## Author: Developer ## Description: NewAddon description. ## SavedVariables: NewAddonSavedVariables @@ -16,20 +16,20 @@ LibStub\LibStub.lua LibAddonMenu-2.0\LibAddonMenu-2.0.lua -LibAddonMenu-2.0\controls\panel.lua -LibAddonMenu-2.0\controls\submenu.lua LibAddonMenu-2.0\controls\button.lua LibAddonMenu-2.0\controls\checkbox.lua LibAddonMenu-2.0\controls\colorpicker.lua LibAddonMenu-2.0\controls\custom.lua LibAddonMenu-2.0\controls\description.lua +LibAddonMenu-2.0\controls\divider.lua LibAddonMenu-2.0\controls\dropdown.lua LibAddonMenu-2.0\controls\editbox.lua LibAddonMenu-2.0\controls\header.lua +LibAddonMenu-2.0\controls\iconpicker.lua +LibAddonMenu-2.0\controls\panel.lua LibAddonMenu-2.0\controls\slider.lua +LibAddonMenu-2.0\controls\submenu.lua LibAddonMenu-2.0\controls\texture.lua -LibAddonMenu-2.0\controls\iconpicker.lua -LibAddonMenu-2.0\controls\divider.lua NewAddon.lua Settings.lua \ No newline at end of file diff --git a/NewAddon/NewAddon.xml b/Elder Scrolls Online Addons/NewAddon/NewAddon.xml similarity index 100% rename from NewAddon/NewAddon.xml rename to Elder Scrolls Online Addons/NewAddon/NewAddon.xml diff --git a/NewAddon/Settings.lua b/Elder Scrolls Online Addons/NewAddon/Settings.lua similarity index 100% rename from NewAddon/Settings.lua rename to Elder Scrolls Online Addons/NewAddon/Settings.lua diff --git a/Notebook2018/Bindings.xml b/Elder Scrolls Online Addons/Notebook2018/Bindings.xml similarity index 100% rename from Notebook2018/Bindings.xml rename to Elder Scrolls Online Addons/Notebook2018/Bindings.xml diff --git a/Notebook2018/Lang/de.lua b/Elder Scrolls Online Addons/Notebook2018/Lang/de.lua similarity index 85% rename from Notebook2018/Lang/de.lua rename to Elder Scrolls Online Addons/Notebook2018/Lang/de.lua index 208cb93..72cc2b4 100644 --- a/Notebook2018/Lang/de.lua +++ b/Elder Scrolls Online Addons/Notebook2018/Lang/de.lua @@ -1,49 +1,56 @@ local localization_strings = { SI_NBUI_ADDON_NAME = "Notizbuch", SI_NBUI_ADDONOPTIONS_NAME = "Notizbuchoptionen", - SI_NBUI_AUTHOR = "Bloodspill & phuein", - + SI_NBUI_AUTHOR = "phuein & Bloodspill", + -- Settings Panel SI_NBUI_DESCRIPTION_INFO = "Ein virtuelles Notizbuch.", - + SI_NBUI_HEADER_BOOK = "Buch", - SI_NBUI_HEADER_COLORS = "Farben", + SI_NBUI_HEADER_THEME = "Thema", SI_NBUI_HEADER_INTERACTIVE = "Interaktiv", - + SI_NBUI_HEADER_EDITMODE = "Formatierte Anzeige", + SI_NBUI_SHOWTITLE_NAME = "Titel des Notizbuchs anzeigen", SI_NBUI_SHOWTITLE_TOOLTIP = "Zeigt den Titel des Notizbuchs an.", - + SI_NBUI_TITLE_NAME = "Titel des Notizbuchs", SI_NBUI_TITLE_TOOLTIP = "Ändert den Titel der Notizbuchs.", - + + SI_NBUI_TEXTURE_NAME = "Buch Textur", + SI_NBUI_TEXTURE_TOOLTIP = "Das für den Stil des Buches verwendete Bild.", + SI_NBUI_COLOR_NAME = "Farbe des Notizbuchs", SI_NBUI_COLOR_TOOLTIP = "Ändert die Farbe des Notizbuchs.", - + SI_NBUI_NEWPAGETITLE_NAME = "Neuer Seitentitel", SI_NBUI_NEWPAGETITLE_TOOLTIP = "Setzt einen Standardtitel für neue Seiten. Leeren Sie diesen Standard auf Datum und Uhrzeit zurück.", SI_NBUI_ACCOUNTWIDE_NAME = "Account-Wide Notebook", SI_NBUI_ACCOUNTWIDE_MAINTEXT = "Dadurch wird die Benutzeroberfläche sofort neu geladen! Möchten Sie fortfahren?", SI_NBUI_ACCOUNTWIDE_TOOLTIP = "Ein Notizbuch für alle Charaktere in deinem Konto.", - + SI_NBUI_ACCOUNTDELETE = "Kontoübergreifend überschreiben", SI_NBUI_ACCOUNTDELETE_TOOLTIP = "Überschreibt das Account-Wide Notebook mit den Seiten des aktuellen Charakters.", SI_NBUI_DIALOG = "Bestätigungsdialoge", SI_NBUI_DIALOG_TOOLTIP = "Ein-/Ausschalten Bestätigungsdialoge", - + SI_NBUI_LOCK_NAME = "Position sperren", SI_NBUI_LOCK_TOOLTIP = "Die Position des Notizbuchs wird fixiert, damit es nicht verschoben werden kann.", - + + SI_NBUI_ONTOP_NAME = "Oben anzeigen", + SI_NBUI_ONTOP_TOOLTIP = "Zeigen Sie das Notebook über anderen UI-Elementen an, um Notizen zu machen.", + SI_NBUI_BUTTON_NAME = "Notizbuch-Icon im Chat-Fenster einblenden", SI_NBUI_BUTTON_TOOLTIP = "Im Chat-Fenster wird ein Notizbuch-Icon hinzugefügt, damit kann man das Notizbuch öffnen und schließen.", - + SI_NBUI_OFFSETMAX_NAME = "x-Icon-Offset wenn Chat-Fenster maximiert", SI_NBUI_OFFSETMAX_TOOLTIP = "x Offsets des Notizbuch-Icon bei maximierten Chat-Fenster.", - + SI_NBUI_OFFSETMIN_NAME = "y-Icon-Offset wenn Chat-Fenster minimiert", SI_NBUI_OFFSETMIN_TOOLTIP = "y Offsets des Notizbuch-Icon bei minimierten Chat-Fenster.", - + SI_NBUI_EDITMODE_HOVER_NAME = "Bearbeitungsmodus An - MouseOver-Effekt", SI_NBUI_EDITMODE_HOVER_TOOLTIP = "Schaltet in den Bearbeitungsmodus wenn man mit der Maus über den Text schwebt.", @@ -55,13 +62,13 @@ local localization_strings = { SI_NBUI_LEAVEEDITMODE_EXIT_NAME = "Bearbeitungsmodus AUS - Maus-Fokus", SI_NBUI_LEAVEEDITMODE_EXIT_TOOLTIP = "Beende den Bearbeitungsmodus sobald die Maus das Text-Fenster verlässt.", - + SI_NBUI_DBLCLICKPAGE_NAME = "Doppelklicken, um alle auszuwählen", SI_NBUI_DBLCLICKPAGE_TOOLTIP = "Wählt beim Doppelklick den ganzen Seitentext anstelle eines Wortes.", SI_NBUI_EMOTEREAD_NAME = "Emote beim Lesen", SI_NBUI_EMOTEREAD_TOOLTIP = "Emote /read beim Öffnen des Notebooks.", - + SI_NBUI_EMOTEIDLE_NAME = "Emote Idle When Closed", SI_NBUI_EMOTEIDLE_TOOLTIP = "Emote /idle nach dem Schließen des Notebooks.", @@ -73,29 +80,29 @@ local localization_strings = { SI_NBUI_TEXTCOLOR_NAME = "Textfarbe", SI_NBUI_TEXTCOLOR_TOOLTIP = "Ändert die Textfarbe Ihres Notizbuchtitels, Seitentitels und Inhalts.", - + SI_NBUI_FORMATTEDMODE_NAME = "Formatierter Textmodus anzeigen", SI_NBUI_FORMATTEDODE_TOOLTIP = "Zeigt formatierten Text (Farben, Bilder ..) über dem Eingabefeld an.", SI_NBUI_WARNING = "Achtung! - Das Setzen dieser Einstellung führt zu einem Ladebildschirm.", - - -- UI Panel + + -- UI Panel SI_NBUI_CLOSEBUTTON_TOOLTIP = "Schließe das Notizbuch.", - + SI_NBUI_RUNBUTTON_TOOLTIP = "Diese Notiz als Lua-Script ausführen.", SI_NBUI_DELETEBUTTON_TITLE = "Notiz löschen", SI_NBUI_DELETEBUTTON_MAINTEXT = "Willst Du diese Notiz löschen?", SI_NBUI_DELETEBUTTON_TOOLTIP = "Löschen der Notiz.", - + SI_NBUI_NEWBUTTON_TITLE = "Neue Notiz", SI_NBUI_NEWBUTTON_MAINTEXT = "Willst Du eine neue Notiz erstellen?", SI_NBUI_NEWBUTTON_TOOLTIP = "Erstellen einer neuen Notiz.", - + SI_NBUI_SAVEBUTTON_TITLE = "Notiz speichern", SI_NBUI_SAVEBUTTON_MAINTEXT = "Willst Du die Änderungen der Notiz speichern?", SI_NBUI_SAVEBUTTON_TOOLTIP = "Die Änderungen die Du in der Notiz gemacht hast werden gespeichert.", - + SI_NBUI_UNDOPAGE_TITLE = "Änderungen der Notiz rückgangig machen", SI_NBUI_UNDOPAGE_MAINTEXT = "Willst Du alle Änderungen der Notiz seit der letzten Speicherung rückgängig zu machen?", SI_NBUI_UNDOBUTTON_TOOLTIP = "Die Änderungen der Notiz werden rückgängig gemacht.", @@ -105,13 +112,19 @@ local localization_strings = { SI_NBUI_MOVEPAGEDOWNBUTTON_TOOLTIP = "Diese Notiz im Index nach unten verschieben.", SI_NBUI_PREVIEWBUTTON_TOOLTIP = "Vorschau dieser Notiz durch Rendern von Farben, Auffüllen und Texturen.", - + + SI_NBUI_CONTEXT_RANDOMLINE = "Zufällige Zeile kopieren", + SI_NBUI_CONTEXT_SENDASMAIL = "Als Mail senden", + SI_NBUI_CONTEXT_COPYFROMMAIL = "Aus Mail kopieren", + SI_NBUI_YES_LABEL = "Ja", SI_NBUI_NO_LABEL = "Nein", - SI_NBUI_NB1INFORMATION_TOOLTIP = "Befehle:\n|c00FF00/nb|r schaltet das Fenster ein/aus.\n|c00FF00/nbs|r schaltet die Einstellungen ein/aus.", - + SI_NBUI_NB1INFORMATION_TOOLTIP = "|c00FF00/nb|r schaltet das Fenster ein/aus.\n|c00FF00/nbs|r schaltet die Einstellungen ein/aus.\n\n|c00FF00Tipp:|r Wenn Sie eine Seite auswählen, werden die Änderungen rückgängig gemacht.", + SI_NBUI_NB1KEYBIND_LABEL = "Notizbuch", + + SI_NBUI_ERROR_INBOXSELECT = "|cFFFFFFNOTEBOOK:|r Bitte wählen Sie eine E-Mail-Nachricht aus.", } for stringId, stringValue in pairs(localization_strings) do diff --git a/Notebook2018/Lang/en.lua b/Elder Scrolls Online Addons/Notebook2018/Lang/en.lua similarity index 76% rename from Notebook2018/Lang/en.lua rename to Elder Scrolls Online Addons/Notebook2018/Lang/en.lua index 7291f48..a79df61 100644 --- a/Notebook2018/Lang/en.lua +++ b/Elder Scrolls Online Addons/Notebook2018/Lang/en.lua @@ -1,24 +1,28 @@ local localization_strings = { SI_NBUI_ADDON_NAME = "Notebook", SI_NBUI_ADDONOPTIONS_NAME = "Notebook Options", - SI_NBUI_AUTHOR = "Bloodspill & phuein", - + SI_NBUI_AUTHOR = "phuein & Bloodspill", + -- Settings Panel SI_NBUI_DESCRIPTION_INFO = "A Virtual Notebook.", - + SI_NBUI_HEADER_BOOK = "Book", - SI_NBUI_HEADER_COLORS = "Colors", + SI_NBUI_HEADER_THEME = "Theme", SI_NBUI_HEADER_INTERACTIVE = "Interactive", - + SI_NBUI_HEADER_EDITMODE = "Formatted Display", + SI_NBUI_SHOWTITLE_NAME = "Show Title", SI_NBUI_SHOWTITLE_TOOLTIP = "Displays the title of the book.", - + SI_NBUI_TITLE_NAME = "Book Title", SI_NBUI_TITLE_TOOLTIP = "Changes the title of the book.", - + + SI_NBUI_TEXTURE_NAME = "Book Texture", + SI_NBUI_TEXTURE_TOOLTIP = "The image used for the style of the book.", + SI_NBUI_COLOR_NAME = "Book Color", SI_NBUI_COLOR_TOOLTIP = "Changes the color of the book.", - + SI_NBUI_NEWPAGETITLE_NAME = "Default New Page Title", SI_NBUI_NEWPAGETITLE_TOOLTIP = "Sets a default title for new pages. Empty this to default back to time and date.", @@ -31,31 +35,37 @@ local localization_strings = { SI_NBUI_DIALOG = "Confirmation Dialogs", SI_NBUI_DIALOG_TOOLTIP = "Turns confirmation dialogs On / Off.", - + SI_NBUI_LOCK_NAME = "Lock Position", SI_NBUI_LOCK_TOOLTIP = "This allows you to secure the notebook in place so that it can not be moved.", - + + SI_NBUI_ONTOP_NAME = "Display on Top", + SI_NBUI_ONTOP_TOOLTIP = "Show the Notebook over other UI elements, to assist with taking notes.", + SI_NBUI_BUTTON_NAME = "Show Chat Button", SI_NBUI_BUTTON_TOOLTIP = "Adds a button in the chat window to open/close the book.", SI_NBUI_OFFSETMAX_NAME = "Offset Maximized Chat Button", SI_NBUI_OFFSETMAX_TOOLTIP = "Offsets the button in the maximized chat window.", - + SI_NBUI_OFFSETMIN_NAME = "Offset Minimized Chat Button", SI_NBUI_OFFSETMIN_TOOLTIP = "Offsets the button in the minimized chat window.", - - SI_NBUI_EDITMODE_HOVER_NAME = "Edit-Mode on Hover", - SI_NBUI_EDITMODE_HOVER_TOOLTIP = "Switch to page Edit Mode when mouse hovers over the page.", - SI_NBUI_EDITMODE_CLICK_NAME = "Edit-Mode on Click", - SI_NBUI_EDITMODE_CLICK_TOOLTIP = "Switch to page Edit Mode when clicking the page.", + SI_NBUI_FORMATTEDMODE_NAME = "Formatted Text Mode", + SI_NBUI_FORMATTEDMODE_TOOLTIP = "Toggle whether Formatted-Mode (colors, images) is available, at all.", + + SI_NBUI_EDITMODE_HOVER_NAME = "Enter Edit-Mode on Hover", + SI_NBUI_EDITMODE_HOVER_TOOLTIP = "Switch to page Edit-Mode when mouse hovers over the page.", + + SI_NBUI_EDITMODE_CLICK_NAME = "Enter Edit-Mode on Click", + SI_NBUI_EDITMODE_CLICK_TOOLTIP = "Switch to page Edit-Mode when clicking the page.", SI_NBUI_LEAVEEDITMODE_FOCUS_NAME = "Leave Edit-Mode on Focus", - SI_NBUI_LEAVEEDITMODE_FOCUS_TOOLTIP = "Leave Edit Mode when the page loses focus (clicking outside of it.)", + SI_NBUI_LEAVEEDITMODE_FOCUS_TOOLTIP = "Leave Edit-Mode when the page loses focus (clicking outside of it.)", SI_NBUI_LEAVEEDITMODE_EXIT_NAME = "Leave Edit-Mode on Exit", - SI_NBUI_LEAVEEDITMODE_EXIT_TOOLTIP = "Leave Edit Mode when mouse exits (moves out of) the page.", - + SI_NBUI_LEAVEEDITMODE_EXIT_TOOLTIP = "Leave Edit-Mode when mouse exits (moves out of) the page.", + SI_NBUI_DBLCLICKPAGE_NAME = "Double-Click To Select All", SI_NBUI_DBLCLICKPAGE_TOOLTIP = "Selects the whole page text, instead of a word, when double-clicking.", @@ -70,32 +80,29 @@ local localization_strings = { SI_NBUI_SELECTCOLOR_NAME = "Text Selection Color", SI_NBUI_SELECTCOLOR_TOOLTIP = "Changes the color of your text selection.", - + SI_NBUI_TEXTCOLOR_NAME = "Text Color", SI_NBUI_TEXTCOLOR_TOOLTIP = "Changes the text color of your notebook title, page title, and content.", - SI_NBUI_FORMATTEDMODE_NAME = "Display Formatted Text Mode", - SI_NBUI_FORMATTEDMODE_TOOLTIP = "Displays formatted text (colors, images..) over the edit text box.", - SI_NBUI_WARNING = "This setting must be applied and will result in a load screen.", - -- UI Panel + -- UI Panel SI_NBUI_CLOSEBUTTON_TOOLTIP = "Close the book.", - + SI_NBUI_RUNBUTTON_TOOLTIP = "Run this page as a Lua script.", SI_NBUI_DELETEBUTTON_TITLE = "Delete Page", SI_NBUI_DELETEBUTTON_MAINTEXT = "Do you want to delete this page?", SI_NBUI_DELETEBUTTON_TOOLTIP = "Delete this page.", - + SI_NBUI_NEWBUTTON_TITLE = "New Page", SI_NBUI_NEWBUTTON_MAINTEXT = "Do you want to create a new page?", SI_NBUI_NEWBUTTON_TOOLTIP = "Create a new page.", - + SI_NBUI_SAVEBUTTON_TITLE = "Save Page", SI_NBUI_SAVEBUTTON_MAINTEXT = "Do you want to save changes made to this page?", SI_NBUI_SAVEBUTTON_TOOLTIP = "Save changes made to this page.", - + SI_NBUI_UNDOPAGE_TITLE = "Undo Page", SI_NBUI_UNDOPAGE_MAINTEXT = "Do you want to undo all changes made to this page? It will go back to last save.", SI_NBUI_UNDOBUTTON_TOOLTIP = "Undo changes made to this page.", @@ -105,13 +112,19 @@ local localization_strings = { SI_NBUI_MOVEPAGEDOWNBUTTON_TOOLTIP = "Move this page down in the index.", SI_NBUI_PREVIEWBUTTON_TOOLTIP = "Preview this page by rendering colors, padding, and textures.", - + + SI_NBUI_CONTEXT_RANDOMLINE = "Copy Random Line", + SI_NBUI_CONTEXT_SENDASMAIL = "Send as Mail", + SI_NBUI_CONTEXT_COPYFROMMAIL = "Copy from Mail", + SI_NBUI_YES_LABEL = "Yes", SI_NBUI_NO_LABEL = "No", - SI_NBUI_NB1INFORMATION_TOOLTIP = "Commands:\n|c00FF00/nb|r toggles the window on/off.\n|c00FF00/nbs|r toggles the settings on/off.", - + SI_NBUI_NB1INFORMATION_TOOLTIP = "|c00FF00/nb|r toggles the window on/off.\n|c00FF00/nbs|r toggles the settings on/off.\n\n|c00FF00Tip:|r Selecting a page will undo your changes.", + SI_NBUI_NB1KEYBIND_LABEL = "Notebook", + + SI_NBUI_ERROR_INBOXSELECT = "|cFFFFFFNOTEBOOK:|r Please select a mail message.", } for stringId, stringValue in pairs(localization_strings) do diff --git a/Notebook2018/Lang/fr.lua b/Elder Scrolls Online Addons/Notebook2018/Lang/fr.lua similarity index 85% rename from Notebook2018/Lang/fr.lua rename to Elder Scrolls Online Addons/Notebook2018/Lang/fr.lua index 33910ae..b571688 100644 --- a/Notebook2018/Lang/fr.lua +++ b/Elder Scrolls Online Addons/Notebook2018/Lang/fr.lua @@ -1,67 +1,74 @@ local localization_strings = { SI_NBUI_ADDON_NAME = "Carnet", SI_NBUI_ADDONOPTIONS_NAME = "Options de Carnet", - SI_NBUI_AUTHOR = "Bloodspill & phuein", - + SI_NBUI_AUTHOR = "phuein & Bloodspill", + -- Settings Panel SI_NBUI_DESCRIPTION_INFO = "Un ordinateur portable virtuel.", - + SI_NBUI_HEADER_BOOK = "Livre", - SI_NBUI_HEADER_COLORS = "Couleurs", + SI_NBUI_HEADER_THEME = "Thème", SI_NBUI_HEADER_INTERACTIVE = "Interactive", - + SI_NBUI_HEADER_EDITMODE = "Affichage formaté", + SI_NBUI_SHOWTITLE_NAME = "Afficher le titre", SI_NBUI_SHOWTITLE_TOOLTIP = "Affiche le titre du livre.", - + SI_NBUI_TITLE_NAME = "Titre De Livre", SI_NBUI_TITLE_TOOLTIP = "Change le titre du livre.", - + + SI_NBUI_TEXTURE_NAME = "Livre de texture", + SI_NBUI_TEXTURE_TOOLTIP = "L'image utilisée pour le style du livre.", + SI_NBUI_COLOR_NAME = "Color Book", SI_NBUI_COLOR_TOOLTIP = "Change la couleur du livre.", - + SI_NBUI_NEWPAGETITLE_NAME = "Titre par défaut de la nouvelle page", SI_NBUI_NEWPAGETITLE_TOOLTIP = "Définit un titre par défaut pour les nouvelles pages. Vider cette option pour revenir à l'heure et à la date par défaut.", SI_NBUI_ACCOUNTWIDE_NAME = "Carnet à l'échelle du compte", SI_NBUI_ACCOUNTWIDE_MAINTEXT = "Cela rechargera immédiatement l'interface utilisateur! Souhaitez-vous continuer?", SI_NBUI_ACCOUNTWIDE_TOOLTIP = "Un bloc-notes pour tous les personnages de votre compte.", - + SI_NBUI_ACCOUNTDELETE = "Remplacer le compte", SI_NBUI_ACCOUNTDELETE_TOOLTIP = "Remplace le bloc-notes au niveau du compte avec les pages du personnage en cours.", SI_NBUI_DIALOG = "Dialogues de confirmation", SI_NBUI_DIALOG_TOOLTIP = "Active / désactive les boîtes de dialogue de confirmation.", - + SI_NBUI_LOCK_NAME = "Position Lock", SI_NBUI_LOCK_TOOLTIP = "Cela vous permet de sécuriser le portable en place afin qu'il ne peut pas être déplacé.", - + + SI_NBUI_ONTOP_NAME = "Afficher en haut", + SI_NBUI_ONTOP_TOOLTIP = "Affichez le bloc-notes par-dessus d'autres éléments de l'interface utilisateur, pour vous aider à prendre des notes.", + SI_NBUI_BUTTON_NAME = "Afficher Chat Button", SI_NBUI_BUTTON_TOOLTIP = "Ajoute un bouton dans la fenêtre de chat pour ouvrir / fermer le livre.", SI_NBUI_OFFSETMAX_NAME = "Décalage bouton de chat maximisée", SI_NBUI_OFFSETMAX_TOOLTIP = "Décalages le bouton dans la fenêtre de chat maximisée.", - + SI_NBUI_OFFSETMIN_NAME = "Décalage bouton de chat minimisé", SI_NBUI_OFFSETMIN_TOOLTIP = "Décalages le bouton dans la fenêtre de chat minimisé.", - + SI_NBUI_EDITMODE_HOVER_NAME = "Mode d'édition sur Hover", SI_NBUI_EDITMODE_HOVER_TOOLTIP = "Passer en mode d'édition de page lorsque la souris survole la page.", - + SI_NBUI_EDITMODE_CLICK_NAME = "Mode d'édition sur clic", SI_NBUI_EDITMODE_CLICK_TOOLTIP = "Passer en mode d'édition de page en cliquant sur la page.", - + SI_NBUI_LEAVEEDITMODE_FOCUS_NAME = "Laisser le mode d'édition en focus", SI_NBUI_LEAVEEDITMODE_FOCUS_TOOLTIP = "Laisser le mode d'édition quand la page perd le focus (en cliquant à l'extérieur de celle-ci.)", - + SI_NBUI_LEAVEEDITMODE_EXIT_NAME = "Laisser le mode édition en sortie", SI_NBUI_LEAVEEDITMODE_EXIT_TOOLTIP = "Laisser le mode Edit lorsque la souris quitte (sort de) la page.", - + SI_NBUI_DBLCLICKPAGE_NAME = "Double-cliquez pour tout sélectionner", SI_NBUI_DBLCLICKPAGE_TOOLTIP = "Sélectionne le texte entier de la page, au lieu d'un mot, en double-cliquant.", SI_NBUI_EMOTEREAD_NAME = "Emote lors de la lecture", SI_NBUI_EMOTEREAD_TOOLTIP = "Emote /read de l'ouverture du portable.", - + SI_NBUI_EMOTEIDLE_NAME = "Emote inactif à la fermeture", SI_NBUI_EMOTEIDLE_TOOLTIP = "Emote /idle après la fermeture du portable.", @@ -73,29 +80,29 @@ local localization_strings = { SI_NBUI_TEXTCOLOR_NAME = "Couleur du texte", SI_NBUI_TEXTCOLOR_TOOLTIP = "Modifie la couleur du texte du titre de votre cahier, du titre de la page et du contenu.", - + SI_NBUI_FORMATTEDMODE_NAME = "Afficher le mode texte mis en forme", SI_NBUI_FORMATTEDMODE_TOOLTIP = "Affiche le texte formaté (couleurs, images ..) au-dessus de la zone de texte d'édition.", SI_NBUI_WARNING = "Ce paramètre doit être appliqué et se traduira par un écran de chargement.", - - -- UI Panel + + -- UI Panel SI_NBUI_CLOSEBUTTON_TOOLTIP = "Ferme le livre.", - + SI_NBUI_RUNBUTTON_TOOLTIP = "Exécutez cette page comme un script Lua.", SI_NBUI_DELETEBUTTON_TITLE = "Supprimer la page", SI_NBUI_DELETEBUTTON_MAINTEXT = "Voulez-vous supprimer cette page?", SI_NBUI_DELETEBUTTON_TOOLTIP = "Supprimer cette page.", - + SI_NBUI_NEWBUTTON_TITLE = "Nouvelle Page", SI_NBUI_NEWBUTTON_MAINTEXT = "Voulez-vous créer une nouvelle page?", SI_NBUI_NEWBUTTON_TOOLTIP = "Créer une nouvelle page.", - + SI_NBUI_SAVEBUTTON_TITLE = "Enregistrer la page.", SI_NBUI_SAVEBUTTON_MAINTEXT = "Voulez-vous enregistrer les modifications apportées à la page?", SI_NBUI_SAVEBUTTON_TOOLTIP = "Enregistrer les modifications apportées à cette page.", - + SI_NBUI_UNDOPAGE_TITLE = "Annuler la page", SI_NBUI_UNDOPAGE_MAINTEXT = "Voulez-vous annuler toutes les modifications apportées à cette page? Il reviendra à la dernière sauvegarde.", SI_NBUI_UNDOBUTTON_TOOLTIP = "Annuler les modifications apportées à cette page.", @@ -105,13 +112,19 @@ local localization_strings = { SI_NBUI_MOVEPAGEDOWNBUTTON_TOOLTIP = "Déplacez cette page dans l'index.", SI_NBUI_PREVIEWBUTTON_TOOLTIP = "Prévisualisez cette page en affichant les couleurs, le remplissage et les textures.", - + + SI_NBUI_CONTEXT_RANDOMLINE = "Copier une ligne aléatoire", + SI_NBUI_CONTEXT_SENDASMAIL = "Envoyer en tant que courrier", + SI_NBUI_CONTEXT_COPYFROMMAIL = "Copier depuis le courrier", + SI_NBUI_YES_LABEL = "Oui", SI_NBUI_NO_LABEL = "Non", - SI_NBUI_NB1INFORMATION_TOOLTIP = "Commandes:\n|c00FF00/nb|r bascule la fenêtre on/off.\n|c00FF00/nbs|r bascule les réglages on/off.", - + SI_NBUI_NB1INFORMATION_TOOLTIP = "|c00FF00/nb|r bascule la fenêtre on/off.\n|c00FF00/nbs|r bascule les réglages on/off.\n\n|c00FF00Conseil:|r La sélection d’une page annule les modifications.", + SI_NBUI_NB1KEYBIND_LABEL = "Carnet", + + SI_NBUI_ERROR_INBOXSELECT = "|cFFFFFFNOTEBOOK:|r Veuillez sélectionner un message électronique.", } for stringId, stringValue in pairs(localization_strings) do diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/LICENSE b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/LICENSE new file mode 100644 index 0000000..f69cbd4 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/LICENSE @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2016 Ryan Lakanen (Seerah) + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua new file mode 100644 index 0000000..20ffe3a --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -0,0 +1,1305 @@ +-- LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah) -- +-- Distributed under The Artistic License 2.0 (see LICENSE) -- +------------------------------------------------------------------ + + +--Register LAM with LibStub +local MAJOR, MINOR = "LibAddonMenu-2.0", 29 +local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) +if not lam then return end --the same or newer version of this lib is already loaded into memory +LibAddonMenu2 = lam + +local messages = {} +local MESSAGE_PREFIX = "[LAM2] " +local function PrintLater(msg) + if CHAT_SYSTEM.primaryContainer then + d(MESSAGE_PREFIX .. msg) + else + messages[#messages + 1] = msg + end +end + +local function FlushMessages() + for i = 1, #messages do + d(MESSAGE_PREFIX .. messages[i]) + end + messages = {} +end + +local logger +if LibDebugLogger then + logger = LibDebugLogger(MAJOR) +end + +if LAMSettingsPanelCreated and not LAMCompatibilityWarning then + PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") + LAMCompatibilityWarning = true +end + +--UPVALUES-- +local wm = WINDOW_MANAGER +local em = EVENT_MANAGER +local sm = SCENE_MANAGER +local cm = CALLBACK_MANAGER +local tconcat = table.concat +local tinsert = table.insert + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local OPTIONS_CREATION_RUNNING = 1 +local OPTIONS_CREATED = 2 +local LAM_CONFIRM_DIALOG = "LAM_CONFIRM_DIALOG" +local LAM_DEFAULTS_DIALOG = "LAM_DEFAULTS" +local LAM_RELOAD_DIALOG = "LAM_RELOAD_DIALOG" + +local addonsForList = {} +local addonToOptionsMap = {} +local optionsState = {} +lam.widgets = lam.widgets or {} +local widgets = lam.widgets +lam.util = lam.util or {} +local util = lam.util +lam.controlsForReload = lam.controlsForReload or {} +local controlsForReload = lam.controlsForReload + +local function GetDefaultValue(default) + if type(default) == "function" then + return default() + end + return default +end + +local function GetStringFromValue(value) + if type(value) == "function" then + return value() + elseif type(value) == "number" then + return GetString(value) + end + return value +end + +local function GetColorForState(disabled) + return disabled and ZO_DEFAULT_DISABLED_COLOR or ZO_DEFAULT_ENABLED_COLOR +end + +local function CreateBaseControl(parent, controlData, controlName) + local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent + control.data = controlData + + control.isHalfWidth = controlData.width == "half" + local width = 510 -- set default width in case a custom parent object is passed + if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end + control:SetWidth(width) + return control +end + +local function CreateLabelAndContainerControl(parent, controlData, controlName) + local control = CreateBaseControl(parent, controlData, controlName) + local width = control:GetWidth() + + local container = wm:CreateControl(nil, control, CT_CONTROL) + container:SetDimensions(width / 3, MIN_HEIGHT) + control.container = container + + local label = wm:CreateControl(nil, control, CT_LABEL) + label:SetFont("ZoFontWinH4") + label:SetHeight(MIN_HEIGHT) + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(GetStringFromValue(controlData.name)) + control.label = label + + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0) + end + + control.data.tooltipText = GetStringFromValue(control.data.tooltip) + control:SetMouseEnabled(true) + control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + return control +end + +local function GetTopPanel(panel) + while panel.panel and panel.panel ~= panel do + panel = panel.panel + end + return panel +end + +local function IsSame(objA, objB) + if #objA ~= #objB then return false end + for i = 1, #objA do + if objA[i] ~= objB[i] then return false end + end + return true +end + +local function RefreshReloadUIButton() + lam.requiresReload = false + + for i = 1, #controlsForReload do + local reloadControl = controlsForReload[i] + if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then + lam.requiresReload = true + break + end + end + + if lam.applyButton then + lam.applyButton:SetHidden(not lam.requiresReload) + end +end + +local function RequestRefreshIfNeeded(control) + -- if our parent window wants to refresh controls, then fire the callback + local panel = GetTopPanel(control) + local panelData = panel.data + if panelData.registerForRefresh then + cm:FireCallbacks("LAM-RefreshPanel", control) + end + RefreshReloadUIButton() +end + +local function RegisterForRefreshIfNeeded(control) + -- if our parent window wants to refresh controls, then add this to the list + local panel = GetTopPanel(control.panel) + local panelData = panel.data + if panelData.registerForRefresh or panelData.registerForDefaults then + tinsert(panel.controlsToRefresh or {}, control) -- prevent errors on custom panels + end +end + +local function RegisterForReloadIfNeeded(control) + if control.data.requiresReload then + tinsert(controlsForReload, control) + control.startValue = {control.data.getFunc()} + end +end + +local function GetConfirmDialog() + if(not ESO_Dialogs[LAM_CONFIRM_DIALOG]) then + ESO_Dialogs[LAM_CONFIRM_DIALOG] = { + canQueue = true, + title = { + text = "", + }, + mainText = { + text = "", + }, + buttons = { + [1] = { + text = SI_DIALOG_CONFIRM, + callback = function(dialog) end, + }, + [2] = { + text = SI_DIALOG_CANCEL, + } + } + } + end + return ESO_Dialogs[LAM_CONFIRM_DIALOG] +end + +local function ShowConfirmationDialog(title, body, callback) + local dialog = GetConfirmDialog() + dialog.title.text = title + dialog.mainText.text = body + dialog.buttons[1].callback = callback + ZO_Dialogs_ShowDialog(LAM_CONFIRM_DIALOG) +end + +local function GetDefaultsDialog() + if(not ESO_Dialogs[LAM_DEFAULTS_DIALOG]) then + ESO_Dialogs[LAM_DEFAULTS_DIALOG] = { + canQueue = true, + title = { + text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP, + }, + mainText = { + text = SI_OPTIONS_RESET_PROMPT, + }, + buttons = { + [1] = { + text = SI_OPTIONS_RESET, + callback = function(dialog) end, + }, + [2] = { + text = SI_DIALOG_CANCEL, + } + } + } + end + return ESO_Dialogs[LAM_DEFAULTS_DIALOG] +end + +local function ShowDefaultsDialog(panel) + local dialog = GetDefaultsDialog() + dialog.buttons[1].callback = function() + panel:ForceDefaults() + RefreshReloadUIButton() + end + ZO_Dialogs_ShowDialog(LAM_DEFAULTS_DIALOG) +end + +local function DiscardChangesOnReloadControls() + for i = 1, #controlsForReload do + local reloadControl = controlsForReload[i] + if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then + reloadControl:UpdateValue(false, unpack(reloadControl.startValue)) + end + end + lam.requiresReload = false + lam.applyButton:SetHidden(true) +end + +local function StorePanelForReopening() + local saveData = ZO_Ingame_SavedVariables["LAM"] or {} + saveData.reopenPanel = lam.currentAddonPanel:GetName() + ZO_Ingame_SavedVariables["LAM"] = saveData +end + +local function RetrievePanelForReopening() + local saveData = ZO_Ingame_SavedVariables["LAM"] + if(saveData) then + ZO_Ingame_SavedVariables["LAM"] = nil + return _G[saveData.reopenPanel] + end +end + +local function HandleReloadUIPressed() + StorePanelForReopening() + ReloadUI() +end + +local function HandleLoadDefaultsPressed() + ShowDefaultsDialog(lam.currentAddonPanel) +end + +local function GetReloadDialog() + if(not ESO_Dialogs[LAM_RELOAD_DIALOG]) then + ESO_Dialogs[LAM_RELOAD_DIALOG] = { + canQueue = true, + title = { + text = util.L["RELOAD_DIALOG_TITLE"], + }, + mainText = { + text = util.L["RELOAD_DIALOG_TEXT"], + }, + buttons = { + [1] = { + text = util.L["RELOAD_DIALOG_RELOAD_BUTTON"], + callback = function() ReloadUI() end, + }, + [2] = { + text = util.L["RELOAD_DIALOG_DISCARD_BUTTON"], + callback = DiscardChangesOnReloadControls, + } + }, + noChoiceCallback = DiscardChangesOnReloadControls, + } + end + return ESO_Dialogs[LAM_CONFIRM_DIALOG] +end + +local function ShowReloadDialogIfNeeded() + if lam.requiresReload then + local dialog = GetReloadDialog() + ZO_Dialogs_ShowDialog(LAM_RELOAD_DIALOG) + end +end + +local function UpdateWarning(control) + local warning + if control.data.warning ~= nil then + warning = util.GetStringFromValue(control.data.warning) + end + + if control.data.requiresReload then + if not warning then + warning = string.format("%s", util.L["RELOAD_UI_WARNING"]) + else + warning = string.format("%s\n\n%s", warning, util.L["RELOAD_UI_WARNING"]) + end + end + + if not warning then + control.warning:SetHidden(true) + else + control.warning.data = {tooltipText = warning} + control.warning:SetHidden(false) + end +end + +local localization = { + en = { + PANEL_NAME = "Addons", + AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" + VERSION = "Version: <>", + WEBSITE = "Visit Website", + FEEDBACK = "Feedback", + TRANSLATION = "Translation", + DONATION = "Donate", + PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", + RELOAD_UI_WARNING = "Changes to this setting require a UI reload in order to take effect.", + RELOAD_DIALOG_TITLE = "UI Reload Required", + RELOAD_DIALOG_TEXT = "Some changes require a UI reload in order to take effect. Do you want to reload now or discard the changes?", + RELOAD_DIALOG_RELOAD_BUTTON = "Reload", + RELOAD_DIALOG_DISCARD_BUTTON = "Discard", + }, + it = { -- provided by JohnnyKing + PANEL_NAME = "Addon", + VERSION = "Versione: <>", + WEBSITE = "Visita il Sitoweb", + FEEDBACK = "Feedback", + TRANSLATION = "Traduzione", + DONATION = "Donare", + RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", + RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", + RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", + RELOAD_DIALOG_RELOAD_BUTTON = "Ricarica", + RELOAD_DIALOG_DISCARD_BUTTON = "Annulla", + }, + fr = { -- provided by Ayantir + PANEL_NAME = "Extensions", + WEBSITE = "Visiter le site Web", + FEEDBACK = "Réaction", + TRANSLATION = "Traduction", + DONATION = "Donner", + RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", + RELOAD_DIALOG_TITLE = "Reload UI requis", + RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recharger", + RELOAD_DIALOG_DISCARD_BUTTON = "Annuler", + }, + de = { -- provided by sirinsidiator + PANEL_NAME = "Erweiterungen", + WEBSITE = "Webseite besuchen", + FEEDBACK = "Feedback", + TRANSLATION = "Übersetzung", + DONATION = "Spende", + RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", + RELOAD_DIALOG_TITLE = "Neuladen benötigt", + RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", + RELOAD_DIALOG_RELOAD_BUTTON = "Neu laden", + RELOAD_DIALOG_DISCARD_BUTTON = "Verwerfen", + }, + ru = { -- provided by TERAB1T + PANEL_NAME = "Дополнения", + VERSION = "Версия: <>", + WEBSITE = "Посетить сайт", + FEEDBACK = "отзыв", + TRANSLATION = "Перевод", + DONATION = "жертвовать", + PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", + RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", + RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", + RELOAD_DIALOG_TEXT = "Для применения некоторых изменений необходима перезагрузка интерфейса. Перезагрузить интерфейс сейчас или отменить изменения?", + RELOAD_DIALOG_RELOAD_BUTTON = "Перезагрузить", + RELOAD_DIALOG_DISCARD_BUTTON = "Отменить изменения", + }, + es = { -- provided by Morganlefai, checked by Kwisatz + PANEL_NAME = "Configuración", + VERSION = "Versión: <>", + WEBSITE = "Visita la página web", + FEEDBACK = "Reaccion", + TRANSLATION = "Traducción", + DONATION = "Donar", + RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", + RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", + RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recargar", + RELOAD_DIALOG_DISCARD_BUTTON = "Cancelar", + }, + jp = { -- provided by k0ta0uchi + PANEL_NAME = "アドオン設定", + WEBSITE = "ウェブサイトを見る", + FEEDBACK = "フィードバック", + TRANSLATION = "訳書", + DONATION = "寄贈する", + }, + zh = { -- provided by bssthu + PANEL_NAME = "插件", + VERSION = "版本: <>", + WEBSITE = "访问网站", + PANEL_INFO_FONT = "EsoZh/fonts/univers57.otf|14|soft-shadow-thin", + }, + pl = { -- provided by EmiruTegryfon + PANEL_NAME = "Dodatki", + VERSION = "Wersja: <>", + WEBSITE = "Odwiedź stronę", + RELOAD_UI_WARNING = "Zmiany będą widoczne po ponownym załadowaniu UI.", + RELOAD_DIALOG_TITLE = "Wymagane przeładowanie UI", + RELOAD_DIALOG_TEXT = "Niektóre zmiany wymagają ponownego załadowania UI. Czy chcesz teraz ponownie załadować, czy porzucić zmiany?", + RELOAD_DIALOG_RELOAD_BUTTON = "Przeładuj", + RELOAD_DIALOG_DISCARD_BUTTON = "Porzuć", + }, + kr = { -- provided by p.walker + PANEL_NAME = "蝠盜蠨", + VERSION = "纄訄: <>", + WEBSITE = "裹芬襴钸 縩紸", + PANEL_INFO_FONT = "EsoKR/fonts/Univers57.otf|14|soft-shadow-thin", + RELOAD_UI_WARNING = "襴 茤訕襄 绀溽靘籴 風滼筼 訁袩靘瀰褄靴 UI 苈穜滠遨襴 靄袔革瓈瓤.", + RELOAD_DIALOG_TITLE = "UI 苈穜滠遨 靄袔", + RELOAD_DIALOG_TEXT = "绀溽瘜 茤訕 謑 UI 苈穜滠遨襄 靄袔穜靘璔 芬靭襴 覈蒵瓈瓤. 诀瀈 苈穜滠遨靘蓜溠蒵瓈灌? 蝄瓈籴 绀溽襄 迨莌靘蓜溠蒵瓈灌?", + RELOAD_DIALOG_RELOAD_BUTTON = "苈穜滠遨", + RELOAD_DIALOG_DISCARD_BUTTON = "绀溽迨莌", + }, + br = { -- provided by mlsevero & FelipeS11 + PANEL_NAME = "Addons", + AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Autor: <>" + VERSION = "Versão: <>", + WEBSITE = "Visite o Website", + FEEDBACK = "Feedback", + TRANSLATION = "Tradução", + DONATION = "Doação", + RELOAD_UI_WARNING = "Mudanças nessa configuração requerem o recarregamento da UI para ter efeito.", + RELOAD_DIALOG_TITLE = "Recarregamento da UI requerida", + RELOAD_DIALOG_TEXT = "Algumas mudanças requerem o recarregamento da UI para ter efeito. Você deseja recarregar agora ou descartar as mudanças?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recarregar", + RELOAD_DIALOG_DISCARD_BUTTON = "Descartar", + }, +} + +util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")] or {}, localization["en"]) +util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead +util.GetStringFromValue = GetStringFromValue +util.GetDefaultValue = GetDefaultValue +util.GetColorForState = GetColorForState +util.CreateBaseControl = CreateBaseControl +util.CreateLabelAndContainerControl = CreateLabelAndContainerControl +util.RequestRefreshIfNeeded = RequestRefreshIfNeeded +util.RegisterForRefreshIfNeeded = RegisterForRefreshIfNeeded +util.RegisterForReloadIfNeeded = RegisterForReloadIfNeeded +util.GetTopPanel = GetTopPanel +util.ShowConfirmationDialog = ShowConfirmationDialog +util.UpdateWarning = UpdateWarning + +local ADDON_DATA_TYPE = 1 +local RESELECTING_DURING_REBUILD = true +local USER_REQUESTED_OPEN = true + + +--INTERNAL FUNCTION +--scrolls ZO_ScrollList `list` to move the row corresponding to `data` +-- into view (does nothing if there is no such row in the list) +--unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for +-- fading near the list's edges - it avoids the fading area by scrolling +-- a little further than the ZO function +local function ScrollDataIntoView(list, data) + local targetIndex = data.sortIndex + if not targetIndex then return end + + local scrollMin, scrollMax = list.scrollbar:GetMinMax() + local scrollTop = list.scrollbar:GetValue() + local controlHeight = list.uniformControlHeight or list.controlHeight + local targetMin = controlHeight * (targetIndex - 1) - 64 + -- subtracting 64 ain't arbitrary, it's the maximum fading height + -- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade) + + if targetMin < scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin)) + else + local listHeight = ZO_ScrollList_GetHeight(list) + local targetMax = controlHeight * targetIndex + 64 - listHeight + + if targetMax > scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax)) + end + end +end + + +--INTERNAL FUNCTION +--constructs a string pattern from the text in `searchEdit` control +-- * metacharacters are escaped, losing their special meaning +-- * whitespace matches anything (including empty substring) +--if there is nothing but whitespace, returns nil +--otherwise returns a filter function, which takes a `data` table argument +-- and returns true iff `data.filterText` matches the pattern +local function GetSearchFilterFunc(searchEdit) + local text = searchEdit:GetText():lower() + local pattern = text:match("(%S+.-)%s*$") + + if not pattern then -- nothing but whitespace + return nil + end + + -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de" + pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0") + + -- replace whitespace with "match shortest anything" + pattern = pattern:gsub("%s+", ".-") + + return function(data) + return data.filterText:lower():find(pattern) ~= nil + end +end + + +--INTERNAL FUNCTION +--populates `addonList` with entries from `addonsForList` +-- addonList = ZO_ScrollList control +-- filter = [optional] function(data) +local function PopulateAddonList(addonList, filter) + local entryList = ZO_ScrollList_GetDataList(addonList) + local numEntries = 0 + local selectedData = nil + local selectionIsFinal = false + + ZO_ScrollList_Clear(addonList) + + for i, data in ipairs(addonsForList) do + if not filter or filter(data) then + local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data) + numEntries = numEntries + 1 + data.sortIndex = numEntries + entryList[numEntries] = dataEntry + -- select the first panel passing the filter, or the currently + -- shown panel, but only if it passes the filter as well + if selectedData == nil or data.panel == lam.pendingAddonPanel or data.panel == lam.currentAddonPanel then + if not selectionIsFinal then + selectedData = data + end + if data.panel == lam.pendingAddonPanel then + lam.pendingAddonPanel = nil + selectionIsFinal = true + end + end + else + data.sortIndex = nil + end + end + + ZO_ScrollList_Commit(addonList) + + if selectedData then + if selectedData.panel == lam.currentAddonPanel then + ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD) + else + ZO_ScrollList_SelectData(addonList, selectedData, nil) + end + ScrollDataIntoView(addonList, selectedData) + end +end + + +--METHOD: REGISTER WIDGET-- +--each widget has its version checked before loading, +--so we only have the most recent one in memory +--Usage: +-- widgetType = "string"; the type of widget being registered +-- widgetVersion = integer; the widget's version number +LAMCreateControl = LAMCreateControl or {} +local lamcc = LAMCreateControl + +function lam:RegisterWidget(widgetType, widgetVersion) + if widgets[widgetType] and widgets[widgetType] >= widgetVersion then + return false + else + widgets[widgetType] = widgetVersion + return true + end +end + +-- INTERNAL METHOD: hijacks the handlers for the actions in the OptionsWindow layer if not already done +local function InitKeybindActions() + if not lam.keybindsInitialized then + lam.keybindsInitialized = true + ZO_PreHook(KEYBOARD_OPTIONS, "ApplySettings", function() + if lam.currentPanelOpened then + if not lam.applyButton:IsHidden() then + HandleReloadUIPressed() + end + return true + end + end) + ZO_PreHook("ZO_Dialogs_ShowDialog", function(dialogName) + if lam.currentPanelOpened and dialogName == "OPTIONS_RESET_TO_DEFAULTS" then + if not lam.defaultButton:IsHidden() then + HandleLoadDefaultsPressed() + end + return true + end + end) + end +end + +-- INTERNAL METHOD: fires the LAM-PanelOpened callback if not already done +local function OpenCurrentPanel() + if lam.currentAddonPanel and not lam.currentPanelOpened then + lam.currentPanelOpened = true + lam.defaultButton:SetHidden(not lam.currentAddonPanel.data.registerForDefaults) + cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel) + end +end + +-- INTERNAL METHOD: fires the LAM-PanelClosed callback if not already done +local function CloseCurrentPanel() + if lam.currentAddonPanel and lam.currentPanelOpened then + lam.currentPanelOpened = false + cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel) + end +end + +--METHOD: OPEN TO ADDON PANEL-- +--opens to a specific addon's option panel +--Usage: +-- panel = userdata; the panel returned by the :RegisterOptionsPanel method +local locSettings = GetString(SI_GAME_MENU_SETTINGS) +function lam:OpenToPanel(panel) + + -- find and select the panel's row in addon list + + local addonList = lam.addonList + local selectedData = nil + + for _, addonData in ipairs(addonsForList) do + if addonData.panel == panel then + selectedData = addonData + ScrollDataIntoView(addonList, selectedData) + lam.pendingAddonPanel = addonData.panel + break + end + end + + ZO_ScrollList_SelectData(addonList, selectedData) + ZO_ScrollList_RefreshVisible(addonList, selectedData) + + local srchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") + srchEdit:Clear() + + -- note that ZO_ScrollList doesn't require `selectedData` to be actually + -- present in the list, and that the list will only be populated once LAM + -- "Addon Settings" menu entry is selected for the first time + + local function openAddonSettingsMenu() + local gameMenu = ZO_GameMenu_InGame.gameMenu + local settingsMenu = gameMenu.headerControls[locSettings] + + if settingsMenu then -- an instance of ZO_TreeNode + local children = settingsMenu:GetChildren() + for i = 1, (children and #children or 0) do + local childNode = children[i] + local data = childNode:GetData() + if data and data.id == lam.panelId then + -- found LAM "Addon Settings" node, yay! + childNode:GetTree():SelectNode(childNode) + break + end + end + end + end + + if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then + openAddonSettingsMenu() + else + sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu) + sm:Show("gameMenuInGame") + end +end + +local TwinOptionsContainer_Index = 0 +local function TwinOptionsContainer(parent, leftWidget, rightWidget) + TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1 + local cParent = parent.scroll or parent + local panel = parent.panel or cParent + local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index), + cParent, CT_CONTROL) + container:SetResizeToFitDescendents(true) + container:SetAnchor(select(2, leftWidget:GetAnchor(0) )) + + leftWidget:ClearAnchors() + leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT) + rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0) + + leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls + rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 ) + + leftWidget:SetParent(container) + rightWidget:SetParent(container) + + container.data = {type = "container"} + container.panel = panel + return container +end + +--INTERNAL FUNCTION +--creates controls when options panel is first shown +--controls anchoring of these controls in the panel +local function CreateOptionsControls(panel) + local addonID = panel:GetName() + if(optionsState[addonID] == OPTIONS_CREATED) then + return false + elseif(optionsState[addonID] == OPTIONS_CREATION_RUNNING) then + return true + end + optionsState[addonID] = OPTIONS_CREATION_RUNNING + + local function CreationFinished() + optionsState[addonID] = OPTIONS_CREATED + cm:FireCallbacks("LAM-PanelControlsCreated", panel) + OpenCurrentPanel() + end + + local optionsTable = addonToOptionsMap[addonID] + if optionsTable then + local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf) + local widget + local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end) + if not status then + return err or true, offsetY, anchorTarget, wasHalf + else + local isHalf = (widgetData.width == "half") + if not anchorTarget then -- the first widget in a panel is just placed in the top left corner + widget:SetAnchor(TOPLEFT) + anchorTarget = widget + elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side + widget.lineControl = anchorTarget + isHalf = false + offsetY = 0 + anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget) + else -- otherwise we just put it below the previous one normally + widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15) + offsetY = 0 + anchorTarget = widget + end + return false, offsetY, anchorTarget, isHalf + end + end + + local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20 + local fifo = {} + local anchorOffset, lastAddedControl, wasHalf + local CreateWidgetsInPanel, err + + local function PrepareForNextPanel() + anchorOffset, lastAddedControl, wasHalf = 0, nil, false + end + + local function SetupCreationCalls(parent, widgetDataTable) + fifo[#fifo + 1] = PrepareForNextPanel + local count = #widgetDataTable + for i = 1, count, THROTTLE_COUNT do + fifo[#fifo + 1] = function() + CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count)) + end + end + return count ~= NonContiguousCount(widgetDataTable) + end + + CreateWidgetsInPanel = function(parent, widgetDataTable, startIndex, endIndex) + for i=startIndex,endIndex do + local widgetData = widgetDataTable[i] + if not widgetData then + PrintLater("Skipped creation of missing entry in the settings menu of " .. addonID .. ".") + else + local widgetType = widgetData.type + local offsetX = 0 + local isSubmenu = (widgetType == "submenu") + if isSubmenu then + wasHalf = false + offsetX = 5 + end + + err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) + if err then + PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) + if logger then + logger:Error(err) + end + end + + if isSubmenu then + if SetupCreationCalls(lastAddedControl, widgetData.controls) then + PrintLater(("The sub menu '%s' of %s is missing some entries."):format(GetStringFromValue(widgetData.name or "unnamed"), addonID)) + end + end + end + end + end + + local function DoCreateSettings() + if #fifo > 0 then + local nextCall = table.remove(fifo, 1) + nextCall() + if(nextCall == PrepareForNextPanel) then + DoCreateSettings() + else + zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT) + end + else + CreationFinished() + end + end + + if SetupCreationCalls(panel, optionsTable) then + PrintLater(("The settings menu of %s is missing some entries."):format(addonID)) + end + DoCreateSettings() + else + CreationFinished() + end + + return true +end + +--INTERNAL FUNCTION +--handles switching between panels +local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel + local currentlySelected = lam.currentAddonPanel + if currentlySelected and currentlySelected ~= panel then + currentlySelected:SetHidden(true) + CloseCurrentPanel() + end + lam.currentAddonPanel = panel + + -- refresh visible rows to reflect panel IsHidden status + ZO_ScrollList_RefreshVisible(lam.addonList) + + if not CreateOptionsControls(panel) then + OpenCurrentPanel() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) +end + +local CheckSafetyAndInitialize +local function ShowSetHandlerWarning(panel, handler) + local hint + if(handler == "OnShow" or handler == "OnEffectivelyShown") then + hint = "'LAM-PanelControlsCreated' or 'LAM-PanelOpened'" + elseif(handler == "OnHide" or handler == "OnEffectivelyHidden") then + hint = "'LAM-PanelClosed'" + end + + if hint then + local message = ("Setting a handler on a panel is not recommended. Use the global callback %s instead. (%s on %s)"):format(hint, handler, panel.data.name) + PrintLater(message) + if logger then + logger:Warn(message) + end + end +end + +--METHOD: REGISTER ADDON PANEL +--registers your addon with LibAddonMenu and creates a panel +--Usage: +-- addonID = "string"; unique ID which will be the global name of your panel +-- panelData = table; data object for your panel - see controls\panel.lua +function lam:RegisterAddonPanel(addonID, panelData) + CheckSafetyAndInitialize(addonID) + local container = lam:GetAddonPanelContainer() + local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel + panel:SetHidden(true) + panel:SetAnchorFill(container) + panel:SetHandler("OnEffectivelyShown", ToggleAddonPanels) + ZO_PreHook(panel, "SetHandler", ShowSetHandlerWarning) + + local function stripMarkup(str) + return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") + end + + local filterParts = {panelData.name, nil, nil} + -- append keywords and author separately, the may be nil + filterParts[#filterParts + 1] = panelData.keywords + filterParts[#filterParts + 1] = panelData.author + + local addonData = { + panel = panel, + name = stripMarkup(panelData.name), + filterText = stripMarkup(tconcat(filterParts, "\t")):lower(), + } + + tinsert(addonsForList, addonData) + + if panelData.slashCommand then + SLASH_COMMANDS[panelData.slashCommand] = function() + lam:OpenToPanel(panel) + end + end + + return panel --return for authors creating options manually +end + + +--METHOD: REGISTER OPTION CONTROLS +--registers the options you want shown for your addon +--these are stored in a table where each key-value pair is the order +--of the options in the panel and the data for that control, respectively +--see exampleoptions.lua for an example +--see controls\.lua for each widget type +--Usage: +-- addonID = "string"; the same string passed to :RegisterAddonPanel +-- optionsTable = table; the table containing all of the options controls and their data +function lam:RegisterOptionControls(addonID, optionsTable) --optionsTable = {sliderData, buttonData, etc} + addonToOptionsMap[addonID] = optionsTable +end + +--INTERNAL FUNCTION +--creates LAM's Addon Settings entry in ZO_GameMenu +local function CreateAddonSettingsMenuEntry() + local panelData = { + id = KEYBOARD_OPTIONS.currentPanelId, + name = util.L["PANEL_NAME"], + } + + KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1 + KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name + + lam.panelId = panelData.id + + local addonListSorted = false + + function panelData.callback() + sm:AddFragment(lam:GetAddonSettingsFragment()) + KEYBOARD_OPTIONS:ChangePanels(lam.panelId) + + local title = LAMAddonSettingsWindow:GetNamedChild("Title") + title:SetText(panelData.name) + + if not addonListSorted and #addonsForList > 0 then + local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") + --we're about to show our list for the first time - let's sort it + table.sort(addonsForList, function(a, b) return a.name < b.name end) + PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit)) + addonListSorted = true + end + end + + function panelData.unselectedCallback() + sm:RemoveFragment(lam:GetAddonSettingsFragment()) + if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011 + SetCameraOptionsPreviewModeEnabled(false) + end + end + + ZO_GameMenu_AddSettingPanel(panelData) +end + + +--INTERNAL FUNCTION +--creates the left-hand menu in LAM's window +local function CreateAddonList(name, parent) + local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList") + + local function addonListRow_OnMouseDown(control, button) + if button == 1 then + local data = ZO_ScrollList_GetData(control) + ZO_ScrollList_SelectData(addonList, data, control) + end + end + + local function addonListRow_OnMouseEnter(control) + ZO_ScrollList_MouseEnter(addonList, control) + end + + local function addonListRow_OnMouseExit(control) + ZO_ScrollList_MouseExit(addonList, control) + end + + local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild) + if not reselectingDuringRebuild then + if previouslySelectedData then + previouslySelectedData.panel:SetHidden(true) + end + if selectedData then + selectedData.panel:SetHidden(false) + PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION) + end + end + end + + local function addonListRow_Setup(control, data) + control:SetText(data.name) + control:SetSelected(not data.panel:IsHidden()) + end + + ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup) + -- I don't know how to make highlights clear properly; they often + -- get stuck and after a while the list is full of highlighted rows + --ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight") + ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select) + + local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE) + local addonListRow_CreateRaw = addonDataType.pool.m_Factory + + local function addonListRow_Create(pool) + local control = addonListRow_CreateRaw(pool) + control:SetHandler("OnMouseDown", addonListRow_OnMouseDown) + --control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter) + --control:SetHandler("OnMouseExit", addonListRow_OnMouseExit) + control:SetHeight(28) + control:SetFont("ZoFontHeader") + control:SetHorizontalAlignment(TEXT_ALIGN_LEFT) + control:SetVerticalAlignment(TEXT_ALIGN_CENTER) + control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + return control + end + + addonDataType.pool.m_Factory = addonListRow_Create + + return addonList +end + + +--INTERNAL FUNCTION +local function CreateSearchFilterBox(name, parent) + local boxControl = wm:CreateControl(name, parent, CT_CONTROL) + + local srchButton = wm:CreateControl("$(parent)Button", boxControl, CT_BUTTON) + srchButton:SetDimensions(32, 32) + srchButton:SetAnchor(LEFT, nil, LEFT, 2, 0) + srchButton:SetNormalTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_up.dds") + srchButton:SetPressedTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_down.dds") + srchButton:SetMouseOverTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_over.dds") + + local srchEdit = wm:CreateControlFromVirtual("$(parent)Edit", boxControl, "ZO_DefaultEdit") + srchEdit:SetAnchor(LEFT, srchButton, RIGHT, 4, 1) + srchEdit:SetAnchor(RIGHT, nil, RIGHT, -4, 1) + srchEdit:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) + + local srchBg = wm:CreateControl("$(parent)Bg", boxControl, CT_BACKDROP) + srchBg:SetAnchorFill() + srchBg:SetAlpha(0) + srchBg:SetCenterColor(0, 0, 0, 0.5) + srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) + srchBg:SetEdgeTexture("", 1, 1, 0, 0) + + -- search backdrop should appear whenever you hover over either + -- the magnifying glass button or the edit field (which is only + -- visible when it contains some text), and also while the edit + -- field has keyboard focus + + local srchActive = false + local srchHover = false + + local function srchBgUpdateAlpha() + if srchActive or srchEdit:HasFocus() then + srchBg:SetAlpha(srchHover and 0.8 or 0.6) + else + srchBg:SetAlpha(srchHover and 0.6 or 0.0) + end + end + + local function srchMouseEnter(control) + srchHover = true + srchBgUpdateAlpha() + end + + local function srchMouseExit(control) + srchHover = false + srchBgUpdateAlpha() + end + + boxControl:SetMouseEnabled(true) + boxControl:SetHitInsets(1, 1, -1, -1) + boxControl:SetHandler("OnMouseEnter", srchMouseEnter) + boxControl:SetHandler("OnMouseExit", srchMouseExit) + + srchButton:SetHandler("OnMouseEnter", srchMouseEnter) + srchButton:SetHandler("OnMouseExit", srchMouseExit) + + local focusLostTime = 0 + + srchButton:SetHandler("OnClicked", function(self) + srchEdit:Clear() + if GetFrameTimeMilliseconds() - focusLostTime < 100 then + -- re-focus the edit box if it lost focus due to this + -- button click (note that this handler may run a few + -- frames later) + srchEdit:TakeFocus() + end + end) + + srchEdit:SetHandler("OnMouseEnter", srchMouseEnter) + srchEdit:SetHandler("OnMouseExit", srchMouseExit) + srchEdit:SetHandler("OnFocusGained", srchBgUpdateAlpha) + + srchEdit:SetHandler("OnFocusLost", function() + focusLostTime = GetFrameTimeMilliseconds() + srchBgUpdateAlpha() + end) + + srchEdit:SetHandler("OnEscape", function(self) + self:Clear() + self:LoseFocus() + end) + + srchEdit:SetHandler("OnTextChanged", function(self) + local filterFunc = GetSearchFilterFunc(self) + if filterFunc then + srchActive = true + srchBg:SetEdgeColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA()) + srchButton:SetState(BSTATE_PRESSED) + else + srchActive = false + srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) + srchButton:SetState(BSTATE_NORMAL) + end + srchBgUpdateAlpha() + PopulateAddonList(lam.addonList, filterFunc) + PlaySound(SOUNDS.SPINNER_DOWN) + end) + + return boxControl +end + + +--INTERNAL FUNCTION +--creates LAM's Addon Settings top-level window +local function CreateAddonSettingsWindow() + local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow") + tlw:SetHidden(true) + tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow + + ZO_ReanchorControlForLeftSidePanel(tlw) + + -- create black background for the window (mimic ZO_RightFootPrintBackground) + + local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE) + bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds") + bgLeft:SetDimensions(1024, 1024) + bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT) + bgLeft:SetDrawLayer(DL_BACKGROUND) + bgLeft:SetExcludeFromResizeToFitExtents(true) + + local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE) + bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds") + bgRight:SetDimensions(64, 1024) + bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT) + bgRight:SetDrawLayer(DL_BACKGROUND) + bgRight:SetExcludeFromResizeToFitExtents(true) + + -- create gray background for addon list (mimic ZO_TreeUnderlay) + + local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE) + underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds") + underlayLeft:SetDimensions(256, 1024) + underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT) + underlayLeft:SetDrawLayer(DL_BACKGROUND) + underlayLeft:SetExcludeFromResizeToFitExtents(true) + + local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE) + underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds") + underlayRight:SetDimensions(128, 1024) + underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT) + underlayRight:SetDrawLayer(DL_BACKGROUND) + underlayRight:SetExcludeFromResizeToFitExtents(true) + + -- create title bar (mimic ZO_OptionsWindow) + + local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL) + title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70) + title:SetFont("ZoFontWinH1") + title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE) + + local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider") + divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108) + + -- create search filter box + + local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw) + srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120) + srchBox:SetDimensions(260, 30) + + -- create scrollable addon list + + local addonList = CreateAddonList("$(parent)AddonList", tlw) + addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160) + addonList:SetDimensions(285, 665) + + lam.addonList = addonList -- for easy access from elsewhere + + -- create container for option panels + + local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL) + panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120) + panelContainer:SetDimensions(645, 675) + + local defaultButton = wm:CreateControlFromVirtual("$(parent)ResetToDefaultButton", tlw, "ZO_DialogButton") + ZO_KeybindButtonTemplate_Setup(defaultButton, "OPTIONS_LOAD_DEFAULTS", HandleLoadDefaultsPressed, GetString(SI_OPTIONS_DEFAULTS)) + defaultButton:SetAnchor(TOPLEFT, panelContainer, BOTTOMLEFT, 0, 2) + lam.defaultButton = defaultButton + + local applyButton = wm:CreateControlFromVirtual("$(parent)ApplyButton", tlw, "ZO_DialogButton") + ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_ADDON_MANAGER_RELOAD)) + applyButton:SetAnchor(TOPRIGHT, panelContainer, BOTTOMRIGHT, 0, 2) + applyButton:SetHidden(true) + lam.applyButton = applyButton + + return tlw +end + + +--INITIALIZING +local safeToInitialize = false +local hasInitialized = false + +local eventHandle = table.concat({MAJOR, MINOR}, "r") +local function OnLoad(_, addonName) + -- wait for the first loaded event + em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED) + safeToInitialize = true +end +em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad) + +local function OnActivated(_, initial) + em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED) + FlushMessages() + + local reopenPanel = RetrievePanelForReopening() + if not initial and reopenPanel then + lam:OpenToPanel(reopenPanel) + end +end +em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated) + +function CheckSafetyAndInitialize(addonID) + if not safeToInitialize then + local msg = string.format("The panel with id '%s' was registered before addon loading has completed. This might break the AddOn Settings menu.", addonID) + PrintLater(msg) + end + if not hasInitialized then + hasInitialized = true + end +end + + +--TODO documentation +function lam:GetAddonPanelContainer() + local fragment = lam:GetAddonSettingsFragment() + local window = fragment:GetControl() + return window:GetNamedChild("PanelContainer") +end + + +--TODO documentation +function lam:GetAddonSettingsFragment() + assert(hasInitialized or safeToInitialize) + if not LAMAddonSettingsFragment then + local window = CreateAddonSettingsWindow() + LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100) + LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState) + if(newState == SCENE_FRAGMENT_SHOWN) then + InitKeybindActions() + PushActionLayerByName("OptionsWindow") + OpenCurrentPanel() + elseif(newState == SCENE_FRAGMENT_HIDDEN) then + CloseCurrentPanel() + RemoveActionLayerByName("OptionsWindow") + ShowReloadDialogIfNeeded() + end + end) + CreateAddonSettingsMenuEntry() + end + return LAMAddonSettingsFragment +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/button.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/button.lua new file mode 100644 index 0000000..17ecfef --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/button.lua @@ -0,0 +1,91 @@ +--[[buttonData = { + type = "button", + name = "My Button", -- string id or function returning a string + func = function() end, + tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + icon = "icon\\path.dds", -- (optional) + isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) + warning = "Will need to reload the UI.", -- (optional) + reference = "MyAddonButton", -- unique global reference to control (optional) +} ]] + +local widgetVersion = 11 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("button", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable = control.data.disabled + if type(disable) == "function" then + disable = disable() + end + control.button:SetEnabled(not disable) +end + +--controlName is optional +local MIN_HEIGHT = 28 -- default_button height +local HALF_WIDTH_LINE_SPACING = 2 +function LAMCreateControl.button(parent, buttonData, controlName) + local control = LAM.util.CreateBaseControl(parent, buttonData, controlName) + control:SetMouseEnabled(true) + + local width = control:GetWidth() + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + end + + if buttonData.icon then + control.button = wm:CreateControl(nil, control, CT_BUTTON) + control.button:SetDimensions(26, 26) + control.button:SetNormalTexture(buttonData.icon) + control.button:SetPressedOffset(2, 2) + else + --control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton") + control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton") + control.button:SetWidth(width / 3) + control.button:SetText(LAM.util.GetStringFromValue(buttonData.name)) + if buttonData.isDangerous then control.button:SetNormalFontColor(ZO_ERROR_COLOR:UnpackRGBA()) end + end + local button = control.button + button:SetAnchor(control.isHalfWidth and CENTER or RIGHT) + button:SetClickSound("Click") + button.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.tooltip)} + button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + button:SetHandler("OnClicked", function(...) + local args = {...} + local function callback() + buttonData.func(unpack(args)) + LAM.util.RequestRefreshIfNeeded(control) + end + + if(buttonData.isDangerous) then + local title = LAM.util.GetStringFromValue(buttonData.name) + local body = LAM.util.GetStringFromValue(buttonData.warning) + LAM.util.ShowConfirmationDialog(title, body, callback) + else + callback() + end + end) + + if buttonData.warning ~= nil then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + if buttonData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/checkbox.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/checkbox.lua new file mode 100644 index 0000000..8f48b63 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/checkbox.lua @@ -0,0 +1,142 @@ +--[[checkboxData = { + type = "checkbox", + name = "My Checkbox", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- a boolean or function that returns a boolean (optional) + reference = "MyAddonCheckbox", -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("checkbox", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +--label +local enabledColor = ZO_DEFAULT_ENABLED_COLOR +local enabledHLcolor = ZO_HIGHLIGHT_TEXT +local disabledColor = ZO_DEFAULT_DISABLED_COLOR +local disabledHLcolor = ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR +--checkbox +local checkboxColor = ZO_NORMAL_TEXT +local checkboxHLcolor = ZO_HIGHLIGHT_TEXT + + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA()) + control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA()) + --control:SetMouseEnabled(not disable) + --control:SetMouseEnabled(true) + + control.isDisabled = disable +end + +local function ToggleCheckbox(control) + if control.value then + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.checkbox:SetText(control.checkedText) + else + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.checkbox:SetText(control.uncheckedText) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value ~= nil then --our value could be false + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + control.value = value + + ToggleCheckbox(control) +end + +local function OnMouseEnter(control) + ZO_Options_OnMouseEnter(control) + + if control.isDisabled then return end + + local label = control.label + if control.value then + label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) + else + label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + end + control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) +end + +local function OnMouseExit(control) + ZO_Options_OnMouseExit(control) + + if control.isDisabled then return end + + local label = control.label + if control.value then + label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + else + label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + end + control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) +end + +--controlName is optional +function LAMCreateControl.checkbox(parent, checkboxData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, checkboxData, controlName) + control:SetHandler("OnMouseEnter", OnMouseEnter) + control:SetHandler("OnMouseExit", OnMouseExit) + control:SetHandler("OnMouseUp", function(control) + if control.isDisabled then return end + PlaySound(SOUNDS.DEFAULT_CLICK) + control.value = not control.value + control:UpdateValue(false, control.value) + end) + + control.checkbox = wm:CreateControl(nil, control.container, CT_LABEL) + local checkbox = control.checkbox + checkbox:SetAnchor(LEFT, control.container, LEFT, 0, 0) + checkbox:SetFont("ZoFontGameBold") + checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) + control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper() + control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper() + + if checkboxData.warning ~= nil or checkboxData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if checkboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/colorpicker.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/colorpicker.lua new file mode 100644 index 0000000..b62cfba --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/colorpicker.lua @@ -0,0 +1,110 @@ +--[[colorpickerData = { + type = "colorpicker", + name = "My Color Picker", -- or string id or function returning a string + getFunc = function() return db.r, db.g, db.b, db.a end, -- (alpha is optional) + setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, -- (alpha is optional) + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, -- (optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color + reference = "MyAddonColorpicker" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end + + control.isDisabled = disable +end + +local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) + if forceDefault then --if we are forcing defaults + local color = LAM.util.GetDefaultValue(control.data.default) + valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a + control.data.setFunc(valueR, valueG, valueB, valueA) + elseif valueR and valueG and valueB then + control.data.setFunc(valueR, valueG, valueB, valueA or 1) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + valueR, valueG, valueB, valueA = control.data.getFunc() + end + + control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) +end + +function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName) + + control.color = control.container + local color = control.color + + control.thumb = wm:CreateControl(nil, color, CT_TEXTURE) + local thumb = control.thumb + thumb:SetDimensions(36, 18) + thumb:SetAnchor(LEFT, color, LEFT, 4, 0) + + color.border = wm:CreateControl(nil, color, CT_TEXTURE) + local border = color.border + border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds") + border:SetTextureCoords(0, .625, 0, .8125) + border:SetDimensions(40, 22) + border:SetAnchor(CENTER, thumb, CENTER, 0, 0) + + local function ColorPickerCallback(r, g, b, a) + control:UpdateValue(false, r, g, b, a) + end + + control:SetHandler("OnMouseUp", function(self, btn, upInside) + if self.isDisabled then return end + + if upInside then + local r, g, b, a = colorpickerData.getFunc() + if IsInGamepadPreferredMode() then + COLOR_PICKER_GAMEPAD:Show(ColorPickerCallback, r, g, b, a) + else + COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a) + end + end + end) + + if colorpickerData.warning ~= nil or colorpickerData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if colorpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/custom.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/custom.lua new file mode 100644 index 0000000..eb6f26c --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/custom.lua @@ -0,0 +1,35 @@ +--[[customData = { + type = "custom", + reference = "MyAddonCustomControl", -- unique name for your control to use as reference (optional) + refreshFunc = function(customControl) end, -- function to call when panel/controls refresh (optional) + width = "full", -- or "half" (optional) +} ]] + +local widgetVersion = 7 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("custom", widgetVersion) then return end + +local function UpdateValue(control) + if control.data.refreshFunc then + control.data.refreshFunc(control) + end +end + +local MIN_HEIGHT = 26 +function LAMCreateControl.custom(parent, customData, controlName) + local control = LAM.util.CreateBaseControl(parent, customData, controlName) + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) + else + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) + end + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/description.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/description.lua new file mode 100644 index 0000000..a53c5b1 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/description.lua @@ -0,0 +1,80 @@ +--[[descriptionData = { + type = "description", + text = "My description text to display.", -- or string id or function returning a string + title = "My Title", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonDescription" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 9 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("description", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + control.desc:SetColor(color:UnpackRGBA()) + if control.title then + control.title:SetColor(color:UnpackRGBA()) + end + control.disabled = disable + end +end + +local function UpdateValue(control) + if control.title then + control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) + end + control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) +end + +function LAMCreateControl.description(parent, descriptionData, controlName) + local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if isHalfWidth then + control:SetDimensionConstraints(width / 2, 0, width / 2, 0) + else + control:SetDimensionConstraints(width, 0, width, 0) + end + + control.desc = wm:CreateControl(nil, control, CT_LABEL) + local desc = control.desc + desc:SetVerticalAlignment(TEXT_ALIGN_TOP) + desc:SetFont("ZoFontGame") + desc:SetText(LAM.util.GetStringFromValue(descriptionData.text)) + desc:SetWidth(isHalfWidth and width / 2 or width) + + if descriptionData.title then + control.title = wm:CreateControl(nil, control, CT_LABEL) + local title = control.title + title:SetWidth(isHalfWidth and width / 2 or width) + title:SetAnchor(TOPLEFT, control, TOPLEFT) + title:SetFont("ZoFontWinH4") + title:SetText(LAM.util.GetStringFromValue(descriptionData.title)) + desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT) + else + desc:SetAnchor(TOPLEFT) + end + + control.UpdateValue = UpdateValue + if descriptionData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control + +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/divider.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/divider.lua new file mode 100644 index 0000000..90ed6e8 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/divider.lua @@ -0,0 +1,45 @@ +--[[dividerData = { + type = "divider", + width = "full", -- or "half" (optional) + height = 10, -- (optional) + alpha = 0.25, -- (optional) + reference = "MyAddonDivider" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 2 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("divider", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local MIN_HEIGHT = 10 +local MAX_HEIGHT = 50 +local MIN_ALPHA = 0 +local MAX_ALPHA = 1 +local DEFAULT_ALPHA = 0.25 + +local function GetValueInRange(value, min, max, default) + if not value or type(value) ~= "number" then + return default + end + return math.min(math.max(min, value), max) +end + +function LAMCreateControl.divider(parent, dividerData, controlName) + local control = LAM.util.CreateBaseControl(parent, dividerData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + local height = GetValueInRange(dividerData.height, MIN_HEIGHT, MAX_HEIGHT, MIN_HEIGHT) + local alpha = GetValueInRange(dividerData.alpha, MIN_ALPHA, MAX_ALPHA, DEFAULT_ALPHA) + + control:SetDimensions(isHalfWidth and width / 2 or width, height) + + control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") + local divider = control.divider + divider:SetWidth(isHalfWidth and width / 2 or width) + divider:SetAnchor(TOPLEFT) + divider:SetAlpha(alpha) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/dropdown.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/dropdown.lua new file mode 100644 index 0000000..2f554cc --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/dropdown.lua @@ -0,0 +1,432 @@ +--[[dropdownData = { + type = "dropdown", + name = "My Dropdown", -- or string id or function returning a string + choices = {"table", "of", "choices"}, + choicesValues = {"foo", 2, "three"}, -- if specified, these values will get passed to setFunc instead (optional) + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + sort = "name-up", -- or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted + width = "full", -- or "half" (optional) + scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonDropdown" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 20 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("dropdown", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER +local SORT_BY_VALUE = { ["value"] = {} } +local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } +local SORT_TYPES = { + name = ZO_SORT_BY_NAME, + numeric = ZO_SORT_BY_NAME_NUMERIC, + value = SORT_BY_VALUE, + numericvalue = SORT_BY_VALUE_NUMERIC, +} +local SORT_ORDERS = { + up = ZO_SORT_ORDER_UP, + down = ZO_SORT_ORDER_DOWN, +} + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.dropdown:SetEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.dropdown:SetSelectedItem(control.choices[value]) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.dropdown:SetSelectedItem(control.choices[value]) + end +end + +local function DropdownCallback(control, choiceText, choice) + choice.control:UpdateValue(false, choice.value or choiceText) +end + +local function SetupTooltips(comboBox, choicesTooltips) + local function ShowTooltip(control) + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end + local function HideTooltip(control) + ClearTooltip(InformationTooltip) + end + + -- allow for tooltips on the drop down entries + local originalShow = comboBox.ShowDropdownInternal + comboBox.ShowDropdownInternal = function(comboBox) + originalShow(comboBox) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control.tooltip = choicesTooltips[i] + entry.onMouseEnter = control:GetHandler("OnMouseEnter") + entry.onMouseExit = control:GetHandler("OnMouseExit") + ZO_PreHookHandler(control, "OnMouseEnter", ShowTooltip) + ZO_PreHookHandler(control, "OnMouseExit", HideTooltip) + end + end + + local originalHide = comboBox.HideDropdownInternal + comboBox.HideDropdownInternal = function(self) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control:SetHandler("OnMouseEnter", entry.onMouseEnter) + control:SetHandler("OnMouseExit", entry.onMouseExit) + control.tooltip = nil + end + originalHide(self) + end +end + +local function UpdateChoices(control, choices, choicesValues, choicesTooltips) + control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?) + ZO_ClearTable(control.choices) + + --build new list of choices + local choices = choices or control.data.choices + local choicesValues = choicesValues or control.data.choicesValues + local choicesTooltips = choicesTooltips or control.data.choicesTooltips + + if choicesValues then + assert(#choices == #choicesValues, "choices and choicesValues need to have the same size") + end + + if choicesTooltips then + assert(#choices == #choicesTooltips, "choices and choicesTooltips need to have the same size") + if not control.scrollHelper then -- only do this for non-scrollable + SetupTooltips(control.dropdown, choicesTooltips) + end + end + + for i = 1, #choices do + local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback) + entry.control = control + if choicesValues then + entry.value = choicesValues[i] + end + if choicesTooltips and control.scrollHelper then + entry.tooltip = choicesTooltips[i] + end + control.choices[entry.value or entry.name] = entry.name + control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort + end +end + +local function GrabSortingInfo(sortInfo) + local t, i = {}, 1 + for info in string.gmatch(sortInfo, "([^%-]+)") do + t[i] = info + i = i + 1 + end + + return t +end + +local ENTRY_ID = 1 +local LAST_ENTRY_ID = 2 +local OFFSET_X_INDEX = 4 +local DEFAULT_VISIBLE_ROWS = 10 +local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = ZO_SCROLLABLE_ENTRY_TEMPLATE_HEIGHT +local SCROLLBAR_PADDING = ZO_SCROLL_BAR_WIDTH +local PADDING_X = GetMenuPadding() +local PADDING_Y = ZO_SCROLLABLE_COMBO_BOX_LIST_PADDING_Y +local LABEL_OFFSET_X = 2 +local CONTENT_PADDING = PADDING_X * 4 +local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed +local ScrollableDropdownHelper = ZO_Object:Subclass() + +function ScrollableDropdownHelper:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function ScrollableDropdownHelper:Initialize(panel, control, visibleRows) + local combobox = control.combobox + local dropdown = control.dropdown + self.panel = panel + self.control = control + self.combobox = combobox + self.dropdown = dropdown + self.visibleRows = visibleRows + + -- clear anchors so we can adjust the width dynamically + dropdown.m_dropdown:ClearAnchors() + dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) + + -- handle dropdown or settingsmenu opening/closing + local function onShow() return self:OnShow() end + local function onHide() self:OnHide() end + local function doHide(closedPanel) + if closedPanel == panel then self:DoHide() end + end + + ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) + ZO_PreHook(dropdown, "HideDropdownInternal", onHide) + combobox:SetHandler("OnEffectivelyHidden", onHide) + cm:RegisterCallback("LAM-PanelClosed", doHide) + + -- dont fade entries near the edges + local scrollList = dropdown.m_scroll + scrollList.selectionTemplate = nil + scrollList.highlightTemplate = nil + ZO_ScrollList_EnableSelection(scrollList, "ZO_SelectionHighlight") + ZO_ScrollList_EnableHighlight(scrollList, "ZO_SelectionHighlight") + ZO_Scroll_SetUseFadeGradient(scrollList, false) + + -- adjust scroll content anchor to mimic menu padding + local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") + local anchor1 = {select(2, scroll:GetAnchor(0))} + local anchor2 = {select(2, scroll:GetAnchor(1))} + anchor1[OFFSET_X_INDEX] = PADDING_X - LABEL_OFFSET_X + anchor2[OFFSET_X_INDEX] = -anchor1[OFFSET_X_INDEX] + scroll:ClearAnchors() + scroll:SetAnchor(unpack(anchor1)) + scroll:SetAnchor(unpack(anchor2)) + ZO_ScrollList_Commit(scrollList) + + -- hook mouse enter/exit + local function onMouseEnter(control) self:OnMouseEnter(control) end + local function onMouseExit(control) self:OnMouseExit(control) end + + -- adjust row setup to mimic the highlight padding + local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, ENTRY_ID) + local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, LAST_ENTRY_ID) + local oSetup = dataType1.setupCallback -- both types have the same setup function + local function SetupEntry(control, data, list) + oSetup(control, data, list) + control.m_label:SetAnchor(LEFT, nil, nil, LABEL_OFFSET_X) + control.m_label:SetAnchor(RIGHT, nil, nil, -LABEL_OFFSET_X) + -- no need to store old ones since we have full ownership of our dropdown controls + if not control.hookedMouseHandlers then --only do it once per control + control.hookedMouseHandlers = true + ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) + ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) + end + end + dataType1.setupCallback = SetupEntry + dataType2.setupCallback = SetupEntry + + -- adjust dimensions based on entries + local scrollContent = scroll:GetNamedChild("Contents") + dropdown.AddMenuItems = ScrollableDropdownHelper.AddMenuItems + + dropdown.AdjustDimensions = function() + local numItems = #dropdown.m_sortedItems + local contentWidth = self:CalculateContentWidth() + CONTENT_PADDING + local anchorOffset = 0 + if(numItems > self.visibleRows) then + numItems = self.visibleRows + contentWidth = contentWidth + SCROLLBAR_PADDING + anchorOffset = -SCROLLBAR_PADDING + end + + local width = zo_max(contentWidth, dropdown.m_container:GetWidth()) + local height = dropdown:GetEntryTemplateHeightWithSpacing() * numItems - dropdown.m_spacing + (PADDING_Y * 2) + ROUNDING_MARGIN + + dropdown.m_dropdown:SetWidth(width) + dropdown.m_dropdown:SetHeight(height) + ZO_ScrollList_SetHeight(dropdown.m_scroll, height) + + scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) + end +end + +local function CreateScrollableComboBoxEntry(self, item, index, isLast) + item.m_index = index + item.m_owner = self + local entryType = isLast and LAST_ENTRY_ID or ENTRY_ID + local entry = ZO_ScrollList_CreateDataEntry(entryType, item) + + return entry +end + +function ScrollableDropdownHelper.AddMenuItems(self) -- self refers to the ZO_ScrollableComboBox here + ZO_ScrollList_Clear(self.m_scroll) + + local numItems = #self.m_sortedItems + local dataList = ZO_ScrollList_GetDataList(self.m_scroll) + + for i = 1, numItems do + local item = self.m_sortedItems[i] + local entry = CreateScrollableComboBoxEntry(self, item, i, i == numItems) + table.insert(dataList, entry) + end + + self:AdjustDimensions() + + ZO_ScrollList_Commit(self.m_scroll) +end + +function ScrollableDropdownHelper:OnShow() + local dropdown = self.dropdown + + -- don't show if there are no entries + if #dropdown.m_sortedItems == 0 then return true end + + if dropdown.m_lastParent ~= ZO_Menus then + dropdown.m_lastParent = dropdown.m_dropdown:GetParent() + dropdown.m_dropdown:SetParent(ZO_Menus) + ZO_Menus:BringWindowToTop() + end +end + +function ScrollableDropdownHelper:OnHide() + local dropdown = self.dropdown + if dropdown.m_lastParent then + dropdown.m_dropdown:SetParent(dropdown.m_lastParent) + dropdown.m_lastParent = nil + end +end + +function ScrollableDropdownHelper:DoHide() + local dropdown = self.dropdown + if dropdown:IsDropdownVisible() then + dropdown:HideDropdown() + end +end + +function ScrollableDropdownHelper:CalculateContentWidth() + local dropdown = self.dropdown + local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) + + local dummy = dataType.pool:AcquireObject() + dataType.setupCallback(dummy, { + m_owner = dropdown, + name = "Dummy" + }, dropdown) + + local maxWidth = 0 + local label = dummy.m_label + local entries = dropdown.m_sortedItems + local numItems = #entries + for index = 1, numItems do + label:SetText(entries[index].name) + local width = label:GetTextWidth() + if (width > maxWidth) then + maxWidth = width + end + end + + dataType.pool:ReleaseObject(dummy.key) + return maxWidth +end + +function ScrollableDropdownHelper:OnMouseEnter(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseEnter(control) + -- show tooltip + if control.m_data.tooltip then + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.m_data.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end +end +function ScrollableDropdownHelper:OnMouseExit(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseExit(control) + -- hide tooltip + if control.m_data.tooltip then + ClearTooltip(InformationTooltip) + end +end + +function LAMCreateControl.dropdown(parent, dropdownData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName) + control.choices = {} + + local countControl = parent + local name = parent:GetName() + if not name or #name == 0 then + countControl = LAMCreateControl + name = "LAM" + end + local comboboxCount = (countControl.comboboxCount or 0) + 1 + countControl.comboboxCount = comboboxCount + control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, dropdownData.scrollable and "ZO_ScrollableComboBox" or "ZO_ComboBox") + + local combobox = control.combobox + combobox:SetAnchor(TOPLEFT) + combobox:SetDimensions(control.container:GetDimensions()) + combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox) + local dropdown = control.dropdown + dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value + + if dropdownData.scrollable then + local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS + control.scrollHelper = ScrollableDropdownHelper:New(LAM.util.GetTopPanel(parent), control, visibleRows) + end + + ZO_PreHook(dropdown, "UpdateItems", function(self) + assert(not self.m_sortsItems, "built-in dropdown sorting was reactivated, sorting is handled by LAM") + if control.m_sortOrder ~= nil and control.m_sortType then + local sortKey = next(control.m_sortType) + local sortFunc = function(item1, item2) return ZO_TableOrderingFunction(item1, item2, sortKey, control.m_sortType, control.m_sortOrder) end + table.sort(self.m_sortedItems, sortFunc) + end + end) + + if dropdownData.sort then + local sortInfo = GrabSortingInfo(dropdownData.sort) + control.m_sortType, control.m_sortOrder = SORT_TYPES[sortInfo[1]], SORT_ORDERS[sortInfo[2]] + elseif dropdownData.choicesValues then + control.m_sortType, control.m_sortOrder = ZO_SORT_ORDER_UP, SORT_BY_VALUE + end + + if dropdownData.warning ~= nil or dropdownData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateChoices = UpdateChoices + control:UpdateChoices(dropdownData.choices, dropdownData.choicesValues) + control.UpdateValue = UpdateValue + control:UpdateValue() + if dropdownData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/editbox.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/editbox.lua new file mode 100644 index 0000000..f9f79ad --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/editbox.lua @@ -0,0 +1,156 @@ +--[[editboxData = { + type = "editbox", + name = "My Editbox", -- or string id or function returning a string + getFunc = function() return db.text end, + setFunc = function(text) db.text = text doStuff() end, + tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) + isMultiline = true, -- boolean (optional) + isExtraWide = true, -- boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.text, -- default value or function that returns the default value (optional) + reference = "MyAddonEditbox" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("editbox", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.editbox:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end + --control.editbox:SetEditEnabled(not disable) + control.editbox:SetMouseEnabled(not disable) +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.editbox:SetText(value) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.editbox:SetText(value) + end +end + +local MIN_HEIGHT = 24 +local HALF_WIDTH_LINE_SPACING = 2 +function LAMCreateControl.editbox(parent, editboxData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, editboxData, controlName) + + local container = control.container + control.bg = wm:CreateControlFromVirtual(nil, container, "ZO_EditBackdrop") + local bg = control.bg + bg:SetAnchorFill() + + if editboxData.isMultiline then + control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditMultiLineForBackdrop") + control.editbox:SetHandler("OnMouseWheel", function(self, delta) + if self:HasFocus() then --only set focus to new spots if the editbox is currently in use + local cursorPos = self:GetCursorPosition() + local text = self:GetText() + local textLen = text:len() + local newPos + if delta > 0 then --scrolling up + local reverseText = text:reverse() + local revCursorPos = textLen - cursorPos + local revPos = reverseText:find("\n", revCursorPos+1) + newPos = revPos and textLen - revPos + else --scrolling down + newPos = text:find("\n", cursorPos+1) + end + if newPos then --if we found a new line, then scroll, otherwise don't + self:SetCursorPosition(newPos) + end + end + end) + else + control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop") + end + local editbox = control.editbox + editbox:SetText(editboxData.getFunc()) + editbox:SetMaxInputChars(3000) + editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end) + editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end) + editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0 + + control.label:ClearAnchors() + container:ClearAnchors() + + control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + + if control.isHalfWidth then + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + end + + if editboxData.isExtraWide then + container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0) + else + container:SetWidth(MIN_WIDTH * 3.2) + end + + if editboxData.isMultiline then + container:SetHeight(MIN_HEIGHT * 3) + else + container:SetHeight(MIN_HEIGHT) + end + + if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then + control:SetHeight(container:GetHeight()) + else + control:SetHeight(container:GetHeight() + control.label:GetHeight()) + end + + editbox:ClearAnchors() + editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2) + editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2) + + if editboxData.warning ~= nil or editboxData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + if editboxData.isExtraWide then + control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0) + else + control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0) + end + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + if editboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/header.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/header.lua new file mode 100644 index 0000000..3eda1d7 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/header.lua @@ -0,0 +1,42 @@ +--[[headerData = { + type = "header", + name = "My Header", -- or string id or function returning a string + width = "full", -- or "half" (optional) + reference = "MyAddonHeader" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 8 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("header", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateValue(control) + control.header:SetText(LAM.util.GetStringFromValue(control.data.name)) +end + +local MIN_HEIGHT = 30 +function LAMCreateControl.header(parent, headerData, controlName) + local control = LAM.util.CreateBaseControl(parent, headerData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + control:SetDimensions(isHalfWidth and width / 2 or width, MIN_HEIGHT) + + control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") + local divider = control.divider + divider:SetWidth(isHalfWidth and width / 2 or width) + divider:SetAnchor(TOPLEFT) + + control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local header = control.header + header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT) + header:SetAnchor(BOTTOMRIGHT) + header:SetText(LAM.util.GetStringFromValue(headerData.name)) + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/iconpicker.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/iconpicker.lua new file mode 100644 index 0000000..2cca460 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/iconpicker.lua @@ -0,0 +1,436 @@ +--[[iconpickerData = { + type = "iconpicker", + name = "My Icon Picker", -- or string id or function returning a string + choices = {"texture path 1", "texture path 2", "texture path 3"}, + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + maxColumns = 5, -- number of icons in one row (optional) + visibleRows = 4.5, -- number of visible rows (optional) + iconSize = 28, -- size of the icons (optional) + defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) + width = "full", --or "half" (optional) + beforeShow = function(control, iconPicker) return preventShow end, -- (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonIconPicker" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 8 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local IconPickerMenu = ZO_Object:Subclass() +local iconPicker +LAM.util.GetIconPickerMenu = function() + if not iconPicker then + iconPicker = IconPickerMenu:New("LAMIconPicker") + local sceneFragment = LAM:GetAddonSettingsFragment() + ZO_PreHook(sceneFragment, "OnHidden", function() + if not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + end) + end + return iconPicker +end + +function IconPickerMenu:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function IconPickerMenu:Initialize(name) + local control = wm:CreateTopLevelWindow(name) + control:SetDrawTier(DT_HIGH) + control:SetHidden(true) + self.control = control + + local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer") + -- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count + scrollContainer:SetAnchorFill() + ZO_Scroll_SetUseFadeGradient(scrollContainer, false) + ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false) + ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value + local scroll = GetControl(scrollContainer, "ScrollChild") + self.scroll = scroll + self.scrollContainer = scrollContainer + + local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP) + bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE) + mouseOver:SetDrawLevel(2) + mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds") + mouseOver:SetHidden(true) + + local function IconFactory(pool) + local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE) + icon:SetMouseEnabled(true) + icon:SetDrawLevel(3) + icon:SetHandler("OnMouseEnter", function() + mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0) + mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0) + mouseOver:SetHidden(false) + if self.customOnMouseEnter then + self.customOnMouseEnter(icon) + else + self:OnMouseEnter(icon) + end + end) + icon:SetHandler("OnMouseExit", function() + mouseOver:ClearAnchors() + mouseOver:SetHidden(true) + if self.customOnMouseExit then + self.customOnMouseExit(icon) + else + self:OnMouseExit(icon) + end + end) + icon:SetHandler("OnMouseUp", function(control, ...) + PlaySound("Click") + icon.OnSelect(icon, icon.texture) + self:Clear() + end) + return icon + end + + local function ResetFunction(icon) + icon:ClearAnchors() + end + + self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction) + self:SetMaxColumns(1) + self.icons = {} + self.color = ZO_DEFAULT_ENABLED_COLOR + + EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function() + if self.refCount ~= nil then + local moc = wm:GetMouseOverControl() + if(moc:GetOwningWindow() ~= control) then + self.refCount = self.refCount - 1 + if self.refCount <= 0 then + self:Clear() + end + end + end + end) +end + +function IconPickerMenu:OnMouseEnter(icon) + InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() +end + +function IconPickerMenu:OnMouseExit(icon) + ClearTooltip(InformationTooltip) +end + +function IconPickerMenu:SetMaxColumns(value) + self.maxCols = value ~= nil and value or 5 +end + +local DEFAULT_SIZE = 28 +function IconPickerMenu:SetIconSize(value) + local iconSize = DEFAULT_SIZE + if value ~= nil then iconSize = math.max(iconSize, value) end + self.iconSize = iconSize +end + +function IconPickerMenu:SetVisibleRows(value) + self.visibleRows = value ~= nil and value or 4.5 +end + +function IconPickerMenu:SetMouseHandlers(onEnter, onExit) + self.customOnMouseEnter = onEnter + self.customOnMouseExit = onExit +end + +function IconPickerMenu:UpdateDimensions() + local iconSize = self.iconSize + local width = iconSize * self.maxCols + 20 + local height = iconSize * self.visibleRows + self.control:SetDimensions(width, height) + + local icons = self.icons + for i = 1, #icons do + local icon = icons[i] + icon:SetDimensions(iconSize, iconSize) + end +end + +function IconPickerMenu:UpdateAnchors() + local iconSize = self.iconSize + local col, maxCols = 1, self.maxCols + local previousCol, previousRow + local scroll = self.scroll + local icons = self.icons + + for i = 1, #icons do + local icon = icons[i] + icon:ClearAnchors() + if i == 1 then + icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0) + previousRow = icon + elseif col == 1 then + icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0) + previousRow = icon + else + icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0) + end + previousCol = icon + col = col >= maxCols and 1 or col + 1 + end +end + +function IconPickerMenu:Clear() + self.icons = {} + self.iconPool:ReleaseAllObjects() + self.control:SetHidden(true) + self.color = ZO_DEFAULT_ENABLED_COLOR + self.refCount = nil + self.parent = nil + self.customOnMouseEnter = nil + self.customOnMouseExit = nil +end + +function IconPickerMenu:AddIcon(texturePath, callback, tooltip) + local icon, key = self.iconPool:AcquireObject() + icon:SetTexture(texturePath) + icon:SetColor(self.color:UnpackRGBA()) + icon.texture = texturePath + icon.tooltip = tooltip + icon.OnSelect = callback + self.icons[#self.icons + 1] = icon +end + +function IconPickerMenu:Show(parent) + if #self.icons == 0 then return false end + if not self.control:IsHidden() then self:Clear() return false end + self:UpdateDimensions() + self:UpdateAnchors() + + local control = self.control + control:ClearAnchors() + control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8) + control:SetHidden(false) + control:BringWindowToTop() + self.parent = parent + self.refCount = 2 + + return true +end + +function IconPickerMenu:SetColor(color) + local icons = self.icons + self.color = color + for i = 1, #icons do + local icon = icons[i] + icon:SetColor(color:UnpackRGBA()) + end +end + +------------------------------------------------------------- + +local function UpdateChoices(control, choices, choicesTooltips) + local data = control.data + if not choices then + choices, choicesTooltips = data.choices, data.choicesTooltips or {} + end + local addedChoices = {} + + local iconPicker = LAM.util.GetIconPickerMenu() + iconPicker:Clear() + for i = 1, #choices do + local texture = choices[i] + if not addedChoices[texture] then -- remove duplicates + iconPicker:AddIcon(choices[i], function(self, texture) + control.icon:SetTexture(texture) + data.setFunc(texture) + LAM.util.RequestRefreshIfNeeded(control) + end, LAM.util.GetStringFromValue(choicesTooltips[i])) + addedChoices[texture] = true + end + end +end + +local function IsDisabled(control) + if type(control.data.disabled) == "function" then + return control.data.disabled() + else + return control.data.disabled + end +end + +local function SetColor(control, color) + local icon = control.icon + if IsDisabled(control) then + icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR + icon:SetColor(icon.color:UnpackRGBA()) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetColor(icon.color) + end +end + +local function UpdateDisabled(control) + local disable = IsDisabled(control) + + control.dropdown:SetMouseEnabled(not disable) + control.dropdownButton:SetEnabled(not disable) + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + + SetColor(control, control.icon.color) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.icon:SetTexture(value) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.icon:SetTexture(value) + end +end + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local function SetIconSize(control, size) + local icon = control.icon + icon.size = size + icon:SetDimensions(size, size) + + local height = size + 4 + control.dropdown:SetDimensions(size + 20, height) + height = math.max(height, MIN_HEIGHT) + control.container:SetHeight(height) + if control.lineControl then + control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING) + else + control:SetHeight(height) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetIconSize(size) + iconPicker:UpdateDimensions() + iconPicker:UpdateAnchors() + end +end + +function LAMCreateControl.iconpicker(parent, iconpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName) + + local function ShowIconPicker() + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container then + iconPicker:Clear() + else + iconPicker:SetMaxColumns(iconpickerData.maxColumns) + iconPicker:SetVisibleRows(iconpickerData.visibleRows) + iconPicker:SetIconSize(control.icon.size) + UpdateChoices(control) + iconPicker:SetColor(control.icon.color) + if iconpickerData.beforeShow then + if iconpickerData.beforeShow(control, iconPicker) then + iconPicker:Clear() + return + end + end + iconPicker:Show(control.container) + end + end + + local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE + control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL) + local dropdown = control.dropdown + dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0) + dropdown:SetMouseEnabled(true) + dropdown:SetHandler("OnMouseUp", ShowIconPicker) + dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE) + local icon = control.icon + icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0) + icon:SetDrawLevel(2) + + local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton") + dropdownButton:SetDimensions(16, 16) + dropdownButton:SetHandler("OnClicked", ShowIconPicker) + dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0) + control.dropdownButton = dropdownButton + + control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + if iconpickerData.warning ~= nil or iconpickerData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateChoices = UpdateChoices + control.UpdateValue = UpdateValue + control:UpdateValue() + control.SetColor = SetColor + control:SetColor() + control.SetIconSize = SetIconSize + control:SetIconSize(iconSize) + + if iconpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/panel.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/panel.lua new file mode 100644 index 0000000..75bb904 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/panel.lua @@ -0,0 +1,168 @@ +--[[panelData = { + type = "panel", + name = "Window Title", -- or string id or function returning a string + displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) + author = "Seerah", -- or string id or function returning a string (optional) + version = "2.0", -- or string id or function returning a string (optional) + website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated or function (optional) + feedback = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where feedback/feature requests/bugs can be reported for the addon or function (optional) + translation = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where translation texts of the addon can be helped with or function (optional) + donation = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where a donation for the addon author can be raised or function (optional) + keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) + slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) + registerForRefresh = true, -- boolean will refresh all options controls when a setting is changed and when the panel is shown (optional) + registerForDefaults = true, -- boolean will set all options controls back to default values (optional) + resetFunc = function() print("defaults reset") end, -- custom function to run after settings are reset to defaults (optional) +} ]] + + +local widgetVersion = 15 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("panel", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER + +local function RefreshPanel(control) + local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu + if LAM.currentAddonPanel ~= panel or not LAM.currentPanelOpened then return end -- we refresh it later when the panel is opened + + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl ~= control and updateControl.UpdateValue then + updateControl:UpdateValue() + end + if updateControl.UpdateDisabled then + updateControl:UpdateDisabled() + end + if updateControl.UpdateWarning then + updateControl:UpdateWarning() + end + end +end + +local function ForceDefaults(panel) + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl.UpdateValue and updateControl.data.default ~= nil then + updateControl:UpdateValue(true) + end + end + + if panel.data.resetFunc then + panel.data.resetFunc() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) +end + +local callbackRegistered = false +LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 +local SEPARATOR = " - " +local COLORED_SEPARATOR = ZO_WHITE:Colorize(SEPARATOR) +local LINK_COLOR = ZO_ColorDef:New("5959D5") +local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") +local LINK_COLOR_DONATE = ZO_ColorDef:New("FFD700") -- golden +local LINK_MOUSE_OVER_COLOR_DONATE = ZO_ColorDef:New("FFF6CC") + +local function CreateButtonControl(control, label, clickAction, relativeTo) + local button = wm:CreateControl(nil, control, CT_BUTTON) + button:SetClickSound("Click") + button:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + button:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) + button:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) + + local OnClicked + local actionType = type(clickAction) + if actionType == "string" then + OnClicked = function() RequestOpenUnsafeURL(clickAction) end + elseif actionType == "function" then + OnClicked = clickAction + end + button:SetHandler("OnClicked", OnClicked) + + if relativeTo then + button:SetAnchor(TOPLEFT, relativeTo, TOPRIGHT, 0, 0) + button:SetText(COLORED_SEPARATOR .. label) + else + button:SetAnchor(TOPLEFT, control.label, BOTTOMLEFT, 0, -2) + button:SetText(label) + end + button:SetDimensions(button:GetLabelControl():GetTextDimensions()) + + return button +end + +function LAMCreateControl.panel(parent, panelData, controlName) + local control = wm:CreateControl(controlName, parent, CT_CONTROL) + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) + label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) + + local previousInfoControl + if panelData.author or panelData.version then + control.info = wm:CreateControl(nil, control, CT_LABEL) + local info = control.info + info:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) + + local output = {} + if panelData.author then + output[#output + 1] = zo_strformat(LAM.util.L["AUTHOR"], LAM.util.GetStringFromValue(panelData.author)) + end + if panelData.version then + output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) + end + info:SetText(table.concat(output, SEPARATOR)) + previousInfoControl = info + end + + if panelData.website then + control.website = CreateButtonControl(control, LAM.util.L["WEBSITE"], panelData.website, previousInfoControl) + previousInfoControl = control.website + end + + if panelData.feedback then + control.feedback = CreateButtonControl(control, LAM.util.L["FEEDBACK"], panelData.feedback, previousInfoControl) + previousInfoControl = control.feedback + end + + if panelData.translation then + control.translation = CreateButtonControl(control, LAM.util.L["TRANSLATION"], panelData.translation, previousInfoControl) + previousInfoControl = control.translation + end + + if panelData.donation then + control.donation = CreateButtonControl(control, LAM.util.L["DONATION"], panelData.donation, previousInfoControl) + local donation = control.donation + previousInfoControl = donation + donation:SetNormalFontColor(LINK_COLOR_DONATE:UnpackRGBA()) + donation:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR_DONATE:UnpackRGBA()) + end + + control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") + LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1 + local container = control.container + container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3) + control.scroll = GetControl(control.container, "ScrollChild") + control.scroll:SetResizeToFitPadding(0, 20) + + if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once + cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel) + callbackRegistered = true + end + + control.ForceDefaults = ForceDefaults + control.RefreshPanel = LAM.util.RequestRefreshIfNeeded + control.data = panelData + control.controlsToRefresh = {} + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/slider.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/slider.lua new file mode 100644 index 0000000..6c80968 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/slider.lua @@ -0,0 +1,220 @@ +--[[sliderData = { + type = "slider", + name = "My Slider", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + min = 0, + max = 20, + step = 1, -- (optional) + clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) + clampFunction = function(value, min, max) return math.max(math.min(value, max), min) end, -- function that is called to clamp the value (optional) + decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) + autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) + inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) + tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonSlider" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("slider", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local strformat = string.format + +local function RoundDecimalToPlace(d, place) + return tonumber(strformat("%." .. tostring(place) .. "f", d)) +end + +local function ClampValue(value, min, max) + return math.max(math.min(value, max), min) +end + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.slider:SetEnabled(not disable) + control.slidervalue:SetEditEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value then + if control.data.decimals then + value = RoundDecimalToPlace(value, control.data.decimals) + end + if control.data.clampInput ~= false then + local clamp = control.data.clampFunction or ClampValue + value = clamp(value, control.data.min, control.data.max) + end + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + + control.slider:SetValue(value) + control.slidervalue:SetText(value) +end + +function LAMCreateControl.slider(parent, sliderData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) + local isInputOnRight = sliderData.inputLocation == "right" + + --skipping creating the backdrop... Is this the actual slider texture? + control.slider = wm:CreateControl(nil, control.container, CT_SLIDER) + local slider = control.slider + slider:SetAnchor(TOPLEFT) + slider:SetHeight(14) + if(isInputOnRight) then + slider:SetAnchor(TOPRIGHT, nil, nil, -60) + else + slider:SetAnchor(TOPRIGHT) + end + slider:SetMouseEnabled(true) + slider:SetOrientation(ORIENTATION_HORIZONTAL) + --put nil for highlighted texture file path, and what look to be texture coords + slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16) + local minValue = sliderData.min + local maxValue = sliderData.max + slider:SetMinMax(minValue, maxValue) + slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + slider:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP) + local bg = slider.bg + bg:SetCenterColor(0, 0, 0) + bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4) + bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4) + + control.minText = wm:CreateControl(nil, slider, CT_LABEL) + local minText = control.minText + minText:SetFont("ZoFontGameSmall") + minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT) + minText:SetText(sliderData.min) + + control.maxText = wm:CreateControl(nil, slider, CT_LABEL) + local maxText = control.maxText + maxText:SetFont("ZoFontGameSmall") + maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT) + maxText:SetText(sliderData.max) + + control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop") + if(isInputOnRight) then + control.slidervalueBG:SetDimensions(60, 26) + control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0) + else + control.slidervalueBG:SetDimensions(50, 16) + control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0) + end + control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop") + local slidervalue = control.slidervalue + slidervalue:ClearAnchors() + slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1) + slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1) + slidervalue:SetTextType(TEXT_TYPE_NUMERIC) + if(isInputOnRight) then + slidervalue:SetFont("ZoFontGameLarge") + else + slidervalue:SetFont("ZoFontGameSmall") + end + + local isHandlingChange = false + local function HandleValueChanged(value) + if isHandlingChange then return end + if sliderData.decimals then + value = RoundDecimalToPlace(value, sliderData.decimals) + end + isHandlingChange = true + slider:SetValue(value) + slidervalue:SetText(value) + isHandlingChange = false + end + + slidervalue:SetHandler("OnEscape", function(self) + HandleValueChanged(sliderData.getFunc()) + self:LoseFocus() + end) + slidervalue:SetHandler("OnEnter", function(self) + self:LoseFocus() + end) + slidervalue:SetHandler("OnFocusLost", function(self) + local value = tonumber(self:GetText()) + control:UpdateValue(false, value) + end) + slidervalue:SetHandler("OnTextChanged", function(self) + local input = self:GetText() + if(#input > 1 and not input:sub(-1):match("[0-9]")) then return end + local value = tonumber(input) + if(value) then + HandleValueChanged(value) + end + end) + if(sliderData.autoSelect) then + ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self) + self:SelectAll() + end) + end + + local range = maxValue - minValue + slider:SetValueStep(sliderData.step or 1) + slider:SetHandler("OnValueChanged", function(self, value, eventReason) + if eventReason == EVENT_REASON_SOFTWARE then return end + HandleValueChanged(value) + end) + slider:SetHandler("OnSliderReleased", function(self, value) + if self:GetEnabled() then + control:UpdateValue(false, value) + end + end) + slider:SetHandler("OnMouseWheel", function(self, value) + if(not self:GetEnabled()) then return end + local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) + control:UpdateValue(false, new_value) + end) + + if sliderData.warning ~= nil or sliderData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + + if sliderData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/submenu.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/submenu.lua new file mode 100644 index 0000000..d7bc8bf --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/submenu.lua @@ -0,0 +1,182 @@ +--[[submenuData = { + type = "submenu", + name = "Submenu Title", -- or string id or function returning a string + icon = "path/to/my/icon.dds", -- or function returning a string (optional) + iconTextureCoords = {left, right, top, bottom}, -- or function returning a table (optional) + tooltip = "My submenu tooltip", -- or string id or function returning a string (optional) + controls = {sliderData, buttonData} -- used by LAM (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + disabledLabel = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonSubmenu" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("submenu", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local am = ANIMATION_MANAGER +local ICON_SIZE = 32 + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + if disable and control.open then + control.open = false + control.animation:PlayFromStart() + end + + control.arrow:SetColor(color:UnpackRGBA()) + control.disabled = disable + end + + local disableLabel = control.disabled or GetDefaultValue(control.data.disabledLabel) + if disableLabel ~= control.disabledLabel then + local color = GetColorForState(disableLabel) + control.label:SetColor(color:UnpackRGBA()) + if(control.icon) then + control.icon:SetDesaturation(disableLabel and 1 or 0) + end + control.disabledLabel = disableLabel + end +end + +local function UpdateValue(control) + control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) + + if control.icon then + control.icon:SetTexture(GetDefaultValue(control.data.icon)) + if(control.data.iconTextureCoords) then + local coords = GetDefaultValue(control.data.iconTextureCoords) + control.icon:SetTextureCoords(unpack(coords)) + end + end + + if control.data.tooltip then + control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) + end +end + +local function AnimateSubmenu(clicked) + local control = clicked:GetParent() + if control.disabled then return end + + control.open = not control.open + if control.open then + control.animation:PlayFromStart() + else + control.animation:PlayFromEnd() + end +end + +function LAMCreateControl.submenu(parent, submenuData, controlName) + local width = parent:GetWidth() - 45 + local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent + control.data = submenuData + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(LAM.util.GetStringFromValue(submenuData.name)) + label:SetMouseEnabled(true) + + if submenuData.icon then + control.icon = wm:CreateControl(nil, control, CT_TEXTURE) + local icon = control.icon + icon:SetTexture(GetDefaultValue(submenuData.icon)) + if(submenuData.iconTextureCoords) then + local coords = GetDefaultValue(submenuData.iconTextureCoords) + icon:SetTextureCoords(unpack(coords)) + end + icon:SetDimensions(ICON_SIZE, ICON_SIZE) + icon:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + icon:SetMouseEnabled(true) + icon:SetDrawLayer(DL_CONTROLS) + label:SetAnchor(TOP, control, TOP, 0, 5, ANCHOR_CONSTRAINS_Y) + label:SetAnchor(LEFT, icon, RIGHT, 10, 0, ANCHOR_CONSTRAINS_X) + label:SetDimensions(width - ICON_SIZE - 5, 30) + else + label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + label:SetDimensions(width, 30) + end + + if submenuData.tooltip then + label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} + label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + if control.icon then + control.icon.data = label.data + control.icon:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control.icon:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end + end + + control.scroll = wm:CreateControl(nil, control, CT_SCROLL) + local scroll = control.scroll + scroll:SetParent(control) + scroll:SetAnchor(TOPLEFT, control.icon or label, BOTTOMLEFT, 0, 10) + scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) + + control.bg = wm:CreateControl(nil, control.icon or label, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, control.icon or label, TOPLEFT, -5, -5) + bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + bg:SetDrawLayer(DL_BACKGROUND) + + control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) + local arrow = control.arrow + arrow:SetDimensions(28, 28) + arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way + arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5) + + --figure out the cool animation later... + control.animation = am:CreateTimeline() + local animation = control.animation + animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count + + control:SetResizeToFitDescendents(true) + control.open = false + label:SetHandler("OnMouseUp", AnimateSubmenu) + if(control.icon) then + control.icon:SetHandler("OnMouseUp", AnimateSubmenu) + end + animation:SetHandler("OnStop", function(self, completedPlaying) + scroll:SetResizeToFitDescendents(control.open) + if control.open then + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds") + scroll:SetResizeToFitPadding(5, 20) + else + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") + scroll:SetResizeToFitPadding(5, 0) + scroll:SetHeight(0) + end + end) + + --small strip at the bottom of the submenu that you can click to close it + control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE) + local btmToggle = control.btmToggle + btmToggle:SetMouseEnabled(true) + btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT) + btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT) + btmToggle:SetHeight(15) + btmToggle:SetAlpha(0) + btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) + + control.UpdateValue = UpdateValue + if submenuData.disabled ~= nil or submenuData.disabledLabel ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/texture.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/texture.lua new file mode 100644 index 0000000..6862ac2 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibAddonMenu-2.0/controls/texture.lua @@ -0,0 +1,45 @@ +--[[textureData = { + type = "texture", + image = "file/path.dds", + imageWidth = 64, -- max of 250 for half width, 510 for full + imageHeight = 32, -- max of 100 + tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + reference = "MyAddonTexture" -- unique global reference to control (optional) +} ]] + +-- TODO: add texture coords support? + +local widgetVersion = 9 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("texture", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local MIN_HEIGHT = 26 +function LAMCreateControl.texture(parent, textureData, controlName) + local control = LAM.util.CreateBaseControl(parent, textureData, controlName) + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) + else + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) + end + + control.texture = wm:CreateControl(nil, control, CT_TEXTURE) + local texture = control.texture + texture:SetAnchor(CENTER) + texture:SetDimensions(textureData.imageWidth, textureData.imageHeight) + texture:SetTexture(textureData.image) + + if textureData.tooltip then + texture:SetMouseEnabled(true) + texture.data = {tooltipText = LAM.util.GetStringFromValue(textureData.tooltip)} + texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + texture:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end + + return control +end diff --git a/Elder Scrolls Online Addons/Notebook2018/Libs/LibStub/LibStub.lua b/Elder Scrolls Online Addons/Notebook2018/Libs/LibStub/LibStub.lua new file mode 100644 index 0000000..e6b8997 --- /dev/null +++ b/Elder Scrolls Online Addons/Notebook2018/Libs/LibStub/LibStub.lua @@ -0,0 +1,38 @@ +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info +-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +-- LibStub developed for World of Warcraft by above members of the WowAce community. +-- Ported to Elder Scrolls Online by Seerah + +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 5 +local LibStub = _G[LIBSTUB_MAJOR] + +local strformat = string.format +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + if type(minor) ~= "number" then + minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.") + end + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(strformat("Cannot find a library instance of %q.", tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end + +LibStub.SILENT = true \ No newline at end of file diff --git a/Notebook2018/Notebook1.lua b/Elder Scrolls Online Addons/Notebook2018/Notebook1.lua similarity index 71% rename from Notebook2018/Notebook1.lua rename to Elder Scrolls Online Addons/Notebook2018/Notebook1.lua index d355a03..ce290fa 100644 --- a/Notebook2018/Notebook1.lua +++ b/Elder Scrolls Online Addons/Notebook2018/Notebook1.lua @@ -2,87 +2,221 @@ if NBUI == nil then NBUI = {} end local buttonCount = 1 local savedVarsStringMax = 1900 +local currentlyViewing = nil +local lastLineSelected = '' --------------------------------------------------------------------------------------------------- -function Set_Button_TextColors(button) +local function Set_Button_TextColors(button) -- Tinker with text color from settings. local color = {unpack(NBUI.db.NB1_TextColor)}; - + color[4] = 0.6 button:SetMouseOverFontColor(unpack(color)) - + color[4] = 0.7 button:SetNormalFontColor(unpack(color)) - + color[4] = 0.8 button:SetPressedFontColor(unpack(color)) end +-- Update the counter from number. +local function UpdateCharacterCounter(len) + NBUI.NBUI_NB1RightPage_CharacterCounter:SetText(len .. ' / ' .. savedVarsStringMax) +end + +local function CopyToChatInput(text) + CHAT_SYSTEM:StartTextEntry(text) + ZO_ChatWindowTextEntryEditBox:SelectAll() +end + +-- Create the right-click menu for each page selection. +local function CreateMenu(title, text, btnID) + -- Hide any other open menus. + ClearMenu() + + AddMenuItem(GetString(SI_NBUI_CONTEXT_RANDOMLINE), function() + -- Split into lines. + lines = {} + for line in text:gmatch('[^\r\n]+') do table.insert(lines, line) end + -- Pick a random line. Avoid repeating same selection. + l = lines[math.random(#lines)] + while #lines > 1 and l == lastLineSelected do + l = lines[math.random(#lines)] + end + CopyToChatInput(l) + -- Track. + lastLineSelected = l + end) + + AddMenuItem(GetString(SI_NBUI_CONTEXT_SENDASMAIL), function() + MAIN_MENU_KEYBOARD:Hide() -- In case it's open. Necessary! + MAIN_MENU_KEYBOARD:ShowScene("mailSend") + + SCENE_MANAGER:CallWhen("mailSend", SCENE_SHOWN, function() + -- MAIL_SEND:ClearFields() + MAIL_SEND.subject:SetText(title) + MAIL_SEND.body:SetText(text) + MAIL_SEND.to:TakeFocus() + end) + end) + + -- Aesthetically, only the currently selected page should have this option. + if currentlyViewing == btnID then + AddMenuItem(GetString(SI_NBUI_CONTEXT_COPYFROMMAIL), function() + -- No mail is selected if empty or just logged in / reloadui. + if MAIL_INBOX.selectedData then + local subject = MAIL_INBOX.selectedData.subject + local body = ReadMail(MAIL_INBOX.selectedData.mailId) + + -- Add into current page. NOTE This doesn't also save the changes. + NBUI.NB1RightPage_Title:SetText(NBUI.UnprotectText(subject)) + NBUI.NB1RightPage_Title:SetCursorPosition(0) + + NBUI.NB1RightPage_Contents:SetText(NBUI.UnprotectText(body)) + NBUI.NB1RightPage_Contents:SetCursorPosition(0) + + -- Update buttons. + NBUI.NB1SavePage_Button:SetHidden(false) + NBUI.NBUI_NB1RightPage_CharacterCounter:SetHidden(false) + + -- Update character counter. + UpdateCharacterCounter(#body) + else + d(GetString(SI_NBUI_ERROR_INBOXSELECT)) + end + end) + end + + ShowMenu(NBUI.NB1MainWindow) +end + function Create_NB1_IndexButton(NB1_IndexPool) local button = WINDOW_MANAGER:CreateControlFromVirtual("NB1_Index" .. NB1_IndexPool:GetNextControlId(), NBUI.NB1LeftPage_ScrollContainer.scrollChild, "ZO_DefaultTextButton") local anchorBtn = buttonCount == 1 and NBUI.NB1LeftPage_ScrollContainer.scrollChild or NB1_IndexPool:AcquireObject(buttonCount-1) - button:SetAnchor(TOPLEFT, anchorBtn, buttonCount == 1 and TOPLEFT or BOTTOMLEFT) - button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) - button:SetFont("ZoFontBookPaper") - button:SetHandler("OnClicked", function(self) + + button:SetAnchor(TOPLEFT, anchorBtn, buttonCount == 1 and TOPLEFT or BOTTOMLEFT) + button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) + button:SetFont("ZoFontBookPaper") + button:EnableMouseButton(MOUSE_BUTTON_INDEX_RIGHT, true) + + button:SetHandler("OnClicked", function(self, button , ctrl , alt , shift , command) + -- Page selection, or loaded at startup. + if button == MOUSE_BUTTON_INDEX_LEFT or not button then + -- File global variable! currentlyViewing = self.id - - NBUI.NB1RightPage_Title:SetHidden(false) - NBUI.NB1RightPage_ScrollContainer:SetHidden(false) - - -- Bug with unsaved variables from game. - local title = self.data.title - if title == nil then - title = "" - end - NBUI.NB1RightPage_Title:SetText(UnprotectText(title)) - NBUI.NB1RightPage_Title:SetCursorPosition(0) - - -- Bug with unsaved variables from game. - local text = self.data.text - if text == nil then - text = "" - end - NBUI.NB1RightPage_Contents:SetText(UnprotectText(text)) - NBUI.NB1RightPage_Contents:SetCursorPosition(0) - - NBUI.NB1SelectedPage_Button:ClearAnchors() - NBUI.NB1SelectedPage_Button:SetAnchorFill(self) - -- hides these buttons - NBUI.NB1SavePage_Button:SetHidden(true) - NBUI.NB1UndoPage_Button:SetHidden(true) - -- shows these buttons - -- NBUI.NB1RunScript_Button:SetHidden(false) - NBUI.NB1SelectedPage_Button:SetHidden(false) - NBUI.NB1DeletePage_Button:SetHidden(false) - NBUI.NB1MovePageUp_Button:SetHidden(false) - NBUI.NB1MovePageDown_Button:SetHidden(false) - NBUI.NBUI_NB1RightPage_CharacterCounter:SetHidden(true) - end) - button:SetWidth(400) - button:SetHorizontalAlignment(TEXT_ALIGN_LEFT) - Set_Button_TextColors(button) - + -- Track page viewed, to reopen on game reload. + NBUI.db.NB1_LastPageSeen = currentlyViewing + end + + -- Bug with unsaved variables from game. + local title = self.data.title + if title == nil then + title = "" + end + + -- Bug with unsaved variables from game. + local text = self.data.text + if text == nil then + text = "" + end + + -- Right click for menu. + if button == MOUSE_BUTTON_INDEX_RIGHT then + CreateMenu(title, text, self.id) + return + end + + -- Left click to display. + NBUI.NB1RightPage_Title:SetHidden(false) + NBUI.NB1RightPage_ScrollContainer:SetHidden(false) + + NBUI.NB1RightPage_Title:SetText(NBUI.UnprotectText(title)) + NBUI.NB1RightPage_Title:SetCursorPosition(0) + + NBUI.NB1RightPage_Contents:SetText(NBUI.UnprotectText(text)) + NBUI.NB1RightPage_Contents:SetCursorPosition(0) + + NBUI.NB1SelectedPage_Button:ClearAnchors() + NBUI.NB1SelectedPage_Button:SetAnchorFill(self) + -- hides these buttons + NBUI.NB1SavePage_Button:SetHidden(true) + -- NBUI.NB1UndoPage_Button:SetHidden(true) + -- shows these buttons + -- NBUI.NB1RunScript_Button:SetHidden(false) + NBUI.NB1SelectedPage_Button:SetHidden(false) + NBUI.NB1DeletePage_Button:SetHidden(false) + NBUI.NB1MovePageUp_Button:SetHidden(false) + NBUI.NB1MovePageDown_Button:SetHidden(false) + NBUI.NBUI_NB1RightPage_CharacterCounter:SetHidden(true) + end) + + button:SetWidth(400) + button:SetHorizontalAlignment(TEXT_ALIGN_LEFT) + Set_Button_TextColors(button) + buttonCount = buttonCount + 1 return button end --------------------------------------------------------------------------------------------------- -function Populate_NB1_ScrollList() +function Populate_NB1_ScrollList(noPageSelect) + -- Load all pages from db. local numPages = #NBUI.db.NB1Pages for i = 1, numPages do local button = NB1_IndexPool:AcquireObject(i) button.data = NBUI.db.NB1Pages[i] button.id = i - button:SetText(UnprotectText(button.data.title)) + + local title = button.data.title + title = NBUI.NoTagsText(title) + + if title == '---' then + button:SetText('|t400:2:esoui/art/miscellaneous/horizontaldivider.dds|t') + -- esoui/art/miscellaneous/horizontaldivider.dds + -- esoui/art/campaign/campaignbrowser_divider_short.dds + -- esoui/art/guild/sectiondivider_left.dds + -- esoui/art/miscellaneous/wide_divider_left.dds + -- button:SetAlpha(1) + else + button:SetText(NBUI.UnprotectText(title)) + end + button:SetHidden(false) + Set_Button_TextColors(button) end + + -- Remove unsaved pages from pool. local activePages = NB1_IndexPool:GetActiveObjectCount() if activePages > numPages then for i = numPages+1, activePages do NB1_IndexPool:ReleaseObject(i) end end + + -- Select a page automatically, if there are any, unless unwanted. + if not noPageSelect and numPages > 0 then + local last = NBUI.db.NB1_LastPageSeen + + if currentlyViewing then + -- Stay on current page, it was just saved. + last = currentlyViewing + else + -- Last page was deleted, so go one back. + if last - 1 == numPages then + last = last - 1 + end + end + + -- Get the button object. + local po = NB1_IndexPool:AcquireObject(last) + + -- At least one page is available. + if po then + -- Display it. + zo_callHandler(po, "OnClicked") + end + end end --------------------------------------------------------------------------------------------------- function Remove_NB1_IndexButton(button) @@ -96,129 +230,145 @@ function CreateNB1() local color = {unpack(NBUI.db.NB1_TextColor)}; --------------------------------------------------------------------------------------------------- NBUI.NB1MainWindow = WINDOW_MANAGER:CreateTopLevelWindow("NBUI_NB1MainWindow") - SCENE_MANAGER:RegisterTopLevel(NBUI.NB1MainWindow, false) + SCENE_MANAGER:RegisterTopLevel(NBUI.NB1MainWindow, false) NBUI.NB1MainWindow:AllowBringToTop(true) NBUI.NB1MainWindow:SetAnchor(NBUI.db.NB1_Anchor.a, GuiRoot, NBUI.db.NB1_Anchor.b, NBUI.db.NB1_Anchor.x, NBUI.db.NB1_Anchor.y) - NBUI.NB1MainWindow:SetClampedToScreen(true) + NBUI.NB1MainWindow:SetClampedToScreen(true) NBUI.NB1MainWindow:SetDimensions(1004, 752) - NBUI.NB1MainWindow:SetDrawLayer(0) - NBUI.NB1MainWindow:SetDrawLevel(0) - NBUI.NB1MainWindow:SetDrawTier(0) + + NBUI.NB1MainWindow:SetDrawTier(0) + local layer = 0 + if NBUI.db.NB1_OnTop then + layer = 1 + end + NBUI.NB1MainWindow:SetDrawLayer(layer) -- Can be on top of other UI elements. + NBUI.NB1MainWindow:SetDrawLevel(0) + NBUI.NB1MainWindow:SetHandler("OnMoveStop", function(self) local _,a,_,b,x,y = self:GetAnchor() NBUI.db.anchor = {["a"]=a, ["b"]=b, ["x"]=x, ["y"]=y} - end) + end) NBUI.NB1MainWindow:SetHandler("OnReceiveDrag", function(self) self:StartMoving() - end) - NBUI.NB1MainWindow:SetHidden(true) - NBUI.NB1MainWindow:SetMouseEnabled(true) + end) + NBUI.NB1MainWindow:SetHidden(true) + NBUI.NB1MainWindow:SetMouseEnabled(true) NBUI.NB1MainWindow:SetMovable(not NBUI.db.NB1_Locked) -- Add fragment to scene, like other UI elements. -- local fragment = ZO_HUDFadeSceneFragment:New(NBUI.NB1MainWindow) -- Add to scenes. -- HUD_SCENE:AddFragment(fragment) -- HUD_UI_SCENE:AddFragment(fragment) ---------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------- NBUI.NB1MainWindow_Cover = WINDOW_MANAGER:CreateControl("NBUI_NB1MainWindow_Cover", NBUI.NB1MainWindow, CT_TEXTURE) NBUI.NB1MainWindow_Cover:SetAnchor(TOPLEFT, NBUI.NB1MainWindow, TOPLEFT, -10, -126) - NBUI.NB1MainWindow_Cover:SetAnchor(BOTTOMRIGHT, NBUI.NB1MainWindow, BOTTOMRIGHT, 10, 146) + NBUI.NB1MainWindow_Cover:SetAnchor(BOTTOMRIGHT, NBUI.NB1MainWindow, BOTTOMRIGHT, 10, 146) NBUI.NB1MainWindow_Cover:SetDimensions(1024, 1024) - NBUI.NB1MainWindow_Cover:SetTexture("/esoui/art/lorelibrary/lorelibrary_paperbook.dds") + NBUI.NB1MainWindow_Cover:SetTexture(NBUI.db.NB1_BookTexture) NBUI.NB1MainWindow_Cover:SetColor(unpack(NBUI.db.NB1_BookColor)) NBUI.NB1MainWindow_Cover:SetAlpha(1) ---***********************************************************************************************-- +--***********************************************************************************************-- -- LEFT PAGE ------------------------------------------------------------------------------------ NBUI.NB1LeftPage_TitleBackdrop = WINDOW_MANAGER:CreateControlFromVirtual("NBUI_NB1LeftPage_TitleBackdrop", NBUI.NB1MainWindow, "ZO_EditBackdrop") - NBUI.NB1LeftPage_TitleBackdrop:SetAnchor(TOPLEFT, NBUI.NB1MainWindow_Cover, TOPLEFT, 85, 160) - NBUI.NB1LeftPage_TitleBackdrop:SetCenterColor(0, 0, 0, 0) + NBUI.NB1LeftPage_TitleBackdrop:SetAnchor(TOPLEFT, NBUI.NB1MainWindow_Cover, TOPLEFT, 85, 160) + NBUI.NB1LeftPage_TitleBackdrop:SetCenterColor(0, 0, 0, 0) NBUI.NB1LeftPage_TitleBackdrop:SetDimensions(420, 45) - NBUI.NB1LeftPage_TitleBackdrop:SetDrawLayer(0) + NBUI.NB1LeftPage_TitleBackdrop:SetDrawLayer(0) NBUI.NB1LeftPage_TitleBackdrop:SetDrawLevel(1) - NBUI.NB1LeftPage_TitleBackdrop:SetDrawTier(0) + NBUI.NB1LeftPage_TitleBackdrop:SetDrawTier(0) NBUI.NB1LeftPage_TitleBackdrop:SetEdgeColor(0, 0, 0, 0) - NBUI.NB1LeftPage_TitleBackdrop:SetHidden(not NBUI.db.NB1_ShowTitle) ---------------------------------------------------------------------------------------------------- + NBUI.NB1LeftPage_TitleBackdrop:SetHidden(not NBUI.db.NB1_ShowTitle) +--------------------------------------------------------------------------------------------------- NBUI.NB1LeftPage_Title = WINDOW_MANAGER:CreateControl("NBUI_NB1LeftPage_Title", NBUI.NB1MainWindow, CT_LABEL) NBUI.NB1LeftPage_Title:SetAnchor(CENTER, NBUI.NB1LeftPage_TitleBackdrop, CENTER, 0, 0) NBUI.NB1LeftPage_Title:SetColor(unpack(NBUI.db.NB1_TextColor)) - NBUI.NB1LeftPage_Title:SetDrawLayer(0) + NBUI.NB1LeftPage_Title:SetDrawLayer(0) NBUI.NB1LeftPage_Title:SetDrawLevel(2) - NBUI.NB1LeftPage_Title:SetDrawTier(0) + NBUI.NB1LeftPage_Title:SetDrawTier(0) NBUI.NB1LeftPage_Title:SetFont("ZoFontBookPaperTitle") - NBUI.NB1LeftPage_Title:SetHidden(not NBUI.db.NB1_ShowTitle) + NBUI.NB1LeftPage_Title:SetHidden(not NBUI.db.NB1_ShowTitle) NBUI.NB1LeftPage_Title:SetText(NBUI.db.NB1_Title) --------------------------------------------------------------------------------------------------- NBUI.NB1Information_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1Information_Button", NBUI.NB1MainWindow, CT_BUTTON) - NBUI.NB1Information_Button:SetAnchor(CENTER, NBUI.NB1LeftPage_TitleBackdrop, RIGHT, -30, 0) + NBUI.NB1Information_Button:SetAnchor(CENTER, NBUI.NB1LeftPage_TitleBackdrop, RIGHT, -30, 0) NBUI.NB1Information_Button:SetDimensions(32, 32) - NBUI.NB1Information_Button:SetDrawLayer(1) + NBUI.NB1Information_Button:SetDrawLayer(1) NBUI.NB1Information_Button:SetDrawLevel(1) - NBUI.NB1Information_Button:SetDrawTier(0) - NBUI.NB1Information_Button:SetHandler("OnClicked", function(self) + NBUI.NB1Information_Button:SetDrawTier(0) + NBUI.NB1Information_Button:SetHandler("OnMouseEnter", function(self) InitializeTooltip(InformationTooltip, self, TOPLEFT, 0, 0, BOTTOMRIGHT) SetTooltipText(InformationTooltip, GetString(SI_NBUI_NB1INFORMATION_TOOLTIP)) end) NBUI.NB1Information_Button:SetHandler("OnMouseExit", function(self) ClearTooltip(InformationTooltip) end) - NBUI.NB1Information_Button:SetHidden(not NBUI.db.NB1_ShowTitle) + NBUI.NB1Information_Button:SetHidden(not NBUI.db.NB1_ShowTitle) NBUI.NB1Information_Button:SetMouseOverTexture("/esoui/art/buttons/info_over.dds") NBUI.NB1Information_Button:SetNormalTexture("/esoui/art/buttons/info_up.dds") NBUI.NB1Information_Button:SetPressedTexture("/esoui/art/buttons/info_down.dds") ---------------------------------------------------------------------------------------------------- - NBUI.NB1LeftPage_Separator = WINDOW_MANAGER:CreateControl("NBUI_NB1LeftPage_Separator", NBUI.NB1MainWindow, CT_TEXTURE) - NBUI.NB1LeftPage_Separator:SetAnchor(CENTER, NBUI.NB1LeftPage_TitleBackdrop, BOTTOM, 0, 0) +--------------------------------------------------------------------------------------------------- + NBUI.NB1LeftPage_Separator = WINDOW_MANAGER:CreateControl("NBUI_NB1LeftPage_Separator", NBUI.NB1MainWindow, CT_TEXTURE) + NBUI.NB1LeftPage_Separator:SetAnchor(CENTER, NBUI.NB1LeftPage_TitleBackdrop, BOTTOM, 0, 0) NBUI.NB1LeftPage_Separator:SetColor(unpack(NBUI.db.NB1_TextColor)) NBUI.NB1LeftPage_Separator:SetDimensions(420, 2) - NBUI.NB1LeftPage_Separator:SetDrawLayer(1) + NBUI.NB1LeftPage_Separator:SetDrawLayer(1) NBUI.NB1LeftPage_Separator:SetDrawLevel(1) - NBUI.NB1LeftPage_Separator:SetDrawTier(0) + NBUI.NB1LeftPage_Separator:SetDrawTier(0) NBUI.NB1LeftPage_Separator:SetHidden(not NBUI.db.NB1_ShowTitle) - NBUI.NB1LeftPage_Separator:SetTexture("/esoui/art/interaction/conversation_divider.dds") + NBUI.NB1LeftPage_Separator:SetTexture("/esoui/art/interaction/conversation_divider.dds") --------------------------------------------------------------------------------------------------- NBUI.NB1LeftPage_Backdrop = WINDOW_MANAGER:CreateControlFromVirtual("NBUI_NB1LeftPage_Backdrop", NBUI.NB1MainWindow, "ZO_EditBackdrop") - NBUI.NB1LeftPage_Backdrop:SetAnchor(BOTTOMLEFT, NBUI.NB1MainWindow_Cover, BOTTOMLEFT, 85, -164) + local top + if (NBUI.db.NB1_ShowTitle) then + top = 220 + else + top = 170 + end + + local height + if (NBUI.db.NB1_ShowTitle) then + height = 625 + else + height = 670 + end + + NBUI.NB1LeftPage_Backdrop:SetAnchor(TOPLEFT, NBUI.NB1MainWindow_Cover, TOPLEFT, 90, top) NBUI.NB1LeftPage_Backdrop:SetCenterColor(0, 0, 0, 0) - if (NBUI.db.NB1_ShowTitle) then - NBUI.NB1LeftPage_Backdrop:SetDimensions(420, 645) - else - NBUI.NB1LeftPage_Backdrop:SetDimensions(420, 690) - end - NBUI.NB1LeftPage_Backdrop:SetDrawLayer(0) + NBUI.NB1LeftPage_Backdrop:SetDimensions(420, height) + NBUI.NB1LeftPage_Backdrop:SetDrawLayer(0) NBUI.NB1LeftPage_Backdrop:SetDrawLevel(1) - NBUI.NB1LeftPage_Backdrop:SetDrawTier(0) - NBUI.NB1LeftPage_Backdrop:SetEdgeColor(0, 0, 0, 0) + NBUI.NB1LeftPage_Backdrop:SetDrawTier(0) + NBUI.NB1LeftPage_Backdrop:SetEdgeColor(0, 0, 0, 0) --------------------------------------------------------------------------------------------------- NBUI.NB1LeftPage_ScrollContainer = WINDOW_MANAGER:CreateControlFromVirtual("NBUI_NB1LeftPage_ScrollContainer", NBUI.NB1MainWindow, "ZO_ScrollContainer") - NBUI.NB1LeftPage_ScrollContainer.scrollChild = NBUI.NB1LeftPage_ScrollContainer:GetNamedChild("ScrollChild") + NBUI.NB1LeftPage_ScrollContainer.scrollChild = NBUI.NB1LeftPage_ScrollContainer:GetNamedChild("ScrollChild") NBUI.NB1LeftPage_ScrollContainer:SetAnchorFill(NBUI.NB1LeftPage_Backdrop) - NBUI.NB1LeftPage_ScrollContainer:SetDrawLayer(0) + NBUI.NB1LeftPage_ScrollContainer:SetDrawLayer(0) NBUI.NB1LeftPage_ScrollContainer:SetDrawLevel(2) NBUI.NB1LeftPage_ScrollContainer:SetDrawTier(0) ---------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------- NBUI.NB1SelectedPage_Button = WINDOW_MANAGER:CreateControl(nil, NBUI.NB1LeftPage_ScrollContainer.scrollChild, CT_TEXTURE) - NBUI.NB1SelectedPage_Button:SetAlpha(.45) - NBUI.NB1SelectedPage_Button:SetDrawLayer(0) - NBUI.NB1SelectedPage_Button:SetDrawLevel(3) - NBUI.NB1SelectedPage_Button:SetDrawTier(0) + NBUI.NB1SelectedPage_Button:SetAlpha(.45) + NBUI.NB1SelectedPage_Button:SetDrawLayer(0) + NBUI.NB1SelectedPage_Button:SetDrawLevel(3) + NBUI.NB1SelectedPage_Button:SetDrawTier(0) NBUI.NB1SelectedPage_Button:SetHidden(true) NBUI.NB1SelectedPage_Button:SetTexture("esoui/art/buttons/generic_highlight.dds") NBUI.NB1SelectedPage_Button:SetWidth(420) ---------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------- NBUI.NB1SavePage_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1SavePage_Button", NBUI.NB1LeftPage_ScrollContainer.scrollChild, CT_BUTTON) - NBUI.NB1SavePage_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -60, -2) + NBUI.NB1SavePage_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -30, -2) NBUI.NB1SavePage_Button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) NBUI.NB1SavePage_Button:SetDimensions(30, 30) - NBUI.NB1SavePage_Button:SetDrawLayer(1) + NBUI.NB1SavePage_Button:SetDrawLayer(2) NBUI.NB1SavePage_Button:SetDrawLevel(1) - NBUI.NB1SavePage_Button:SetDrawTier(0) + NBUI.NB1SavePage_Button:SetDrawTier(0) NBUI.NB1SavePage_Button:SetHandler("OnClicked", function(self) if (NBUI.db.NB1_ShowDialog) then ZO_Dialogs_ShowDialog("NBUI_NB1CONFIRM_SAVE") else NBUI.NB1SavePage(self) - end + end end) NBUI.NB1SavePage_Button:SetHandler("OnMouseEnter", function(self) InitializeTooltip(InformationTooltip, self, TOPLEFT, 0, 0, BOTTOMRIGHT) @@ -227,18 +377,18 @@ function CreateNB1() NBUI.NB1SavePage_Button:SetHandler("OnMouseExit", function(self) ClearTooltip(InformationTooltip) end) - NBUI.NB1SavePage_Button:SetHidden(true) + NBUI.NB1SavePage_Button:SetHidden(true) NBUI.NB1SavePage_Button:SetMouseOverTexture("/esoui/art/buttons/edit_save_over.dds") NBUI.NB1SavePage_Button:SetNormalTexture("/esoui/art/buttons/edit_save_up.dds") - NBUI.NB1SavePage_Button:SetPressedTexture("/esoui/art/buttons/edit_save_down.dds") ---------------------------------------------------------------------------------------------------- + NBUI.NB1SavePage_Button:SetPressedTexture("/esoui/art/buttons/edit_save_down.dds") +--------------------------------------------------------------------------------------------------- NBUI.NB1MovePageUp_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1MovePageUp_Button", NBUI.NB1LeftPage_ScrollContainer.scrollChild, CT_BUTTON) - NBUI.NB1MovePageUp_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -126, 0) + NBUI.NB1MovePageUp_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -96, 0) NBUI.NB1MovePageUp_Button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) NBUI.NB1MovePageUp_Button:SetDimensions(20, 20) - NBUI.NB1MovePageUp_Button:SetDrawLayer(1) + NBUI.NB1MovePageUp_Button:SetDrawLayer(2) NBUI.NB1MovePageUp_Button:SetDrawLevel(1) - NBUI.NB1MovePageUp_Button:SetDrawTier(0) + NBUI.NB1MovePageUp_Button:SetDrawTier(0) NBUI.NB1MovePageUp_Button:SetHandler("OnClicked", function(self) -- if (NBUI.db.NB1_ShowDialog) then -- ZO_Dialogs_ShowDialog("NBUI_NB1CONFIRM_MOVEPAGEUP") @@ -253,18 +403,18 @@ function CreateNB1() NBUI.NB1MovePageUp_Button:SetHandler("OnMouseExit", function(self) ClearTooltip(InformationTooltip) end) - NBUI.NB1MovePageUp_Button:SetHidden(true) + NBUI.NB1MovePageUp_Button:SetHidden(true) NBUI.NB1MovePageUp_Button:SetMouseOverTexture("esoui/art/buttons/gamepad/gp_uparrow.dds") NBUI.NB1MovePageUp_Button:SetNormalTexture("esoui/art/buttons/gamepad/gp_uparrow.dds") - NBUI.NB1MovePageUp_Button:SetPressedTexture("esoui/art/buttons/gamepad/gp_uparrow.dds") ---------------------------------------------------------------------------------------------------- + NBUI.NB1MovePageUp_Button:SetPressedTexture("esoui/art/buttons/gamepad/gp_uparrow.dds") +--------------------------------------------------------------------------------------------------- NBUI.NB1MovePageDown_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1MovePageDown_Button", NBUI.NB1LeftPage_ScrollContainer.scrollChild, CT_BUTTON) - NBUI.NB1MovePageDown_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -96, 0) + NBUI.NB1MovePageDown_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -66, 0) NBUI.NB1MovePageDown_Button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) NBUI.NB1MovePageDown_Button:SetDimensions(20, 20) - NBUI.NB1MovePageDown_Button:SetDrawLayer(1) + NBUI.NB1MovePageDown_Button:SetDrawLayer(2) NBUI.NB1MovePageDown_Button:SetDrawLevel(1) - NBUI.NB1MovePageDown_Button:SetDrawTier(0) + NBUI.NB1MovePageDown_Button:SetDrawTier(0) NBUI.NB1MovePageDown_Button:SetHandler("OnClicked", function(self) -- if (NBUI.db.NB1_ShowDialog) then -- ZO_Dialogs_ShowDialog("NBUI_NB1CONFIRM_MOVEPAGEDOWN") @@ -279,44 +429,44 @@ function CreateNB1() NBUI.NB1MovePageDown_Button:SetHandler("OnMouseExit", function(self) ClearTooltip(InformationTooltip) end) - NBUI.NB1MovePageDown_Button:SetHidden(true) + NBUI.NB1MovePageDown_Button:SetHidden(true) NBUI.NB1MovePageDown_Button:SetMouseOverTexture("esoui/art/buttons/gamepad/gp_downarrow.dds") NBUI.NB1MovePageDown_Button:SetNormalTexture("esoui/art/buttons/gamepad/gp_downarrow.dds") NBUI.NB1MovePageDown_Button:SetPressedTexture("esoui/art/buttons/gamepad/gp_downarrow.dds") ---------------------------------------------------------------------------------------------------- - NBUI.NB1UndoPage_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1UndoPage_Button", NBUI.NB1LeftPage_ScrollContainer.scrollChild, CT_BUTTON) - NBUI.NB1UndoPage_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -30, 0) - NBUI.NB1UndoPage_Button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) - NBUI.NB1UndoPage_Button:SetDimensions(32, 35) - NBUI.NB1UndoPage_Button:SetDrawLayer(1) - NBUI.NB1UndoPage_Button:SetDrawLevel(1) - NBUI.NB1UndoPage_Button:SetDrawTier(0) - NBUI.NB1UndoPage_Button:SetHandler("OnClicked", function(self) - if (NBUI.db.NB1_ShowDialog) then - ZO_Dialogs_ShowDialog("NBUI_NB1CONFIRM_UNDO") - else - NBUI.NB1UndoPage() - end - end) - NBUI.NB1UndoPage_Button:SetHandler("OnMouseEnter", function(self) - InitializeTooltip(InformationTooltip, self, TOPLEFT, 0, 0, BOTTOMRIGHT) - SetTooltipText(InformationTooltip, GetString(SI_NBUI_UNDOBUTTON_TOOLTIP)) - end) - NBUI.NB1UndoPage_Button:SetHandler("OnMouseExit", function(self) - ClearTooltip(InformationTooltip) - end) - NBUI.NB1UndoPage_Button:SetHidden(true) - NBUI.NB1UndoPage_Button:SetMouseOverTexture("/esoui/art/contacts/social_note_over.dds") - NBUI.NB1UndoPage_Button:SetNormalTexture("/esoui/art/contacts/social_note_up.dds") - NBUI.NB1UndoPage_Button:SetPressedTexture("/esoui/art/contacts/social_note_down.dds") ---------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------- + -- NBUI.NB1UndoPage_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1UndoPage_Button", NBUI.NB1LeftPage_ScrollContainer.scrollChild, CT_BUTTON) + -- NBUI.NB1UndoPage_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -30, 0) + -- NBUI.NB1UndoPage_Button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) + -- NBUI.NB1UndoPage_Button:SetDimensions(32, 35) + -- NBUI.NB1UndoPage_Button:SetDrawLayer(2) + -- NBUI.NB1UndoPage_Button:SetDrawLevel(1) + -- NBUI.NB1UndoPage_Button:SetDrawTier(0) + -- NBUI.NB1UndoPage_Button:SetHandler("OnClicked", function(self) + -- if (NBUI.db.NB1_ShowDialog) then + -- ZO_Dialogs_ShowDialog("NBUI_NB1CONFIRM_UNDO") + -- else + -- NBUI.NB1UndoPage() + -- end + -- end) + -- NBUI.NB1UndoPage_Button:SetHandler("OnMouseEnter", function(self) + -- InitializeTooltip(InformationTooltip, self, TOPLEFT, 0, 0, BOTTOMRIGHT) + -- SetTooltipText(InformationTooltip, GetString(SI_NBUI_UNDOBUTTON_TOOLTIP)) + -- end) + -- NBUI.NB1UndoPage_Button:SetHandler("OnMouseExit", function(self) + -- ClearTooltip(InformationTooltip) + -- end) + -- NBUI.NB1UndoPage_Button:SetHidden(true) + -- NBUI.NB1UndoPage_Button:SetMouseOverTexture("/esoui/art/contacts/social_note_over.dds") + -- NBUI.NB1UndoPage_Button:SetNormalTexture("/esoui/art/contacts/social_note_up.dds") + -- NBUI.NB1UndoPage_Button:SetPressedTexture("/esoui/art/contacts/social_note_down.dds") +--------------------------------------------------------------------------------------------------- -- NBUI.NB1RunScript_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1RunScript_Button", NBUI.NB1LeftPage_ScrollContainer.scrollChild, CT_BUTTON) - -- NBUI.NB1RunScript_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -30, -2) + -- NBUI.NB1RunScript_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, -30, -2) -- NBUI.NB1RunScript_Button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) -- NBUI.NB1RunScript_Button:SetDimensions(28, 28) - -- NBUI.NB1RunScript_Button:SetDrawLayer(1) + -- NBUI.NB1RunScript_Button:SetDrawLayer(2) -- NBUI.NB1RunScript_Button:SetDrawLevel(1) - -- NBUI.NB1RunScript_Button:SetDrawTier(0) + -- NBUI.NB1RunScript_Button:SetDrawTier(0) -- NBUI.NB1RunScript_Button:SetHandler("OnClicked", function(self) -- local NBUIScript = zo_loadstring(NBUI.NB1RightPage_Contents:GetText()) -- if NBUIScript then @@ -330,24 +480,26 @@ function CreateNB1() -- NBUI.NB1RunScript_Button:SetHandler("OnMouseExit", function(self) -- ClearTooltip(InformationTooltip) -- end) - -- NBUI.NB1RunScript_Button:SetHidden(true) + -- NBUI.NB1RunScript_Button:SetHidden(true) -- NBUI.NB1RunScript_Button:SetMouseOverTexture("/esoui/art/buttons/edit_over.dds") -- NBUI.NB1RunScript_Button:SetNormalTexture("/esoui/art/buttons/edit_up.dds") -- NBUI.NB1RunScript_Button:SetPressedTexture("/esoui/art/buttons/edit_down.dds") --------------------------------------------------------------------------------------------------- NBUI.NB1DeletePage_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1DeletePage_Button", NBUI.NB1LeftPage_ScrollContainer.scrollChild, CT_BUTTON) - NBUI.NB1DeletePage_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, 0, 0) + NBUI.NB1DeletePage_Button:SetAnchor(RIGHT, NBUI.NB1SelectedPage_Button, RIGHT, 0, 0) NBUI.NB1DeletePage_Button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) NBUI.NB1DeletePage_Button:SetDimensions(26, 26) - NBUI.NB1DeletePage_Button:SetDrawLayer(1) + NBUI.NB1DeletePage_Button:SetDrawLayer(2) NBUI.NB1DeletePage_Button:SetDrawLevel(1) NBUI.NB1DeletePage_Button:SetDrawTier(0) NBUI.NB1DeletePage_Button:SetHandler("OnClicked", function(self) - if (NBUI.db.NB1_ShowDialog) then - ZO_Dialogs_ShowDialog("NBUI_NB1CONFIRM_DELETE") - else - NBUI.NB1DeletePage() - end + -- if (NBUI.db.NB1_ShowDialog) then + -- ZO_Dialogs_ShowDialog("NBUI_NB1CONFIRM_DELETE") + -- else + -- NBUI.NB1DeletePage() + -- end + -- NOTE Always confirm deletion! + ZO_Dialogs_ShowDialog("NBUI_NB1CONFIRM_DELETE") end) NBUI.NB1DeletePage_Button:SetHandler("OnMouseEnter", function(self) InitializeTooltip(InformationTooltip, self, TOPLEFT, 0, 0, BOTTOMRIGHT) @@ -355,68 +507,68 @@ function CreateNB1() end) NBUI.NB1DeletePage_Button:SetHandler("OnMouseExit", function(self) ClearTooltip(InformationTooltip) - end) + end) NBUI.NB1DeletePage_Button:SetMouseOverTexture("/esoui/art/buttons/decline_over.dds") NBUI.NB1DeletePage_Button:SetNormalTexture("/esoui/art/buttons/decline_up.dds") - NBUI.NB1DeletePage_Button:SetPressedTexture("/esoui/art/buttons/decline_down.dds") ---***********************************************************************************************-- --- RIGHT PAGE ----------------------------------------------------------------------------------- + NBUI.NB1DeletePage_Button:SetPressedTexture("/esoui/art/buttons/decline_down.dds") +--***********************************************************************************************-- +-- RIGHT PAGE ----------------------------------------------------------------------------------- NBUI.NB1RightPage_TitleBackdrop = WINDOW_MANAGER:CreateControlFromVirtual("NBUI_NB1RightPage_TitleBackdrop", NBUI.NB1MainWindow, "ZO_EditBackdrop") - NBUI.NB1RightPage_TitleBackdrop:SetAnchor(TOPRIGHT, NBUI.NB1MainWindow_Cover, TOPRIGHT, -70, 160) - NBUI.NB1RightPage_TitleBackdrop:SetCenterColor(0, 0, 0, 0) + NBUI.NB1RightPage_TitleBackdrop:SetAnchor(TOPRIGHT, NBUI.NB1MainWindow_Cover, TOPRIGHT, -70, 160) + NBUI.NB1RightPage_TitleBackdrop:SetCenterColor(0, 0, 0, 0) NBUI.NB1RightPage_TitleBackdrop:SetDimensions(420, 45) NBUI.NB1RightPage_TitleBackdrop:SetDrawLayer(0) NBUI.NB1RightPage_TitleBackdrop:SetDrawLevel(1) - NBUI.NB1RightPage_TitleBackdrop:SetDrawTier(0) - NBUI.NB1RightPage_TitleBackdrop:SetEdgeColor(0, 0, 0, 0) ---------------------------------------------------------------------------------------------------- + NBUI.NB1RightPage_TitleBackdrop:SetDrawTier(0) + NBUI.NB1RightPage_TitleBackdrop:SetEdgeColor(0, 0, 0, 0) +--------------------------------------------------------------------------------------------------- NBUI.NB1RightPage_Backdrop = WINDOW_MANAGER:CreateControlFromVirtual("NBUI_NB1RightPage_Backdrop", NBUI.NB1MainWindow, "ZO_EditBackdrop") - NBUI.NB1RightPage_Backdrop:SetAnchor(BOTTOMRIGHT, NBUI.NB1MainWindow_Cover, BOTTOMRIGHT, -70, -164) + NBUI.NB1RightPage_Backdrop:SetAnchor(BOTTOMRIGHT, NBUI.NB1MainWindow_Cover, BOTTOMRIGHT, -70, -164) NBUI.NB1RightPage_Backdrop:SetCenterColor(0, 0, 0, 0) NBUI.NB1RightPage_Backdrop:SetDimensions(420, 645) NBUI.NB1RightPage_Backdrop:SetDrawLayer(0) NBUI.NB1RightPage_Backdrop:SetDrawLevel(1) - NBUI.NB1RightPage_Backdrop:SetDrawTier(0) + NBUI.NB1RightPage_Backdrop:SetDrawTier(0) NBUI.NB1RightPage_Backdrop:SetEdgeColor(0, 0, 0, 0) ---------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------- NBUI.NB1RightPage_Title = WINDOW_MANAGER:CreateControlFromVirtual("NBUI_NB1RightPage_Title", NBUI.NB1RightPage_TitleBackdrop, "ZO_DefaultEditForBackdrop") NBUI.NB1RightPage_Title:SetColor(unpack(NBUI.db.NB1_TextColor)) NBUI.NB1RightPage_Title:SetDrawLayer(0) NBUI.NB1RightPage_Title:SetDrawLevel(2) - NBUI.NB1RightPage_Title:SetDrawTier(0) + NBUI.NB1RightPage_Title:SetDrawTier(0) NBUI.NB1RightPage_Title:SetFont("ZoFontBookPaperTitle") - NBUI.NB1RightPage_Title:SetHandler("OnEscape", NBUI.NB1RightPage_Title.LoseFocus) - NBUI.NB1RightPage_Title:SetHandler("OnTab", function() - NBUI.NB1RightPage_Contents:TakeFocus() + NBUI.NB1RightPage_Title:SetHandler("OnEscape", NBUI.NB1RightPage_Title.LoseFocus) + NBUI.NB1RightPage_Title:SetHandler("OnTab", function() + NBUI.NB1RightPage_Contents:TakeFocus() end) - NBUI.NB1RightPage_Title:SetHandler("OnMouseDoubleClick", function(self) + NBUI.NB1RightPage_Title:SetHandler("OnMouseDoubleClick", function(self) zo_callLater(function() self:SelectAll() end, 100) - end) + end) NBUI.NB1RightPage_Title:SetHandler("OnTextChanged", function(self) local NB1Pages = NBUI.db.NB1Pages[currentlyViewing] if not NB1Pages or self:GetText() ~= NB1Pages.title or self:GetText() then NBUI.NB1SavePage_Button:SetHidden(false) - NBUI.NB1UndoPage_Button:SetHidden(false) + -- NBUI.NB1UndoPage_Button:SetHidden(false) else NBUI.NB1SavePage_Button:SetHidden(true) - NBUI.NB1UndoPage_Button:SetHidden(true) + -- NBUI.NB1UndoPage_Button:SetHidden(true) end end) - NBUI.NB1RightPage_Title:SetMaxInputChars(33) + NBUI.NB1RightPage_Title:SetMaxInputChars(MAIL_MAX_SUBJECT_CHARACTERS) NBUI.NB1RightPage_Title:SetHidden(true) ---------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------- NBUI.NB1RightPage_ScrollContainer = WINDOW_MANAGER:CreateControlFromVirtual("NBUI_NB1RightPage_ScrollContainer", NBUI.NB1MainWindow, "ZO_ScrollContainer") NBUI.NB1RightPage_ScrollContainer.scrollChild = NBUI.NB1RightPage_ScrollContainer:GetNamedChild("ScrollChild") -- NBUI.NB1RightPage_ScrollContainer:SetAnchorFill(NBUI.NB1RightPage_Backdrop) NBUI.NB1RightPage_ScrollContainer:ClearAnchors() NBUI.NB1RightPage_ScrollContainer:SetAnchor(TOPLEFT, NBUI.NB1RightPage_Backdrop, TOPLEFT, 0, 0) NBUI.NB1RightPage_ScrollContainer:SetAnchor(BOTTOMRIGHT, NBUI.NB1RightPage_Backdrop, BOTTOMRIGHT, 0, -30) -- Extra space on bottom of page. - NBUI.NB1RightPage_ScrollContainer:SetDrawLayer(0) + NBUI.NB1RightPage_ScrollContainer:SetDrawLayer(0) NBUI.NB1RightPage_ScrollContainer:SetDrawLevel(2) NBUI.NB1RightPage_ScrollContainer:SetDrawTier(0) NBUI.NB1RightPage_ScrollContainer:SetHidden(true) - ---------------------------------------------------------------------------------------------------- + +--------------------------------------------------------------------------------------------------- NBUI.NBUI_NB1RightPage_CharacterCounter = WINDOW_MANAGER:CreateControl("NBUI_NB1RightPage_CharacterCounter", NBUI.NB1RightPage_ScrollContainer, CT_LABEL) NBUI.NBUI_NB1RightPage_CharacterCounter:SetAnchor(BOTTOMRIGHT, NBUI.NB1RightPage_ScrollContainer, BOTTOMRIGHT, -30, 25) @@ -427,8 +579,8 @@ function CreateNB1() color[4] = 0.5 NBUI.NBUI_NB1RightPage_CharacterCounter:SetColor(unpack(color)) NBUI.NBUI_NB1RightPage_CharacterCounter:SetHidden(true) - ---------------------------------------------------------------------------------------------------- + +--------------------------------------------------------------------------------------------------- NBUI.NB1RightPage_Contents = WINDOW_MANAGER:CreateControlFromVirtual("NBUI_NB1RightPage_Contents", NBUI.NB1RightPage_ScrollContainer, "ZO_DefaultEditMultiLineForBackdrop") NBUI.NB1RightPage_Contents:ClearAnchors() NBUI.NB1RightPage_Contents:SetAnchor(TOPLEFT, NBUI.NB1RightPage_ScrollContainer, TOPLEFT, 6, 5) @@ -438,12 +590,12 @@ function CreateNB1() NBUI.NB1RightPage_Contents:SetDrawLayer(0) NBUI.NB1RightPage_Contents:SetDrawLevel(3) NBUI.NB1RightPage_Contents:SetDrawTier(1) - NBUI.NB1RightPage_Contents:SetMaxInputChars(3000) -- Visual max, higher than saveable max. + NBUI.NB1RightPage_Contents:SetMaxInputChars(3000) -- Visual max, higher than saveable max. -- MAIL_MAX_BODY_CHARACTERS NBUI.NB1RightPage_Contents:SetFont("ZoFontBookPaper") -- NBUI.NB1RightPage_Contents:SetMultiLine(true) if NBUI.db.NB1_FormattedMode then NBUI.NB1RightPage_Contents:SetHidden(true) end NBUI.NB1RightPage_Contents:SetSelectionColor(unpack(NBUI.db.NB1_SelectionColor)) - + NBUI.NB1RightPage_Contents:SetHandler("OnFocusLost", function() if NBUI.db.NB1_FormattedMode and NBUI.db.NB1_LeaveEditModeOnFocus then NBUI.NB1RightPage_Contents:SetHidden(true) @@ -456,10 +608,10 @@ function CreateNB1() NBUI.NB1RightPage_ContentsLabel:SetHidden(false) end end) - + NBUI.NB1RightPage_Contents:SetHandler("OnEscape", NBUI.NB1RightPage_Contents.LoseFocus) - NBUI.NB1RightPage_Contents:SetHandler("OnTab", function() - NBUI.NB1RightPage_Title:TakeFocus() + NBUI.NB1RightPage_Contents:SetHandler("OnTab", function() + NBUI.NB1RightPage_Title:TakeFocus() end) NBUI.NB1RightPage_Contents:SetHandler("OnMouseDoubleClick", function(self) @@ -495,28 +647,29 @@ function CreateNB1() local text = self:GetText() if not page or text ~= page.text or text then NBUI.NB1SavePage_Button:SetHidden(false) - NBUI.NB1UndoPage_Button:SetHidden(false) + -- NBUI.NB1UndoPage_Button:SetHidden(false) else NBUI.NB1SavePage_Button:SetHidden(true) - NBUI.NB1UndoPage_Button:SetHidden(true) + -- NBUI.NB1UndoPage_Button:SetHidden(true) end - + -- Update label display. NBUI.NB1RightPage_ContentsLabel:SetText(text) NBUI.NB1RightPage_ContentsLabel:UpdateHeight() - - -- Update character counter. + -- NOTE: SavedVars won't save a string with over 2,000 character bytes. local textLen = #text if textLen > savedVarsStringMax then NBUI.NB1SavePage_Button:SetHidden(true) end - NBUI.NBUI_NB1RightPage_CharacterCounter:SetText(textLen .. ' / ' .. savedVarsStringMax) + + -- Update character counter. + UpdateCharacterCounter(textLen) NBUI.NBUI_NB1RightPage_CharacterCounter:SetHidden(false) end) - ---------------------------------------------------------------------------------------------------- - NBUI.NB1RightPage_ContentsLabel = WINDOW_MANAGER:CreateControl("NBUI_NB1RightPage_ContentsLabel", NBUI.NB1RightPage_ScrollContainer.scrollChild, CT_LABEL) + +--------------------------------------------------------------------------------------------------- + NBUI.NB1RightPage_ContentsLabel = WINDOW_MANAGER:CreateControl("NBUI_NB1RightPage_ContentsLabel", NBUI.NB1RightPage_ScrollContainer.scrollChild, CT_LABEL) NBUI.NB1RightPage_ContentsLabel:SetAnchor(TOPLEFT, NBUI.NB1RightPage_ScrollContainer.scrollChild, TOPLEFT, 6, 5) -- Matches Editbox. NBUI.NB1RightPage_ContentsLabel:SetWidth(NBUI.NB1RightPage_ScrollContainer:GetWidth()-20) NBUI.NB1RightPage_ContentsLabel:SetHeight(NBUI.NB1RightPage_ScrollContainer:GetHeight()) @@ -557,10 +710,10 @@ function CreateNB1() end end, 100) end ---------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------- NBUI.NB1NewPage_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1NewPage_Button", NBUI.NB1MainWindow, CT_BUTTON) - NBUI.NB1NewPage_Button:SetAnchor(TOPRIGHT, NBUI.NB1RightPage_TitleBackdrop, TOPRIGHT, 34, -25) - NBUI.NB1NewPage_Button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) + NBUI.NB1NewPage_Button:SetAnchor(TOPRIGHT, NBUI.NB1RightPage_TitleBackdrop, TOPRIGHT, 34, -25) + NBUI.NB1NewPage_Button:SetClickSound(SOUNDS.BOOK_PAGE_TURN) NBUI.NB1NewPage_Button:SetDimensions(32, 32) NBUI.NB1NewPage_Button:SetDrawLayer(1) NBUI.NB1NewPage_Button:SetDrawLevel(2) @@ -570,7 +723,7 @@ function CreateNB1() ZO_Dialogs_ShowDialog("NBUI_NB1CONFIRM_NEWPAGE") else NBUI.NB1NewPage(self) - end + end end) NBUI.NB1NewPage_Button:SetHandler("OnMouseEnter", function(self) InitializeTooltip(InformationTooltip, self, TOPLEFT, 0, 0, BOTTOMRIGHT) @@ -578,30 +731,30 @@ function CreateNB1() end) NBUI.NB1NewPage_Button:SetHandler("OnMouseExit", function(self) ClearTooltip(InformationTooltip) - end) + end) NBUI.NB1NewPage_Button:SetMouseOverTexture("/esoui/art/chatwindow/chat_addtab_over.dds") NBUI.NB1NewPage_Button:SetNormalTexture("/esoui/art/chatwindow/chat_addtab_up.dds") NBUI.NB1NewPage_Button:SetPressedTexture("/esoui/art/chatwindow/chat_addtab_down.dds") - - NBUI.NB1NewPage_Button.highlight = WINDOW_MANAGER:CreateControl("NBUI_NB1NewPage_Button_highlight", NBUI.NB1NewPage_Button, CT_TEXTURE) + + NBUI.NB1NewPage_Button.highlight = WINDOW_MANAGER:CreateControl("NBUI_NB1NewPage_Button_highlight", NBUI.NB1NewPage_Button, CT_TEXTURE) NBUI.NB1NewPage_Button.highlight:SetAnchor(TOPLEFT, NBUI.NB1NewPage_Button, TOPLEFT, -15, -6) NBUI.NB1NewPage_Button.highlight:SetAnchor(BOTTOMRIGHT, NBUI.NB1NewPage_Button, BOTTOMRIGHT, 6, 15) - NBUI.NB1NewPage_Button.highlight:SetColor(0, 0.8, 0, 0) + NBUI.NB1NewPage_Button.highlight:SetColor(0, 0.8, 0, 0) NBUI.NB1NewPage_Button.highlight:SetDrawLayer(1) NBUI.NB1NewPage_Button.highlight:SetDrawLevel(1) - NBUI.NB1NewPage_Button.highlight:SetDrawTier(0) + NBUI.NB1NewPage_Button.highlight:SetDrawTier(0) NBUI.NB1NewPage_Button.highlight:SetTexture("/esoui/art/chatwindow/maximize_up.dds") NBUI.NB1NewPage_Button.highlight:SetAlpha(1) ---***********************************************************************************************-- --- MAIN WINDOW CLOSE BUTTON --------------------------------------------------------------------- +--***********************************************************************************************-- +-- MAIN WINDOW CLOSE BUTTON --------------------------------------------------------------------- --[[ NBUI.NB1Close_Button = WINDOW_MANAGER:CreateControlFromVirtual("NBUI_NB1Close_Button", NBUI.NB1MainWindow, "ZO_CloseButton") NBUI.NB1Close_Button:SetDimensions(16, 16) NBUI.NB1Close_Button:SetAnchor(TOPRIGHT, NBUI.NB1RightPage_TitleBackdrop, TOPRIGHT, 40, -25) - NBUI.NB1Close_Button:SetHandler("OnClicked", function(self) - NBUI.NB1MainWindow:SetHidden(true) + NBUI.NB1Close_Button:SetHandler("OnClicked", function(self) + NBUI.NB1MainWindow:SetHidden(true) NBUI.NB1MainWindow:SetTopmost(false) - end) + end) NBUI.NB1Close_Button:SetHandler("OnMouseEnter", function(self) InitializeTooltip(InformationTooltip, self, TOPLEFT, 0, 0, BOTTOMRIGHT) SetTooltipText(InformationTooltip, GetString(SI_NBUI_CLOSEBUTTON_TOOLTIP)) @@ -612,15 +765,15 @@ function CreateNB1() ]]-- NBUI.NB1Close_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1Close_Button", NBUI.NB1MainWindow, CT_BUTTON) - NBUI.NB1Close_Button:SetAnchor(BOTTOMRIGHT, NBUI.NB1RightPage_Backdrop, BOTTOMRIGHT, 46, 16) - NBUI.NB1Close_Button:SetClickSound(SOUNDS.BOOK_CLOSE) + NBUI.NB1Close_Button:SetAnchor(BOTTOMRIGHT, NBUI.NB1RightPage_Backdrop, BOTTOMRIGHT, 46, 16) + NBUI.NB1Close_Button:SetClickSound(SOUNDS.BOOK_CLOSE) NBUI.NB1Close_Button:SetDimensions(25, 25) NBUI.NB1Close_Button:SetDrawLayer(1) NBUI.NB1Close_Button:SetDrawLevel(2) - NBUI.NB1Close_Button:SetDrawTier(0) + NBUI.NB1Close_Button:SetDrawTier(0) NBUI.NB1Close_Button:SetHandler("OnClicked", NBUI.NB1KeyBindToggle - -- function(self) - -- NBUI.NB1MainWindow:SetHidden(true) + -- function(self) + -- NBUI.NB1MainWindow:SetHidden(true) -- if SCENE_MANAGER:IsInUIMode() then -- SCENE_MANAGER:SetInUIMode(false) -- end @@ -637,33 +790,33 @@ function CreateNB1() NBUI.NB1Close_Button:SetMouseOverTexture("/esoui/art/buttons/closebutton_mouseover.dds") NBUI.NB1Close_Button:SetNormalTexture("/esoui/art/buttons/closebutton_up.dds") NBUI.NB1Close_Button:SetPressedTexture("/esoui/art/buttons/closebutton_down.dds") - - NBUI.NB1Close_ButtonTexture = WINDOW_MANAGER:CreateControl("NBUI_NB1Close_ButtonTexture", NBUI.NB1Close_Button, CT_TEXTURE) + + NBUI.NB1Close_ButtonTexture = WINDOW_MANAGER:CreateControl("NBUI_NB1Close_ButtonTexture", NBUI.NB1Close_Button, CT_TEXTURE) NBUI.NB1Close_ButtonTexture:SetAnchor(TOPLEFT, NBUI.NB1Close_Button, TOPLEFT, -20, -11) NBUI.NB1Close_ButtonTexture:SetAnchor(BOTTOMRIGHT, NBUI.NB1Close_Button, BOTTOMRIGHT, 10, 20) - NBUI.NB1Close_ButtonTexture:SetColor(0.8, 0, 0, 0) + NBUI.NB1Close_ButtonTexture:SetColor(0.8, 0, 0, 0) NBUI.NB1Close_ButtonTexture:SetDrawLayer(1) NBUI.NB1Close_ButtonTexture:SetDrawLevel(1) - NBUI.NB1Close_ButtonTexture:SetDrawTier(0) + NBUI.NB1Close_ButtonTexture:SetDrawTier(0) NBUI.NB1Close_ButtonTexture:SetTexture("/esoui/art/chatwindow/maximize_up.dds")--("/esoui/art/buttons/cancel_up.dds") NBUI.NB1Close_ButtonTexture:SetTextureRotation(4.7, .61, .32) NBUI.NB1Close_ButtonTexture:SetAlpha(1) - ---***********************************************************************************************-- + +--***********************************************************************************************-- -- CHAT WINDOW BUTTONS -------------------------------------------------------------------------- - NBUI.NB1MaxChatWin_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1MaxChatWin_Button", ZO_ChatWindow, CT_BUTTON) + NBUI.NB1MaxChatWin_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1MaxChatWin_Button", ZO_ChatWindow, CT_BUTTON) NBUI.NB1MaxChatWin_Button:SetDimensions(32, 32) - NBUI.NB1MaxChatWin_Button:SetAnchor(CENTER, ZO_ChatWindowOptions, CENTER, -40, 1) + NBUI.NB1MaxChatWin_Button:SetAnchor(CENTER, ZO_ChatWindowOptions, CENTER, -30 + NBUI.db.NB1_ChatButton_Max_Offset, 1) -- NBUI.NB1MaxChatWin_Button:SetAnchor(TOPRIGHT, ZO_ChatWindow, TOPRIGHT, NBUI.db.NB1_MaxOffsetChatButton, 7) NBUI.NB1MaxChatWin_Button:SetMouseOverTexture("/esoui/art/mainmenu/menubar_journal_down.dds") - NBUI.NB1MaxChatWin_Button:SetHidden(not NBUI.db.NB1_ChatButton) + NBUI.NB1MaxChatWin_Button:SetHidden(not NBUI.db.NB1_ChatButton) NBUI.NB1MaxChatWin_Button:SetHandler("OnClicked", function(self) --if button == 1 then NBUI.NB1KeyBindToggle() --elseif button == 2 then - --DoCommand("/nb1s") + --DoCommand("/nb1s") --end - end) + end) NBUI.NB1MaxChatWin_Button:SetHandler("OnMouseEnter", function(self) InitializeTooltip(InformationTooltip, self, TOPLEFT, 0, 0, BOTTOMRIGHT) SetTooltipText(InformationTooltip, NBUI.db.NB1_Title) @@ -671,8 +824,8 @@ function CreateNB1() NBUI.NB1MaxChatWin_Button:SetHandler("OnMouseExit", function(self) ClearTooltip(InformationTooltip) end) - - NBUI.NB1MaxChatWin_ButtonTexture = WINDOW_MANAGER:CreateControl("NBUI_NB1MaxTexureChatButton", ZO_ChatWindow, CT_TEXTURE) + + NBUI.NB1MaxChatWin_ButtonTexture = WINDOW_MANAGER:CreateControl("NBUI_NB1MaxTexureChatButton", ZO_ChatWindow, CT_TEXTURE) NBUI.NB1MaxChatWin_ButtonTexture:SetAnchorFill(NBUI.NB1MaxChatWin_Button) NBUI.NB1MaxChatWin_ButtonTexture:SetColor(unpack(NBUI.db.NB1_BookColor)) NBUI.NB1MaxChatWin_ButtonTexture:SetDrawTier(DT_HIGH) @@ -681,13 +834,13 @@ function CreateNB1() NBUI.NB1MinChatWin_Button = WINDOW_MANAGER:CreateControl("NBUI_NB1MinChatWin_Button", ZO_ChatWindowMinBar, CT_BUTTON) NBUI.NB1MinChatWin_Button:SetDimensions(32, 32) - NBUI.NB1MinChatWin_Button:SetAnchor(TOPLEFT, ZO_ChatWindowMinBar, nil, 0, 220) + NBUI.NB1MinChatWin_Button:SetAnchor(TOPLEFT, ZO_ChatWindowMinBar, nil, 0, 230 + NBUI.db.NB1_ChatButton_Min_Offset) -- NBUI.NB1MinChatWin_Button:SetAnchor(BOTTOMLEFT, ZO_ChatWindowMinBar, BOTTOMLEFT, -3, NBUI.db.NB1_MinOffsetChatButton) NBUI.NB1MinChatWin_Button:SetMouseOverTexture("/esoui/art/mainmenu/menubar_journal_down.dds") NBUI.NB1MinChatWin_Button:SetHidden(not NBUI.db.NB1_ChatButton) NBUI.NB1MinChatWin_Button:SetHandler("OnClicked", function(self) NBUI.NB1KeyBindToggle() - end) + end) NBUI.NB1MinChatWin_Button:SetHandler("OnMouseEnter", function(self) InitializeTooltip(InformationTooltip, self, TOPLEFT, 0, 0, BOTTOMRIGHT) SetTooltipText(InformationTooltip, NBUI.db.NB1_Title) @@ -696,12 +849,12 @@ function CreateNB1() ClearTooltip(InformationTooltip) end) - NBUI.NB1MinChatWin_ButtonTexture = WINDOW_MANAGER:CreateControl("NBUI_NB1MinTexureChatButton", ZO_ChatWindowMinBar, CT_TEXTURE) + NBUI.NB1MinChatWin_ButtonTexture = WINDOW_MANAGER:CreateControl("NBUI_NB1MinTexureChatButton", ZO_ChatWindowMinBar, CT_TEXTURE) NBUI.NB1MinChatWin_ButtonTexture:SetAnchorFill(NBUI.NB1MinChatWin_Button) NBUI.NB1MinChatWin_ButtonTexture:SetColor(unpack(NBUI.db.NB1_BookColor)) NBUI.NB1MinChatWin_ButtonTexture:SetDrawTier(DT_HIGH) NBUI.NB1MinChatWin_ButtonTexture:SetHidden(not NBUI.db.NB1_ChatButton) - NBUI.NB1MinChatWin_ButtonTexture:SetTexture("/esoui/art/mainmenu/menubar_journal_up.dds") + NBUI.NB1MinChatWin_ButtonTexture:SetTexture("/esoui/art/mainmenu/menubar_journal_up.dds") end -- Return date and time as shown below, @@ -728,9 +881,9 @@ function NBUI.NB1NewTitle(self) return title end -function NBUI.NB1NewPage(self) +function NBUI.NB1NewPage(self) currentlyViewing = nil - + NBUI.NB1RightPage_Title:SetHidden(false) NBUI.NB1RightPage_ScrollContainer:SetHidden(false) @@ -741,14 +894,14 @@ function NBUI.NB1NewPage(self) --NBUI.NB1RightPage_Title:TakeFocus() NBUI.NB1RightPage_Contents:Clear() NBUI.NB1SavePage(self) - - NBUI.NB1UndoPage_Button:SetHidden(true) -end + + -- NBUI.NB1UndoPage_Button:SetHidden(true) +end NB1ConfirmNewDialog = { title={ text = GetString(SI_NBUI_NEWBUTTON_TITLE)}, mainText={ text = GetString(SI_NBUI_NEWBUTTON_MAINTEXT)}, buttons = { - [1]={ + [1]={ text = GetString(SI_NBUI_YES_LABEL), callback = function(self) NBUI.NB1NewPage(self) zo_callLater(function() SetGameCameraUIMode(true) end, 10) @@ -766,44 +919,49 @@ function NBUI.NB1SavePage(self) titleText = NBUI.NB1RightPage_Title:GetText() end local pageText = NBUI.NB1RightPage_Contents:GetText() - local safe_titleText = ProtectText(titleText) - local safe_pageText = ProtectText(pageText) - + local safe_titleText = NBUI.ProtectText(titleText) + local safe_pageText = NBUI.ProtectText(pageText) + -- NOTE: SavedVars won't save a string with over 2,000 character bytes. local textLen = #safe_pageText -- d(textLen) if textLen > savedVarsStringMax then - d('Page is too long to save!') + d('|cFFFFFFNOTEBOOK:|r Page is too long to save!') return end - + if currentlyViewing == nil then --if this was a new page table.insert(NBUI.db.NB1Pages, {["title"] = safe_titleText, ["text"]=safe_pageText}) currentlyViewing = #NBUI.db.NB1Pages - NBUI.NB1SelectedPage_Button:SetHidden(false) - NBUI.NB1SelectedPage_Button:ClearAnchors() - self.new = true + -- NBUI.NB1SelectedPage_Button:SetHidden(false) + -- NBUI.NB1SelectedPage_Button:ClearAnchors() + -- self.new = true else - NBUI.db.NB1Pages[currentlyViewing].title = safe_titleText - NBUI.db.NB1Pages[currentlyViewing].text = safe_pageText - self.new = false - end - - Populate_NB1_ScrollList() - if self.new then - -- NBUI.NB1SelectedPage_Button:SetAnchorFill(_G["NBUI_Index"..currentlyViewing]) - NBUI.NB1SelectedPage_Button:SetAnchorFill(NB1_IndexPool:AcquireObject(currentlyViewing)) + NBUI.db.NB1Pages[currentlyViewing].title = safe_titleText + NBUI.db.NB1Pages[currentlyViewing].text = safe_pageText + -- self.new = false end + -- Update buttons. NBUI.NB1SavePage_Button:SetHidden(true) - NBUI.NB1UndoPage_Button:SetHidden(true) - NBUI.NBUI_NB1RightPage_CharacterCounter:SetHidden(true) + + -- Load all pages in db and select one. + Populate_NB1_ScrollList(true) + + -- Display selection element and buttons. + -- if self.new then + -- -- NBUI.NB1SelectedPage_Button:SetAnchorFill(_G["NBUI_Index"..currentlyViewing]) + -- NBUI.NB1SelectedPage_Button:SetAnchorFill(NB1_IndexPool:AcquireObject(currentlyViewing)) + -- end + + -- NBUI.NB1UndoPage_Button:SetHidden(true) + -- NBUI.NBUI_NB1RightPage_CharacterCounter:SetHidden(true) end NB1ConfirmSaveDialog = { title = { text = GetString(SI_NBUI_SAVEBUTTON_TITLE)}, mainText = { text = GetString(SI_NBUI_SAVEBUTTON_MAINTEXT)}, buttons = { - [1]={ + [1]={ text = GetString(SI_NBUI_YES_LABEL), callback = function(self) NBUI.NB1SavePage(self) zo_callLater(function() SetGameCameraUIMode(true) end, 10) @@ -814,20 +972,20 @@ NB1ConfirmSaveDialog = { } ZO_Dialogs_RegisterCustomDialog("NBUI_NB1CONFIRM_SAVE", NB1ConfirmSaveDialog) -function NBUI.NB1UndoPage() +function NBUI.NB1UndoPage() if currentlyViewing then NBUI.NB1RightPage_Title:SetText(NBUI.db.NB1Pages[currentlyViewing].title) NBUI.NB1RightPage_Contents:SetText(NBUI.db.NB1Pages[currentlyViewing].text) end - + NBUI.NB1SavePage_Button:SetHidden(true) - NBUI.NB1UndoPage_Button:SetHidden(true) + -- NBUI.NB1UndoPage_Button:SetHidden(true) end NB1ConfirmUndoDialog = { title = { text = GetString(SI_NBUI_UNDOPAGE_TITLE)}, mainText = { text = GetString(SI_NBUI_UNDOPAGE_MAINTEXT)}, buttons = { - [1]={ + [1]={ text = GetString(SI_NBUI_YES_LABEL), callback = function() NBUI.NB1UndoPage() zo_callLater(function() SetGameCameraUIMode(true) end, 10) @@ -843,22 +1001,23 @@ function NBUI.NB1DeletePage() if currentlyViewing then table.remove(NBUI.db.NB1Pages, currentlyViewing) currentlyViewing = nil + -- Load all pages in db and select one. Populate_NB1_ScrollList() - NBUI.NB1SelectedPage_Button:SetHidden(true) + -- NBUI.NB1SelectedPage_Button:SetHidden(true) end - NBUI.NB1RightPage_Title:Clear() - NBUI.NB1RightPage_Contents:Clear() + -- NBUI.NB1RightPage_Title:Clear() + -- NBUI.NB1RightPage_Contents:Clear() + + -- NBUI.NB1RightPage_Title:SetHidden(true) + -- NBUI.NB1RightPage_ScrollContainer:SetHidden(true) - NBUI.NB1RightPage_Title:SetHidden(true) - NBUI.NB1RightPage_ScrollContainer:SetHidden(true) - - NBUI.NB1DeletePage_Button:SetHidden(true) - NBUI.NB1SavePage_Button:SetHidden(true) - NBUI.NB1UndoPage_Button:SetHidden(true) + -- NBUI.NB1DeletePage_Button:SetHidden(true) + -- NBUI.NB1SavePage_Button:SetHidden(true) + -- NBUI.NB1UndoPage_Button:SetHidden(true) - NBUI.NB1MovePageUp_Button:SetHidden(true) - NBUI.NB1MovePageDown_Button:SetHidden(true) + -- NBUI.NB1MovePageUp_Button:SetHidden(true) + -- NBUI.NB1MovePageDown_Button:SetHidden(true) -- NBUI.NB1RunScript_Button:SetHidden(true) end NB1ConfirmDeleteDialog = { @@ -887,8 +1046,8 @@ function NBUI.NB1MovePageUp(self) local page = table.remove(NBUI.db.NB1Pages, currentlyViewing) table.insert(NBUI.db.NB1Pages, currentlyViewing-1, page) currentlyViewing = currentlyViewing-1 - - Populate_NB1_ScrollList() + + Populate_NB1_ScrollList(true) NBUI.NB1SelectedPage_Button:SetAnchorFill(NB1_IndexPool:AcquireObject(currentlyViewing)) NBUI.NB1SelectedPage_Button:SetHidden(false) end @@ -904,8 +1063,8 @@ function NBUI.NB1MovePageDown(self) local page = table.remove(NBUI.db.NB1Pages, currentlyViewing) table.insert(NBUI.db.NB1Pages, currentlyViewing+1, page) currentlyViewing = currentlyViewing+1 - - Populate_NB1_ScrollList() + + Populate_NB1_ScrollList(true) NBUI.NB1SelectedPage_Button:SetAnchorFill(NB1_IndexPool:AcquireObject(currentlyViewing)) NBUI.NB1SelectedPage_Button:SetHidden(false) end @@ -916,7 +1075,7 @@ function NBUI.NB1Preview(self) local newState = not state -- Toggle. NBUI.db.NB1Pages[currentlyViewing].preview = not oldState - d(state, NBUI.db.NB1Pages[currentlyViewing].preview) + -- d(state, NBUI.db.NB1Pages[currentlyViewing].preview) -- Apply template for preview mode. if newState then WINDOW_MANAGER:ApplyTemplateToControl(NBUI.NB1RightPage_Contents, "ZO_SavingEditBox") @@ -936,7 +1095,7 @@ function NBUI.NB1KeyBindToggle() end end --- Selects the line under cursor for an EditBox control. +-- Selects the line under the cursor. function NBUI.SelectLine(control) local cursor = control:GetCursorPosition() local text = control:GetText() @@ -946,11 +1105,19 @@ function NBUI.SelectLine(control) local t = text:sub(0, cursor) t = t:reverse() first = t:find('\n') - if first == nil then first = 0 else first = cursor-first end + if first == nil then + first = 0 + else + first = cursor - first + end -- Find first Newline after cursor, or endoftext. local last = nil last = text:find('\n', cursor) - if last == nil then last = text:len() end + if last == nil then + last = text:len() + else + last = last -1 + end control:SetSelection(first, last) end diff --git a/Notebook2018/Notebook2018.txt b/Elder Scrolls Online Addons/Notebook2018/Notebook2018.txt similarity index 89% rename from Notebook2018/Notebook2018.txt rename to Elder Scrolls Online Addons/Notebook2018/Notebook2018.txt index 42e801c..e89e015 100644 --- a/Notebook2018/Notebook2018.txt +++ b/Elder Scrolls Online Addons/Notebook2018/Notebook2018.txt @@ -1,8 +1,8 @@ ## Title: Notebook 2018 -## Description: A notebook. -## APIVersion: 100026 -## Version: 4.53 -## Author: Bloodspill & phuein +## Description: An advanced notebook. +## APIVersion: 100027 +## Version: 4.70 +## Author: phuein & Bloodspill ## SavedVariables: NBUISVDB NBUISVDBACCT ## OptionalDependsOn: LibStub LibAddonMenu-2.0 diff --git a/Notebook2018/Settings.lua b/Elder Scrolls Online Addons/Notebook2018/Settings.lua similarity index 85% rename from Notebook2018/Settings.lua rename to Elder Scrolls Online Addons/Notebook2018/Settings.lua index 31a8968..4ef18c8 100644 --- a/Notebook2018/Settings.lua +++ b/Elder Scrolls Online Addons/Notebook2018/Settings.lua @@ -270,10 +270,26 @@ function CreateNBUISettings() }, }) - -- Colors category. -- + -- Theme category. -- table.insert(optionsData, { type = "header", - name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(SI_NBUI_HEADER_COLORS)), + name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(SI_NBUI_HEADER_THEME)), + }) + + -- Change book texture. + table.insert(optionsData, { + type = "dropdown", + name = GetString(SI_NBUI_TEXTURE_NAME), + tooltip = GetString(SI_NBUI_TEXTURE_TOOLTIP), + choices = NBUI.BookTexturesNames, + choicesValues = NBUI.BookTextures, + getFunc = function() return NBUI.db.NB1_BookTexture end, + setFunc = function(v) + NBUI.db.NB1_BookTexture = v + -- Apply. + NBUI.NB1MainWindow_Cover:SetTexture(v) + end, + default = NBUI.settings.NB1_BookTexture, }) -- Change book color. @@ -284,10 +300,11 @@ function CreateNBUISettings() getFunc = function() return unpack(NBUI.db.NB1_BookColor) end, setFunc = function(r, g, b, a) NBUI.db.NB1_BookColor = {r, g, b, a} + -- Apply. NBUI.NB1MainWindow_Cover:SetColor(r, g, b, a) NBUI.NB1MaxChatWin_ButtonTexture:SetColor(r, g, b, a) NBUI.NB1MinChatWin_ButtonTexture:SetColor(r, g, b, a) - end, + end, default = { r = NBUI.settings.NB1_BookColor[1], g = NBUI.settings.NB1_BookColor[2], b = NBUI.settings.NB1_BookColor[3], a = NBUI.settings.NB1_BookColor[4]}, }) @@ -299,13 +316,14 @@ function CreateNBUISettings() getFunc = function() return unpack(NBUI.db.NB1_TextColor) end, setFunc = function(r, g, b, a) NBUI.db.NB1_TextColor = {r, g, b, a} + -- Apply. NBUI.NB1LeftPage_Title:SetColor(unpack(NBUI.db.NB1_TextColor)) NBUI.NB1LeftPage_Separator:SetColor(unpack(NBUI.db.NB1_TextColor)) NBUI.NB1RightPage_Title:SetColor(unpack(NBUI.db.NB1_TextColor)) NBUI.NB1RightPage_Contents:SetColor(unpack(NBUI.db.NB1_TextColor)) NBUI.NB1RightPage_ContentsLabel:SetColor(unpack(NBUI.db.NB1_TextColor)) Populate_NB1_ScrollList() - end, + end, }) -- Selection color. R, G, B, A. Between 0 to 1. @@ -316,8 +334,9 @@ function CreateNBUISettings() getFunc = function() return unpack(NBUI.db.NB1_SelectionColor) end, setFunc = function(r, g, b, a) NBUI.db.NB1_SelectionColor = {r, g, b, a} + -- Apply. NBUI.NB1RightPage_Contents:SetSelectionColor(unpack(NBUI.db.NB1_SelectionColor)) - end, + end, }) -- Interactive category. -- @@ -334,7 +353,7 @@ function CreateNBUISettings() getFunc = function() return NBUI.db.NB1_ShowDialog end, setFunc = function(value) NBUI.db.NB1_ShowDialog = value - end, + end, default = NBUI.settings.NB1_ShowDialog, }) @@ -347,10 +366,27 @@ function CreateNBUISettings() setFunc = function(value) NBUI.db.NB1_Locked = value NBUI.NB1MainWindow:SetMovable(not NBUI.db.NB1_Locked) - end, + end, default = NBUI.settings.NB1_Locked, }) + -- Display on top of other UI elements. + table.insert(optionsData, { + type = "checkbox", + name = GetString(SI_NBUI_ONTOP_NAME), + tooltip = GetString(SI_NBUI_ONTOP_TOOLTIP), + getFunc = function() return NBUI.db.NB1_OnTop end, + setFunc = function(value) + NBUI.db.NB1_OnTop = value + local v = 0 + if value then + v = 1 + end + NBUI.NB1MainWindow:SetDrawLayer(v) + end, + default = NBUI.settings.NB1_OnTop, + }) + -- Toggle chat button. table.insert(optionsData, { type = "checkbox", @@ -363,45 +399,47 @@ function CreateNBUISettings() NBUI.NB1MaxChatWin_ButtonTexture:SetHidden(not NBUI.db.NB1_ChatButton) NBUI.NB1MinChatWin_Button:SetHidden(not NBUI.db.NB1_ChatButton) NBUI.NB1MinChatWin_ButtonTexture:SetHidden(not NBUI.db.NB1_ChatButton) - end, + end, default = NBUI.settings.NB1_ChatButton, }) - -- Switch to Edit Mode on mouse hover over page. - table.insert(optionsData, { - type = "checkbox", - name = GetString(SI_NBUI_EDITMODE_HOVER_NAME), - tooltip = GetString(SI_NBUI_EDITMODE_HOVER_TOOLTIP), - getFunc = function() return NBUI.db.NB1_EditModeHover end, - setFunc = function(v) NBUI.db.NB1_EditModeHover = v end, - }) - - -- Switch to Edit Mode on mouse click on page. + -- Opened-chat button offset. table.insert(optionsData, { - type = "checkbox", - name = GetString(SI_NBUI_EDITMODE_CLICK_NAME), - tooltip = GetString(SI_NBUI_EDITMODE_CLICK_TOOLTIP), - getFunc = function() return NBUI.db.NB1_EditModeClick end, - setFunc = function(v) NBUI.db.NB1_EditModeClick = v end, - }) - - -- Leave Edit Mode on page lose focus. - table.insert(optionsData, { - type = "checkbox", - name = GetString(SI_NBUI_LEAVEEDITMODE_FOCUS_NAME), - tooltip = GetString(SI_NBUI_LEAVEEDITMODE_FOCUS_TOOLTIP), - getFunc = function() return NBUI.db.NB1_LeaveEditModeOnFocus end, - setFunc = function(v) NBUI.db.NB1_LeaveEditModeOnFocus = v end, - }) + type = "slider", + name = GetString(SI_NBUI_OFFSETMAX_NAME), + tooltip = GetString(SI_NBUI_OFFSETMAX_TOOLTIP), + min = -180, + max = 40, + step = 1, --(optional) + disabled = function() return not NBUI.db.NB1_ChatButton end, + getFunc = function() return NBUI.db.NB1_ChatButton_Max_Offset end, + setFunc = function(value) + NBUI.db.NB1_ChatButton_Max_Offset = value + -- Anchoring must be done the same way as the original! + NBUI.NB1MaxChatWin_Button:ClearAnchors() + NBUI.NB1MaxChatWin_Button:SetAnchor(CENTER, ZO_ChatWindowOptions, CENTER, -30 + NBUI.db.NB1_ChatButton_Max_Offset, 1) + end, + default = NBUI.settings.NB1_ChatButton_Max_Offset, +}) - -- Leave Edit Mode on mouse exit page. + -- Closed-chat button offset. table.insert(optionsData, { - type = "checkbox", - name = GetString(SI_NBUI_LEAVEEDITMODE_EXIT_NAME), - tooltip = GetString(SI_NBUI_LEAVEEDITMODE_EXIT_TOOLTIP), - getFunc = function() return NBUI.db.NB1_LeaveEditModeOnExit end, - setFunc = function(v) NBUI.db.NB1_LeaveEditModeOnExit = v end, - }) + type = "slider", + name = GetString(SI_NBUI_OFFSETMIN_NAME), + tooltip = GetString(SI_NBUI_OFFSETMIN_TOOLTIP), + min = -100, + max = 220, + step = 1, --(optional) + disabled = function() return not NBUI.db.NB1_ChatButton end, + getFunc = function() return NBUI.db.NB1_ChatButton_Min_Offset end, + setFunc = function(value) + NBUI.db.NB1_ChatButton_Min_Offset = value + -- Anchoring must be done the same way as the original! + NBUI.NB1MinChatWin_Button:ClearAnchors() + NBUI.NB1MinChatWin_Button:SetAnchor(TOPLEFT, ZO_ChatWindowMinBar, nil, 0, 230 + NBUI.db.NB1_ChatButton_Min_Offset) + end, + default = NBUI.settings.NB1_ChatButton_Min_Offset, +}) -- Emote /read when opening the Notebook. table.insert(optionsData, { @@ -439,7 +477,13 @@ function CreateNBUISettings() setFunc = function(v) NBUI.db.NB1_DoubleClickSelectPage = v end, }) - -- Display Text-Formatting mode over Editbox. + -- Formatted display category. -- + table.insert(optionsData, { + type = "header", + name = ZO_HIGHLIGHT_TEXT:Colorize(GetString(SI_NBUI_HEADER_EDITMODE)), + }) + + -- Display Text-Formatting mode over Editbox, at all. table.insert(optionsData, { type = "checkbox", name = GetString(SI_NBUI_FORMATTEDMODE_NAME), @@ -457,5 +501,41 @@ function CreateNBUISettings() end, }) + -- Switch to Edit Mode on mouse hover over page. + table.insert(optionsData, { + type = "checkbox", + name = GetString(SI_NBUI_EDITMODE_HOVER_NAME), + tooltip = GetString(SI_NBUI_EDITMODE_HOVER_TOOLTIP), + getFunc = function() return NBUI.db.NB1_EditModeHover end, + setFunc = function(v) NBUI.db.NB1_EditModeHover = v end, + }) + + -- Switch to Edit Mode on mouse click on page. + table.insert(optionsData, { + type = "checkbox", + name = GetString(SI_NBUI_EDITMODE_CLICK_NAME), + tooltip = GetString(SI_NBUI_EDITMODE_CLICK_TOOLTIP), + getFunc = function() return NBUI.db.NB1_EditModeClick end, + setFunc = function(v) NBUI.db.NB1_EditModeClick = v end, + }) + + -- Leave Edit Mode on page lose focus. + table.insert(optionsData, { + type = "checkbox", + name = GetString(SI_NBUI_LEAVEEDITMODE_FOCUS_NAME), + tooltip = GetString(SI_NBUI_LEAVEEDITMODE_FOCUS_TOOLTIP), + getFunc = function() return NBUI.db.NB1_LeaveEditModeOnFocus end, + setFunc = function(v) NBUI.db.NB1_LeaveEditModeOnFocus = v end, + }) + + -- Leave Edit Mode on mouse exit page. + table.insert(optionsData, { + type = "checkbox", + name = GetString(SI_NBUI_LEAVEEDITMODE_EXIT_NAME), + tooltip = GetString(SI_NBUI_LEAVEEDITMODE_EXIT_TOOLTIP), + getFunc = function() return NBUI.db.NB1_LeaveEditModeOnExit end, + setFunc = function(v) NBUI.db.NB1_LeaveEditModeOnExit = v end, + }) + LAM:RegisterOptionControls("NBUIOptions", optionsData) end \ No newline at end of file diff --git a/Notebook2018/Startup.lua b/Elder Scrolls Online Addons/Notebook2018/Startup.lua similarity index 67% rename from Notebook2018/Startup.lua rename to Elder Scrolls Online Addons/Notebook2018/Startup.lua index 3715e3e..5b99345 100644 --- a/Notebook2018/Startup.lua +++ b/Elder Scrolls Online Addons/Notebook2018/Startup.lua @@ -4,16 +4,19 @@ NBUI.name = "Notebook2018" -- NBUI.version = "4.13" NBUI.settings = { NB1_Anchor = {a = CENTER, b = CENTER, x = 0, y = -20}, - NB1_BookColor = {1, 1, 1, 1}, + NB1_BookColor = {1, 1, 1, 1}, -- Color the book's texture. NB1_TextColor = {0, 0, 0, 0.7}, -- Notebook title, page title, and text. NB1_SelectionColor = {1, 1, 1, 0.5}, -- R, G, B, A. Between 0 and 1. NB1_ShowTitle = true, NB1_Title = "Notebook", NB1_Locked = true, NB1_NewPageTitle = "", -- Empty defaults to time and date. - NB1_ShowDialog = true, + NB1_ShowDialog = true, NB1_ChatButton = true, + NB1_ChatButton_Max_Offset = 0, -- Offsets the button's position. + NB1_ChatButton_Min_Offset = 0, -- .. NB1Pages = {}, + NB1_LastPageSeen = 1, NB1_AccountWide = false, -- Pages saved for all characters. Overrides character pages! NB1_EditModeHover = false, -- Enter Edit Mode on mouse hover on page. NB1_EditModeClick = true, -- Enter Edit Mode on mouse click on page. @@ -24,16 +27,38 @@ NBUI.settings = { NB1_EmoteIdle = true, -- Emotes /idle after closing the Notebook. NB1_SelectLine = true, -- Select whole line with by tripleclicking it. NB1_FormattedMode = true, -- Whether to display formatted-text mode Label over Editbox. + NB1_BookTexture = "esoui/art/lorelibrary/lorelibrary_paperbook.dds", -- The texture to use as the book. + NB1_OnTop = true, -- The book stays on top of other UI elements, to help with taking notes. } -function ProtectText(text) +-- TODO This one has less space for text: +-- esoui/art/lorelibrary/lorelibrary_dwemerbook.dds +-- Maybe increase base size from 1024 for it? Or option to resize texture? +-- NBUI.NB1MainWindow_Cover:SetTextureCoords(0, 1, 0, 1) +NBUI.BookTextures = { + "esoui/art/lorelibrary/lorelibrary_paperbook.dds", + "esoui/art/lorelibrary/lorelibrary_rubbingbook.dds", + "esoui/art/lorelibrary/lorelibrary_skinbook.dds", +} +NBUI.BookTexturesNames = { + "Paper Book", + "Rubbing Book", + "Skin Book", +} + +function NBUI.ProtectText(text) return text:gsub([[\]], [[%%92]]) end -function UnprotectText(text) +function NBUI.UnprotectText(text) return text:gsub([[%%92]], [[\]]) end +function NBUI.NoTagsText(text) + -- Remove color tags. + return text:gsub('|c%w%w%w%w%w%w', ''):gsub('|r', '') +end + function NBUI.Initialize() -- Load saved variables. NBUI.dbCharacter = ZO_SavedVars:New("NBUISVDB", 1, nil, NBUI.settings) @@ -45,11 +70,11 @@ function NBUI.Initialize() if NBUI.db.NB1_AccountWide then NBUI.db = NBUI.dbAccount end - + NB1_IndexPool = ZO_ObjectPool:New(Create_NB1_IndexButton, Remove_NB1_IndexButton) - + CreateNB1() - + Populate_NB1_ScrollList() end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/Bindings.xml b/Elder Scrolls Online Addons/PersonalTimer2018/Bindings.xml new file mode 100644 index 0000000..10a9672 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/Bindings.xml @@ -0,0 +1,15 @@ + + + + + PersonalTimer_ProcessStartPause() + + + PersonalTimer_ProcessReset() + + + PersonalTimer_ProcessRestart() + + + + diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/PersonalTimer.lua b/Elder Scrolls Online Addons/PersonalTimer2018/PersonalTimer.lua new file mode 100644 index 0000000..d31d247 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/PersonalTimer.lua @@ -0,0 +1,301 @@ +local PersonalTimer = { + --Metadata + name = "PersonalTimer2018", + readableName = "Personal Timer 2018", + version = "1.0", + author = "lazeeman0 & phuein", + settingsVersion = 1, + + --Slash command + slashCommand = "/pt", + + --Display Formats + displayFormats = { + [1] = "SS.m", + [2] = "MM:SS.m", + [3] = "HH:MM:SS.m", + }, + displayValues = { + [1] = "%0.2fs", + [2] = "%02d:%02d.%.02s", + [3] = "%02d:%02d:%02d.%.02s", + }, + + --right mouse actions for when the mouse is enabled + rightMouseActions = { + reset = "Reset", + restart = "Restart", + }, + + --Variables + prefix = "Timer: ", + postfix = "", + startTime = 0, + currentTime = 0, + currentEllapsedSeconds = 0, + running = false, +} + +-- Default values for saved variables +local defaults = { + left = 100, + top = 100, + displayFormat = PersonalTimer.displayFormats.seconds, + locked = false, + enableMouseActions = false, + rightMouseAction = PersonalTimer.rightMouseActions.reset, + displayFont = "ZoFontWinH5", +} + +-- Register LibAddonMenu +local LAM = LibStub("LibAddonMenu-2.0") + +-- Build the settings menu +function PersonalTimer.BuildSettingsMenu() + local panelData = { + type = "panel", + name = PersonalTimer.readableName, + displayName = PersonalTimer.readableName, + author = PersonalTimer.author, + version = PersonalTimer.version, + slashCommand = PersonalTimer.slashCommand, --(optional) will register a keybind to open to this panel + registerForRefresh = true, + } + + local optionsTable = { + [1] = { + type = "dropdown", + name = "Display format", + tooltip = "The timer display format.", + choices = { + PersonalTimer.displayFormats.seconds, + PersonalTimer.displayFormats.minutes, + PersonalTimer.displayFormats.hours + }, + getFunc = function() return PersonalTimer.savedVariables.displayFormat end, + setFunc = function(df) + PersonalTimer.savedVariables.displayFormat = df + PersonalTimer.UpdateDisplayType(PersonalTimer.running) + end, + }, + [2] = { + type = "checkbox", + name = "Enable mouse actions", + tooltip = "Enable's mouse actions on the timer:\n\nleft mouse button -> start/pause\nright mouse button -> reset/restart timer\nmiddle mouse button -> toggle format", + getFunc = function() return PersonalTimer.savedVariables.enableMouseActions end, + setFunc = function(value) + PersonalTimer.savedVariables.enableMouseActions = value + if value then + PersonalTimer.savedVariables.locked = true + PersonalTimerUI:SetMovable(false) + end + end, + warning = "When enabling, timer will be locked automatically.", --(optional) + }, + [3] = { + type = "dropdown", + name = "Right mouse button action", + tooltip = "What clicking the right mouse button on the timer will do", + choices = { + PersonalTimer.rightMouseActions.reset, + PersonalTimer.rightMouseActions.restart, + }, + getFunc = function() return PersonalTimer.savedVariables.rightMouseAction end, + setFunc = function(value) + PersonalTimer.savedVariables.rightMouseAction = value + end, + disabled = function() return not PersonalTimer.savedVariables.enableMouseActions end, + }, + [4] = { + type = "checkbox", + name = "Lock timer position", + tooltip = "Lock the timer's position on the screen", + getFunc = function() return PersonalTimer.savedVariables.locked end, + setFunc = function(value) + PersonalTimer.savedVariables.locked = value + PersonalTimerUI:SetMovable(not value) + end, + disabled = function() return PersonalTimer.savedVariables.enableMouseActions end, + }, + -- [5] = { + -- type = "dropdown", + -- name = "Display Size", + -- tooltip = "The timer display text size.", + -- choices = { + -- "ZoFontWinH1", + -- "ZoFontWinH2", + -- "ZoFontWinH3", + -- "ZoFontWinH4", + -- "ZoFontWinH5" + -- }, + -- getFunc = function() return PersonalTimer.savedVariables.displayFont end, + -- setFunc = function(font) + -- PersonalTimer.savedVariables.displaySize = font + -- --UpdateDisplayType(PersonalTimer.running) + -- PersonalTimerUICounter:SetFont(font) + -- end, + -- }, + } + + LAM:RegisterAddonPanel("PersonalTimerSettingsMenu", panelData) + LAM:RegisterOptionControls("PersonalTimerSettingsMenu", optionsTable) +end + +function PersonalTimer.UpdateDisplayType(running) + -- Seconds. + if PersonalTimer.savedVariables.displayFormat == 1 then + PersonalTimerUICounter:SetText(PersonalTimer.prefix .. string.format("", seconds) .. PersonalTimer.postfix) + -- Minutes. + elseif PersonalTimer.savedVariables.displayFormat == 2 then + local obj = PersonalTimer.secondsToTime(seconds) + PersonalTimerUICounter:SetText(PersonalTimer.prefix .. + string.format("", obj.h, obj.m, obj.s, tonumber(obj.milli)) .. + PersonalTimer.postfix) + -- Hours. + else + local obj = PersonalTimer.secondsToTime(seconds) + PersonalTimerUICounter:SetText(PersonalTimer.prefix .. + string.format("", obj.h, obj.m, obj.s, tonumber(obj.milli)) .. + PersonalTimer.postfix) + end + + + + if PersonalTimer.savedVariables.displayFormat == PersonalTimer.displayFormats.seconds then + PersonalTimer.showTimeFunction = function(seconds) + PersonalTimer.displaySeconds(seconds) + end + else + PersonalTimer.showTimeFunction = function(seconds) + PersonalTimer.displayTime(seconds) + end + end + + if not running then + PersonalTimer.showTimeFunction(PersonalTimer.currentEllapsedSeconds); + end +end + +function PersonalTimer.secondsToTime(seconds) + local obj = {} + + if seconds <= 0 then + obj.h = 0 + obj.m = 0 + obj.s = 0 + obj.milli = 0 + else + -- extract milliseconds + local secs = math.floor(seconds) + local milli = math.floor((seconds - secs) * 1000) + + -- extract hours + local hours = math.floor(secs / 3600) + + --extract minutes + local minutes = math.floor((secs / 60) % 60) + + -- extract seconds + local seconds = math.floor(secs % 60) + + --create the final array + obj.h = hours + obj.m = minutes + obj.s = seconds + obj.milli = milli + end + + return obj +end + +function PersonalTimer.PersonalTimerUpdate() + if PersonalTimer.running then + local delta = GetFrameDeltaTimeSeconds() + + PersonalTimer.currentEllapsedSeconds = PersonalTimer.currentEllapsedSeconds + delta + PersonalTimer.showTimeFunction(PersonalTimer.currentEllapsedSeconds) + end +end + +function PersonalTimer.RestorePosition() + PersonalTimerUI:ClearAnchors() + PersonalTimerUI:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, PersonalTimer.savedVariables.left, PersonalTimer.savedVariables.top); + PersonalTimerUI:SetHandler("OnUpdate", function() PersonalTimer.PersonalTimerUpdate() end) + PersonalTimerUI:SetHandler("OnMoveStop", function() PersonalTimer.PersonalTimerMoveStop() end) + PersonalTimerUI:SetHandler("OnMouseUp", function(event, button, ctrl, alt, sshift, command) PersonalTimer.PersonalTimerProcessMouseUp(event, button, ctrl, alt, sshift, command) end) +end + +function PersonalTimer.ToggleDisplayType() + if PersonalTimer.savedVariables.displayFormat == PersonalTimer.displayFormats.seconds then + PersonalTimer.savedVariables.displayFormat = PersonalTimer.displayFormats.hours + else + PersonalTimer.savedVariables.displayFormat = PersonalTimer.displayFormats.seconds + end + + PersonalTimer.UpdateDisplayType(PersonalTimer.running) +end + +function PersonalTimer.PersonalTimerProcessMouseUp(event, button, ctrl, alt, sshift, command) + if WINDOW_MANAGER:GetMouseOverControl() == WINDOW_MANAGER:GetControlByName("PersonalTimerUI", "") then + if PersonalTimer.savedVariables.enableMouseActions and PersonalTimer.savedVariables.locked then + if button == 1 then + PersonalTimer_ProcessStartPause() + elseif button == 2 then + if PersonalTimer.savedVariables.rightMouseAction == PersonalTimer.rightMouseActions.reset then + PersonalTimer_ProcessReset() + else + PersonalTimer_ProcessRestart() + end + elseif button == 3 then + -- PersonalTimer.ToggleDisplayType() + end + end + end +end + +function PersonalTimer_ProcessStartPause() + PersonalTimer.running = not PersonalTimer.running +end + +function PersonalTimer_ProcessReset() + PersonalTimer.running = false + PersonalTimer.currentEllapsedSeconds = 0 + PersonalTimer.UpdateDisplayType(PersonalTimer.running) +end + +function PersonalTimer_ProcessRestart() + PersonalTimer.currentEllapsedSeconds = 0 + PersonalTimer.running = true +end + +function PersonalTimer.PersonalTimerMoveStop() + PersonalTimer.savedVariables.left = PersonalTimerUI:GetLeft() + PersonalTimer.savedVariables.top = PersonalTimerUI:GetTop() +end + +function PersonalTimer.OnAddOnLoaded(eventCode, addOnName) + if addOnName == PersonalTimer.name then + PersonalTimerUIBackdrop:SetAlpha(0.0) + + ZO_CreateStringId("SI_BINDING_NAME_PERSONAL_TIMER_START_PAUSE", "Start/Pause Timer") + ZO_CreateStringId("SI_BINDING_NAME_PERSONAL_TIMER_RESET", "Reset Timer") + ZO_CreateStringId("SI_BINDING_NAME_PERSONAL_TIMER_RESTART", "Restart Timer") + + PersonalTimer.savedVariables = ZO_SavedVars:New("PersonalTimerSavedVariables", + PersonalTimer.settingsVersion, nil, defaults, "default") + + PersonalTimer.RestorePosition() + PersonalTimer.UpdateDisplayType(PersonalTimer.running) + PersonalTimerUI:SetMovable(not PersonalTimer.savedVariables.locked) + PersonalTimerUICounter:SetFont(PersonalTimer.savedVariables.displayFont) + + PersonalTimer.BuildSettingsMenu() + end +end + +EVENT_MANAGER:RegisterForEvent(PersonalTimer.name, EVENT_ADD_ON_LOADED, PersonalTimer.OnAddOnLoaded) + +-- Needed to bind CTRL/Shift+KEY. +function KEYBINDING_MANAGER:IsChordingAlwaysEnabled() + return true +end \ No newline at end of file diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/PersonalTimer.xml b/Elder Scrolls Online Addons/PersonalTimer2018/PersonalTimer.xml new file mode 100644 index 0000000..a4abfa5 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/PersonalTimer.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/PersonalTimer2018.txt b/Elder Scrolls Online Addons/PersonalTimer2018/PersonalTimer2018.txt new file mode 100644 index 0000000..54c19b2 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/PersonalTimer2018.txt @@ -0,0 +1,24 @@ +## Title: Personal Timer 2018 +## APIVersion: 100022 +## SavedVariables: PersonalTimerSavedVariables +## Author: lazeeman0 & phuein + +lib\LibStub\LibStub.lua + +lib\LibAddonMenu-2.0\LibAddonMenu-2.0.lua +lib\LibAddonMenu-2.0\controls\panel.lua +lib\LibAddonMenu-2.0\controls\submenu.lua +lib\LibAddonMenu-2.0\controls\button.lua +lib\LibAddonMenu-2.0\controls\checkbox.lua +lib\LibAddonMenu-2.0\controls\colorpicker.lua +lib\LibAddonMenu-2.0\controls\custom.lua +lib\LibAddonMenu-2.0\controls\description.lua +lib\LibAddonMenu-2.0\controls\dropdown.lua +lib\LibAddonMenu-2.0\controls\editbox.lua +lib\LibAddonMenu-2.0\controls\header.lua +lib\LibAddonMenu-2.0\controls\slider.lua +lib\LibAddonMenu-2.0\controls\texture.lua + +PersonalTimer.lua +PersonalTimer.xml +Bindings.xml \ No newline at end of file diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/LICENSE b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/LICENSE new file mode 100644 index 0000000..f69cbd4 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/LICENSE @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2016 Ryan Lakanen (Seerah) + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua new file mode 100644 index 0000000..20ffe3a --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -0,0 +1,1305 @@ +-- LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah) -- +-- Distributed under The Artistic License 2.0 (see LICENSE) -- +------------------------------------------------------------------ + + +--Register LAM with LibStub +local MAJOR, MINOR = "LibAddonMenu-2.0", 29 +local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) +if not lam then return end --the same or newer version of this lib is already loaded into memory +LibAddonMenu2 = lam + +local messages = {} +local MESSAGE_PREFIX = "[LAM2] " +local function PrintLater(msg) + if CHAT_SYSTEM.primaryContainer then + d(MESSAGE_PREFIX .. msg) + else + messages[#messages + 1] = msg + end +end + +local function FlushMessages() + for i = 1, #messages do + d(MESSAGE_PREFIX .. messages[i]) + end + messages = {} +end + +local logger +if LibDebugLogger then + logger = LibDebugLogger(MAJOR) +end + +if LAMSettingsPanelCreated and not LAMCompatibilityWarning then + PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") + LAMCompatibilityWarning = true +end + +--UPVALUES-- +local wm = WINDOW_MANAGER +local em = EVENT_MANAGER +local sm = SCENE_MANAGER +local cm = CALLBACK_MANAGER +local tconcat = table.concat +local tinsert = table.insert + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local OPTIONS_CREATION_RUNNING = 1 +local OPTIONS_CREATED = 2 +local LAM_CONFIRM_DIALOG = "LAM_CONFIRM_DIALOG" +local LAM_DEFAULTS_DIALOG = "LAM_DEFAULTS" +local LAM_RELOAD_DIALOG = "LAM_RELOAD_DIALOG" + +local addonsForList = {} +local addonToOptionsMap = {} +local optionsState = {} +lam.widgets = lam.widgets or {} +local widgets = lam.widgets +lam.util = lam.util or {} +local util = lam.util +lam.controlsForReload = lam.controlsForReload or {} +local controlsForReload = lam.controlsForReload + +local function GetDefaultValue(default) + if type(default) == "function" then + return default() + end + return default +end + +local function GetStringFromValue(value) + if type(value) == "function" then + return value() + elseif type(value) == "number" then + return GetString(value) + end + return value +end + +local function GetColorForState(disabled) + return disabled and ZO_DEFAULT_DISABLED_COLOR or ZO_DEFAULT_ENABLED_COLOR +end + +local function CreateBaseControl(parent, controlData, controlName) + local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent + control.data = controlData + + control.isHalfWidth = controlData.width == "half" + local width = 510 -- set default width in case a custom parent object is passed + if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end + control:SetWidth(width) + return control +end + +local function CreateLabelAndContainerControl(parent, controlData, controlName) + local control = CreateBaseControl(parent, controlData, controlName) + local width = control:GetWidth() + + local container = wm:CreateControl(nil, control, CT_CONTROL) + container:SetDimensions(width / 3, MIN_HEIGHT) + control.container = container + + local label = wm:CreateControl(nil, control, CT_LABEL) + label:SetFont("ZoFontWinH4") + label:SetHeight(MIN_HEIGHT) + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(GetStringFromValue(controlData.name)) + control.label = label + + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0) + end + + control.data.tooltipText = GetStringFromValue(control.data.tooltip) + control:SetMouseEnabled(true) + control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + return control +end + +local function GetTopPanel(panel) + while panel.panel and panel.panel ~= panel do + panel = panel.panel + end + return panel +end + +local function IsSame(objA, objB) + if #objA ~= #objB then return false end + for i = 1, #objA do + if objA[i] ~= objB[i] then return false end + end + return true +end + +local function RefreshReloadUIButton() + lam.requiresReload = false + + for i = 1, #controlsForReload do + local reloadControl = controlsForReload[i] + if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then + lam.requiresReload = true + break + end + end + + if lam.applyButton then + lam.applyButton:SetHidden(not lam.requiresReload) + end +end + +local function RequestRefreshIfNeeded(control) + -- if our parent window wants to refresh controls, then fire the callback + local panel = GetTopPanel(control) + local panelData = panel.data + if panelData.registerForRefresh then + cm:FireCallbacks("LAM-RefreshPanel", control) + end + RefreshReloadUIButton() +end + +local function RegisterForRefreshIfNeeded(control) + -- if our parent window wants to refresh controls, then add this to the list + local panel = GetTopPanel(control.panel) + local panelData = panel.data + if panelData.registerForRefresh or panelData.registerForDefaults then + tinsert(panel.controlsToRefresh or {}, control) -- prevent errors on custom panels + end +end + +local function RegisterForReloadIfNeeded(control) + if control.data.requiresReload then + tinsert(controlsForReload, control) + control.startValue = {control.data.getFunc()} + end +end + +local function GetConfirmDialog() + if(not ESO_Dialogs[LAM_CONFIRM_DIALOG]) then + ESO_Dialogs[LAM_CONFIRM_DIALOG] = { + canQueue = true, + title = { + text = "", + }, + mainText = { + text = "", + }, + buttons = { + [1] = { + text = SI_DIALOG_CONFIRM, + callback = function(dialog) end, + }, + [2] = { + text = SI_DIALOG_CANCEL, + } + } + } + end + return ESO_Dialogs[LAM_CONFIRM_DIALOG] +end + +local function ShowConfirmationDialog(title, body, callback) + local dialog = GetConfirmDialog() + dialog.title.text = title + dialog.mainText.text = body + dialog.buttons[1].callback = callback + ZO_Dialogs_ShowDialog(LAM_CONFIRM_DIALOG) +end + +local function GetDefaultsDialog() + if(not ESO_Dialogs[LAM_DEFAULTS_DIALOG]) then + ESO_Dialogs[LAM_DEFAULTS_DIALOG] = { + canQueue = true, + title = { + text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP, + }, + mainText = { + text = SI_OPTIONS_RESET_PROMPT, + }, + buttons = { + [1] = { + text = SI_OPTIONS_RESET, + callback = function(dialog) end, + }, + [2] = { + text = SI_DIALOG_CANCEL, + } + } + } + end + return ESO_Dialogs[LAM_DEFAULTS_DIALOG] +end + +local function ShowDefaultsDialog(panel) + local dialog = GetDefaultsDialog() + dialog.buttons[1].callback = function() + panel:ForceDefaults() + RefreshReloadUIButton() + end + ZO_Dialogs_ShowDialog(LAM_DEFAULTS_DIALOG) +end + +local function DiscardChangesOnReloadControls() + for i = 1, #controlsForReload do + local reloadControl = controlsForReload[i] + if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then + reloadControl:UpdateValue(false, unpack(reloadControl.startValue)) + end + end + lam.requiresReload = false + lam.applyButton:SetHidden(true) +end + +local function StorePanelForReopening() + local saveData = ZO_Ingame_SavedVariables["LAM"] or {} + saveData.reopenPanel = lam.currentAddonPanel:GetName() + ZO_Ingame_SavedVariables["LAM"] = saveData +end + +local function RetrievePanelForReopening() + local saveData = ZO_Ingame_SavedVariables["LAM"] + if(saveData) then + ZO_Ingame_SavedVariables["LAM"] = nil + return _G[saveData.reopenPanel] + end +end + +local function HandleReloadUIPressed() + StorePanelForReopening() + ReloadUI() +end + +local function HandleLoadDefaultsPressed() + ShowDefaultsDialog(lam.currentAddonPanel) +end + +local function GetReloadDialog() + if(not ESO_Dialogs[LAM_RELOAD_DIALOG]) then + ESO_Dialogs[LAM_RELOAD_DIALOG] = { + canQueue = true, + title = { + text = util.L["RELOAD_DIALOG_TITLE"], + }, + mainText = { + text = util.L["RELOAD_DIALOG_TEXT"], + }, + buttons = { + [1] = { + text = util.L["RELOAD_DIALOG_RELOAD_BUTTON"], + callback = function() ReloadUI() end, + }, + [2] = { + text = util.L["RELOAD_DIALOG_DISCARD_BUTTON"], + callback = DiscardChangesOnReloadControls, + } + }, + noChoiceCallback = DiscardChangesOnReloadControls, + } + end + return ESO_Dialogs[LAM_CONFIRM_DIALOG] +end + +local function ShowReloadDialogIfNeeded() + if lam.requiresReload then + local dialog = GetReloadDialog() + ZO_Dialogs_ShowDialog(LAM_RELOAD_DIALOG) + end +end + +local function UpdateWarning(control) + local warning + if control.data.warning ~= nil then + warning = util.GetStringFromValue(control.data.warning) + end + + if control.data.requiresReload then + if not warning then + warning = string.format("%s", util.L["RELOAD_UI_WARNING"]) + else + warning = string.format("%s\n\n%s", warning, util.L["RELOAD_UI_WARNING"]) + end + end + + if not warning then + control.warning:SetHidden(true) + else + control.warning.data = {tooltipText = warning} + control.warning:SetHidden(false) + end +end + +local localization = { + en = { + PANEL_NAME = "Addons", + AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" + VERSION = "Version: <>", + WEBSITE = "Visit Website", + FEEDBACK = "Feedback", + TRANSLATION = "Translation", + DONATION = "Donate", + PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", + RELOAD_UI_WARNING = "Changes to this setting require a UI reload in order to take effect.", + RELOAD_DIALOG_TITLE = "UI Reload Required", + RELOAD_DIALOG_TEXT = "Some changes require a UI reload in order to take effect. Do you want to reload now or discard the changes?", + RELOAD_DIALOG_RELOAD_BUTTON = "Reload", + RELOAD_DIALOG_DISCARD_BUTTON = "Discard", + }, + it = { -- provided by JohnnyKing + PANEL_NAME = "Addon", + VERSION = "Versione: <>", + WEBSITE = "Visita il Sitoweb", + FEEDBACK = "Feedback", + TRANSLATION = "Traduzione", + DONATION = "Donare", + RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", + RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", + RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", + RELOAD_DIALOG_RELOAD_BUTTON = "Ricarica", + RELOAD_DIALOG_DISCARD_BUTTON = "Annulla", + }, + fr = { -- provided by Ayantir + PANEL_NAME = "Extensions", + WEBSITE = "Visiter le site Web", + FEEDBACK = "Réaction", + TRANSLATION = "Traduction", + DONATION = "Donner", + RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", + RELOAD_DIALOG_TITLE = "Reload UI requis", + RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recharger", + RELOAD_DIALOG_DISCARD_BUTTON = "Annuler", + }, + de = { -- provided by sirinsidiator + PANEL_NAME = "Erweiterungen", + WEBSITE = "Webseite besuchen", + FEEDBACK = "Feedback", + TRANSLATION = "Übersetzung", + DONATION = "Spende", + RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", + RELOAD_DIALOG_TITLE = "Neuladen benötigt", + RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", + RELOAD_DIALOG_RELOAD_BUTTON = "Neu laden", + RELOAD_DIALOG_DISCARD_BUTTON = "Verwerfen", + }, + ru = { -- provided by TERAB1T + PANEL_NAME = "Дополнения", + VERSION = "Версия: <>", + WEBSITE = "Посетить сайт", + FEEDBACK = "отзыв", + TRANSLATION = "Перевод", + DONATION = "жертвовать", + PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", + RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", + RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", + RELOAD_DIALOG_TEXT = "Для применения некоторых изменений необходима перезагрузка интерфейса. Перезагрузить интерфейс сейчас или отменить изменения?", + RELOAD_DIALOG_RELOAD_BUTTON = "Перезагрузить", + RELOAD_DIALOG_DISCARD_BUTTON = "Отменить изменения", + }, + es = { -- provided by Morganlefai, checked by Kwisatz + PANEL_NAME = "Configuración", + VERSION = "Versión: <>", + WEBSITE = "Visita la página web", + FEEDBACK = "Reaccion", + TRANSLATION = "Traducción", + DONATION = "Donar", + RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", + RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", + RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recargar", + RELOAD_DIALOG_DISCARD_BUTTON = "Cancelar", + }, + jp = { -- provided by k0ta0uchi + PANEL_NAME = "アドオン設定", + WEBSITE = "ウェブサイトを見る", + FEEDBACK = "フィードバック", + TRANSLATION = "訳書", + DONATION = "寄贈する", + }, + zh = { -- provided by bssthu + PANEL_NAME = "插件", + VERSION = "版本: <>", + WEBSITE = "访问网站", + PANEL_INFO_FONT = "EsoZh/fonts/univers57.otf|14|soft-shadow-thin", + }, + pl = { -- provided by EmiruTegryfon + PANEL_NAME = "Dodatki", + VERSION = "Wersja: <>", + WEBSITE = "Odwiedź stronę", + RELOAD_UI_WARNING = "Zmiany będą widoczne po ponownym załadowaniu UI.", + RELOAD_DIALOG_TITLE = "Wymagane przeładowanie UI", + RELOAD_DIALOG_TEXT = "Niektóre zmiany wymagają ponownego załadowania UI. Czy chcesz teraz ponownie załadować, czy porzucić zmiany?", + RELOAD_DIALOG_RELOAD_BUTTON = "Przeładuj", + RELOAD_DIALOG_DISCARD_BUTTON = "Porzuć", + }, + kr = { -- provided by p.walker + PANEL_NAME = "蝠盜蠨", + VERSION = "纄訄: <>", + WEBSITE = "裹芬襴钸 縩紸", + PANEL_INFO_FONT = "EsoKR/fonts/Univers57.otf|14|soft-shadow-thin", + RELOAD_UI_WARNING = "襴 茤訕襄 绀溽靘籴 風滼筼 訁袩靘瀰褄靴 UI 苈穜滠遨襴 靄袔革瓈瓤.", + RELOAD_DIALOG_TITLE = "UI 苈穜滠遨 靄袔", + RELOAD_DIALOG_TEXT = "绀溽瘜 茤訕 謑 UI 苈穜滠遨襄 靄袔穜靘璔 芬靭襴 覈蒵瓈瓤. 诀瀈 苈穜滠遨靘蓜溠蒵瓈灌? 蝄瓈籴 绀溽襄 迨莌靘蓜溠蒵瓈灌?", + RELOAD_DIALOG_RELOAD_BUTTON = "苈穜滠遨", + RELOAD_DIALOG_DISCARD_BUTTON = "绀溽迨莌", + }, + br = { -- provided by mlsevero & FelipeS11 + PANEL_NAME = "Addons", + AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Autor: <>" + VERSION = "Versão: <>", + WEBSITE = "Visite o Website", + FEEDBACK = "Feedback", + TRANSLATION = "Tradução", + DONATION = "Doação", + RELOAD_UI_WARNING = "Mudanças nessa configuração requerem o recarregamento da UI para ter efeito.", + RELOAD_DIALOG_TITLE = "Recarregamento da UI requerida", + RELOAD_DIALOG_TEXT = "Algumas mudanças requerem o recarregamento da UI para ter efeito. Você deseja recarregar agora ou descartar as mudanças?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recarregar", + RELOAD_DIALOG_DISCARD_BUTTON = "Descartar", + }, +} + +util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")] or {}, localization["en"]) +util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead +util.GetStringFromValue = GetStringFromValue +util.GetDefaultValue = GetDefaultValue +util.GetColorForState = GetColorForState +util.CreateBaseControl = CreateBaseControl +util.CreateLabelAndContainerControl = CreateLabelAndContainerControl +util.RequestRefreshIfNeeded = RequestRefreshIfNeeded +util.RegisterForRefreshIfNeeded = RegisterForRefreshIfNeeded +util.RegisterForReloadIfNeeded = RegisterForReloadIfNeeded +util.GetTopPanel = GetTopPanel +util.ShowConfirmationDialog = ShowConfirmationDialog +util.UpdateWarning = UpdateWarning + +local ADDON_DATA_TYPE = 1 +local RESELECTING_DURING_REBUILD = true +local USER_REQUESTED_OPEN = true + + +--INTERNAL FUNCTION +--scrolls ZO_ScrollList `list` to move the row corresponding to `data` +-- into view (does nothing if there is no such row in the list) +--unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for +-- fading near the list's edges - it avoids the fading area by scrolling +-- a little further than the ZO function +local function ScrollDataIntoView(list, data) + local targetIndex = data.sortIndex + if not targetIndex then return end + + local scrollMin, scrollMax = list.scrollbar:GetMinMax() + local scrollTop = list.scrollbar:GetValue() + local controlHeight = list.uniformControlHeight or list.controlHeight + local targetMin = controlHeight * (targetIndex - 1) - 64 + -- subtracting 64 ain't arbitrary, it's the maximum fading height + -- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade) + + if targetMin < scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin)) + else + local listHeight = ZO_ScrollList_GetHeight(list) + local targetMax = controlHeight * targetIndex + 64 - listHeight + + if targetMax > scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax)) + end + end +end + + +--INTERNAL FUNCTION +--constructs a string pattern from the text in `searchEdit` control +-- * metacharacters are escaped, losing their special meaning +-- * whitespace matches anything (including empty substring) +--if there is nothing but whitespace, returns nil +--otherwise returns a filter function, which takes a `data` table argument +-- and returns true iff `data.filterText` matches the pattern +local function GetSearchFilterFunc(searchEdit) + local text = searchEdit:GetText():lower() + local pattern = text:match("(%S+.-)%s*$") + + if not pattern then -- nothing but whitespace + return nil + end + + -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de" + pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0") + + -- replace whitespace with "match shortest anything" + pattern = pattern:gsub("%s+", ".-") + + return function(data) + return data.filterText:lower():find(pattern) ~= nil + end +end + + +--INTERNAL FUNCTION +--populates `addonList` with entries from `addonsForList` +-- addonList = ZO_ScrollList control +-- filter = [optional] function(data) +local function PopulateAddonList(addonList, filter) + local entryList = ZO_ScrollList_GetDataList(addonList) + local numEntries = 0 + local selectedData = nil + local selectionIsFinal = false + + ZO_ScrollList_Clear(addonList) + + for i, data in ipairs(addonsForList) do + if not filter or filter(data) then + local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data) + numEntries = numEntries + 1 + data.sortIndex = numEntries + entryList[numEntries] = dataEntry + -- select the first panel passing the filter, or the currently + -- shown panel, but only if it passes the filter as well + if selectedData == nil or data.panel == lam.pendingAddonPanel or data.panel == lam.currentAddonPanel then + if not selectionIsFinal then + selectedData = data + end + if data.panel == lam.pendingAddonPanel then + lam.pendingAddonPanel = nil + selectionIsFinal = true + end + end + else + data.sortIndex = nil + end + end + + ZO_ScrollList_Commit(addonList) + + if selectedData then + if selectedData.panel == lam.currentAddonPanel then + ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD) + else + ZO_ScrollList_SelectData(addonList, selectedData, nil) + end + ScrollDataIntoView(addonList, selectedData) + end +end + + +--METHOD: REGISTER WIDGET-- +--each widget has its version checked before loading, +--so we only have the most recent one in memory +--Usage: +-- widgetType = "string"; the type of widget being registered +-- widgetVersion = integer; the widget's version number +LAMCreateControl = LAMCreateControl or {} +local lamcc = LAMCreateControl + +function lam:RegisterWidget(widgetType, widgetVersion) + if widgets[widgetType] and widgets[widgetType] >= widgetVersion then + return false + else + widgets[widgetType] = widgetVersion + return true + end +end + +-- INTERNAL METHOD: hijacks the handlers for the actions in the OptionsWindow layer if not already done +local function InitKeybindActions() + if not lam.keybindsInitialized then + lam.keybindsInitialized = true + ZO_PreHook(KEYBOARD_OPTIONS, "ApplySettings", function() + if lam.currentPanelOpened then + if not lam.applyButton:IsHidden() then + HandleReloadUIPressed() + end + return true + end + end) + ZO_PreHook("ZO_Dialogs_ShowDialog", function(dialogName) + if lam.currentPanelOpened and dialogName == "OPTIONS_RESET_TO_DEFAULTS" then + if not lam.defaultButton:IsHidden() then + HandleLoadDefaultsPressed() + end + return true + end + end) + end +end + +-- INTERNAL METHOD: fires the LAM-PanelOpened callback if not already done +local function OpenCurrentPanel() + if lam.currentAddonPanel and not lam.currentPanelOpened then + lam.currentPanelOpened = true + lam.defaultButton:SetHidden(not lam.currentAddonPanel.data.registerForDefaults) + cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel) + end +end + +-- INTERNAL METHOD: fires the LAM-PanelClosed callback if not already done +local function CloseCurrentPanel() + if lam.currentAddonPanel and lam.currentPanelOpened then + lam.currentPanelOpened = false + cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel) + end +end + +--METHOD: OPEN TO ADDON PANEL-- +--opens to a specific addon's option panel +--Usage: +-- panel = userdata; the panel returned by the :RegisterOptionsPanel method +local locSettings = GetString(SI_GAME_MENU_SETTINGS) +function lam:OpenToPanel(panel) + + -- find and select the panel's row in addon list + + local addonList = lam.addonList + local selectedData = nil + + for _, addonData in ipairs(addonsForList) do + if addonData.panel == panel then + selectedData = addonData + ScrollDataIntoView(addonList, selectedData) + lam.pendingAddonPanel = addonData.panel + break + end + end + + ZO_ScrollList_SelectData(addonList, selectedData) + ZO_ScrollList_RefreshVisible(addonList, selectedData) + + local srchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") + srchEdit:Clear() + + -- note that ZO_ScrollList doesn't require `selectedData` to be actually + -- present in the list, and that the list will only be populated once LAM + -- "Addon Settings" menu entry is selected for the first time + + local function openAddonSettingsMenu() + local gameMenu = ZO_GameMenu_InGame.gameMenu + local settingsMenu = gameMenu.headerControls[locSettings] + + if settingsMenu then -- an instance of ZO_TreeNode + local children = settingsMenu:GetChildren() + for i = 1, (children and #children or 0) do + local childNode = children[i] + local data = childNode:GetData() + if data and data.id == lam.panelId then + -- found LAM "Addon Settings" node, yay! + childNode:GetTree():SelectNode(childNode) + break + end + end + end + end + + if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then + openAddonSettingsMenu() + else + sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu) + sm:Show("gameMenuInGame") + end +end + +local TwinOptionsContainer_Index = 0 +local function TwinOptionsContainer(parent, leftWidget, rightWidget) + TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1 + local cParent = parent.scroll or parent + local panel = parent.panel or cParent + local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index), + cParent, CT_CONTROL) + container:SetResizeToFitDescendents(true) + container:SetAnchor(select(2, leftWidget:GetAnchor(0) )) + + leftWidget:ClearAnchors() + leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT) + rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0) + + leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls + rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 ) + + leftWidget:SetParent(container) + rightWidget:SetParent(container) + + container.data = {type = "container"} + container.panel = panel + return container +end + +--INTERNAL FUNCTION +--creates controls when options panel is first shown +--controls anchoring of these controls in the panel +local function CreateOptionsControls(panel) + local addonID = panel:GetName() + if(optionsState[addonID] == OPTIONS_CREATED) then + return false + elseif(optionsState[addonID] == OPTIONS_CREATION_RUNNING) then + return true + end + optionsState[addonID] = OPTIONS_CREATION_RUNNING + + local function CreationFinished() + optionsState[addonID] = OPTIONS_CREATED + cm:FireCallbacks("LAM-PanelControlsCreated", panel) + OpenCurrentPanel() + end + + local optionsTable = addonToOptionsMap[addonID] + if optionsTable then + local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf) + local widget + local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end) + if not status then + return err or true, offsetY, anchorTarget, wasHalf + else + local isHalf = (widgetData.width == "half") + if not anchorTarget then -- the first widget in a panel is just placed in the top left corner + widget:SetAnchor(TOPLEFT) + anchorTarget = widget + elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side + widget.lineControl = anchorTarget + isHalf = false + offsetY = 0 + anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget) + else -- otherwise we just put it below the previous one normally + widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15) + offsetY = 0 + anchorTarget = widget + end + return false, offsetY, anchorTarget, isHalf + end + end + + local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20 + local fifo = {} + local anchorOffset, lastAddedControl, wasHalf + local CreateWidgetsInPanel, err + + local function PrepareForNextPanel() + anchorOffset, lastAddedControl, wasHalf = 0, nil, false + end + + local function SetupCreationCalls(parent, widgetDataTable) + fifo[#fifo + 1] = PrepareForNextPanel + local count = #widgetDataTable + for i = 1, count, THROTTLE_COUNT do + fifo[#fifo + 1] = function() + CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count)) + end + end + return count ~= NonContiguousCount(widgetDataTable) + end + + CreateWidgetsInPanel = function(parent, widgetDataTable, startIndex, endIndex) + for i=startIndex,endIndex do + local widgetData = widgetDataTable[i] + if not widgetData then + PrintLater("Skipped creation of missing entry in the settings menu of " .. addonID .. ".") + else + local widgetType = widgetData.type + local offsetX = 0 + local isSubmenu = (widgetType == "submenu") + if isSubmenu then + wasHalf = false + offsetX = 5 + end + + err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) + if err then + PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) + if logger then + logger:Error(err) + end + end + + if isSubmenu then + if SetupCreationCalls(lastAddedControl, widgetData.controls) then + PrintLater(("The sub menu '%s' of %s is missing some entries."):format(GetStringFromValue(widgetData.name or "unnamed"), addonID)) + end + end + end + end + end + + local function DoCreateSettings() + if #fifo > 0 then + local nextCall = table.remove(fifo, 1) + nextCall() + if(nextCall == PrepareForNextPanel) then + DoCreateSettings() + else + zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT) + end + else + CreationFinished() + end + end + + if SetupCreationCalls(panel, optionsTable) then + PrintLater(("The settings menu of %s is missing some entries."):format(addonID)) + end + DoCreateSettings() + else + CreationFinished() + end + + return true +end + +--INTERNAL FUNCTION +--handles switching between panels +local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel + local currentlySelected = lam.currentAddonPanel + if currentlySelected and currentlySelected ~= panel then + currentlySelected:SetHidden(true) + CloseCurrentPanel() + end + lam.currentAddonPanel = panel + + -- refresh visible rows to reflect panel IsHidden status + ZO_ScrollList_RefreshVisible(lam.addonList) + + if not CreateOptionsControls(panel) then + OpenCurrentPanel() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) +end + +local CheckSafetyAndInitialize +local function ShowSetHandlerWarning(panel, handler) + local hint + if(handler == "OnShow" or handler == "OnEffectivelyShown") then + hint = "'LAM-PanelControlsCreated' or 'LAM-PanelOpened'" + elseif(handler == "OnHide" or handler == "OnEffectivelyHidden") then + hint = "'LAM-PanelClosed'" + end + + if hint then + local message = ("Setting a handler on a panel is not recommended. Use the global callback %s instead. (%s on %s)"):format(hint, handler, panel.data.name) + PrintLater(message) + if logger then + logger:Warn(message) + end + end +end + +--METHOD: REGISTER ADDON PANEL +--registers your addon with LibAddonMenu and creates a panel +--Usage: +-- addonID = "string"; unique ID which will be the global name of your panel +-- panelData = table; data object for your panel - see controls\panel.lua +function lam:RegisterAddonPanel(addonID, panelData) + CheckSafetyAndInitialize(addonID) + local container = lam:GetAddonPanelContainer() + local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel + panel:SetHidden(true) + panel:SetAnchorFill(container) + panel:SetHandler("OnEffectivelyShown", ToggleAddonPanels) + ZO_PreHook(panel, "SetHandler", ShowSetHandlerWarning) + + local function stripMarkup(str) + return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") + end + + local filterParts = {panelData.name, nil, nil} + -- append keywords and author separately, the may be nil + filterParts[#filterParts + 1] = panelData.keywords + filterParts[#filterParts + 1] = panelData.author + + local addonData = { + panel = panel, + name = stripMarkup(panelData.name), + filterText = stripMarkup(tconcat(filterParts, "\t")):lower(), + } + + tinsert(addonsForList, addonData) + + if panelData.slashCommand then + SLASH_COMMANDS[panelData.slashCommand] = function() + lam:OpenToPanel(panel) + end + end + + return panel --return for authors creating options manually +end + + +--METHOD: REGISTER OPTION CONTROLS +--registers the options you want shown for your addon +--these are stored in a table where each key-value pair is the order +--of the options in the panel and the data for that control, respectively +--see exampleoptions.lua for an example +--see controls\.lua for each widget type +--Usage: +-- addonID = "string"; the same string passed to :RegisterAddonPanel +-- optionsTable = table; the table containing all of the options controls and their data +function lam:RegisterOptionControls(addonID, optionsTable) --optionsTable = {sliderData, buttonData, etc} + addonToOptionsMap[addonID] = optionsTable +end + +--INTERNAL FUNCTION +--creates LAM's Addon Settings entry in ZO_GameMenu +local function CreateAddonSettingsMenuEntry() + local panelData = { + id = KEYBOARD_OPTIONS.currentPanelId, + name = util.L["PANEL_NAME"], + } + + KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1 + KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name + + lam.panelId = panelData.id + + local addonListSorted = false + + function panelData.callback() + sm:AddFragment(lam:GetAddonSettingsFragment()) + KEYBOARD_OPTIONS:ChangePanels(lam.panelId) + + local title = LAMAddonSettingsWindow:GetNamedChild("Title") + title:SetText(panelData.name) + + if not addonListSorted and #addonsForList > 0 then + local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") + --we're about to show our list for the first time - let's sort it + table.sort(addonsForList, function(a, b) return a.name < b.name end) + PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit)) + addonListSorted = true + end + end + + function panelData.unselectedCallback() + sm:RemoveFragment(lam:GetAddonSettingsFragment()) + if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011 + SetCameraOptionsPreviewModeEnabled(false) + end + end + + ZO_GameMenu_AddSettingPanel(panelData) +end + + +--INTERNAL FUNCTION +--creates the left-hand menu in LAM's window +local function CreateAddonList(name, parent) + local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList") + + local function addonListRow_OnMouseDown(control, button) + if button == 1 then + local data = ZO_ScrollList_GetData(control) + ZO_ScrollList_SelectData(addonList, data, control) + end + end + + local function addonListRow_OnMouseEnter(control) + ZO_ScrollList_MouseEnter(addonList, control) + end + + local function addonListRow_OnMouseExit(control) + ZO_ScrollList_MouseExit(addonList, control) + end + + local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild) + if not reselectingDuringRebuild then + if previouslySelectedData then + previouslySelectedData.panel:SetHidden(true) + end + if selectedData then + selectedData.panel:SetHidden(false) + PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION) + end + end + end + + local function addonListRow_Setup(control, data) + control:SetText(data.name) + control:SetSelected(not data.panel:IsHidden()) + end + + ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup) + -- I don't know how to make highlights clear properly; they often + -- get stuck and after a while the list is full of highlighted rows + --ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight") + ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select) + + local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE) + local addonListRow_CreateRaw = addonDataType.pool.m_Factory + + local function addonListRow_Create(pool) + local control = addonListRow_CreateRaw(pool) + control:SetHandler("OnMouseDown", addonListRow_OnMouseDown) + --control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter) + --control:SetHandler("OnMouseExit", addonListRow_OnMouseExit) + control:SetHeight(28) + control:SetFont("ZoFontHeader") + control:SetHorizontalAlignment(TEXT_ALIGN_LEFT) + control:SetVerticalAlignment(TEXT_ALIGN_CENTER) + control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + return control + end + + addonDataType.pool.m_Factory = addonListRow_Create + + return addonList +end + + +--INTERNAL FUNCTION +local function CreateSearchFilterBox(name, parent) + local boxControl = wm:CreateControl(name, parent, CT_CONTROL) + + local srchButton = wm:CreateControl("$(parent)Button", boxControl, CT_BUTTON) + srchButton:SetDimensions(32, 32) + srchButton:SetAnchor(LEFT, nil, LEFT, 2, 0) + srchButton:SetNormalTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_up.dds") + srchButton:SetPressedTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_down.dds") + srchButton:SetMouseOverTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_over.dds") + + local srchEdit = wm:CreateControlFromVirtual("$(parent)Edit", boxControl, "ZO_DefaultEdit") + srchEdit:SetAnchor(LEFT, srchButton, RIGHT, 4, 1) + srchEdit:SetAnchor(RIGHT, nil, RIGHT, -4, 1) + srchEdit:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) + + local srchBg = wm:CreateControl("$(parent)Bg", boxControl, CT_BACKDROP) + srchBg:SetAnchorFill() + srchBg:SetAlpha(0) + srchBg:SetCenterColor(0, 0, 0, 0.5) + srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) + srchBg:SetEdgeTexture("", 1, 1, 0, 0) + + -- search backdrop should appear whenever you hover over either + -- the magnifying glass button or the edit field (which is only + -- visible when it contains some text), and also while the edit + -- field has keyboard focus + + local srchActive = false + local srchHover = false + + local function srchBgUpdateAlpha() + if srchActive or srchEdit:HasFocus() then + srchBg:SetAlpha(srchHover and 0.8 or 0.6) + else + srchBg:SetAlpha(srchHover and 0.6 or 0.0) + end + end + + local function srchMouseEnter(control) + srchHover = true + srchBgUpdateAlpha() + end + + local function srchMouseExit(control) + srchHover = false + srchBgUpdateAlpha() + end + + boxControl:SetMouseEnabled(true) + boxControl:SetHitInsets(1, 1, -1, -1) + boxControl:SetHandler("OnMouseEnter", srchMouseEnter) + boxControl:SetHandler("OnMouseExit", srchMouseExit) + + srchButton:SetHandler("OnMouseEnter", srchMouseEnter) + srchButton:SetHandler("OnMouseExit", srchMouseExit) + + local focusLostTime = 0 + + srchButton:SetHandler("OnClicked", function(self) + srchEdit:Clear() + if GetFrameTimeMilliseconds() - focusLostTime < 100 then + -- re-focus the edit box if it lost focus due to this + -- button click (note that this handler may run a few + -- frames later) + srchEdit:TakeFocus() + end + end) + + srchEdit:SetHandler("OnMouseEnter", srchMouseEnter) + srchEdit:SetHandler("OnMouseExit", srchMouseExit) + srchEdit:SetHandler("OnFocusGained", srchBgUpdateAlpha) + + srchEdit:SetHandler("OnFocusLost", function() + focusLostTime = GetFrameTimeMilliseconds() + srchBgUpdateAlpha() + end) + + srchEdit:SetHandler("OnEscape", function(self) + self:Clear() + self:LoseFocus() + end) + + srchEdit:SetHandler("OnTextChanged", function(self) + local filterFunc = GetSearchFilterFunc(self) + if filterFunc then + srchActive = true + srchBg:SetEdgeColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA()) + srchButton:SetState(BSTATE_PRESSED) + else + srchActive = false + srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) + srchButton:SetState(BSTATE_NORMAL) + end + srchBgUpdateAlpha() + PopulateAddonList(lam.addonList, filterFunc) + PlaySound(SOUNDS.SPINNER_DOWN) + end) + + return boxControl +end + + +--INTERNAL FUNCTION +--creates LAM's Addon Settings top-level window +local function CreateAddonSettingsWindow() + local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow") + tlw:SetHidden(true) + tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow + + ZO_ReanchorControlForLeftSidePanel(tlw) + + -- create black background for the window (mimic ZO_RightFootPrintBackground) + + local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE) + bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds") + bgLeft:SetDimensions(1024, 1024) + bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT) + bgLeft:SetDrawLayer(DL_BACKGROUND) + bgLeft:SetExcludeFromResizeToFitExtents(true) + + local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE) + bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds") + bgRight:SetDimensions(64, 1024) + bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT) + bgRight:SetDrawLayer(DL_BACKGROUND) + bgRight:SetExcludeFromResizeToFitExtents(true) + + -- create gray background for addon list (mimic ZO_TreeUnderlay) + + local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE) + underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds") + underlayLeft:SetDimensions(256, 1024) + underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT) + underlayLeft:SetDrawLayer(DL_BACKGROUND) + underlayLeft:SetExcludeFromResizeToFitExtents(true) + + local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE) + underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds") + underlayRight:SetDimensions(128, 1024) + underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT) + underlayRight:SetDrawLayer(DL_BACKGROUND) + underlayRight:SetExcludeFromResizeToFitExtents(true) + + -- create title bar (mimic ZO_OptionsWindow) + + local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL) + title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70) + title:SetFont("ZoFontWinH1") + title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE) + + local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider") + divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108) + + -- create search filter box + + local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw) + srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120) + srchBox:SetDimensions(260, 30) + + -- create scrollable addon list + + local addonList = CreateAddonList("$(parent)AddonList", tlw) + addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160) + addonList:SetDimensions(285, 665) + + lam.addonList = addonList -- for easy access from elsewhere + + -- create container for option panels + + local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL) + panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120) + panelContainer:SetDimensions(645, 675) + + local defaultButton = wm:CreateControlFromVirtual("$(parent)ResetToDefaultButton", tlw, "ZO_DialogButton") + ZO_KeybindButtonTemplate_Setup(defaultButton, "OPTIONS_LOAD_DEFAULTS", HandleLoadDefaultsPressed, GetString(SI_OPTIONS_DEFAULTS)) + defaultButton:SetAnchor(TOPLEFT, panelContainer, BOTTOMLEFT, 0, 2) + lam.defaultButton = defaultButton + + local applyButton = wm:CreateControlFromVirtual("$(parent)ApplyButton", tlw, "ZO_DialogButton") + ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_ADDON_MANAGER_RELOAD)) + applyButton:SetAnchor(TOPRIGHT, panelContainer, BOTTOMRIGHT, 0, 2) + applyButton:SetHidden(true) + lam.applyButton = applyButton + + return tlw +end + + +--INITIALIZING +local safeToInitialize = false +local hasInitialized = false + +local eventHandle = table.concat({MAJOR, MINOR}, "r") +local function OnLoad(_, addonName) + -- wait for the first loaded event + em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED) + safeToInitialize = true +end +em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad) + +local function OnActivated(_, initial) + em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED) + FlushMessages() + + local reopenPanel = RetrievePanelForReopening() + if not initial and reopenPanel then + lam:OpenToPanel(reopenPanel) + end +end +em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated) + +function CheckSafetyAndInitialize(addonID) + if not safeToInitialize then + local msg = string.format("The panel with id '%s' was registered before addon loading has completed. This might break the AddOn Settings menu.", addonID) + PrintLater(msg) + end + if not hasInitialized then + hasInitialized = true + end +end + + +--TODO documentation +function lam:GetAddonPanelContainer() + local fragment = lam:GetAddonSettingsFragment() + local window = fragment:GetControl() + return window:GetNamedChild("PanelContainer") +end + + +--TODO documentation +function lam:GetAddonSettingsFragment() + assert(hasInitialized or safeToInitialize) + if not LAMAddonSettingsFragment then + local window = CreateAddonSettingsWindow() + LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100) + LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState) + if(newState == SCENE_FRAGMENT_SHOWN) then + InitKeybindActions() + PushActionLayerByName("OptionsWindow") + OpenCurrentPanel() + elseif(newState == SCENE_FRAGMENT_HIDDEN) then + CloseCurrentPanel() + RemoveActionLayerByName("OptionsWindow") + ShowReloadDialogIfNeeded() + end + end) + CreateAddonSettingsMenuEntry() + end + return LAMAddonSettingsFragment +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/button.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/button.lua new file mode 100644 index 0000000..17ecfef --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/button.lua @@ -0,0 +1,91 @@ +--[[buttonData = { + type = "button", + name = "My Button", -- string id or function returning a string + func = function() end, + tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + icon = "icon\\path.dds", -- (optional) + isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) + warning = "Will need to reload the UI.", -- (optional) + reference = "MyAddonButton", -- unique global reference to control (optional) +} ]] + +local widgetVersion = 11 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("button", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable = control.data.disabled + if type(disable) == "function" then + disable = disable() + end + control.button:SetEnabled(not disable) +end + +--controlName is optional +local MIN_HEIGHT = 28 -- default_button height +local HALF_WIDTH_LINE_SPACING = 2 +function LAMCreateControl.button(parent, buttonData, controlName) + local control = LAM.util.CreateBaseControl(parent, buttonData, controlName) + control:SetMouseEnabled(true) + + local width = control:GetWidth() + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + end + + if buttonData.icon then + control.button = wm:CreateControl(nil, control, CT_BUTTON) + control.button:SetDimensions(26, 26) + control.button:SetNormalTexture(buttonData.icon) + control.button:SetPressedOffset(2, 2) + else + --control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton") + control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton") + control.button:SetWidth(width / 3) + control.button:SetText(LAM.util.GetStringFromValue(buttonData.name)) + if buttonData.isDangerous then control.button:SetNormalFontColor(ZO_ERROR_COLOR:UnpackRGBA()) end + end + local button = control.button + button:SetAnchor(control.isHalfWidth and CENTER or RIGHT) + button:SetClickSound("Click") + button.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.tooltip)} + button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + button:SetHandler("OnClicked", function(...) + local args = {...} + local function callback() + buttonData.func(unpack(args)) + LAM.util.RequestRefreshIfNeeded(control) + end + + if(buttonData.isDangerous) then + local title = LAM.util.GetStringFromValue(buttonData.name) + local body = LAM.util.GetStringFromValue(buttonData.warning) + LAM.util.ShowConfirmationDialog(title, body, callback) + else + callback() + end + end) + + if buttonData.warning ~= nil then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + if buttonData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/checkbox.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/checkbox.lua new file mode 100644 index 0000000..8f48b63 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/checkbox.lua @@ -0,0 +1,142 @@ +--[[checkboxData = { + type = "checkbox", + name = "My Checkbox", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- a boolean or function that returns a boolean (optional) + reference = "MyAddonCheckbox", -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("checkbox", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +--label +local enabledColor = ZO_DEFAULT_ENABLED_COLOR +local enabledHLcolor = ZO_HIGHLIGHT_TEXT +local disabledColor = ZO_DEFAULT_DISABLED_COLOR +local disabledHLcolor = ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR +--checkbox +local checkboxColor = ZO_NORMAL_TEXT +local checkboxHLcolor = ZO_HIGHLIGHT_TEXT + + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA()) + control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA()) + --control:SetMouseEnabled(not disable) + --control:SetMouseEnabled(true) + + control.isDisabled = disable +end + +local function ToggleCheckbox(control) + if control.value then + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.checkbox:SetText(control.checkedText) + else + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.checkbox:SetText(control.uncheckedText) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value ~= nil then --our value could be false + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + control.value = value + + ToggleCheckbox(control) +end + +local function OnMouseEnter(control) + ZO_Options_OnMouseEnter(control) + + if control.isDisabled then return end + + local label = control.label + if control.value then + label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) + else + label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + end + control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) +end + +local function OnMouseExit(control) + ZO_Options_OnMouseExit(control) + + if control.isDisabled then return end + + local label = control.label + if control.value then + label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + else + label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + end + control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) +end + +--controlName is optional +function LAMCreateControl.checkbox(parent, checkboxData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, checkboxData, controlName) + control:SetHandler("OnMouseEnter", OnMouseEnter) + control:SetHandler("OnMouseExit", OnMouseExit) + control:SetHandler("OnMouseUp", function(control) + if control.isDisabled then return end + PlaySound(SOUNDS.DEFAULT_CLICK) + control.value = not control.value + control:UpdateValue(false, control.value) + end) + + control.checkbox = wm:CreateControl(nil, control.container, CT_LABEL) + local checkbox = control.checkbox + checkbox:SetAnchor(LEFT, control.container, LEFT, 0, 0) + checkbox:SetFont("ZoFontGameBold") + checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) + control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper() + control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper() + + if checkboxData.warning ~= nil or checkboxData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if checkboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/colorpicker.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/colorpicker.lua new file mode 100644 index 0000000..b62cfba --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/colorpicker.lua @@ -0,0 +1,110 @@ +--[[colorpickerData = { + type = "colorpicker", + name = "My Color Picker", -- or string id or function returning a string + getFunc = function() return db.r, db.g, db.b, db.a end, -- (alpha is optional) + setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, -- (alpha is optional) + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, -- (optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color + reference = "MyAddonColorpicker" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end + + control.isDisabled = disable +end + +local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) + if forceDefault then --if we are forcing defaults + local color = LAM.util.GetDefaultValue(control.data.default) + valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a + control.data.setFunc(valueR, valueG, valueB, valueA) + elseif valueR and valueG and valueB then + control.data.setFunc(valueR, valueG, valueB, valueA or 1) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + valueR, valueG, valueB, valueA = control.data.getFunc() + end + + control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) +end + +function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName) + + control.color = control.container + local color = control.color + + control.thumb = wm:CreateControl(nil, color, CT_TEXTURE) + local thumb = control.thumb + thumb:SetDimensions(36, 18) + thumb:SetAnchor(LEFT, color, LEFT, 4, 0) + + color.border = wm:CreateControl(nil, color, CT_TEXTURE) + local border = color.border + border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds") + border:SetTextureCoords(0, .625, 0, .8125) + border:SetDimensions(40, 22) + border:SetAnchor(CENTER, thumb, CENTER, 0, 0) + + local function ColorPickerCallback(r, g, b, a) + control:UpdateValue(false, r, g, b, a) + end + + control:SetHandler("OnMouseUp", function(self, btn, upInside) + if self.isDisabled then return end + + if upInside then + local r, g, b, a = colorpickerData.getFunc() + if IsInGamepadPreferredMode() then + COLOR_PICKER_GAMEPAD:Show(ColorPickerCallback, r, g, b, a) + else + COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a) + end + end + end) + + if colorpickerData.warning ~= nil or colorpickerData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if colorpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/custom.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/custom.lua new file mode 100644 index 0000000..eb6f26c --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/custom.lua @@ -0,0 +1,35 @@ +--[[customData = { + type = "custom", + reference = "MyAddonCustomControl", -- unique name for your control to use as reference (optional) + refreshFunc = function(customControl) end, -- function to call when panel/controls refresh (optional) + width = "full", -- or "half" (optional) +} ]] + +local widgetVersion = 7 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("custom", widgetVersion) then return end + +local function UpdateValue(control) + if control.data.refreshFunc then + control.data.refreshFunc(control) + end +end + +local MIN_HEIGHT = 26 +function LAMCreateControl.custom(parent, customData, controlName) + local control = LAM.util.CreateBaseControl(parent, customData, controlName) + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) + else + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) + end + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/description.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/description.lua new file mode 100644 index 0000000..a53c5b1 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/description.lua @@ -0,0 +1,80 @@ +--[[descriptionData = { + type = "description", + text = "My description text to display.", -- or string id or function returning a string + title = "My Title", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonDescription" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 9 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("description", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + control.desc:SetColor(color:UnpackRGBA()) + if control.title then + control.title:SetColor(color:UnpackRGBA()) + end + control.disabled = disable + end +end + +local function UpdateValue(control) + if control.title then + control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) + end + control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) +end + +function LAMCreateControl.description(parent, descriptionData, controlName) + local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if isHalfWidth then + control:SetDimensionConstraints(width / 2, 0, width / 2, 0) + else + control:SetDimensionConstraints(width, 0, width, 0) + end + + control.desc = wm:CreateControl(nil, control, CT_LABEL) + local desc = control.desc + desc:SetVerticalAlignment(TEXT_ALIGN_TOP) + desc:SetFont("ZoFontGame") + desc:SetText(LAM.util.GetStringFromValue(descriptionData.text)) + desc:SetWidth(isHalfWidth and width / 2 or width) + + if descriptionData.title then + control.title = wm:CreateControl(nil, control, CT_LABEL) + local title = control.title + title:SetWidth(isHalfWidth and width / 2 or width) + title:SetAnchor(TOPLEFT, control, TOPLEFT) + title:SetFont("ZoFontWinH4") + title:SetText(LAM.util.GetStringFromValue(descriptionData.title)) + desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT) + else + desc:SetAnchor(TOPLEFT) + end + + control.UpdateValue = UpdateValue + if descriptionData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control + +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/divider.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/divider.lua new file mode 100644 index 0000000..90ed6e8 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/divider.lua @@ -0,0 +1,45 @@ +--[[dividerData = { + type = "divider", + width = "full", -- or "half" (optional) + height = 10, -- (optional) + alpha = 0.25, -- (optional) + reference = "MyAddonDivider" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 2 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("divider", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local MIN_HEIGHT = 10 +local MAX_HEIGHT = 50 +local MIN_ALPHA = 0 +local MAX_ALPHA = 1 +local DEFAULT_ALPHA = 0.25 + +local function GetValueInRange(value, min, max, default) + if not value or type(value) ~= "number" then + return default + end + return math.min(math.max(min, value), max) +end + +function LAMCreateControl.divider(parent, dividerData, controlName) + local control = LAM.util.CreateBaseControl(parent, dividerData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + local height = GetValueInRange(dividerData.height, MIN_HEIGHT, MAX_HEIGHT, MIN_HEIGHT) + local alpha = GetValueInRange(dividerData.alpha, MIN_ALPHA, MAX_ALPHA, DEFAULT_ALPHA) + + control:SetDimensions(isHalfWidth and width / 2 or width, height) + + control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") + local divider = control.divider + divider:SetWidth(isHalfWidth and width / 2 or width) + divider:SetAnchor(TOPLEFT) + divider:SetAlpha(alpha) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/dropdown.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/dropdown.lua new file mode 100644 index 0000000..2f554cc --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/dropdown.lua @@ -0,0 +1,432 @@ +--[[dropdownData = { + type = "dropdown", + name = "My Dropdown", -- or string id or function returning a string + choices = {"table", "of", "choices"}, + choicesValues = {"foo", 2, "three"}, -- if specified, these values will get passed to setFunc instead (optional) + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + sort = "name-up", -- or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted + width = "full", -- or "half" (optional) + scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonDropdown" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 20 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("dropdown", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER +local SORT_BY_VALUE = { ["value"] = {} } +local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } +local SORT_TYPES = { + name = ZO_SORT_BY_NAME, + numeric = ZO_SORT_BY_NAME_NUMERIC, + value = SORT_BY_VALUE, + numericvalue = SORT_BY_VALUE_NUMERIC, +} +local SORT_ORDERS = { + up = ZO_SORT_ORDER_UP, + down = ZO_SORT_ORDER_DOWN, +} + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.dropdown:SetEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.dropdown:SetSelectedItem(control.choices[value]) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.dropdown:SetSelectedItem(control.choices[value]) + end +end + +local function DropdownCallback(control, choiceText, choice) + choice.control:UpdateValue(false, choice.value or choiceText) +end + +local function SetupTooltips(comboBox, choicesTooltips) + local function ShowTooltip(control) + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end + local function HideTooltip(control) + ClearTooltip(InformationTooltip) + end + + -- allow for tooltips on the drop down entries + local originalShow = comboBox.ShowDropdownInternal + comboBox.ShowDropdownInternal = function(comboBox) + originalShow(comboBox) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control.tooltip = choicesTooltips[i] + entry.onMouseEnter = control:GetHandler("OnMouseEnter") + entry.onMouseExit = control:GetHandler("OnMouseExit") + ZO_PreHookHandler(control, "OnMouseEnter", ShowTooltip) + ZO_PreHookHandler(control, "OnMouseExit", HideTooltip) + end + end + + local originalHide = comboBox.HideDropdownInternal + comboBox.HideDropdownInternal = function(self) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control:SetHandler("OnMouseEnter", entry.onMouseEnter) + control:SetHandler("OnMouseExit", entry.onMouseExit) + control.tooltip = nil + end + originalHide(self) + end +end + +local function UpdateChoices(control, choices, choicesValues, choicesTooltips) + control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?) + ZO_ClearTable(control.choices) + + --build new list of choices + local choices = choices or control.data.choices + local choicesValues = choicesValues or control.data.choicesValues + local choicesTooltips = choicesTooltips or control.data.choicesTooltips + + if choicesValues then + assert(#choices == #choicesValues, "choices and choicesValues need to have the same size") + end + + if choicesTooltips then + assert(#choices == #choicesTooltips, "choices and choicesTooltips need to have the same size") + if not control.scrollHelper then -- only do this for non-scrollable + SetupTooltips(control.dropdown, choicesTooltips) + end + end + + for i = 1, #choices do + local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback) + entry.control = control + if choicesValues then + entry.value = choicesValues[i] + end + if choicesTooltips and control.scrollHelper then + entry.tooltip = choicesTooltips[i] + end + control.choices[entry.value or entry.name] = entry.name + control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort + end +end + +local function GrabSortingInfo(sortInfo) + local t, i = {}, 1 + for info in string.gmatch(sortInfo, "([^%-]+)") do + t[i] = info + i = i + 1 + end + + return t +end + +local ENTRY_ID = 1 +local LAST_ENTRY_ID = 2 +local OFFSET_X_INDEX = 4 +local DEFAULT_VISIBLE_ROWS = 10 +local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = ZO_SCROLLABLE_ENTRY_TEMPLATE_HEIGHT +local SCROLLBAR_PADDING = ZO_SCROLL_BAR_WIDTH +local PADDING_X = GetMenuPadding() +local PADDING_Y = ZO_SCROLLABLE_COMBO_BOX_LIST_PADDING_Y +local LABEL_OFFSET_X = 2 +local CONTENT_PADDING = PADDING_X * 4 +local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed +local ScrollableDropdownHelper = ZO_Object:Subclass() + +function ScrollableDropdownHelper:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function ScrollableDropdownHelper:Initialize(panel, control, visibleRows) + local combobox = control.combobox + local dropdown = control.dropdown + self.panel = panel + self.control = control + self.combobox = combobox + self.dropdown = dropdown + self.visibleRows = visibleRows + + -- clear anchors so we can adjust the width dynamically + dropdown.m_dropdown:ClearAnchors() + dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) + + -- handle dropdown or settingsmenu opening/closing + local function onShow() return self:OnShow() end + local function onHide() self:OnHide() end + local function doHide(closedPanel) + if closedPanel == panel then self:DoHide() end + end + + ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) + ZO_PreHook(dropdown, "HideDropdownInternal", onHide) + combobox:SetHandler("OnEffectivelyHidden", onHide) + cm:RegisterCallback("LAM-PanelClosed", doHide) + + -- dont fade entries near the edges + local scrollList = dropdown.m_scroll + scrollList.selectionTemplate = nil + scrollList.highlightTemplate = nil + ZO_ScrollList_EnableSelection(scrollList, "ZO_SelectionHighlight") + ZO_ScrollList_EnableHighlight(scrollList, "ZO_SelectionHighlight") + ZO_Scroll_SetUseFadeGradient(scrollList, false) + + -- adjust scroll content anchor to mimic menu padding + local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") + local anchor1 = {select(2, scroll:GetAnchor(0))} + local anchor2 = {select(2, scroll:GetAnchor(1))} + anchor1[OFFSET_X_INDEX] = PADDING_X - LABEL_OFFSET_X + anchor2[OFFSET_X_INDEX] = -anchor1[OFFSET_X_INDEX] + scroll:ClearAnchors() + scroll:SetAnchor(unpack(anchor1)) + scroll:SetAnchor(unpack(anchor2)) + ZO_ScrollList_Commit(scrollList) + + -- hook mouse enter/exit + local function onMouseEnter(control) self:OnMouseEnter(control) end + local function onMouseExit(control) self:OnMouseExit(control) end + + -- adjust row setup to mimic the highlight padding + local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, ENTRY_ID) + local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, LAST_ENTRY_ID) + local oSetup = dataType1.setupCallback -- both types have the same setup function + local function SetupEntry(control, data, list) + oSetup(control, data, list) + control.m_label:SetAnchor(LEFT, nil, nil, LABEL_OFFSET_X) + control.m_label:SetAnchor(RIGHT, nil, nil, -LABEL_OFFSET_X) + -- no need to store old ones since we have full ownership of our dropdown controls + if not control.hookedMouseHandlers then --only do it once per control + control.hookedMouseHandlers = true + ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) + ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) + end + end + dataType1.setupCallback = SetupEntry + dataType2.setupCallback = SetupEntry + + -- adjust dimensions based on entries + local scrollContent = scroll:GetNamedChild("Contents") + dropdown.AddMenuItems = ScrollableDropdownHelper.AddMenuItems + + dropdown.AdjustDimensions = function() + local numItems = #dropdown.m_sortedItems + local contentWidth = self:CalculateContentWidth() + CONTENT_PADDING + local anchorOffset = 0 + if(numItems > self.visibleRows) then + numItems = self.visibleRows + contentWidth = contentWidth + SCROLLBAR_PADDING + anchorOffset = -SCROLLBAR_PADDING + end + + local width = zo_max(contentWidth, dropdown.m_container:GetWidth()) + local height = dropdown:GetEntryTemplateHeightWithSpacing() * numItems - dropdown.m_spacing + (PADDING_Y * 2) + ROUNDING_MARGIN + + dropdown.m_dropdown:SetWidth(width) + dropdown.m_dropdown:SetHeight(height) + ZO_ScrollList_SetHeight(dropdown.m_scroll, height) + + scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) + end +end + +local function CreateScrollableComboBoxEntry(self, item, index, isLast) + item.m_index = index + item.m_owner = self + local entryType = isLast and LAST_ENTRY_ID or ENTRY_ID + local entry = ZO_ScrollList_CreateDataEntry(entryType, item) + + return entry +end + +function ScrollableDropdownHelper.AddMenuItems(self) -- self refers to the ZO_ScrollableComboBox here + ZO_ScrollList_Clear(self.m_scroll) + + local numItems = #self.m_sortedItems + local dataList = ZO_ScrollList_GetDataList(self.m_scroll) + + for i = 1, numItems do + local item = self.m_sortedItems[i] + local entry = CreateScrollableComboBoxEntry(self, item, i, i == numItems) + table.insert(dataList, entry) + end + + self:AdjustDimensions() + + ZO_ScrollList_Commit(self.m_scroll) +end + +function ScrollableDropdownHelper:OnShow() + local dropdown = self.dropdown + + -- don't show if there are no entries + if #dropdown.m_sortedItems == 0 then return true end + + if dropdown.m_lastParent ~= ZO_Menus then + dropdown.m_lastParent = dropdown.m_dropdown:GetParent() + dropdown.m_dropdown:SetParent(ZO_Menus) + ZO_Menus:BringWindowToTop() + end +end + +function ScrollableDropdownHelper:OnHide() + local dropdown = self.dropdown + if dropdown.m_lastParent then + dropdown.m_dropdown:SetParent(dropdown.m_lastParent) + dropdown.m_lastParent = nil + end +end + +function ScrollableDropdownHelper:DoHide() + local dropdown = self.dropdown + if dropdown:IsDropdownVisible() then + dropdown:HideDropdown() + end +end + +function ScrollableDropdownHelper:CalculateContentWidth() + local dropdown = self.dropdown + local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) + + local dummy = dataType.pool:AcquireObject() + dataType.setupCallback(dummy, { + m_owner = dropdown, + name = "Dummy" + }, dropdown) + + local maxWidth = 0 + local label = dummy.m_label + local entries = dropdown.m_sortedItems + local numItems = #entries + for index = 1, numItems do + label:SetText(entries[index].name) + local width = label:GetTextWidth() + if (width > maxWidth) then + maxWidth = width + end + end + + dataType.pool:ReleaseObject(dummy.key) + return maxWidth +end + +function ScrollableDropdownHelper:OnMouseEnter(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseEnter(control) + -- show tooltip + if control.m_data.tooltip then + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.m_data.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end +end +function ScrollableDropdownHelper:OnMouseExit(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseExit(control) + -- hide tooltip + if control.m_data.tooltip then + ClearTooltip(InformationTooltip) + end +end + +function LAMCreateControl.dropdown(parent, dropdownData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName) + control.choices = {} + + local countControl = parent + local name = parent:GetName() + if not name or #name == 0 then + countControl = LAMCreateControl + name = "LAM" + end + local comboboxCount = (countControl.comboboxCount or 0) + 1 + countControl.comboboxCount = comboboxCount + control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, dropdownData.scrollable and "ZO_ScrollableComboBox" or "ZO_ComboBox") + + local combobox = control.combobox + combobox:SetAnchor(TOPLEFT) + combobox:SetDimensions(control.container:GetDimensions()) + combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox) + local dropdown = control.dropdown + dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value + + if dropdownData.scrollable then + local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS + control.scrollHelper = ScrollableDropdownHelper:New(LAM.util.GetTopPanel(parent), control, visibleRows) + end + + ZO_PreHook(dropdown, "UpdateItems", function(self) + assert(not self.m_sortsItems, "built-in dropdown sorting was reactivated, sorting is handled by LAM") + if control.m_sortOrder ~= nil and control.m_sortType then + local sortKey = next(control.m_sortType) + local sortFunc = function(item1, item2) return ZO_TableOrderingFunction(item1, item2, sortKey, control.m_sortType, control.m_sortOrder) end + table.sort(self.m_sortedItems, sortFunc) + end + end) + + if dropdownData.sort then + local sortInfo = GrabSortingInfo(dropdownData.sort) + control.m_sortType, control.m_sortOrder = SORT_TYPES[sortInfo[1]], SORT_ORDERS[sortInfo[2]] + elseif dropdownData.choicesValues then + control.m_sortType, control.m_sortOrder = ZO_SORT_ORDER_UP, SORT_BY_VALUE + end + + if dropdownData.warning ~= nil or dropdownData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateChoices = UpdateChoices + control:UpdateChoices(dropdownData.choices, dropdownData.choicesValues) + control.UpdateValue = UpdateValue + control:UpdateValue() + if dropdownData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/editbox.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/editbox.lua new file mode 100644 index 0000000..f9f79ad --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/editbox.lua @@ -0,0 +1,156 @@ +--[[editboxData = { + type = "editbox", + name = "My Editbox", -- or string id or function returning a string + getFunc = function() return db.text end, + setFunc = function(text) db.text = text doStuff() end, + tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) + isMultiline = true, -- boolean (optional) + isExtraWide = true, -- boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.text, -- default value or function that returns the default value (optional) + reference = "MyAddonEditbox" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("editbox", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.editbox:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end + --control.editbox:SetEditEnabled(not disable) + control.editbox:SetMouseEnabled(not disable) +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.editbox:SetText(value) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.editbox:SetText(value) + end +end + +local MIN_HEIGHT = 24 +local HALF_WIDTH_LINE_SPACING = 2 +function LAMCreateControl.editbox(parent, editboxData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, editboxData, controlName) + + local container = control.container + control.bg = wm:CreateControlFromVirtual(nil, container, "ZO_EditBackdrop") + local bg = control.bg + bg:SetAnchorFill() + + if editboxData.isMultiline then + control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditMultiLineForBackdrop") + control.editbox:SetHandler("OnMouseWheel", function(self, delta) + if self:HasFocus() then --only set focus to new spots if the editbox is currently in use + local cursorPos = self:GetCursorPosition() + local text = self:GetText() + local textLen = text:len() + local newPos + if delta > 0 then --scrolling up + local reverseText = text:reverse() + local revCursorPos = textLen - cursorPos + local revPos = reverseText:find("\n", revCursorPos+1) + newPos = revPos and textLen - revPos + else --scrolling down + newPos = text:find("\n", cursorPos+1) + end + if newPos then --if we found a new line, then scroll, otherwise don't + self:SetCursorPosition(newPos) + end + end + end) + else + control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop") + end + local editbox = control.editbox + editbox:SetText(editboxData.getFunc()) + editbox:SetMaxInputChars(3000) + editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end) + editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end) + editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0 + + control.label:ClearAnchors() + container:ClearAnchors() + + control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + + if control.isHalfWidth then + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + end + + if editboxData.isExtraWide then + container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0) + else + container:SetWidth(MIN_WIDTH * 3.2) + end + + if editboxData.isMultiline then + container:SetHeight(MIN_HEIGHT * 3) + else + container:SetHeight(MIN_HEIGHT) + end + + if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then + control:SetHeight(container:GetHeight()) + else + control:SetHeight(container:GetHeight() + control.label:GetHeight()) + end + + editbox:ClearAnchors() + editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2) + editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2) + + if editboxData.warning ~= nil or editboxData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + if editboxData.isExtraWide then + control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0) + else + control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0) + end + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + if editboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/header.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/header.lua new file mode 100644 index 0000000..3eda1d7 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/header.lua @@ -0,0 +1,42 @@ +--[[headerData = { + type = "header", + name = "My Header", -- or string id or function returning a string + width = "full", -- or "half" (optional) + reference = "MyAddonHeader" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 8 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("header", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateValue(control) + control.header:SetText(LAM.util.GetStringFromValue(control.data.name)) +end + +local MIN_HEIGHT = 30 +function LAMCreateControl.header(parent, headerData, controlName) + local control = LAM.util.CreateBaseControl(parent, headerData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + control:SetDimensions(isHalfWidth and width / 2 or width, MIN_HEIGHT) + + control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") + local divider = control.divider + divider:SetWidth(isHalfWidth and width / 2 or width) + divider:SetAnchor(TOPLEFT) + + control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local header = control.header + header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT) + header:SetAnchor(BOTTOMRIGHT) + header:SetText(LAM.util.GetStringFromValue(headerData.name)) + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/iconpicker.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/iconpicker.lua new file mode 100644 index 0000000..2cca460 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/iconpicker.lua @@ -0,0 +1,436 @@ +--[[iconpickerData = { + type = "iconpicker", + name = "My Icon Picker", -- or string id or function returning a string + choices = {"texture path 1", "texture path 2", "texture path 3"}, + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + maxColumns = 5, -- number of icons in one row (optional) + visibleRows = 4.5, -- number of visible rows (optional) + iconSize = 28, -- size of the icons (optional) + defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) + width = "full", --or "half" (optional) + beforeShow = function(control, iconPicker) return preventShow end, -- (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonIconPicker" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 8 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local IconPickerMenu = ZO_Object:Subclass() +local iconPicker +LAM.util.GetIconPickerMenu = function() + if not iconPicker then + iconPicker = IconPickerMenu:New("LAMIconPicker") + local sceneFragment = LAM:GetAddonSettingsFragment() + ZO_PreHook(sceneFragment, "OnHidden", function() + if not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + end) + end + return iconPicker +end + +function IconPickerMenu:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function IconPickerMenu:Initialize(name) + local control = wm:CreateTopLevelWindow(name) + control:SetDrawTier(DT_HIGH) + control:SetHidden(true) + self.control = control + + local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer") + -- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count + scrollContainer:SetAnchorFill() + ZO_Scroll_SetUseFadeGradient(scrollContainer, false) + ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false) + ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value + local scroll = GetControl(scrollContainer, "ScrollChild") + self.scroll = scroll + self.scrollContainer = scrollContainer + + local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP) + bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE) + mouseOver:SetDrawLevel(2) + mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds") + mouseOver:SetHidden(true) + + local function IconFactory(pool) + local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE) + icon:SetMouseEnabled(true) + icon:SetDrawLevel(3) + icon:SetHandler("OnMouseEnter", function() + mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0) + mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0) + mouseOver:SetHidden(false) + if self.customOnMouseEnter then + self.customOnMouseEnter(icon) + else + self:OnMouseEnter(icon) + end + end) + icon:SetHandler("OnMouseExit", function() + mouseOver:ClearAnchors() + mouseOver:SetHidden(true) + if self.customOnMouseExit then + self.customOnMouseExit(icon) + else + self:OnMouseExit(icon) + end + end) + icon:SetHandler("OnMouseUp", function(control, ...) + PlaySound("Click") + icon.OnSelect(icon, icon.texture) + self:Clear() + end) + return icon + end + + local function ResetFunction(icon) + icon:ClearAnchors() + end + + self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction) + self:SetMaxColumns(1) + self.icons = {} + self.color = ZO_DEFAULT_ENABLED_COLOR + + EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function() + if self.refCount ~= nil then + local moc = wm:GetMouseOverControl() + if(moc:GetOwningWindow() ~= control) then + self.refCount = self.refCount - 1 + if self.refCount <= 0 then + self:Clear() + end + end + end + end) +end + +function IconPickerMenu:OnMouseEnter(icon) + InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() +end + +function IconPickerMenu:OnMouseExit(icon) + ClearTooltip(InformationTooltip) +end + +function IconPickerMenu:SetMaxColumns(value) + self.maxCols = value ~= nil and value or 5 +end + +local DEFAULT_SIZE = 28 +function IconPickerMenu:SetIconSize(value) + local iconSize = DEFAULT_SIZE + if value ~= nil then iconSize = math.max(iconSize, value) end + self.iconSize = iconSize +end + +function IconPickerMenu:SetVisibleRows(value) + self.visibleRows = value ~= nil and value or 4.5 +end + +function IconPickerMenu:SetMouseHandlers(onEnter, onExit) + self.customOnMouseEnter = onEnter + self.customOnMouseExit = onExit +end + +function IconPickerMenu:UpdateDimensions() + local iconSize = self.iconSize + local width = iconSize * self.maxCols + 20 + local height = iconSize * self.visibleRows + self.control:SetDimensions(width, height) + + local icons = self.icons + for i = 1, #icons do + local icon = icons[i] + icon:SetDimensions(iconSize, iconSize) + end +end + +function IconPickerMenu:UpdateAnchors() + local iconSize = self.iconSize + local col, maxCols = 1, self.maxCols + local previousCol, previousRow + local scroll = self.scroll + local icons = self.icons + + for i = 1, #icons do + local icon = icons[i] + icon:ClearAnchors() + if i == 1 then + icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0) + previousRow = icon + elseif col == 1 then + icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0) + previousRow = icon + else + icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0) + end + previousCol = icon + col = col >= maxCols and 1 or col + 1 + end +end + +function IconPickerMenu:Clear() + self.icons = {} + self.iconPool:ReleaseAllObjects() + self.control:SetHidden(true) + self.color = ZO_DEFAULT_ENABLED_COLOR + self.refCount = nil + self.parent = nil + self.customOnMouseEnter = nil + self.customOnMouseExit = nil +end + +function IconPickerMenu:AddIcon(texturePath, callback, tooltip) + local icon, key = self.iconPool:AcquireObject() + icon:SetTexture(texturePath) + icon:SetColor(self.color:UnpackRGBA()) + icon.texture = texturePath + icon.tooltip = tooltip + icon.OnSelect = callback + self.icons[#self.icons + 1] = icon +end + +function IconPickerMenu:Show(parent) + if #self.icons == 0 then return false end + if not self.control:IsHidden() then self:Clear() return false end + self:UpdateDimensions() + self:UpdateAnchors() + + local control = self.control + control:ClearAnchors() + control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8) + control:SetHidden(false) + control:BringWindowToTop() + self.parent = parent + self.refCount = 2 + + return true +end + +function IconPickerMenu:SetColor(color) + local icons = self.icons + self.color = color + for i = 1, #icons do + local icon = icons[i] + icon:SetColor(color:UnpackRGBA()) + end +end + +------------------------------------------------------------- + +local function UpdateChoices(control, choices, choicesTooltips) + local data = control.data + if not choices then + choices, choicesTooltips = data.choices, data.choicesTooltips or {} + end + local addedChoices = {} + + local iconPicker = LAM.util.GetIconPickerMenu() + iconPicker:Clear() + for i = 1, #choices do + local texture = choices[i] + if not addedChoices[texture] then -- remove duplicates + iconPicker:AddIcon(choices[i], function(self, texture) + control.icon:SetTexture(texture) + data.setFunc(texture) + LAM.util.RequestRefreshIfNeeded(control) + end, LAM.util.GetStringFromValue(choicesTooltips[i])) + addedChoices[texture] = true + end + end +end + +local function IsDisabled(control) + if type(control.data.disabled) == "function" then + return control.data.disabled() + else + return control.data.disabled + end +end + +local function SetColor(control, color) + local icon = control.icon + if IsDisabled(control) then + icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR + icon:SetColor(icon.color:UnpackRGBA()) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetColor(icon.color) + end +end + +local function UpdateDisabled(control) + local disable = IsDisabled(control) + + control.dropdown:SetMouseEnabled(not disable) + control.dropdownButton:SetEnabled(not disable) + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + + SetColor(control, control.icon.color) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.icon:SetTexture(value) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.icon:SetTexture(value) + end +end + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local function SetIconSize(control, size) + local icon = control.icon + icon.size = size + icon:SetDimensions(size, size) + + local height = size + 4 + control.dropdown:SetDimensions(size + 20, height) + height = math.max(height, MIN_HEIGHT) + control.container:SetHeight(height) + if control.lineControl then + control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING) + else + control:SetHeight(height) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetIconSize(size) + iconPicker:UpdateDimensions() + iconPicker:UpdateAnchors() + end +end + +function LAMCreateControl.iconpicker(parent, iconpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName) + + local function ShowIconPicker() + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container then + iconPicker:Clear() + else + iconPicker:SetMaxColumns(iconpickerData.maxColumns) + iconPicker:SetVisibleRows(iconpickerData.visibleRows) + iconPicker:SetIconSize(control.icon.size) + UpdateChoices(control) + iconPicker:SetColor(control.icon.color) + if iconpickerData.beforeShow then + if iconpickerData.beforeShow(control, iconPicker) then + iconPicker:Clear() + return + end + end + iconPicker:Show(control.container) + end + end + + local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE + control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL) + local dropdown = control.dropdown + dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0) + dropdown:SetMouseEnabled(true) + dropdown:SetHandler("OnMouseUp", ShowIconPicker) + dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE) + local icon = control.icon + icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0) + icon:SetDrawLevel(2) + + local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton") + dropdownButton:SetDimensions(16, 16) + dropdownButton:SetHandler("OnClicked", ShowIconPicker) + dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0) + control.dropdownButton = dropdownButton + + control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + if iconpickerData.warning ~= nil or iconpickerData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateChoices = UpdateChoices + control.UpdateValue = UpdateValue + control:UpdateValue() + control.SetColor = SetColor + control:SetColor() + control.SetIconSize = SetIconSize + control:SetIconSize(iconSize) + + if iconpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/panel.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/panel.lua new file mode 100644 index 0000000..75bb904 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/panel.lua @@ -0,0 +1,168 @@ +--[[panelData = { + type = "panel", + name = "Window Title", -- or string id or function returning a string + displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) + author = "Seerah", -- or string id or function returning a string (optional) + version = "2.0", -- or string id or function returning a string (optional) + website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated or function (optional) + feedback = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where feedback/feature requests/bugs can be reported for the addon or function (optional) + translation = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where translation texts of the addon can be helped with or function (optional) + donation = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where a donation for the addon author can be raised or function (optional) + keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) + slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) + registerForRefresh = true, -- boolean will refresh all options controls when a setting is changed and when the panel is shown (optional) + registerForDefaults = true, -- boolean will set all options controls back to default values (optional) + resetFunc = function() print("defaults reset") end, -- custom function to run after settings are reset to defaults (optional) +} ]] + + +local widgetVersion = 15 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("panel", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER + +local function RefreshPanel(control) + local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu + if LAM.currentAddonPanel ~= panel or not LAM.currentPanelOpened then return end -- we refresh it later when the panel is opened + + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl ~= control and updateControl.UpdateValue then + updateControl:UpdateValue() + end + if updateControl.UpdateDisabled then + updateControl:UpdateDisabled() + end + if updateControl.UpdateWarning then + updateControl:UpdateWarning() + end + end +end + +local function ForceDefaults(panel) + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl.UpdateValue and updateControl.data.default ~= nil then + updateControl:UpdateValue(true) + end + end + + if panel.data.resetFunc then + panel.data.resetFunc() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) +end + +local callbackRegistered = false +LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 +local SEPARATOR = " - " +local COLORED_SEPARATOR = ZO_WHITE:Colorize(SEPARATOR) +local LINK_COLOR = ZO_ColorDef:New("5959D5") +local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") +local LINK_COLOR_DONATE = ZO_ColorDef:New("FFD700") -- golden +local LINK_MOUSE_OVER_COLOR_DONATE = ZO_ColorDef:New("FFF6CC") + +local function CreateButtonControl(control, label, clickAction, relativeTo) + local button = wm:CreateControl(nil, control, CT_BUTTON) + button:SetClickSound("Click") + button:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + button:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) + button:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) + + local OnClicked + local actionType = type(clickAction) + if actionType == "string" then + OnClicked = function() RequestOpenUnsafeURL(clickAction) end + elseif actionType == "function" then + OnClicked = clickAction + end + button:SetHandler("OnClicked", OnClicked) + + if relativeTo then + button:SetAnchor(TOPLEFT, relativeTo, TOPRIGHT, 0, 0) + button:SetText(COLORED_SEPARATOR .. label) + else + button:SetAnchor(TOPLEFT, control.label, BOTTOMLEFT, 0, -2) + button:SetText(label) + end + button:SetDimensions(button:GetLabelControl():GetTextDimensions()) + + return button +end + +function LAMCreateControl.panel(parent, panelData, controlName) + local control = wm:CreateControl(controlName, parent, CT_CONTROL) + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) + label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) + + local previousInfoControl + if panelData.author or panelData.version then + control.info = wm:CreateControl(nil, control, CT_LABEL) + local info = control.info + info:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) + + local output = {} + if panelData.author then + output[#output + 1] = zo_strformat(LAM.util.L["AUTHOR"], LAM.util.GetStringFromValue(panelData.author)) + end + if panelData.version then + output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) + end + info:SetText(table.concat(output, SEPARATOR)) + previousInfoControl = info + end + + if panelData.website then + control.website = CreateButtonControl(control, LAM.util.L["WEBSITE"], panelData.website, previousInfoControl) + previousInfoControl = control.website + end + + if panelData.feedback then + control.feedback = CreateButtonControl(control, LAM.util.L["FEEDBACK"], panelData.feedback, previousInfoControl) + previousInfoControl = control.feedback + end + + if panelData.translation then + control.translation = CreateButtonControl(control, LAM.util.L["TRANSLATION"], panelData.translation, previousInfoControl) + previousInfoControl = control.translation + end + + if panelData.donation then + control.donation = CreateButtonControl(control, LAM.util.L["DONATION"], panelData.donation, previousInfoControl) + local donation = control.donation + previousInfoControl = donation + donation:SetNormalFontColor(LINK_COLOR_DONATE:UnpackRGBA()) + donation:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR_DONATE:UnpackRGBA()) + end + + control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") + LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1 + local container = control.container + container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3) + control.scroll = GetControl(control.container, "ScrollChild") + control.scroll:SetResizeToFitPadding(0, 20) + + if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once + cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel) + callbackRegistered = true + end + + control.ForceDefaults = ForceDefaults + control.RefreshPanel = LAM.util.RequestRefreshIfNeeded + control.data = panelData + control.controlsToRefresh = {} + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/slider.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/slider.lua new file mode 100644 index 0000000..6c80968 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/slider.lua @@ -0,0 +1,220 @@ +--[[sliderData = { + type = "slider", + name = "My Slider", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + min = 0, + max = 20, + step = 1, -- (optional) + clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) + clampFunction = function(value, min, max) return math.max(math.min(value, max), min) end, -- function that is called to clamp the value (optional) + decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) + autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) + inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) + tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonSlider" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("slider", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local strformat = string.format + +local function RoundDecimalToPlace(d, place) + return tonumber(strformat("%." .. tostring(place) .. "f", d)) +end + +local function ClampValue(value, min, max) + return math.max(math.min(value, max), min) +end + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.slider:SetEnabled(not disable) + control.slidervalue:SetEditEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value then + if control.data.decimals then + value = RoundDecimalToPlace(value, control.data.decimals) + end + if control.data.clampInput ~= false then + local clamp = control.data.clampFunction or ClampValue + value = clamp(value, control.data.min, control.data.max) + end + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + + control.slider:SetValue(value) + control.slidervalue:SetText(value) +end + +function LAMCreateControl.slider(parent, sliderData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) + local isInputOnRight = sliderData.inputLocation == "right" + + --skipping creating the backdrop... Is this the actual slider texture? + control.slider = wm:CreateControl(nil, control.container, CT_SLIDER) + local slider = control.slider + slider:SetAnchor(TOPLEFT) + slider:SetHeight(14) + if(isInputOnRight) then + slider:SetAnchor(TOPRIGHT, nil, nil, -60) + else + slider:SetAnchor(TOPRIGHT) + end + slider:SetMouseEnabled(true) + slider:SetOrientation(ORIENTATION_HORIZONTAL) + --put nil for highlighted texture file path, and what look to be texture coords + slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16) + local minValue = sliderData.min + local maxValue = sliderData.max + slider:SetMinMax(minValue, maxValue) + slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + slider:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP) + local bg = slider.bg + bg:SetCenterColor(0, 0, 0) + bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4) + bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4) + + control.minText = wm:CreateControl(nil, slider, CT_LABEL) + local minText = control.minText + minText:SetFont("ZoFontGameSmall") + minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT) + minText:SetText(sliderData.min) + + control.maxText = wm:CreateControl(nil, slider, CT_LABEL) + local maxText = control.maxText + maxText:SetFont("ZoFontGameSmall") + maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT) + maxText:SetText(sliderData.max) + + control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop") + if(isInputOnRight) then + control.slidervalueBG:SetDimensions(60, 26) + control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0) + else + control.slidervalueBG:SetDimensions(50, 16) + control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0) + end + control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop") + local slidervalue = control.slidervalue + slidervalue:ClearAnchors() + slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1) + slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1) + slidervalue:SetTextType(TEXT_TYPE_NUMERIC) + if(isInputOnRight) then + slidervalue:SetFont("ZoFontGameLarge") + else + slidervalue:SetFont("ZoFontGameSmall") + end + + local isHandlingChange = false + local function HandleValueChanged(value) + if isHandlingChange then return end + if sliderData.decimals then + value = RoundDecimalToPlace(value, sliderData.decimals) + end + isHandlingChange = true + slider:SetValue(value) + slidervalue:SetText(value) + isHandlingChange = false + end + + slidervalue:SetHandler("OnEscape", function(self) + HandleValueChanged(sliderData.getFunc()) + self:LoseFocus() + end) + slidervalue:SetHandler("OnEnter", function(self) + self:LoseFocus() + end) + slidervalue:SetHandler("OnFocusLost", function(self) + local value = tonumber(self:GetText()) + control:UpdateValue(false, value) + end) + slidervalue:SetHandler("OnTextChanged", function(self) + local input = self:GetText() + if(#input > 1 and not input:sub(-1):match("[0-9]")) then return end + local value = tonumber(input) + if(value) then + HandleValueChanged(value) + end + end) + if(sliderData.autoSelect) then + ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self) + self:SelectAll() + end) + end + + local range = maxValue - minValue + slider:SetValueStep(sliderData.step or 1) + slider:SetHandler("OnValueChanged", function(self, value, eventReason) + if eventReason == EVENT_REASON_SOFTWARE then return end + HandleValueChanged(value) + end) + slider:SetHandler("OnSliderReleased", function(self, value) + if self:GetEnabled() then + control:UpdateValue(false, value) + end + end) + slider:SetHandler("OnMouseWheel", function(self, value) + if(not self:GetEnabled()) then return end + local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) + control:UpdateValue(false, new_value) + end) + + if sliderData.warning ~= nil or sliderData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + + if sliderData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/submenu.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/submenu.lua new file mode 100644 index 0000000..d7bc8bf --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/submenu.lua @@ -0,0 +1,182 @@ +--[[submenuData = { + type = "submenu", + name = "Submenu Title", -- or string id or function returning a string + icon = "path/to/my/icon.dds", -- or function returning a string (optional) + iconTextureCoords = {left, right, top, bottom}, -- or function returning a table (optional) + tooltip = "My submenu tooltip", -- or string id or function returning a string (optional) + controls = {sliderData, buttonData} -- used by LAM (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + disabledLabel = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonSubmenu" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("submenu", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local am = ANIMATION_MANAGER +local ICON_SIZE = 32 + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + if disable and control.open then + control.open = false + control.animation:PlayFromStart() + end + + control.arrow:SetColor(color:UnpackRGBA()) + control.disabled = disable + end + + local disableLabel = control.disabled or GetDefaultValue(control.data.disabledLabel) + if disableLabel ~= control.disabledLabel then + local color = GetColorForState(disableLabel) + control.label:SetColor(color:UnpackRGBA()) + if(control.icon) then + control.icon:SetDesaturation(disableLabel and 1 or 0) + end + control.disabledLabel = disableLabel + end +end + +local function UpdateValue(control) + control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) + + if control.icon then + control.icon:SetTexture(GetDefaultValue(control.data.icon)) + if(control.data.iconTextureCoords) then + local coords = GetDefaultValue(control.data.iconTextureCoords) + control.icon:SetTextureCoords(unpack(coords)) + end + end + + if control.data.tooltip then + control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) + end +end + +local function AnimateSubmenu(clicked) + local control = clicked:GetParent() + if control.disabled then return end + + control.open = not control.open + if control.open then + control.animation:PlayFromStart() + else + control.animation:PlayFromEnd() + end +end + +function LAMCreateControl.submenu(parent, submenuData, controlName) + local width = parent:GetWidth() - 45 + local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent + control.data = submenuData + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(LAM.util.GetStringFromValue(submenuData.name)) + label:SetMouseEnabled(true) + + if submenuData.icon then + control.icon = wm:CreateControl(nil, control, CT_TEXTURE) + local icon = control.icon + icon:SetTexture(GetDefaultValue(submenuData.icon)) + if(submenuData.iconTextureCoords) then + local coords = GetDefaultValue(submenuData.iconTextureCoords) + icon:SetTextureCoords(unpack(coords)) + end + icon:SetDimensions(ICON_SIZE, ICON_SIZE) + icon:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + icon:SetMouseEnabled(true) + icon:SetDrawLayer(DL_CONTROLS) + label:SetAnchor(TOP, control, TOP, 0, 5, ANCHOR_CONSTRAINS_Y) + label:SetAnchor(LEFT, icon, RIGHT, 10, 0, ANCHOR_CONSTRAINS_X) + label:SetDimensions(width - ICON_SIZE - 5, 30) + else + label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + label:SetDimensions(width, 30) + end + + if submenuData.tooltip then + label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} + label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + if control.icon then + control.icon.data = label.data + control.icon:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control.icon:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end + end + + control.scroll = wm:CreateControl(nil, control, CT_SCROLL) + local scroll = control.scroll + scroll:SetParent(control) + scroll:SetAnchor(TOPLEFT, control.icon or label, BOTTOMLEFT, 0, 10) + scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) + + control.bg = wm:CreateControl(nil, control.icon or label, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, control.icon or label, TOPLEFT, -5, -5) + bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + bg:SetDrawLayer(DL_BACKGROUND) + + control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) + local arrow = control.arrow + arrow:SetDimensions(28, 28) + arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way + arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5) + + --figure out the cool animation later... + control.animation = am:CreateTimeline() + local animation = control.animation + animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count + + control:SetResizeToFitDescendents(true) + control.open = false + label:SetHandler("OnMouseUp", AnimateSubmenu) + if(control.icon) then + control.icon:SetHandler("OnMouseUp", AnimateSubmenu) + end + animation:SetHandler("OnStop", function(self, completedPlaying) + scroll:SetResizeToFitDescendents(control.open) + if control.open then + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds") + scroll:SetResizeToFitPadding(5, 20) + else + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") + scroll:SetResizeToFitPadding(5, 0) + scroll:SetHeight(0) + end + end) + + --small strip at the bottom of the submenu that you can click to close it + control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE) + local btmToggle = control.btmToggle + btmToggle:SetMouseEnabled(true) + btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT) + btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT) + btmToggle:SetHeight(15) + btmToggle:SetAlpha(0) + btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) + + control.UpdateValue = UpdateValue + if submenuData.disabled ~= nil or submenuData.disabledLabel ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/texture.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/texture.lua new file mode 100644 index 0000000..6862ac2 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibAddonMenu-2.0/controls/texture.lua @@ -0,0 +1,45 @@ +--[[textureData = { + type = "texture", + image = "file/path.dds", + imageWidth = 64, -- max of 250 for half width, 510 for full + imageHeight = 32, -- max of 100 + tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + reference = "MyAddonTexture" -- unique global reference to control (optional) +} ]] + +-- TODO: add texture coords support? + +local widgetVersion = 9 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("texture", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local MIN_HEIGHT = 26 +function LAMCreateControl.texture(parent, textureData, controlName) + local control = LAM.util.CreateBaseControl(parent, textureData, controlName) + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) + else + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) + end + + control.texture = wm:CreateControl(nil, control, CT_TEXTURE) + local texture = control.texture + texture:SetAnchor(CENTER) + texture:SetDimensions(textureData.imageWidth, textureData.imageHeight) + texture:SetTexture(textureData.image) + + if textureData.tooltip then + texture:SetMouseEnabled(true) + texture.data = {tooltipText = LAM.util.GetStringFromValue(textureData.tooltip)} + texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + texture:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end + + return control +end diff --git a/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibStub/LibStub.lua b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibStub/LibStub.lua new file mode 100644 index 0000000..e6b8997 --- /dev/null +++ b/Elder Scrolls Online Addons/PersonalTimer2018/lib/LibStub/LibStub.lua @@ -0,0 +1,38 @@ +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info +-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +-- LibStub developed for World of Warcraft by above members of the WowAce community. +-- Ported to Elder Scrolls Online by Seerah + +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 5 +local LibStub = _G[LIBSTUB_MAJOR] + +local strformat = string.format +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + if type(minor) ~= "number" then + minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.") + end + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(strformat("Cannot find a library instance of %q.", tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end + +LibStub.SILENT = true \ No newline at end of file diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/LICENSE b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/LICENSE new file mode 100644 index 0000000..f69cbd4 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/LICENSE @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2016 Ryan Lakanen (Seerah) + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua new file mode 100644 index 0000000..20ffe3a --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -0,0 +1,1305 @@ +-- LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah) -- +-- Distributed under The Artistic License 2.0 (see LICENSE) -- +------------------------------------------------------------------ + + +--Register LAM with LibStub +local MAJOR, MINOR = "LibAddonMenu-2.0", 29 +local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) +if not lam then return end --the same or newer version of this lib is already loaded into memory +LibAddonMenu2 = lam + +local messages = {} +local MESSAGE_PREFIX = "[LAM2] " +local function PrintLater(msg) + if CHAT_SYSTEM.primaryContainer then + d(MESSAGE_PREFIX .. msg) + else + messages[#messages + 1] = msg + end +end + +local function FlushMessages() + for i = 1, #messages do + d(MESSAGE_PREFIX .. messages[i]) + end + messages = {} +end + +local logger +if LibDebugLogger then + logger = LibDebugLogger(MAJOR) +end + +if LAMSettingsPanelCreated and not LAMCompatibilityWarning then + PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") + LAMCompatibilityWarning = true +end + +--UPVALUES-- +local wm = WINDOW_MANAGER +local em = EVENT_MANAGER +local sm = SCENE_MANAGER +local cm = CALLBACK_MANAGER +local tconcat = table.concat +local tinsert = table.insert + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local OPTIONS_CREATION_RUNNING = 1 +local OPTIONS_CREATED = 2 +local LAM_CONFIRM_DIALOG = "LAM_CONFIRM_DIALOG" +local LAM_DEFAULTS_DIALOG = "LAM_DEFAULTS" +local LAM_RELOAD_DIALOG = "LAM_RELOAD_DIALOG" + +local addonsForList = {} +local addonToOptionsMap = {} +local optionsState = {} +lam.widgets = lam.widgets or {} +local widgets = lam.widgets +lam.util = lam.util or {} +local util = lam.util +lam.controlsForReload = lam.controlsForReload or {} +local controlsForReload = lam.controlsForReload + +local function GetDefaultValue(default) + if type(default) == "function" then + return default() + end + return default +end + +local function GetStringFromValue(value) + if type(value) == "function" then + return value() + elseif type(value) == "number" then + return GetString(value) + end + return value +end + +local function GetColorForState(disabled) + return disabled and ZO_DEFAULT_DISABLED_COLOR or ZO_DEFAULT_ENABLED_COLOR +end + +local function CreateBaseControl(parent, controlData, controlName) + local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent + control.data = controlData + + control.isHalfWidth = controlData.width == "half" + local width = 510 -- set default width in case a custom parent object is passed + if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end + control:SetWidth(width) + return control +end + +local function CreateLabelAndContainerControl(parent, controlData, controlName) + local control = CreateBaseControl(parent, controlData, controlName) + local width = control:GetWidth() + + local container = wm:CreateControl(nil, control, CT_CONTROL) + container:SetDimensions(width / 3, MIN_HEIGHT) + control.container = container + + local label = wm:CreateControl(nil, control, CT_LABEL) + label:SetFont("ZoFontWinH4") + label:SetHeight(MIN_HEIGHT) + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(GetStringFromValue(controlData.name)) + control.label = label + + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0) + end + + control.data.tooltipText = GetStringFromValue(control.data.tooltip) + control:SetMouseEnabled(true) + control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + return control +end + +local function GetTopPanel(panel) + while panel.panel and panel.panel ~= panel do + panel = panel.panel + end + return panel +end + +local function IsSame(objA, objB) + if #objA ~= #objB then return false end + for i = 1, #objA do + if objA[i] ~= objB[i] then return false end + end + return true +end + +local function RefreshReloadUIButton() + lam.requiresReload = false + + for i = 1, #controlsForReload do + local reloadControl = controlsForReload[i] + if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then + lam.requiresReload = true + break + end + end + + if lam.applyButton then + lam.applyButton:SetHidden(not lam.requiresReload) + end +end + +local function RequestRefreshIfNeeded(control) + -- if our parent window wants to refresh controls, then fire the callback + local panel = GetTopPanel(control) + local panelData = panel.data + if panelData.registerForRefresh then + cm:FireCallbacks("LAM-RefreshPanel", control) + end + RefreshReloadUIButton() +end + +local function RegisterForRefreshIfNeeded(control) + -- if our parent window wants to refresh controls, then add this to the list + local panel = GetTopPanel(control.panel) + local panelData = panel.data + if panelData.registerForRefresh or panelData.registerForDefaults then + tinsert(panel.controlsToRefresh or {}, control) -- prevent errors on custom panels + end +end + +local function RegisterForReloadIfNeeded(control) + if control.data.requiresReload then + tinsert(controlsForReload, control) + control.startValue = {control.data.getFunc()} + end +end + +local function GetConfirmDialog() + if(not ESO_Dialogs[LAM_CONFIRM_DIALOG]) then + ESO_Dialogs[LAM_CONFIRM_DIALOG] = { + canQueue = true, + title = { + text = "", + }, + mainText = { + text = "", + }, + buttons = { + [1] = { + text = SI_DIALOG_CONFIRM, + callback = function(dialog) end, + }, + [2] = { + text = SI_DIALOG_CANCEL, + } + } + } + end + return ESO_Dialogs[LAM_CONFIRM_DIALOG] +end + +local function ShowConfirmationDialog(title, body, callback) + local dialog = GetConfirmDialog() + dialog.title.text = title + dialog.mainText.text = body + dialog.buttons[1].callback = callback + ZO_Dialogs_ShowDialog(LAM_CONFIRM_DIALOG) +end + +local function GetDefaultsDialog() + if(not ESO_Dialogs[LAM_DEFAULTS_DIALOG]) then + ESO_Dialogs[LAM_DEFAULTS_DIALOG] = { + canQueue = true, + title = { + text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP, + }, + mainText = { + text = SI_OPTIONS_RESET_PROMPT, + }, + buttons = { + [1] = { + text = SI_OPTIONS_RESET, + callback = function(dialog) end, + }, + [2] = { + text = SI_DIALOG_CANCEL, + } + } + } + end + return ESO_Dialogs[LAM_DEFAULTS_DIALOG] +end + +local function ShowDefaultsDialog(panel) + local dialog = GetDefaultsDialog() + dialog.buttons[1].callback = function() + panel:ForceDefaults() + RefreshReloadUIButton() + end + ZO_Dialogs_ShowDialog(LAM_DEFAULTS_DIALOG) +end + +local function DiscardChangesOnReloadControls() + for i = 1, #controlsForReload do + local reloadControl = controlsForReload[i] + if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then + reloadControl:UpdateValue(false, unpack(reloadControl.startValue)) + end + end + lam.requiresReload = false + lam.applyButton:SetHidden(true) +end + +local function StorePanelForReopening() + local saveData = ZO_Ingame_SavedVariables["LAM"] or {} + saveData.reopenPanel = lam.currentAddonPanel:GetName() + ZO_Ingame_SavedVariables["LAM"] = saveData +end + +local function RetrievePanelForReopening() + local saveData = ZO_Ingame_SavedVariables["LAM"] + if(saveData) then + ZO_Ingame_SavedVariables["LAM"] = nil + return _G[saveData.reopenPanel] + end +end + +local function HandleReloadUIPressed() + StorePanelForReopening() + ReloadUI() +end + +local function HandleLoadDefaultsPressed() + ShowDefaultsDialog(lam.currentAddonPanel) +end + +local function GetReloadDialog() + if(not ESO_Dialogs[LAM_RELOAD_DIALOG]) then + ESO_Dialogs[LAM_RELOAD_DIALOG] = { + canQueue = true, + title = { + text = util.L["RELOAD_DIALOG_TITLE"], + }, + mainText = { + text = util.L["RELOAD_DIALOG_TEXT"], + }, + buttons = { + [1] = { + text = util.L["RELOAD_DIALOG_RELOAD_BUTTON"], + callback = function() ReloadUI() end, + }, + [2] = { + text = util.L["RELOAD_DIALOG_DISCARD_BUTTON"], + callback = DiscardChangesOnReloadControls, + } + }, + noChoiceCallback = DiscardChangesOnReloadControls, + } + end + return ESO_Dialogs[LAM_CONFIRM_DIALOG] +end + +local function ShowReloadDialogIfNeeded() + if lam.requiresReload then + local dialog = GetReloadDialog() + ZO_Dialogs_ShowDialog(LAM_RELOAD_DIALOG) + end +end + +local function UpdateWarning(control) + local warning + if control.data.warning ~= nil then + warning = util.GetStringFromValue(control.data.warning) + end + + if control.data.requiresReload then + if not warning then + warning = string.format("%s", util.L["RELOAD_UI_WARNING"]) + else + warning = string.format("%s\n\n%s", warning, util.L["RELOAD_UI_WARNING"]) + end + end + + if not warning then + control.warning:SetHidden(true) + else + control.warning.data = {tooltipText = warning} + control.warning:SetHidden(false) + end +end + +local localization = { + en = { + PANEL_NAME = "Addons", + AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" + VERSION = "Version: <>", + WEBSITE = "Visit Website", + FEEDBACK = "Feedback", + TRANSLATION = "Translation", + DONATION = "Donate", + PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", + RELOAD_UI_WARNING = "Changes to this setting require a UI reload in order to take effect.", + RELOAD_DIALOG_TITLE = "UI Reload Required", + RELOAD_DIALOG_TEXT = "Some changes require a UI reload in order to take effect. Do you want to reload now or discard the changes?", + RELOAD_DIALOG_RELOAD_BUTTON = "Reload", + RELOAD_DIALOG_DISCARD_BUTTON = "Discard", + }, + it = { -- provided by JohnnyKing + PANEL_NAME = "Addon", + VERSION = "Versione: <>", + WEBSITE = "Visita il Sitoweb", + FEEDBACK = "Feedback", + TRANSLATION = "Traduzione", + DONATION = "Donare", + RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", + RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", + RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", + RELOAD_DIALOG_RELOAD_BUTTON = "Ricarica", + RELOAD_DIALOG_DISCARD_BUTTON = "Annulla", + }, + fr = { -- provided by Ayantir + PANEL_NAME = "Extensions", + WEBSITE = "Visiter le site Web", + FEEDBACK = "Réaction", + TRANSLATION = "Traduction", + DONATION = "Donner", + RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", + RELOAD_DIALOG_TITLE = "Reload UI requis", + RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recharger", + RELOAD_DIALOG_DISCARD_BUTTON = "Annuler", + }, + de = { -- provided by sirinsidiator + PANEL_NAME = "Erweiterungen", + WEBSITE = "Webseite besuchen", + FEEDBACK = "Feedback", + TRANSLATION = "Übersetzung", + DONATION = "Spende", + RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", + RELOAD_DIALOG_TITLE = "Neuladen benötigt", + RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", + RELOAD_DIALOG_RELOAD_BUTTON = "Neu laden", + RELOAD_DIALOG_DISCARD_BUTTON = "Verwerfen", + }, + ru = { -- provided by TERAB1T + PANEL_NAME = "Дополнения", + VERSION = "Версия: <>", + WEBSITE = "Посетить сайт", + FEEDBACK = "отзыв", + TRANSLATION = "Перевод", + DONATION = "жертвовать", + PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", + RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", + RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", + RELOAD_DIALOG_TEXT = "Для применения некоторых изменений необходима перезагрузка интерфейса. Перезагрузить интерфейс сейчас или отменить изменения?", + RELOAD_DIALOG_RELOAD_BUTTON = "Перезагрузить", + RELOAD_DIALOG_DISCARD_BUTTON = "Отменить изменения", + }, + es = { -- provided by Morganlefai, checked by Kwisatz + PANEL_NAME = "Configuración", + VERSION = "Versión: <>", + WEBSITE = "Visita la página web", + FEEDBACK = "Reaccion", + TRANSLATION = "Traducción", + DONATION = "Donar", + RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", + RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", + RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recargar", + RELOAD_DIALOG_DISCARD_BUTTON = "Cancelar", + }, + jp = { -- provided by k0ta0uchi + PANEL_NAME = "アドオン設定", + WEBSITE = "ウェブサイトを見る", + FEEDBACK = "フィードバック", + TRANSLATION = "訳書", + DONATION = "寄贈する", + }, + zh = { -- provided by bssthu + PANEL_NAME = "插件", + VERSION = "版本: <>", + WEBSITE = "访问网站", + PANEL_INFO_FONT = "EsoZh/fonts/univers57.otf|14|soft-shadow-thin", + }, + pl = { -- provided by EmiruTegryfon + PANEL_NAME = "Dodatki", + VERSION = "Wersja: <>", + WEBSITE = "Odwiedź stronę", + RELOAD_UI_WARNING = "Zmiany będą widoczne po ponownym załadowaniu UI.", + RELOAD_DIALOG_TITLE = "Wymagane przeładowanie UI", + RELOAD_DIALOG_TEXT = "Niektóre zmiany wymagają ponownego załadowania UI. Czy chcesz teraz ponownie załadować, czy porzucić zmiany?", + RELOAD_DIALOG_RELOAD_BUTTON = "Przeładuj", + RELOAD_DIALOG_DISCARD_BUTTON = "Porzuć", + }, + kr = { -- provided by p.walker + PANEL_NAME = "蝠盜蠨", + VERSION = "纄訄: <>", + WEBSITE = "裹芬襴钸 縩紸", + PANEL_INFO_FONT = "EsoKR/fonts/Univers57.otf|14|soft-shadow-thin", + RELOAD_UI_WARNING = "襴 茤訕襄 绀溽靘籴 風滼筼 訁袩靘瀰褄靴 UI 苈穜滠遨襴 靄袔革瓈瓤.", + RELOAD_DIALOG_TITLE = "UI 苈穜滠遨 靄袔", + RELOAD_DIALOG_TEXT = "绀溽瘜 茤訕 謑 UI 苈穜滠遨襄 靄袔穜靘璔 芬靭襴 覈蒵瓈瓤. 诀瀈 苈穜滠遨靘蓜溠蒵瓈灌? 蝄瓈籴 绀溽襄 迨莌靘蓜溠蒵瓈灌?", + RELOAD_DIALOG_RELOAD_BUTTON = "苈穜滠遨", + RELOAD_DIALOG_DISCARD_BUTTON = "绀溽迨莌", + }, + br = { -- provided by mlsevero & FelipeS11 + PANEL_NAME = "Addons", + AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Autor: <>" + VERSION = "Versão: <>", + WEBSITE = "Visite o Website", + FEEDBACK = "Feedback", + TRANSLATION = "Tradução", + DONATION = "Doação", + RELOAD_UI_WARNING = "Mudanças nessa configuração requerem o recarregamento da UI para ter efeito.", + RELOAD_DIALOG_TITLE = "Recarregamento da UI requerida", + RELOAD_DIALOG_TEXT = "Algumas mudanças requerem o recarregamento da UI para ter efeito. Você deseja recarregar agora ou descartar as mudanças?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recarregar", + RELOAD_DIALOG_DISCARD_BUTTON = "Descartar", + }, +} + +util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")] or {}, localization["en"]) +util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead +util.GetStringFromValue = GetStringFromValue +util.GetDefaultValue = GetDefaultValue +util.GetColorForState = GetColorForState +util.CreateBaseControl = CreateBaseControl +util.CreateLabelAndContainerControl = CreateLabelAndContainerControl +util.RequestRefreshIfNeeded = RequestRefreshIfNeeded +util.RegisterForRefreshIfNeeded = RegisterForRefreshIfNeeded +util.RegisterForReloadIfNeeded = RegisterForReloadIfNeeded +util.GetTopPanel = GetTopPanel +util.ShowConfirmationDialog = ShowConfirmationDialog +util.UpdateWarning = UpdateWarning + +local ADDON_DATA_TYPE = 1 +local RESELECTING_DURING_REBUILD = true +local USER_REQUESTED_OPEN = true + + +--INTERNAL FUNCTION +--scrolls ZO_ScrollList `list` to move the row corresponding to `data` +-- into view (does nothing if there is no such row in the list) +--unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for +-- fading near the list's edges - it avoids the fading area by scrolling +-- a little further than the ZO function +local function ScrollDataIntoView(list, data) + local targetIndex = data.sortIndex + if not targetIndex then return end + + local scrollMin, scrollMax = list.scrollbar:GetMinMax() + local scrollTop = list.scrollbar:GetValue() + local controlHeight = list.uniformControlHeight or list.controlHeight + local targetMin = controlHeight * (targetIndex - 1) - 64 + -- subtracting 64 ain't arbitrary, it's the maximum fading height + -- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade) + + if targetMin < scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin)) + else + local listHeight = ZO_ScrollList_GetHeight(list) + local targetMax = controlHeight * targetIndex + 64 - listHeight + + if targetMax > scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax)) + end + end +end + + +--INTERNAL FUNCTION +--constructs a string pattern from the text in `searchEdit` control +-- * metacharacters are escaped, losing their special meaning +-- * whitespace matches anything (including empty substring) +--if there is nothing but whitespace, returns nil +--otherwise returns a filter function, which takes a `data` table argument +-- and returns true iff `data.filterText` matches the pattern +local function GetSearchFilterFunc(searchEdit) + local text = searchEdit:GetText():lower() + local pattern = text:match("(%S+.-)%s*$") + + if not pattern then -- nothing but whitespace + return nil + end + + -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de" + pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0") + + -- replace whitespace with "match shortest anything" + pattern = pattern:gsub("%s+", ".-") + + return function(data) + return data.filterText:lower():find(pattern) ~= nil + end +end + + +--INTERNAL FUNCTION +--populates `addonList` with entries from `addonsForList` +-- addonList = ZO_ScrollList control +-- filter = [optional] function(data) +local function PopulateAddonList(addonList, filter) + local entryList = ZO_ScrollList_GetDataList(addonList) + local numEntries = 0 + local selectedData = nil + local selectionIsFinal = false + + ZO_ScrollList_Clear(addonList) + + for i, data in ipairs(addonsForList) do + if not filter or filter(data) then + local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data) + numEntries = numEntries + 1 + data.sortIndex = numEntries + entryList[numEntries] = dataEntry + -- select the first panel passing the filter, or the currently + -- shown panel, but only if it passes the filter as well + if selectedData == nil or data.panel == lam.pendingAddonPanel or data.panel == lam.currentAddonPanel then + if not selectionIsFinal then + selectedData = data + end + if data.panel == lam.pendingAddonPanel then + lam.pendingAddonPanel = nil + selectionIsFinal = true + end + end + else + data.sortIndex = nil + end + end + + ZO_ScrollList_Commit(addonList) + + if selectedData then + if selectedData.panel == lam.currentAddonPanel then + ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD) + else + ZO_ScrollList_SelectData(addonList, selectedData, nil) + end + ScrollDataIntoView(addonList, selectedData) + end +end + + +--METHOD: REGISTER WIDGET-- +--each widget has its version checked before loading, +--so we only have the most recent one in memory +--Usage: +-- widgetType = "string"; the type of widget being registered +-- widgetVersion = integer; the widget's version number +LAMCreateControl = LAMCreateControl or {} +local lamcc = LAMCreateControl + +function lam:RegisterWidget(widgetType, widgetVersion) + if widgets[widgetType] and widgets[widgetType] >= widgetVersion then + return false + else + widgets[widgetType] = widgetVersion + return true + end +end + +-- INTERNAL METHOD: hijacks the handlers for the actions in the OptionsWindow layer if not already done +local function InitKeybindActions() + if not lam.keybindsInitialized then + lam.keybindsInitialized = true + ZO_PreHook(KEYBOARD_OPTIONS, "ApplySettings", function() + if lam.currentPanelOpened then + if not lam.applyButton:IsHidden() then + HandleReloadUIPressed() + end + return true + end + end) + ZO_PreHook("ZO_Dialogs_ShowDialog", function(dialogName) + if lam.currentPanelOpened and dialogName == "OPTIONS_RESET_TO_DEFAULTS" then + if not lam.defaultButton:IsHidden() then + HandleLoadDefaultsPressed() + end + return true + end + end) + end +end + +-- INTERNAL METHOD: fires the LAM-PanelOpened callback if not already done +local function OpenCurrentPanel() + if lam.currentAddonPanel and not lam.currentPanelOpened then + lam.currentPanelOpened = true + lam.defaultButton:SetHidden(not lam.currentAddonPanel.data.registerForDefaults) + cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel) + end +end + +-- INTERNAL METHOD: fires the LAM-PanelClosed callback if not already done +local function CloseCurrentPanel() + if lam.currentAddonPanel and lam.currentPanelOpened then + lam.currentPanelOpened = false + cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel) + end +end + +--METHOD: OPEN TO ADDON PANEL-- +--opens to a specific addon's option panel +--Usage: +-- panel = userdata; the panel returned by the :RegisterOptionsPanel method +local locSettings = GetString(SI_GAME_MENU_SETTINGS) +function lam:OpenToPanel(panel) + + -- find and select the panel's row in addon list + + local addonList = lam.addonList + local selectedData = nil + + for _, addonData in ipairs(addonsForList) do + if addonData.panel == panel then + selectedData = addonData + ScrollDataIntoView(addonList, selectedData) + lam.pendingAddonPanel = addonData.panel + break + end + end + + ZO_ScrollList_SelectData(addonList, selectedData) + ZO_ScrollList_RefreshVisible(addonList, selectedData) + + local srchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") + srchEdit:Clear() + + -- note that ZO_ScrollList doesn't require `selectedData` to be actually + -- present in the list, and that the list will only be populated once LAM + -- "Addon Settings" menu entry is selected for the first time + + local function openAddonSettingsMenu() + local gameMenu = ZO_GameMenu_InGame.gameMenu + local settingsMenu = gameMenu.headerControls[locSettings] + + if settingsMenu then -- an instance of ZO_TreeNode + local children = settingsMenu:GetChildren() + for i = 1, (children and #children or 0) do + local childNode = children[i] + local data = childNode:GetData() + if data and data.id == lam.panelId then + -- found LAM "Addon Settings" node, yay! + childNode:GetTree():SelectNode(childNode) + break + end + end + end + end + + if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then + openAddonSettingsMenu() + else + sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu) + sm:Show("gameMenuInGame") + end +end + +local TwinOptionsContainer_Index = 0 +local function TwinOptionsContainer(parent, leftWidget, rightWidget) + TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1 + local cParent = parent.scroll or parent + local panel = parent.panel or cParent + local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index), + cParent, CT_CONTROL) + container:SetResizeToFitDescendents(true) + container:SetAnchor(select(2, leftWidget:GetAnchor(0) )) + + leftWidget:ClearAnchors() + leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT) + rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0) + + leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls + rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 ) + + leftWidget:SetParent(container) + rightWidget:SetParent(container) + + container.data = {type = "container"} + container.panel = panel + return container +end + +--INTERNAL FUNCTION +--creates controls when options panel is first shown +--controls anchoring of these controls in the panel +local function CreateOptionsControls(panel) + local addonID = panel:GetName() + if(optionsState[addonID] == OPTIONS_CREATED) then + return false + elseif(optionsState[addonID] == OPTIONS_CREATION_RUNNING) then + return true + end + optionsState[addonID] = OPTIONS_CREATION_RUNNING + + local function CreationFinished() + optionsState[addonID] = OPTIONS_CREATED + cm:FireCallbacks("LAM-PanelControlsCreated", panel) + OpenCurrentPanel() + end + + local optionsTable = addonToOptionsMap[addonID] + if optionsTable then + local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf) + local widget + local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end) + if not status then + return err or true, offsetY, anchorTarget, wasHalf + else + local isHalf = (widgetData.width == "half") + if not anchorTarget then -- the first widget in a panel is just placed in the top left corner + widget:SetAnchor(TOPLEFT) + anchorTarget = widget + elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side + widget.lineControl = anchorTarget + isHalf = false + offsetY = 0 + anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget) + else -- otherwise we just put it below the previous one normally + widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15) + offsetY = 0 + anchorTarget = widget + end + return false, offsetY, anchorTarget, isHalf + end + end + + local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20 + local fifo = {} + local anchorOffset, lastAddedControl, wasHalf + local CreateWidgetsInPanel, err + + local function PrepareForNextPanel() + anchorOffset, lastAddedControl, wasHalf = 0, nil, false + end + + local function SetupCreationCalls(parent, widgetDataTable) + fifo[#fifo + 1] = PrepareForNextPanel + local count = #widgetDataTable + for i = 1, count, THROTTLE_COUNT do + fifo[#fifo + 1] = function() + CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count)) + end + end + return count ~= NonContiguousCount(widgetDataTable) + end + + CreateWidgetsInPanel = function(parent, widgetDataTable, startIndex, endIndex) + for i=startIndex,endIndex do + local widgetData = widgetDataTable[i] + if not widgetData then + PrintLater("Skipped creation of missing entry in the settings menu of " .. addonID .. ".") + else + local widgetType = widgetData.type + local offsetX = 0 + local isSubmenu = (widgetType == "submenu") + if isSubmenu then + wasHalf = false + offsetX = 5 + end + + err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) + if err then + PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) + if logger then + logger:Error(err) + end + end + + if isSubmenu then + if SetupCreationCalls(lastAddedControl, widgetData.controls) then + PrintLater(("The sub menu '%s' of %s is missing some entries."):format(GetStringFromValue(widgetData.name or "unnamed"), addonID)) + end + end + end + end + end + + local function DoCreateSettings() + if #fifo > 0 then + local nextCall = table.remove(fifo, 1) + nextCall() + if(nextCall == PrepareForNextPanel) then + DoCreateSettings() + else + zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT) + end + else + CreationFinished() + end + end + + if SetupCreationCalls(panel, optionsTable) then + PrintLater(("The settings menu of %s is missing some entries."):format(addonID)) + end + DoCreateSettings() + else + CreationFinished() + end + + return true +end + +--INTERNAL FUNCTION +--handles switching between panels +local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel + local currentlySelected = lam.currentAddonPanel + if currentlySelected and currentlySelected ~= panel then + currentlySelected:SetHidden(true) + CloseCurrentPanel() + end + lam.currentAddonPanel = panel + + -- refresh visible rows to reflect panel IsHidden status + ZO_ScrollList_RefreshVisible(lam.addonList) + + if not CreateOptionsControls(panel) then + OpenCurrentPanel() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) +end + +local CheckSafetyAndInitialize +local function ShowSetHandlerWarning(panel, handler) + local hint + if(handler == "OnShow" or handler == "OnEffectivelyShown") then + hint = "'LAM-PanelControlsCreated' or 'LAM-PanelOpened'" + elseif(handler == "OnHide" or handler == "OnEffectivelyHidden") then + hint = "'LAM-PanelClosed'" + end + + if hint then + local message = ("Setting a handler on a panel is not recommended. Use the global callback %s instead. (%s on %s)"):format(hint, handler, panel.data.name) + PrintLater(message) + if logger then + logger:Warn(message) + end + end +end + +--METHOD: REGISTER ADDON PANEL +--registers your addon with LibAddonMenu and creates a panel +--Usage: +-- addonID = "string"; unique ID which will be the global name of your panel +-- panelData = table; data object for your panel - see controls\panel.lua +function lam:RegisterAddonPanel(addonID, panelData) + CheckSafetyAndInitialize(addonID) + local container = lam:GetAddonPanelContainer() + local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel + panel:SetHidden(true) + panel:SetAnchorFill(container) + panel:SetHandler("OnEffectivelyShown", ToggleAddonPanels) + ZO_PreHook(panel, "SetHandler", ShowSetHandlerWarning) + + local function stripMarkup(str) + return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") + end + + local filterParts = {panelData.name, nil, nil} + -- append keywords and author separately, the may be nil + filterParts[#filterParts + 1] = panelData.keywords + filterParts[#filterParts + 1] = panelData.author + + local addonData = { + panel = panel, + name = stripMarkup(panelData.name), + filterText = stripMarkup(tconcat(filterParts, "\t")):lower(), + } + + tinsert(addonsForList, addonData) + + if panelData.slashCommand then + SLASH_COMMANDS[panelData.slashCommand] = function() + lam:OpenToPanel(panel) + end + end + + return panel --return for authors creating options manually +end + + +--METHOD: REGISTER OPTION CONTROLS +--registers the options you want shown for your addon +--these are stored in a table where each key-value pair is the order +--of the options in the panel and the data for that control, respectively +--see exampleoptions.lua for an example +--see controls\.lua for each widget type +--Usage: +-- addonID = "string"; the same string passed to :RegisterAddonPanel +-- optionsTable = table; the table containing all of the options controls and their data +function lam:RegisterOptionControls(addonID, optionsTable) --optionsTable = {sliderData, buttonData, etc} + addonToOptionsMap[addonID] = optionsTable +end + +--INTERNAL FUNCTION +--creates LAM's Addon Settings entry in ZO_GameMenu +local function CreateAddonSettingsMenuEntry() + local panelData = { + id = KEYBOARD_OPTIONS.currentPanelId, + name = util.L["PANEL_NAME"], + } + + KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1 + KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name + + lam.panelId = panelData.id + + local addonListSorted = false + + function panelData.callback() + sm:AddFragment(lam:GetAddonSettingsFragment()) + KEYBOARD_OPTIONS:ChangePanels(lam.panelId) + + local title = LAMAddonSettingsWindow:GetNamedChild("Title") + title:SetText(panelData.name) + + if not addonListSorted and #addonsForList > 0 then + local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") + --we're about to show our list for the first time - let's sort it + table.sort(addonsForList, function(a, b) return a.name < b.name end) + PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit)) + addonListSorted = true + end + end + + function panelData.unselectedCallback() + sm:RemoveFragment(lam:GetAddonSettingsFragment()) + if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011 + SetCameraOptionsPreviewModeEnabled(false) + end + end + + ZO_GameMenu_AddSettingPanel(panelData) +end + + +--INTERNAL FUNCTION +--creates the left-hand menu in LAM's window +local function CreateAddonList(name, parent) + local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList") + + local function addonListRow_OnMouseDown(control, button) + if button == 1 then + local data = ZO_ScrollList_GetData(control) + ZO_ScrollList_SelectData(addonList, data, control) + end + end + + local function addonListRow_OnMouseEnter(control) + ZO_ScrollList_MouseEnter(addonList, control) + end + + local function addonListRow_OnMouseExit(control) + ZO_ScrollList_MouseExit(addonList, control) + end + + local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild) + if not reselectingDuringRebuild then + if previouslySelectedData then + previouslySelectedData.panel:SetHidden(true) + end + if selectedData then + selectedData.panel:SetHidden(false) + PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION) + end + end + end + + local function addonListRow_Setup(control, data) + control:SetText(data.name) + control:SetSelected(not data.panel:IsHidden()) + end + + ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup) + -- I don't know how to make highlights clear properly; they often + -- get stuck and after a while the list is full of highlighted rows + --ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight") + ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select) + + local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE) + local addonListRow_CreateRaw = addonDataType.pool.m_Factory + + local function addonListRow_Create(pool) + local control = addonListRow_CreateRaw(pool) + control:SetHandler("OnMouseDown", addonListRow_OnMouseDown) + --control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter) + --control:SetHandler("OnMouseExit", addonListRow_OnMouseExit) + control:SetHeight(28) + control:SetFont("ZoFontHeader") + control:SetHorizontalAlignment(TEXT_ALIGN_LEFT) + control:SetVerticalAlignment(TEXT_ALIGN_CENTER) + control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + return control + end + + addonDataType.pool.m_Factory = addonListRow_Create + + return addonList +end + + +--INTERNAL FUNCTION +local function CreateSearchFilterBox(name, parent) + local boxControl = wm:CreateControl(name, parent, CT_CONTROL) + + local srchButton = wm:CreateControl("$(parent)Button", boxControl, CT_BUTTON) + srchButton:SetDimensions(32, 32) + srchButton:SetAnchor(LEFT, nil, LEFT, 2, 0) + srchButton:SetNormalTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_up.dds") + srchButton:SetPressedTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_down.dds") + srchButton:SetMouseOverTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_over.dds") + + local srchEdit = wm:CreateControlFromVirtual("$(parent)Edit", boxControl, "ZO_DefaultEdit") + srchEdit:SetAnchor(LEFT, srchButton, RIGHT, 4, 1) + srchEdit:SetAnchor(RIGHT, nil, RIGHT, -4, 1) + srchEdit:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) + + local srchBg = wm:CreateControl("$(parent)Bg", boxControl, CT_BACKDROP) + srchBg:SetAnchorFill() + srchBg:SetAlpha(0) + srchBg:SetCenterColor(0, 0, 0, 0.5) + srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) + srchBg:SetEdgeTexture("", 1, 1, 0, 0) + + -- search backdrop should appear whenever you hover over either + -- the magnifying glass button or the edit field (which is only + -- visible when it contains some text), and also while the edit + -- field has keyboard focus + + local srchActive = false + local srchHover = false + + local function srchBgUpdateAlpha() + if srchActive or srchEdit:HasFocus() then + srchBg:SetAlpha(srchHover and 0.8 or 0.6) + else + srchBg:SetAlpha(srchHover and 0.6 or 0.0) + end + end + + local function srchMouseEnter(control) + srchHover = true + srchBgUpdateAlpha() + end + + local function srchMouseExit(control) + srchHover = false + srchBgUpdateAlpha() + end + + boxControl:SetMouseEnabled(true) + boxControl:SetHitInsets(1, 1, -1, -1) + boxControl:SetHandler("OnMouseEnter", srchMouseEnter) + boxControl:SetHandler("OnMouseExit", srchMouseExit) + + srchButton:SetHandler("OnMouseEnter", srchMouseEnter) + srchButton:SetHandler("OnMouseExit", srchMouseExit) + + local focusLostTime = 0 + + srchButton:SetHandler("OnClicked", function(self) + srchEdit:Clear() + if GetFrameTimeMilliseconds() - focusLostTime < 100 then + -- re-focus the edit box if it lost focus due to this + -- button click (note that this handler may run a few + -- frames later) + srchEdit:TakeFocus() + end + end) + + srchEdit:SetHandler("OnMouseEnter", srchMouseEnter) + srchEdit:SetHandler("OnMouseExit", srchMouseExit) + srchEdit:SetHandler("OnFocusGained", srchBgUpdateAlpha) + + srchEdit:SetHandler("OnFocusLost", function() + focusLostTime = GetFrameTimeMilliseconds() + srchBgUpdateAlpha() + end) + + srchEdit:SetHandler("OnEscape", function(self) + self:Clear() + self:LoseFocus() + end) + + srchEdit:SetHandler("OnTextChanged", function(self) + local filterFunc = GetSearchFilterFunc(self) + if filterFunc then + srchActive = true + srchBg:SetEdgeColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA()) + srchButton:SetState(BSTATE_PRESSED) + else + srchActive = false + srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) + srchButton:SetState(BSTATE_NORMAL) + end + srchBgUpdateAlpha() + PopulateAddonList(lam.addonList, filterFunc) + PlaySound(SOUNDS.SPINNER_DOWN) + end) + + return boxControl +end + + +--INTERNAL FUNCTION +--creates LAM's Addon Settings top-level window +local function CreateAddonSettingsWindow() + local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow") + tlw:SetHidden(true) + tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow + + ZO_ReanchorControlForLeftSidePanel(tlw) + + -- create black background for the window (mimic ZO_RightFootPrintBackground) + + local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE) + bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds") + bgLeft:SetDimensions(1024, 1024) + bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT) + bgLeft:SetDrawLayer(DL_BACKGROUND) + bgLeft:SetExcludeFromResizeToFitExtents(true) + + local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE) + bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds") + bgRight:SetDimensions(64, 1024) + bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT) + bgRight:SetDrawLayer(DL_BACKGROUND) + bgRight:SetExcludeFromResizeToFitExtents(true) + + -- create gray background for addon list (mimic ZO_TreeUnderlay) + + local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE) + underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds") + underlayLeft:SetDimensions(256, 1024) + underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT) + underlayLeft:SetDrawLayer(DL_BACKGROUND) + underlayLeft:SetExcludeFromResizeToFitExtents(true) + + local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE) + underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds") + underlayRight:SetDimensions(128, 1024) + underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT) + underlayRight:SetDrawLayer(DL_BACKGROUND) + underlayRight:SetExcludeFromResizeToFitExtents(true) + + -- create title bar (mimic ZO_OptionsWindow) + + local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL) + title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70) + title:SetFont("ZoFontWinH1") + title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE) + + local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider") + divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108) + + -- create search filter box + + local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw) + srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120) + srchBox:SetDimensions(260, 30) + + -- create scrollable addon list + + local addonList = CreateAddonList("$(parent)AddonList", tlw) + addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160) + addonList:SetDimensions(285, 665) + + lam.addonList = addonList -- for easy access from elsewhere + + -- create container for option panels + + local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL) + panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120) + panelContainer:SetDimensions(645, 675) + + local defaultButton = wm:CreateControlFromVirtual("$(parent)ResetToDefaultButton", tlw, "ZO_DialogButton") + ZO_KeybindButtonTemplate_Setup(defaultButton, "OPTIONS_LOAD_DEFAULTS", HandleLoadDefaultsPressed, GetString(SI_OPTIONS_DEFAULTS)) + defaultButton:SetAnchor(TOPLEFT, panelContainer, BOTTOMLEFT, 0, 2) + lam.defaultButton = defaultButton + + local applyButton = wm:CreateControlFromVirtual("$(parent)ApplyButton", tlw, "ZO_DialogButton") + ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_ADDON_MANAGER_RELOAD)) + applyButton:SetAnchor(TOPRIGHT, panelContainer, BOTTOMRIGHT, 0, 2) + applyButton:SetHidden(true) + lam.applyButton = applyButton + + return tlw +end + + +--INITIALIZING +local safeToInitialize = false +local hasInitialized = false + +local eventHandle = table.concat({MAJOR, MINOR}, "r") +local function OnLoad(_, addonName) + -- wait for the first loaded event + em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED) + safeToInitialize = true +end +em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad) + +local function OnActivated(_, initial) + em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED) + FlushMessages() + + local reopenPanel = RetrievePanelForReopening() + if not initial and reopenPanel then + lam:OpenToPanel(reopenPanel) + end +end +em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated) + +function CheckSafetyAndInitialize(addonID) + if not safeToInitialize then + local msg = string.format("The panel with id '%s' was registered before addon loading has completed. This might break the AddOn Settings menu.", addonID) + PrintLater(msg) + end + if not hasInitialized then + hasInitialized = true + end +end + + +--TODO documentation +function lam:GetAddonPanelContainer() + local fragment = lam:GetAddonSettingsFragment() + local window = fragment:GetControl() + return window:GetNamedChild("PanelContainer") +end + + +--TODO documentation +function lam:GetAddonSettingsFragment() + assert(hasInitialized or safeToInitialize) + if not LAMAddonSettingsFragment then + local window = CreateAddonSettingsWindow() + LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100) + LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState) + if(newState == SCENE_FRAGMENT_SHOWN) then + InitKeybindActions() + PushActionLayerByName("OptionsWindow") + OpenCurrentPanel() + elseif(newState == SCENE_FRAGMENT_HIDDEN) then + CloseCurrentPanel() + RemoveActionLayerByName("OptionsWindow") + ShowReloadDialogIfNeeded() + end + end) + CreateAddonSettingsMenuEntry() + end + return LAMAddonSettingsFragment +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/button.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/button.lua new file mode 100644 index 0000000..17ecfef --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/button.lua @@ -0,0 +1,91 @@ +--[[buttonData = { + type = "button", + name = "My Button", -- string id or function returning a string + func = function() end, + tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + icon = "icon\\path.dds", -- (optional) + isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) + warning = "Will need to reload the UI.", -- (optional) + reference = "MyAddonButton", -- unique global reference to control (optional) +} ]] + +local widgetVersion = 11 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("button", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable = control.data.disabled + if type(disable) == "function" then + disable = disable() + end + control.button:SetEnabled(not disable) +end + +--controlName is optional +local MIN_HEIGHT = 28 -- default_button height +local HALF_WIDTH_LINE_SPACING = 2 +function LAMCreateControl.button(parent, buttonData, controlName) + local control = LAM.util.CreateBaseControl(parent, buttonData, controlName) + control:SetMouseEnabled(true) + + local width = control:GetWidth() + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + end + + if buttonData.icon then + control.button = wm:CreateControl(nil, control, CT_BUTTON) + control.button:SetDimensions(26, 26) + control.button:SetNormalTexture(buttonData.icon) + control.button:SetPressedOffset(2, 2) + else + --control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton") + control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton") + control.button:SetWidth(width / 3) + control.button:SetText(LAM.util.GetStringFromValue(buttonData.name)) + if buttonData.isDangerous then control.button:SetNormalFontColor(ZO_ERROR_COLOR:UnpackRGBA()) end + end + local button = control.button + button:SetAnchor(control.isHalfWidth and CENTER or RIGHT) + button:SetClickSound("Click") + button.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.tooltip)} + button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + button:SetHandler("OnClicked", function(...) + local args = {...} + local function callback() + buttonData.func(unpack(args)) + LAM.util.RequestRefreshIfNeeded(control) + end + + if(buttonData.isDangerous) then + local title = LAM.util.GetStringFromValue(buttonData.name) + local body = LAM.util.GetStringFromValue(buttonData.warning) + LAM.util.ShowConfirmationDialog(title, body, callback) + else + callback() + end + end) + + if buttonData.warning ~= nil then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + if buttonData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/checkbox.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/checkbox.lua new file mode 100644 index 0000000..8f48b63 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/checkbox.lua @@ -0,0 +1,142 @@ +--[[checkboxData = { + type = "checkbox", + name = "My Checkbox", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- a boolean or function that returns a boolean (optional) + reference = "MyAddonCheckbox", -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("checkbox", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +--label +local enabledColor = ZO_DEFAULT_ENABLED_COLOR +local enabledHLcolor = ZO_HIGHLIGHT_TEXT +local disabledColor = ZO_DEFAULT_DISABLED_COLOR +local disabledHLcolor = ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR +--checkbox +local checkboxColor = ZO_NORMAL_TEXT +local checkboxHLcolor = ZO_HIGHLIGHT_TEXT + + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA()) + control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA()) + --control:SetMouseEnabled(not disable) + --control:SetMouseEnabled(true) + + control.isDisabled = disable +end + +local function ToggleCheckbox(control) + if control.value then + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.checkbox:SetText(control.checkedText) + else + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.checkbox:SetText(control.uncheckedText) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value ~= nil then --our value could be false + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + control.value = value + + ToggleCheckbox(control) +end + +local function OnMouseEnter(control) + ZO_Options_OnMouseEnter(control) + + if control.isDisabled then return end + + local label = control.label + if control.value then + label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) + else + label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + end + control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) +end + +local function OnMouseExit(control) + ZO_Options_OnMouseExit(control) + + if control.isDisabled then return end + + local label = control.label + if control.value then + label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + else + label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + end + control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) +end + +--controlName is optional +function LAMCreateControl.checkbox(parent, checkboxData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, checkboxData, controlName) + control:SetHandler("OnMouseEnter", OnMouseEnter) + control:SetHandler("OnMouseExit", OnMouseExit) + control:SetHandler("OnMouseUp", function(control) + if control.isDisabled then return end + PlaySound(SOUNDS.DEFAULT_CLICK) + control.value = not control.value + control:UpdateValue(false, control.value) + end) + + control.checkbox = wm:CreateControl(nil, control.container, CT_LABEL) + local checkbox = control.checkbox + checkbox:SetAnchor(LEFT, control.container, LEFT, 0, 0) + checkbox:SetFont("ZoFontGameBold") + checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) + control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper() + control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper() + + if checkboxData.warning ~= nil or checkboxData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if checkboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/colorpicker.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/colorpicker.lua new file mode 100644 index 0000000..b62cfba --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/colorpicker.lua @@ -0,0 +1,110 @@ +--[[colorpickerData = { + type = "colorpicker", + name = "My Color Picker", -- or string id or function returning a string + getFunc = function() return db.r, db.g, db.b, db.a end, -- (alpha is optional) + setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, -- (alpha is optional) + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, -- (optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color + reference = "MyAddonColorpicker" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end + + control.isDisabled = disable +end + +local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) + if forceDefault then --if we are forcing defaults + local color = LAM.util.GetDefaultValue(control.data.default) + valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a + control.data.setFunc(valueR, valueG, valueB, valueA) + elseif valueR and valueG and valueB then + control.data.setFunc(valueR, valueG, valueB, valueA or 1) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + valueR, valueG, valueB, valueA = control.data.getFunc() + end + + control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) +end + +function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName) + + control.color = control.container + local color = control.color + + control.thumb = wm:CreateControl(nil, color, CT_TEXTURE) + local thumb = control.thumb + thumb:SetDimensions(36, 18) + thumb:SetAnchor(LEFT, color, LEFT, 4, 0) + + color.border = wm:CreateControl(nil, color, CT_TEXTURE) + local border = color.border + border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds") + border:SetTextureCoords(0, .625, 0, .8125) + border:SetDimensions(40, 22) + border:SetAnchor(CENTER, thumb, CENTER, 0, 0) + + local function ColorPickerCallback(r, g, b, a) + control:UpdateValue(false, r, g, b, a) + end + + control:SetHandler("OnMouseUp", function(self, btn, upInside) + if self.isDisabled then return end + + if upInside then + local r, g, b, a = colorpickerData.getFunc() + if IsInGamepadPreferredMode() then + COLOR_PICKER_GAMEPAD:Show(ColorPickerCallback, r, g, b, a) + else + COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a) + end + end + end) + + if colorpickerData.warning ~= nil or colorpickerData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if colorpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/custom.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/custom.lua new file mode 100644 index 0000000..eb6f26c --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/custom.lua @@ -0,0 +1,35 @@ +--[[customData = { + type = "custom", + reference = "MyAddonCustomControl", -- unique name for your control to use as reference (optional) + refreshFunc = function(customControl) end, -- function to call when panel/controls refresh (optional) + width = "full", -- or "half" (optional) +} ]] + +local widgetVersion = 7 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("custom", widgetVersion) then return end + +local function UpdateValue(control) + if control.data.refreshFunc then + control.data.refreshFunc(control) + end +end + +local MIN_HEIGHT = 26 +function LAMCreateControl.custom(parent, customData, controlName) + local control = LAM.util.CreateBaseControl(parent, customData, controlName) + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) + else + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) + end + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/description.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/description.lua new file mode 100644 index 0000000..a53c5b1 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/description.lua @@ -0,0 +1,80 @@ +--[[descriptionData = { + type = "description", + text = "My description text to display.", -- or string id or function returning a string + title = "My Title", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonDescription" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 9 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("description", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + control.desc:SetColor(color:UnpackRGBA()) + if control.title then + control.title:SetColor(color:UnpackRGBA()) + end + control.disabled = disable + end +end + +local function UpdateValue(control) + if control.title then + control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) + end + control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) +end + +function LAMCreateControl.description(parent, descriptionData, controlName) + local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if isHalfWidth then + control:SetDimensionConstraints(width / 2, 0, width / 2, 0) + else + control:SetDimensionConstraints(width, 0, width, 0) + end + + control.desc = wm:CreateControl(nil, control, CT_LABEL) + local desc = control.desc + desc:SetVerticalAlignment(TEXT_ALIGN_TOP) + desc:SetFont("ZoFontGame") + desc:SetText(LAM.util.GetStringFromValue(descriptionData.text)) + desc:SetWidth(isHalfWidth and width / 2 or width) + + if descriptionData.title then + control.title = wm:CreateControl(nil, control, CT_LABEL) + local title = control.title + title:SetWidth(isHalfWidth and width / 2 or width) + title:SetAnchor(TOPLEFT, control, TOPLEFT) + title:SetFont("ZoFontWinH4") + title:SetText(LAM.util.GetStringFromValue(descriptionData.title)) + desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT) + else + desc:SetAnchor(TOPLEFT) + end + + control.UpdateValue = UpdateValue + if descriptionData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control + +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/divider.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/divider.lua new file mode 100644 index 0000000..90ed6e8 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/divider.lua @@ -0,0 +1,45 @@ +--[[dividerData = { + type = "divider", + width = "full", -- or "half" (optional) + height = 10, -- (optional) + alpha = 0.25, -- (optional) + reference = "MyAddonDivider" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 2 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("divider", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local MIN_HEIGHT = 10 +local MAX_HEIGHT = 50 +local MIN_ALPHA = 0 +local MAX_ALPHA = 1 +local DEFAULT_ALPHA = 0.25 + +local function GetValueInRange(value, min, max, default) + if not value or type(value) ~= "number" then + return default + end + return math.min(math.max(min, value), max) +end + +function LAMCreateControl.divider(parent, dividerData, controlName) + local control = LAM.util.CreateBaseControl(parent, dividerData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + local height = GetValueInRange(dividerData.height, MIN_HEIGHT, MAX_HEIGHT, MIN_HEIGHT) + local alpha = GetValueInRange(dividerData.alpha, MIN_ALPHA, MAX_ALPHA, DEFAULT_ALPHA) + + control:SetDimensions(isHalfWidth and width / 2 or width, height) + + control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") + local divider = control.divider + divider:SetWidth(isHalfWidth and width / 2 or width) + divider:SetAnchor(TOPLEFT) + divider:SetAlpha(alpha) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/dropdown.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/dropdown.lua new file mode 100644 index 0000000..2f554cc --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/dropdown.lua @@ -0,0 +1,432 @@ +--[[dropdownData = { + type = "dropdown", + name = "My Dropdown", -- or string id or function returning a string + choices = {"table", "of", "choices"}, + choicesValues = {"foo", 2, "three"}, -- if specified, these values will get passed to setFunc instead (optional) + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + sort = "name-up", -- or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted + width = "full", -- or "half" (optional) + scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonDropdown" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 20 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("dropdown", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER +local SORT_BY_VALUE = { ["value"] = {} } +local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } +local SORT_TYPES = { + name = ZO_SORT_BY_NAME, + numeric = ZO_SORT_BY_NAME_NUMERIC, + value = SORT_BY_VALUE, + numericvalue = SORT_BY_VALUE_NUMERIC, +} +local SORT_ORDERS = { + up = ZO_SORT_ORDER_UP, + down = ZO_SORT_ORDER_DOWN, +} + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.dropdown:SetEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.dropdown:SetSelectedItem(control.choices[value]) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.dropdown:SetSelectedItem(control.choices[value]) + end +end + +local function DropdownCallback(control, choiceText, choice) + choice.control:UpdateValue(false, choice.value or choiceText) +end + +local function SetupTooltips(comboBox, choicesTooltips) + local function ShowTooltip(control) + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end + local function HideTooltip(control) + ClearTooltip(InformationTooltip) + end + + -- allow for tooltips on the drop down entries + local originalShow = comboBox.ShowDropdownInternal + comboBox.ShowDropdownInternal = function(comboBox) + originalShow(comboBox) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control.tooltip = choicesTooltips[i] + entry.onMouseEnter = control:GetHandler("OnMouseEnter") + entry.onMouseExit = control:GetHandler("OnMouseExit") + ZO_PreHookHandler(control, "OnMouseEnter", ShowTooltip) + ZO_PreHookHandler(control, "OnMouseExit", HideTooltip) + end + end + + local originalHide = comboBox.HideDropdownInternal + comboBox.HideDropdownInternal = function(self) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control:SetHandler("OnMouseEnter", entry.onMouseEnter) + control:SetHandler("OnMouseExit", entry.onMouseExit) + control.tooltip = nil + end + originalHide(self) + end +end + +local function UpdateChoices(control, choices, choicesValues, choicesTooltips) + control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?) + ZO_ClearTable(control.choices) + + --build new list of choices + local choices = choices or control.data.choices + local choicesValues = choicesValues or control.data.choicesValues + local choicesTooltips = choicesTooltips or control.data.choicesTooltips + + if choicesValues then + assert(#choices == #choicesValues, "choices and choicesValues need to have the same size") + end + + if choicesTooltips then + assert(#choices == #choicesTooltips, "choices and choicesTooltips need to have the same size") + if not control.scrollHelper then -- only do this for non-scrollable + SetupTooltips(control.dropdown, choicesTooltips) + end + end + + for i = 1, #choices do + local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback) + entry.control = control + if choicesValues then + entry.value = choicesValues[i] + end + if choicesTooltips and control.scrollHelper then + entry.tooltip = choicesTooltips[i] + end + control.choices[entry.value or entry.name] = entry.name + control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort + end +end + +local function GrabSortingInfo(sortInfo) + local t, i = {}, 1 + for info in string.gmatch(sortInfo, "([^%-]+)") do + t[i] = info + i = i + 1 + end + + return t +end + +local ENTRY_ID = 1 +local LAST_ENTRY_ID = 2 +local OFFSET_X_INDEX = 4 +local DEFAULT_VISIBLE_ROWS = 10 +local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = ZO_SCROLLABLE_ENTRY_TEMPLATE_HEIGHT +local SCROLLBAR_PADDING = ZO_SCROLL_BAR_WIDTH +local PADDING_X = GetMenuPadding() +local PADDING_Y = ZO_SCROLLABLE_COMBO_BOX_LIST_PADDING_Y +local LABEL_OFFSET_X = 2 +local CONTENT_PADDING = PADDING_X * 4 +local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed +local ScrollableDropdownHelper = ZO_Object:Subclass() + +function ScrollableDropdownHelper:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function ScrollableDropdownHelper:Initialize(panel, control, visibleRows) + local combobox = control.combobox + local dropdown = control.dropdown + self.panel = panel + self.control = control + self.combobox = combobox + self.dropdown = dropdown + self.visibleRows = visibleRows + + -- clear anchors so we can adjust the width dynamically + dropdown.m_dropdown:ClearAnchors() + dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) + + -- handle dropdown or settingsmenu opening/closing + local function onShow() return self:OnShow() end + local function onHide() self:OnHide() end + local function doHide(closedPanel) + if closedPanel == panel then self:DoHide() end + end + + ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) + ZO_PreHook(dropdown, "HideDropdownInternal", onHide) + combobox:SetHandler("OnEffectivelyHidden", onHide) + cm:RegisterCallback("LAM-PanelClosed", doHide) + + -- dont fade entries near the edges + local scrollList = dropdown.m_scroll + scrollList.selectionTemplate = nil + scrollList.highlightTemplate = nil + ZO_ScrollList_EnableSelection(scrollList, "ZO_SelectionHighlight") + ZO_ScrollList_EnableHighlight(scrollList, "ZO_SelectionHighlight") + ZO_Scroll_SetUseFadeGradient(scrollList, false) + + -- adjust scroll content anchor to mimic menu padding + local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") + local anchor1 = {select(2, scroll:GetAnchor(0))} + local anchor2 = {select(2, scroll:GetAnchor(1))} + anchor1[OFFSET_X_INDEX] = PADDING_X - LABEL_OFFSET_X + anchor2[OFFSET_X_INDEX] = -anchor1[OFFSET_X_INDEX] + scroll:ClearAnchors() + scroll:SetAnchor(unpack(anchor1)) + scroll:SetAnchor(unpack(anchor2)) + ZO_ScrollList_Commit(scrollList) + + -- hook mouse enter/exit + local function onMouseEnter(control) self:OnMouseEnter(control) end + local function onMouseExit(control) self:OnMouseExit(control) end + + -- adjust row setup to mimic the highlight padding + local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, ENTRY_ID) + local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, LAST_ENTRY_ID) + local oSetup = dataType1.setupCallback -- both types have the same setup function + local function SetupEntry(control, data, list) + oSetup(control, data, list) + control.m_label:SetAnchor(LEFT, nil, nil, LABEL_OFFSET_X) + control.m_label:SetAnchor(RIGHT, nil, nil, -LABEL_OFFSET_X) + -- no need to store old ones since we have full ownership of our dropdown controls + if not control.hookedMouseHandlers then --only do it once per control + control.hookedMouseHandlers = true + ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) + ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) + end + end + dataType1.setupCallback = SetupEntry + dataType2.setupCallback = SetupEntry + + -- adjust dimensions based on entries + local scrollContent = scroll:GetNamedChild("Contents") + dropdown.AddMenuItems = ScrollableDropdownHelper.AddMenuItems + + dropdown.AdjustDimensions = function() + local numItems = #dropdown.m_sortedItems + local contentWidth = self:CalculateContentWidth() + CONTENT_PADDING + local anchorOffset = 0 + if(numItems > self.visibleRows) then + numItems = self.visibleRows + contentWidth = contentWidth + SCROLLBAR_PADDING + anchorOffset = -SCROLLBAR_PADDING + end + + local width = zo_max(contentWidth, dropdown.m_container:GetWidth()) + local height = dropdown:GetEntryTemplateHeightWithSpacing() * numItems - dropdown.m_spacing + (PADDING_Y * 2) + ROUNDING_MARGIN + + dropdown.m_dropdown:SetWidth(width) + dropdown.m_dropdown:SetHeight(height) + ZO_ScrollList_SetHeight(dropdown.m_scroll, height) + + scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) + end +end + +local function CreateScrollableComboBoxEntry(self, item, index, isLast) + item.m_index = index + item.m_owner = self + local entryType = isLast and LAST_ENTRY_ID or ENTRY_ID + local entry = ZO_ScrollList_CreateDataEntry(entryType, item) + + return entry +end + +function ScrollableDropdownHelper.AddMenuItems(self) -- self refers to the ZO_ScrollableComboBox here + ZO_ScrollList_Clear(self.m_scroll) + + local numItems = #self.m_sortedItems + local dataList = ZO_ScrollList_GetDataList(self.m_scroll) + + for i = 1, numItems do + local item = self.m_sortedItems[i] + local entry = CreateScrollableComboBoxEntry(self, item, i, i == numItems) + table.insert(dataList, entry) + end + + self:AdjustDimensions() + + ZO_ScrollList_Commit(self.m_scroll) +end + +function ScrollableDropdownHelper:OnShow() + local dropdown = self.dropdown + + -- don't show if there are no entries + if #dropdown.m_sortedItems == 0 then return true end + + if dropdown.m_lastParent ~= ZO_Menus then + dropdown.m_lastParent = dropdown.m_dropdown:GetParent() + dropdown.m_dropdown:SetParent(ZO_Menus) + ZO_Menus:BringWindowToTop() + end +end + +function ScrollableDropdownHelper:OnHide() + local dropdown = self.dropdown + if dropdown.m_lastParent then + dropdown.m_dropdown:SetParent(dropdown.m_lastParent) + dropdown.m_lastParent = nil + end +end + +function ScrollableDropdownHelper:DoHide() + local dropdown = self.dropdown + if dropdown:IsDropdownVisible() then + dropdown:HideDropdown() + end +end + +function ScrollableDropdownHelper:CalculateContentWidth() + local dropdown = self.dropdown + local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) + + local dummy = dataType.pool:AcquireObject() + dataType.setupCallback(dummy, { + m_owner = dropdown, + name = "Dummy" + }, dropdown) + + local maxWidth = 0 + local label = dummy.m_label + local entries = dropdown.m_sortedItems + local numItems = #entries + for index = 1, numItems do + label:SetText(entries[index].name) + local width = label:GetTextWidth() + if (width > maxWidth) then + maxWidth = width + end + end + + dataType.pool:ReleaseObject(dummy.key) + return maxWidth +end + +function ScrollableDropdownHelper:OnMouseEnter(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseEnter(control) + -- show tooltip + if control.m_data.tooltip then + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.m_data.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end +end +function ScrollableDropdownHelper:OnMouseExit(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseExit(control) + -- hide tooltip + if control.m_data.tooltip then + ClearTooltip(InformationTooltip) + end +end + +function LAMCreateControl.dropdown(parent, dropdownData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName) + control.choices = {} + + local countControl = parent + local name = parent:GetName() + if not name or #name == 0 then + countControl = LAMCreateControl + name = "LAM" + end + local comboboxCount = (countControl.comboboxCount or 0) + 1 + countControl.comboboxCount = comboboxCount + control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, dropdownData.scrollable and "ZO_ScrollableComboBox" or "ZO_ComboBox") + + local combobox = control.combobox + combobox:SetAnchor(TOPLEFT) + combobox:SetDimensions(control.container:GetDimensions()) + combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox) + local dropdown = control.dropdown + dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value + + if dropdownData.scrollable then + local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS + control.scrollHelper = ScrollableDropdownHelper:New(LAM.util.GetTopPanel(parent), control, visibleRows) + end + + ZO_PreHook(dropdown, "UpdateItems", function(self) + assert(not self.m_sortsItems, "built-in dropdown sorting was reactivated, sorting is handled by LAM") + if control.m_sortOrder ~= nil and control.m_sortType then + local sortKey = next(control.m_sortType) + local sortFunc = function(item1, item2) return ZO_TableOrderingFunction(item1, item2, sortKey, control.m_sortType, control.m_sortOrder) end + table.sort(self.m_sortedItems, sortFunc) + end + end) + + if dropdownData.sort then + local sortInfo = GrabSortingInfo(dropdownData.sort) + control.m_sortType, control.m_sortOrder = SORT_TYPES[sortInfo[1]], SORT_ORDERS[sortInfo[2]] + elseif dropdownData.choicesValues then + control.m_sortType, control.m_sortOrder = ZO_SORT_ORDER_UP, SORT_BY_VALUE + end + + if dropdownData.warning ~= nil or dropdownData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateChoices = UpdateChoices + control:UpdateChoices(dropdownData.choices, dropdownData.choicesValues) + control.UpdateValue = UpdateValue + control:UpdateValue() + if dropdownData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/editbox.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/editbox.lua new file mode 100644 index 0000000..f9f79ad --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/editbox.lua @@ -0,0 +1,156 @@ +--[[editboxData = { + type = "editbox", + name = "My Editbox", -- or string id or function returning a string + getFunc = function() return db.text end, + setFunc = function(text) db.text = text doStuff() end, + tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) + isMultiline = true, -- boolean (optional) + isExtraWide = true, -- boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.text, -- default value or function that returns the default value (optional) + reference = "MyAddonEditbox" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("editbox", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.editbox:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end + --control.editbox:SetEditEnabled(not disable) + control.editbox:SetMouseEnabled(not disable) +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.editbox:SetText(value) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.editbox:SetText(value) + end +end + +local MIN_HEIGHT = 24 +local HALF_WIDTH_LINE_SPACING = 2 +function LAMCreateControl.editbox(parent, editboxData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, editboxData, controlName) + + local container = control.container + control.bg = wm:CreateControlFromVirtual(nil, container, "ZO_EditBackdrop") + local bg = control.bg + bg:SetAnchorFill() + + if editboxData.isMultiline then + control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditMultiLineForBackdrop") + control.editbox:SetHandler("OnMouseWheel", function(self, delta) + if self:HasFocus() then --only set focus to new spots if the editbox is currently in use + local cursorPos = self:GetCursorPosition() + local text = self:GetText() + local textLen = text:len() + local newPos + if delta > 0 then --scrolling up + local reverseText = text:reverse() + local revCursorPos = textLen - cursorPos + local revPos = reverseText:find("\n", revCursorPos+1) + newPos = revPos and textLen - revPos + else --scrolling down + newPos = text:find("\n", cursorPos+1) + end + if newPos then --if we found a new line, then scroll, otherwise don't + self:SetCursorPosition(newPos) + end + end + end) + else + control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop") + end + local editbox = control.editbox + editbox:SetText(editboxData.getFunc()) + editbox:SetMaxInputChars(3000) + editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end) + editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end) + editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0 + + control.label:ClearAnchors() + container:ClearAnchors() + + control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + + if control.isHalfWidth then + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + end + + if editboxData.isExtraWide then + container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0) + else + container:SetWidth(MIN_WIDTH * 3.2) + end + + if editboxData.isMultiline then + container:SetHeight(MIN_HEIGHT * 3) + else + container:SetHeight(MIN_HEIGHT) + end + + if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then + control:SetHeight(container:GetHeight()) + else + control:SetHeight(container:GetHeight() + control.label:GetHeight()) + end + + editbox:ClearAnchors() + editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2) + editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2) + + if editboxData.warning ~= nil or editboxData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + if editboxData.isExtraWide then + control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0) + else + control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0) + end + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + if editboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/header.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/header.lua new file mode 100644 index 0000000..3eda1d7 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/header.lua @@ -0,0 +1,42 @@ +--[[headerData = { + type = "header", + name = "My Header", -- or string id or function returning a string + width = "full", -- or "half" (optional) + reference = "MyAddonHeader" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 8 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("header", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateValue(control) + control.header:SetText(LAM.util.GetStringFromValue(control.data.name)) +end + +local MIN_HEIGHT = 30 +function LAMCreateControl.header(parent, headerData, controlName) + local control = LAM.util.CreateBaseControl(parent, headerData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + control:SetDimensions(isHalfWidth and width / 2 or width, MIN_HEIGHT) + + control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") + local divider = control.divider + divider:SetWidth(isHalfWidth and width / 2 or width) + divider:SetAnchor(TOPLEFT) + + control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local header = control.header + header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT) + header:SetAnchor(BOTTOMRIGHT) + header:SetText(LAM.util.GetStringFromValue(headerData.name)) + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/iconpicker.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/iconpicker.lua new file mode 100644 index 0000000..2cca460 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/iconpicker.lua @@ -0,0 +1,436 @@ +--[[iconpickerData = { + type = "iconpicker", + name = "My Icon Picker", -- or string id or function returning a string + choices = {"texture path 1", "texture path 2", "texture path 3"}, + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + maxColumns = 5, -- number of icons in one row (optional) + visibleRows = 4.5, -- number of visible rows (optional) + iconSize = 28, -- size of the icons (optional) + defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) + width = "full", --or "half" (optional) + beforeShow = function(control, iconPicker) return preventShow end, -- (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonIconPicker" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 8 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local IconPickerMenu = ZO_Object:Subclass() +local iconPicker +LAM.util.GetIconPickerMenu = function() + if not iconPicker then + iconPicker = IconPickerMenu:New("LAMIconPicker") + local sceneFragment = LAM:GetAddonSettingsFragment() + ZO_PreHook(sceneFragment, "OnHidden", function() + if not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + end) + end + return iconPicker +end + +function IconPickerMenu:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function IconPickerMenu:Initialize(name) + local control = wm:CreateTopLevelWindow(name) + control:SetDrawTier(DT_HIGH) + control:SetHidden(true) + self.control = control + + local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer") + -- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count + scrollContainer:SetAnchorFill() + ZO_Scroll_SetUseFadeGradient(scrollContainer, false) + ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false) + ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value + local scroll = GetControl(scrollContainer, "ScrollChild") + self.scroll = scroll + self.scrollContainer = scrollContainer + + local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP) + bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE) + mouseOver:SetDrawLevel(2) + mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds") + mouseOver:SetHidden(true) + + local function IconFactory(pool) + local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE) + icon:SetMouseEnabled(true) + icon:SetDrawLevel(3) + icon:SetHandler("OnMouseEnter", function() + mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0) + mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0) + mouseOver:SetHidden(false) + if self.customOnMouseEnter then + self.customOnMouseEnter(icon) + else + self:OnMouseEnter(icon) + end + end) + icon:SetHandler("OnMouseExit", function() + mouseOver:ClearAnchors() + mouseOver:SetHidden(true) + if self.customOnMouseExit then + self.customOnMouseExit(icon) + else + self:OnMouseExit(icon) + end + end) + icon:SetHandler("OnMouseUp", function(control, ...) + PlaySound("Click") + icon.OnSelect(icon, icon.texture) + self:Clear() + end) + return icon + end + + local function ResetFunction(icon) + icon:ClearAnchors() + end + + self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction) + self:SetMaxColumns(1) + self.icons = {} + self.color = ZO_DEFAULT_ENABLED_COLOR + + EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function() + if self.refCount ~= nil then + local moc = wm:GetMouseOverControl() + if(moc:GetOwningWindow() ~= control) then + self.refCount = self.refCount - 1 + if self.refCount <= 0 then + self:Clear() + end + end + end + end) +end + +function IconPickerMenu:OnMouseEnter(icon) + InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() +end + +function IconPickerMenu:OnMouseExit(icon) + ClearTooltip(InformationTooltip) +end + +function IconPickerMenu:SetMaxColumns(value) + self.maxCols = value ~= nil and value or 5 +end + +local DEFAULT_SIZE = 28 +function IconPickerMenu:SetIconSize(value) + local iconSize = DEFAULT_SIZE + if value ~= nil then iconSize = math.max(iconSize, value) end + self.iconSize = iconSize +end + +function IconPickerMenu:SetVisibleRows(value) + self.visibleRows = value ~= nil and value or 4.5 +end + +function IconPickerMenu:SetMouseHandlers(onEnter, onExit) + self.customOnMouseEnter = onEnter + self.customOnMouseExit = onExit +end + +function IconPickerMenu:UpdateDimensions() + local iconSize = self.iconSize + local width = iconSize * self.maxCols + 20 + local height = iconSize * self.visibleRows + self.control:SetDimensions(width, height) + + local icons = self.icons + for i = 1, #icons do + local icon = icons[i] + icon:SetDimensions(iconSize, iconSize) + end +end + +function IconPickerMenu:UpdateAnchors() + local iconSize = self.iconSize + local col, maxCols = 1, self.maxCols + local previousCol, previousRow + local scroll = self.scroll + local icons = self.icons + + for i = 1, #icons do + local icon = icons[i] + icon:ClearAnchors() + if i == 1 then + icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0) + previousRow = icon + elseif col == 1 then + icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0) + previousRow = icon + else + icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0) + end + previousCol = icon + col = col >= maxCols and 1 or col + 1 + end +end + +function IconPickerMenu:Clear() + self.icons = {} + self.iconPool:ReleaseAllObjects() + self.control:SetHidden(true) + self.color = ZO_DEFAULT_ENABLED_COLOR + self.refCount = nil + self.parent = nil + self.customOnMouseEnter = nil + self.customOnMouseExit = nil +end + +function IconPickerMenu:AddIcon(texturePath, callback, tooltip) + local icon, key = self.iconPool:AcquireObject() + icon:SetTexture(texturePath) + icon:SetColor(self.color:UnpackRGBA()) + icon.texture = texturePath + icon.tooltip = tooltip + icon.OnSelect = callback + self.icons[#self.icons + 1] = icon +end + +function IconPickerMenu:Show(parent) + if #self.icons == 0 then return false end + if not self.control:IsHidden() then self:Clear() return false end + self:UpdateDimensions() + self:UpdateAnchors() + + local control = self.control + control:ClearAnchors() + control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8) + control:SetHidden(false) + control:BringWindowToTop() + self.parent = parent + self.refCount = 2 + + return true +end + +function IconPickerMenu:SetColor(color) + local icons = self.icons + self.color = color + for i = 1, #icons do + local icon = icons[i] + icon:SetColor(color:UnpackRGBA()) + end +end + +------------------------------------------------------------- + +local function UpdateChoices(control, choices, choicesTooltips) + local data = control.data + if not choices then + choices, choicesTooltips = data.choices, data.choicesTooltips or {} + end + local addedChoices = {} + + local iconPicker = LAM.util.GetIconPickerMenu() + iconPicker:Clear() + for i = 1, #choices do + local texture = choices[i] + if not addedChoices[texture] then -- remove duplicates + iconPicker:AddIcon(choices[i], function(self, texture) + control.icon:SetTexture(texture) + data.setFunc(texture) + LAM.util.RequestRefreshIfNeeded(control) + end, LAM.util.GetStringFromValue(choicesTooltips[i])) + addedChoices[texture] = true + end + end +end + +local function IsDisabled(control) + if type(control.data.disabled) == "function" then + return control.data.disabled() + else + return control.data.disabled + end +end + +local function SetColor(control, color) + local icon = control.icon + if IsDisabled(control) then + icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR + icon:SetColor(icon.color:UnpackRGBA()) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetColor(icon.color) + end +end + +local function UpdateDisabled(control) + local disable = IsDisabled(control) + + control.dropdown:SetMouseEnabled(not disable) + control.dropdownButton:SetEnabled(not disable) + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + + SetColor(control, control.icon.color) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.icon:SetTexture(value) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.icon:SetTexture(value) + end +end + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local function SetIconSize(control, size) + local icon = control.icon + icon.size = size + icon:SetDimensions(size, size) + + local height = size + 4 + control.dropdown:SetDimensions(size + 20, height) + height = math.max(height, MIN_HEIGHT) + control.container:SetHeight(height) + if control.lineControl then + control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING) + else + control:SetHeight(height) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetIconSize(size) + iconPicker:UpdateDimensions() + iconPicker:UpdateAnchors() + end +end + +function LAMCreateControl.iconpicker(parent, iconpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName) + + local function ShowIconPicker() + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container then + iconPicker:Clear() + else + iconPicker:SetMaxColumns(iconpickerData.maxColumns) + iconPicker:SetVisibleRows(iconpickerData.visibleRows) + iconPicker:SetIconSize(control.icon.size) + UpdateChoices(control) + iconPicker:SetColor(control.icon.color) + if iconpickerData.beforeShow then + if iconpickerData.beforeShow(control, iconPicker) then + iconPicker:Clear() + return + end + end + iconPicker:Show(control.container) + end + end + + local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE + control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL) + local dropdown = control.dropdown + dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0) + dropdown:SetMouseEnabled(true) + dropdown:SetHandler("OnMouseUp", ShowIconPicker) + dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE) + local icon = control.icon + icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0) + icon:SetDrawLevel(2) + + local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton") + dropdownButton:SetDimensions(16, 16) + dropdownButton:SetHandler("OnClicked", ShowIconPicker) + dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0) + control.dropdownButton = dropdownButton + + control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + if iconpickerData.warning ~= nil or iconpickerData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateChoices = UpdateChoices + control.UpdateValue = UpdateValue + control:UpdateValue() + control.SetColor = SetColor + control:SetColor() + control.SetIconSize = SetIconSize + control:SetIconSize(iconSize) + + if iconpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/panel.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/panel.lua new file mode 100644 index 0000000..75bb904 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/panel.lua @@ -0,0 +1,168 @@ +--[[panelData = { + type = "panel", + name = "Window Title", -- or string id or function returning a string + displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) + author = "Seerah", -- or string id or function returning a string (optional) + version = "2.0", -- or string id or function returning a string (optional) + website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated or function (optional) + feedback = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where feedback/feature requests/bugs can be reported for the addon or function (optional) + translation = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where translation texts of the addon can be helped with or function (optional) + donation = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where a donation for the addon author can be raised or function (optional) + keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) + slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) + registerForRefresh = true, -- boolean will refresh all options controls when a setting is changed and when the panel is shown (optional) + registerForDefaults = true, -- boolean will set all options controls back to default values (optional) + resetFunc = function() print("defaults reset") end, -- custom function to run after settings are reset to defaults (optional) +} ]] + + +local widgetVersion = 15 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("panel", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER + +local function RefreshPanel(control) + local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu + if LAM.currentAddonPanel ~= panel or not LAM.currentPanelOpened then return end -- we refresh it later when the panel is opened + + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl ~= control and updateControl.UpdateValue then + updateControl:UpdateValue() + end + if updateControl.UpdateDisabled then + updateControl:UpdateDisabled() + end + if updateControl.UpdateWarning then + updateControl:UpdateWarning() + end + end +end + +local function ForceDefaults(panel) + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl.UpdateValue and updateControl.data.default ~= nil then + updateControl:UpdateValue(true) + end + end + + if panel.data.resetFunc then + panel.data.resetFunc() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) +end + +local callbackRegistered = false +LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 +local SEPARATOR = " - " +local COLORED_SEPARATOR = ZO_WHITE:Colorize(SEPARATOR) +local LINK_COLOR = ZO_ColorDef:New("5959D5") +local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") +local LINK_COLOR_DONATE = ZO_ColorDef:New("FFD700") -- golden +local LINK_MOUSE_OVER_COLOR_DONATE = ZO_ColorDef:New("FFF6CC") + +local function CreateButtonControl(control, label, clickAction, relativeTo) + local button = wm:CreateControl(nil, control, CT_BUTTON) + button:SetClickSound("Click") + button:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + button:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) + button:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) + + local OnClicked + local actionType = type(clickAction) + if actionType == "string" then + OnClicked = function() RequestOpenUnsafeURL(clickAction) end + elseif actionType == "function" then + OnClicked = clickAction + end + button:SetHandler("OnClicked", OnClicked) + + if relativeTo then + button:SetAnchor(TOPLEFT, relativeTo, TOPRIGHT, 0, 0) + button:SetText(COLORED_SEPARATOR .. label) + else + button:SetAnchor(TOPLEFT, control.label, BOTTOMLEFT, 0, -2) + button:SetText(label) + end + button:SetDimensions(button:GetLabelControl():GetTextDimensions()) + + return button +end + +function LAMCreateControl.panel(parent, panelData, controlName) + local control = wm:CreateControl(controlName, parent, CT_CONTROL) + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) + label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) + + local previousInfoControl + if panelData.author or panelData.version then + control.info = wm:CreateControl(nil, control, CT_LABEL) + local info = control.info + info:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) + + local output = {} + if panelData.author then + output[#output + 1] = zo_strformat(LAM.util.L["AUTHOR"], LAM.util.GetStringFromValue(panelData.author)) + end + if panelData.version then + output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) + end + info:SetText(table.concat(output, SEPARATOR)) + previousInfoControl = info + end + + if panelData.website then + control.website = CreateButtonControl(control, LAM.util.L["WEBSITE"], panelData.website, previousInfoControl) + previousInfoControl = control.website + end + + if panelData.feedback then + control.feedback = CreateButtonControl(control, LAM.util.L["FEEDBACK"], panelData.feedback, previousInfoControl) + previousInfoControl = control.feedback + end + + if panelData.translation then + control.translation = CreateButtonControl(control, LAM.util.L["TRANSLATION"], panelData.translation, previousInfoControl) + previousInfoControl = control.translation + end + + if panelData.donation then + control.donation = CreateButtonControl(control, LAM.util.L["DONATION"], panelData.donation, previousInfoControl) + local donation = control.donation + previousInfoControl = donation + donation:SetNormalFontColor(LINK_COLOR_DONATE:UnpackRGBA()) + donation:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR_DONATE:UnpackRGBA()) + end + + control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") + LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1 + local container = control.container + container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3) + control.scroll = GetControl(control.container, "ScrollChild") + control.scroll:SetResizeToFitPadding(0, 20) + + if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once + cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel) + callbackRegistered = true + end + + control.ForceDefaults = ForceDefaults + control.RefreshPanel = LAM.util.RequestRefreshIfNeeded + control.data = panelData + control.controlsToRefresh = {} + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/slider.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/slider.lua new file mode 100644 index 0000000..6c80968 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/slider.lua @@ -0,0 +1,220 @@ +--[[sliderData = { + type = "slider", + name = "My Slider", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + min = 0, + max = 20, + step = 1, -- (optional) + clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) + clampFunction = function(value, min, max) return math.max(math.min(value, max), min) end, -- function that is called to clamp the value (optional) + decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) + autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) + inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) + tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonSlider" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("slider", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local strformat = string.format + +local function RoundDecimalToPlace(d, place) + return tonumber(strformat("%." .. tostring(place) .. "f", d)) +end + +local function ClampValue(value, min, max) + return math.max(math.min(value, max), min) +end + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.slider:SetEnabled(not disable) + control.slidervalue:SetEditEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value then + if control.data.decimals then + value = RoundDecimalToPlace(value, control.data.decimals) + end + if control.data.clampInput ~= false then + local clamp = control.data.clampFunction or ClampValue + value = clamp(value, control.data.min, control.data.max) + end + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + + control.slider:SetValue(value) + control.slidervalue:SetText(value) +end + +function LAMCreateControl.slider(parent, sliderData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) + local isInputOnRight = sliderData.inputLocation == "right" + + --skipping creating the backdrop... Is this the actual slider texture? + control.slider = wm:CreateControl(nil, control.container, CT_SLIDER) + local slider = control.slider + slider:SetAnchor(TOPLEFT) + slider:SetHeight(14) + if(isInputOnRight) then + slider:SetAnchor(TOPRIGHT, nil, nil, -60) + else + slider:SetAnchor(TOPRIGHT) + end + slider:SetMouseEnabled(true) + slider:SetOrientation(ORIENTATION_HORIZONTAL) + --put nil for highlighted texture file path, and what look to be texture coords + slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16) + local minValue = sliderData.min + local maxValue = sliderData.max + slider:SetMinMax(minValue, maxValue) + slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + slider:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP) + local bg = slider.bg + bg:SetCenterColor(0, 0, 0) + bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4) + bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4) + + control.minText = wm:CreateControl(nil, slider, CT_LABEL) + local minText = control.minText + minText:SetFont("ZoFontGameSmall") + minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT) + minText:SetText(sliderData.min) + + control.maxText = wm:CreateControl(nil, slider, CT_LABEL) + local maxText = control.maxText + maxText:SetFont("ZoFontGameSmall") + maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT) + maxText:SetText(sliderData.max) + + control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop") + if(isInputOnRight) then + control.slidervalueBG:SetDimensions(60, 26) + control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0) + else + control.slidervalueBG:SetDimensions(50, 16) + control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0) + end + control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop") + local slidervalue = control.slidervalue + slidervalue:ClearAnchors() + slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1) + slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1) + slidervalue:SetTextType(TEXT_TYPE_NUMERIC) + if(isInputOnRight) then + slidervalue:SetFont("ZoFontGameLarge") + else + slidervalue:SetFont("ZoFontGameSmall") + end + + local isHandlingChange = false + local function HandleValueChanged(value) + if isHandlingChange then return end + if sliderData.decimals then + value = RoundDecimalToPlace(value, sliderData.decimals) + end + isHandlingChange = true + slider:SetValue(value) + slidervalue:SetText(value) + isHandlingChange = false + end + + slidervalue:SetHandler("OnEscape", function(self) + HandleValueChanged(sliderData.getFunc()) + self:LoseFocus() + end) + slidervalue:SetHandler("OnEnter", function(self) + self:LoseFocus() + end) + slidervalue:SetHandler("OnFocusLost", function(self) + local value = tonumber(self:GetText()) + control:UpdateValue(false, value) + end) + slidervalue:SetHandler("OnTextChanged", function(self) + local input = self:GetText() + if(#input > 1 and not input:sub(-1):match("[0-9]")) then return end + local value = tonumber(input) + if(value) then + HandleValueChanged(value) + end + end) + if(sliderData.autoSelect) then + ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self) + self:SelectAll() + end) + end + + local range = maxValue - minValue + slider:SetValueStep(sliderData.step or 1) + slider:SetHandler("OnValueChanged", function(self, value, eventReason) + if eventReason == EVENT_REASON_SOFTWARE then return end + HandleValueChanged(value) + end) + slider:SetHandler("OnSliderReleased", function(self, value) + if self:GetEnabled() then + control:UpdateValue(false, value) + end + end) + slider:SetHandler("OnMouseWheel", function(self, value) + if(not self:GetEnabled()) then return end + local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) + control:UpdateValue(false, new_value) + end) + + if sliderData.warning ~= nil or sliderData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + + if sliderData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/submenu.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/submenu.lua new file mode 100644 index 0000000..d7bc8bf --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/submenu.lua @@ -0,0 +1,182 @@ +--[[submenuData = { + type = "submenu", + name = "Submenu Title", -- or string id or function returning a string + icon = "path/to/my/icon.dds", -- or function returning a string (optional) + iconTextureCoords = {left, right, top, bottom}, -- or function returning a table (optional) + tooltip = "My submenu tooltip", -- or string id or function returning a string (optional) + controls = {sliderData, buttonData} -- used by LAM (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + disabledLabel = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonSubmenu" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("submenu", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local am = ANIMATION_MANAGER +local ICON_SIZE = 32 + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + if disable and control.open then + control.open = false + control.animation:PlayFromStart() + end + + control.arrow:SetColor(color:UnpackRGBA()) + control.disabled = disable + end + + local disableLabel = control.disabled or GetDefaultValue(control.data.disabledLabel) + if disableLabel ~= control.disabledLabel then + local color = GetColorForState(disableLabel) + control.label:SetColor(color:UnpackRGBA()) + if(control.icon) then + control.icon:SetDesaturation(disableLabel and 1 or 0) + end + control.disabledLabel = disableLabel + end +end + +local function UpdateValue(control) + control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) + + if control.icon then + control.icon:SetTexture(GetDefaultValue(control.data.icon)) + if(control.data.iconTextureCoords) then + local coords = GetDefaultValue(control.data.iconTextureCoords) + control.icon:SetTextureCoords(unpack(coords)) + end + end + + if control.data.tooltip then + control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) + end +end + +local function AnimateSubmenu(clicked) + local control = clicked:GetParent() + if control.disabled then return end + + control.open = not control.open + if control.open then + control.animation:PlayFromStart() + else + control.animation:PlayFromEnd() + end +end + +function LAMCreateControl.submenu(parent, submenuData, controlName) + local width = parent:GetWidth() - 45 + local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent + control.data = submenuData + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(LAM.util.GetStringFromValue(submenuData.name)) + label:SetMouseEnabled(true) + + if submenuData.icon then + control.icon = wm:CreateControl(nil, control, CT_TEXTURE) + local icon = control.icon + icon:SetTexture(GetDefaultValue(submenuData.icon)) + if(submenuData.iconTextureCoords) then + local coords = GetDefaultValue(submenuData.iconTextureCoords) + icon:SetTextureCoords(unpack(coords)) + end + icon:SetDimensions(ICON_SIZE, ICON_SIZE) + icon:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + icon:SetMouseEnabled(true) + icon:SetDrawLayer(DL_CONTROLS) + label:SetAnchor(TOP, control, TOP, 0, 5, ANCHOR_CONSTRAINS_Y) + label:SetAnchor(LEFT, icon, RIGHT, 10, 0, ANCHOR_CONSTRAINS_X) + label:SetDimensions(width - ICON_SIZE - 5, 30) + else + label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + label:SetDimensions(width, 30) + end + + if submenuData.tooltip then + label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} + label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + if control.icon then + control.icon.data = label.data + control.icon:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control.icon:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end + end + + control.scroll = wm:CreateControl(nil, control, CT_SCROLL) + local scroll = control.scroll + scroll:SetParent(control) + scroll:SetAnchor(TOPLEFT, control.icon or label, BOTTOMLEFT, 0, 10) + scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) + + control.bg = wm:CreateControl(nil, control.icon or label, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, control.icon or label, TOPLEFT, -5, -5) + bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + bg:SetDrawLayer(DL_BACKGROUND) + + control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) + local arrow = control.arrow + arrow:SetDimensions(28, 28) + arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way + arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5) + + --figure out the cool animation later... + control.animation = am:CreateTimeline() + local animation = control.animation + animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count + + control:SetResizeToFitDescendents(true) + control.open = false + label:SetHandler("OnMouseUp", AnimateSubmenu) + if(control.icon) then + control.icon:SetHandler("OnMouseUp", AnimateSubmenu) + end + animation:SetHandler("OnStop", function(self, completedPlaying) + scroll:SetResizeToFitDescendents(control.open) + if control.open then + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds") + scroll:SetResizeToFitPadding(5, 20) + else + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") + scroll:SetResizeToFitPadding(5, 0) + scroll:SetHeight(0) + end + end) + + --small strip at the bottom of the submenu that you can click to close it + control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE) + local btmToggle = control.btmToggle + btmToggle:SetMouseEnabled(true) + btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT) + btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT) + btmToggle:SetHeight(15) + btmToggle:SetAlpha(0) + btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) + + control.UpdateValue = UpdateValue + if submenuData.disabled ~= nil or submenuData.disabledLabel ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/texture.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/texture.lua new file mode 100644 index 0000000..6862ac2 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibAddonMenu-2.0/controls/texture.lua @@ -0,0 +1,45 @@ +--[[textureData = { + type = "texture", + image = "file/path.dds", + imageWidth = 64, -- max of 250 for half width, 510 for full + imageHeight = 32, -- max of 100 + tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + reference = "MyAddonTexture" -- unique global reference to control (optional) +} ]] + +-- TODO: add texture coords support? + +local widgetVersion = 9 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("texture", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local MIN_HEIGHT = 26 +function LAMCreateControl.texture(parent, textureData, controlName) + local control = LAM.util.CreateBaseControl(parent, textureData, controlName) + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) + else + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) + end + + control.texture = wm:CreateControl(nil, control, CT_TEXTURE) + local texture = control.texture + texture:SetAnchor(CENTER) + texture:SetDimensions(textureData.imageWidth, textureData.imageHeight) + texture:SetTexture(textureData.image) + + if textureData.tooltip then + texture:SetMouseEnabled(true) + texture.data = {tooltipText = LAM.util.GetStringFromValue(textureData.tooltip)} + texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + texture:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end + + return control +end diff --git a/Elder Scrolls Online Addons/PvPFPS2018/LibStub/LibStub.lua b/Elder Scrolls Online Addons/PvPFPS2018/LibStub/LibStub.lua new file mode 100644 index 0000000..e6b8997 --- /dev/null +++ b/Elder Scrolls Online Addons/PvPFPS2018/LibStub/LibStub.lua @@ -0,0 +1,38 @@ +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info +-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +-- LibStub developed for World of Warcraft by above members of the WowAce community. +-- Ported to Elder Scrolls Online by Seerah + +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 5 +local LibStub = _G[LIBSTUB_MAJOR] + +local strformat = string.format +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + if type(minor) ~= "number" then + minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.") + end + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(strformat("Cannot find a library instance of %q.", tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end + +LibStub.SILENT = true \ No newline at end of file diff --git a/PvPFPS2018/PvPFPS2018.lua b/Elder Scrolls Online Addons/PvPFPS2018/PvPFPS2018.lua similarity index 90% rename from PvPFPS2018/PvPFPS2018.lua rename to Elder Scrolls Online Addons/PvPFPS2018/PvPFPS2018.lua index 928d64f..b39a959 100644 --- a/PvPFPS2018/PvPFPS2018.lua +++ b/Elder Scrolls Online Addons/PvPFPS2018/PvPFPS2018.lua @@ -1,6 +1,5 @@ pvpfps = { name = "PvPFPS2018", -- Matches folder and Manifest file names. - version = "1.1", author = "phuein", color = "00DDDD", -- Used in menu titles and so on. menuName = "PvP FPS 2018", -- Unique identifier for menu object. @@ -17,8 +16,11 @@ local savedVars = pvpfps.savedVars local LAM = LibStub("LibAddonMenu-2.0") --- Set later from current. -local curSS = nil +-- Returns current SubSampling level. +-- Repeated use in functions will set their own curSS variable locally! +local function curSS() + return GetSetting(SETTING_TYPE_GRAPHICS, GRAPHICS_SETTING_SUB_SAMPLING) +end -- Wraps text with a color. local function Colorize(text, color) @@ -61,7 +63,7 @@ local optionsTable = { end, setFunc = function(v) -- Change into new value if being used. - local changed = savedVars.normalSS == curSS + local changed = savedVars.normalSS == curSS() savedVars.normalSS = v if changed then changeSS(v) end end, @@ -78,7 +80,7 @@ local optionsTable = { end, setFunc = function(v) -- Change into new value if being used. - local changed = savedVars.lowSS == curSS + local changed = savedVars.lowSS == curSS() savedVars.lowSS = v if changed then changeSS(v) end end, @@ -123,6 +125,8 @@ local function LoadMenu() end local function changeSS(v) + local curSS = GetSetting(SETTING_TYPE_GRAPHICS, GRAPHICS_SETTING_SUB_SAMPLING) + v = tonumber(v) -- Only valid values accepted. if v == nil or v == curSS then @@ -136,15 +140,15 @@ local function changeSS(v) end SetSetting(SETTING_TYPE_GRAPHICS, GRAPHICS_SETTING_SUB_SAMPLING, v) - local oldSS = curSS - curSS = v - d('Changed SubSampling from '..oldSS..' to '..curSS..'.') + d('Changed SubSampling from '..curSS..' to '..v..'.') end pvpfps.CheckPVP = function(e) -- Automatic changer can be manually disabled tamporarily. if savedVars.disabled then return end + local curSS = GetSetting(SETTING_TYPE_GRAPHICS, GRAPHICS_SETTING_SUB_SAMPLING) + if IsInCyrodiil() or IsActiveWorldBattleground() then if curSS == savedVars.lowSS then return end @@ -158,7 +162,6 @@ pvpfps.CheckPVP = function(e) end SetSetting(SETTING_TYPE_GRAPHICS, GRAPHICS_SETTING_SUB_SAMPLING, savedVars.lowSS) - curSS = savedVars.lowSS else if curSS == savedVars.normalSS then return end @@ -172,7 +175,6 @@ pvpfps.CheckPVP = function(e) end SetSetting(SETTING_TYPE_GRAPHICS, GRAPHICS_SETTING_SUB_SAMPLING, savedVars.normalSS) - curSS = savedVars.normalSS end end EVENT_MANAGER:RegisterForEvent(pvpfps.name, EVENT_PLAYER_ACTIVATED, pvpfps.CheckPVP) @@ -195,7 +197,7 @@ pvpfps.OnLoaded = function(e, addonName) end -- Load settings. - curSS = GetSetting(SETTING_TYPE_GRAPHICS, GRAPHICS_SETTING_SUB_SAMPLING) + local curSS = GetSetting(SETTING_TYPE_GRAPHICS, GRAPHICS_SETTING_SUB_SAMPLING) if not savedVars.normalSS then savedVars.normalSS = curSS end end EVENT_MANAGER:RegisterForEvent(pvpfps.name, EVENT_ADD_ON_LOADED, pvpfps.OnLoaded) \ No newline at end of file diff --git a/PvPFPS2018/PvPFPS2018.txt b/Elder Scrolls Online Addons/PvPFPS2018/PvPFPS2018.txt similarity index 98% rename from PvPFPS2018/PvPFPS2018.txt rename to Elder Scrolls Online Addons/PvPFPS2018/PvPFPS2018.txt index 63d41ae..3ef2a5f 100644 --- a/PvPFPS2018/PvPFPS2018.txt +++ b/Elder Scrolls Online Addons/PvPFPS2018/PvPFPS2018.txt @@ -2,7 +2,7 @@ ## Author: phuein ## APIVersion: 100023 ## Description: Reduce SubSampling quality while in PvP zones (Cyrodiil, Battlegrounds.) -## Version: 1.1 +## Version: 1.21 ## SavedVariables: PVPFPSAddonSavedVars ## OptionalDependsOn: LibAddonMenu-2.0 diff --git a/ShowMount/Bindings.xml b/Elder Scrolls Online Addons/ShowMount/Bindings.xml similarity index 100% rename from ShowMount/Bindings.xml rename to Elder Scrolls Online Addons/ShowMount/Bindings.xml diff --git a/ShowMount/Languages/en.lua b/Elder Scrolls Online Addons/ShowMount/Languages/en.lua similarity index 100% rename from ShowMount/Languages/en.lua rename to Elder Scrolls Online Addons/ShowMount/Languages/en.lua diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/LICENSE b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/LICENSE new file mode 100644 index 0000000..f69cbd4 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/LICENSE @@ -0,0 +1,201 @@ + The Artistic License 2.0 + + Copyright (c) 2016 Ryan Lakanen (Seerah) + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/LibAddonMenu-2.0.lua new file mode 100644 index 0000000..20ffe3a --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/LibAddonMenu-2.0.lua @@ -0,0 +1,1305 @@ +-- LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah) -- +-- Distributed under The Artistic License 2.0 (see LICENSE) -- +------------------------------------------------------------------ + + +--Register LAM with LibStub +local MAJOR, MINOR = "LibAddonMenu-2.0", 29 +local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) +if not lam then return end --the same or newer version of this lib is already loaded into memory +LibAddonMenu2 = lam + +local messages = {} +local MESSAGE_PREFIX = "[LAM2] " +local function PrintLater(msg) + if CHAT_SYSTEM.primaryContainer then + d(MESSAGE_PREFIX .. msg) + else + messages[#messages + 1] = msg + end +end + +local function FlushMessages() + for i = 1, #messages do + d(MESSAGE_PREFIX .. messages[i]) + end + messages = {} +end + +local logger +if LibDebugLogger then + logger = LibDebugLogger(MAJOR) +end + +if LAMSettingsPanelCreated and not LAMCompatibilityWarning then + PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") + LAMCompatibilityWarning = true +end + +--UPVALUES-- +local wm = WINDOW_MANAGER +local em = EVENT_MANAGER +local sm = SCENE_MANAGER +local cm = CALLBACK_MANAGER +local tconcat = table.concat +local tinsert = table.insert + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local OPTIONS_CREATION_RUNNING = 1 +local OPTIONS_CREATED = 2 +local LAM_CONFIRM_DIALOG = "LAM_CONFIRM_DIALOG" +local LAM_DEFAULTS_DIALOG = "LAM_DEFAULTS" +local LAM_RELOAD_DIALOG = "LAM_RELOAD_DIALOG" + +local addonsForList = {} +local addonToOptionsMap = {} +local optionsState = {} +lam.widgets = lam.widgets or {} +local widgets = lam.widgets +lam.util = lam.util or {} +local util = lam.util +lam.controlsForReload = lam.controlsForReload or {} +local controlsForReload = lam.controlsForReload + +local function GetDefaultValue(default) + if type(default) == "function" then + return default() + end + return default +end + +local function GetStringFromValue(value) + if type(value) == "function" then + return value() + elseif type(value) == "number" then + return GetString(value) + end + return value +end + +local function GetColorForState(disabled) + return disabled and ZO_DEFAULT_DISABLED_COLOR or ZO_DEFAULT_ENABLED_COLOR +end + +local function CreateBaseControl(parent, controlData, controlName) + local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent + control.data = controlData + + control.isHalfWidth = controlData.width == "half" + local width = 510 -- set default width in case a custom parent object is passed + if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end + control:SetWidth(width) + return control +end + +local function CreateLabelAndContainerControl(parent, controlData, controlName) + local control = CreateBaseControl(parent, controlData, controlName) + local width = control:GetWidth() + + local container = wm:CreateControl(nil, control, CT_CONTROL) + container:SetDimensions(width / 3, MIN_HEIGHT) + control.container = container + + local label = wm:CreateControl(nil, control, CT_LABEL) + label:SetFont("ZoFontWinH4") + label:SetHeight(MIN_HEIGHT) + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(GetStringFromValue(controlData.name)) + control.label = label + + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0) + end + + control.data.tooltipText = GetStringFromValue(control.data.tooltip) + control:SetMouseEnabled(true) + control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + return control +end + +local function GetTopPanel(panel) + while panel.panel and panel.panel ~= panel do + panel = panel.panel + end + return panel +end + +local function IsSame(objA, objB) + if #objA ~= #objB then return false end + for i = 1, #objA do + if objA[i] ~= objB[i] then return false end + end + return true +end + +local function RefreshReloadUIButton() + lam.requiresReload = false + + for i = 1, #controlsForReload do + local reloadControl = controlsForReload[i] + if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then + lam.requiresReload = true + break + end + end + + if lam.applyButton then + lam.applyButton:SetHidden(not lam.requiresReload) + end +end + +local function RequestRefreshIfNeeded(control) + -- if our parent window wants to refresh controls, then fire the callback + local panel = GetTopPanel(control) + local panelData = panel.data + if panelData.registerForRefresh then + cm:FireCallbacks("LAM-RefreshPanel", control) + end + RefreshReloadUIButton() +end + +local function RegisterForRefreshIfNeeded(control) + -- if our parent window wants to refresh controls, then add this to the list + local panel = GetTopPanel(control.panel) + local panelData = panel.data + if panelData.registerForRefresh or panelData.registerForDefaults then + tinsert(panel.controlsToRefresh or {}, control) -- prevent errors on custom panels + end +end + +local function RegisterForReloadIfNeeded(control) + if control.data.requiresReload then + tinsert(controlsForReload, control) + control.startValue = {control.data.getFunc()} + end +end + +local function GetConfirmDialog() + if(not ESO_Dialogs[LAM_CONFIRM_DIALOG]) then + ESO_Dialogs[LAM_CONFIRM_DIALOG] = { + canQueue = true, + title = { + text = "", + }, + mainText = { + text = "", + }, + buttons = { + [1] = { + text = SI_DIALOG_CONFIRM, + callback = function(dialog) end, + }, + [2] = { + text = SI_DIALOG_CANCEL, + } + } + } + end + return ESO_Dialogs[LAM_CONFIRM_DIALOG] +end + +local function ShowConfirmationDialog(title, body, callback) + local dialog = GetConfirmDialog() + dialog.title.text = title + dialog.mainText.text = body + dialog.buttons[1].callback = callback + ZO_Dialogs_ShowDialog(LAM_CONFIRM_DIALOG) +end + +local function GetDefaultsDialog() + if(not ESO_Dialogs[LAM_DEFAULTS_DIALOG]) then + ESO_Dialogs[LAM_DEFAULTS_DIALOG] = { + canQueue = true, + title = { + text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP, + }, + mainText = { + text = SI_OPTIONS_RESET_PROMPT, + }, + buttons = { + [1] = { + text = SI_OPTIONS_RESET, + callback = function(dialog) end, + }, + [2] = { + text = SI_DIALOG_CANCEL, + } + } + } + end + return ESO_Dialogs[LAM_DEFAULTS_DIALOG] +end + +local function ShowDefaultsDialog(panel) + local dialog = GetDefaultsDialog() + dialog.buttons[1].callback = function() + panel:ForceDefaults() + RefreshReloadUIButton() + end + ZO_Dialogs_ShowDialog(LAM_DEFAULTS_DIALOG) +end + +local function DiscardChangesOnReloadControls() + for i = 1, #controlsForReload do + local reloadControl = controlsForReload[i] + if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then + reloadControl:UpdateValue(false, unpack(reloadControl.startValue)) + end + end + lam.requiresReload = false + lam.applyButton:SetHidden(true) +end + +local function StorePanelForReopening() + local saveData = ZO_Ingame_SavedVariables["LAM"] or {} + saveData.reopenPanel = lam.currentAddonPanel:GetName() + ZO_Ingame_SavedVariables["LAM"] = saveData +end + +local function RetrievePanelForReopening() + local saveData = ZO_Ingame_SavedVariables["LAM"] + if(saveData) then + ZO_Ingame_SavedVariables["LAM"] = nil + return _G[saveData.reopenPanel] + end +end + +local function HandleReloadUIPressed() + StorePanelForReopening() + ReloadUI() +end + +local function HandleLoadDefaultsPressed() + ShowDefaultsDialog(lam.currentAddonPanel) +end + +local function GetReloadDialog() + if(not ESO_Dialogs[LAM_RELOAD_DIALOG]) then + ESO_Dialogs[LAM_RELOAD_DIALOG] = { + canQueue = true, + title = { + text = util.L["RELOAD_DIALOG_TITLE"], + }, + mainText = { + text = util.L["RELOAD_DIALOG_TEXT"], + }, + buttons = { + [1] = { + text = util.L["RELOAD_DIALOG_RELOAD_BUTTON"], + callback = function() ReloadUI() end, + }, + [2] = { + text = util.L["RELOAD_DIALOG_DISCARD_BUTTON"], + callback = DiscardChangesOnReloadControls, + } + }, + noChoiceCallback = DiscardChangesOnReloadControls, + } + end + return ESO_Dialogs[LAM_CONFIRM_DIALOG] +end + +local function ShowReloadDialogIfNeeded() + if lam.requiresReload then + local dialog = GetReloadDialog() + ZO_Dialogs_ShowDialog(LAM_RELOAD_DIALOG) + end +end + +local function UpdateWarning(control) + local warning + if control.data.warning ~= nil then + warning = util.GetStringFromValue(control.data.warning) + end + + if control.data.requiresReload then + if not warning then + warning = string.format("%s", util.L["RELOAD_UI_WARNING"]) + else + warning = string.format("%s\n\n%s", warning, util.L["RELOAD_UI_WARNING"]) + end + end + + if not warning then + control.warning:SetHidden(true) + else + control.warning.data = {tooltipText = warning} + control.warning:SetHidden(false) + end +end + +local localization = { + en = { + PANEL_NAME = "Addons", + AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" + VERSION = "Version: <>", + WEBSITE = "Visit Website", + FEEDBACK = "Feedback", + TRANSLATION = "Translation", + DONATION = "Donate", + PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", + RELOAD_UI_WARNING = "Changes to this setting require a UI reload in order to take effect.", + RELOAD_DIALOG_TITLE = "UI Reload Required", + RELOAD_DIALOG_TEXT = "Some changes require a UI reload in order to take effect. Do you want to reload now or discard the changes?", + RELOAD_DIALOG_RELOAD_BUTTON = "Reload", + RELOAD_DIALOG_DISCARD_BUTTON = "Discard", + }, + it = { -- provided by JohnnyKing + PANEL_NAME = "Addon", + VERSION = "Versione: <>", + WEBSITE = "Visita il Sitoweb", + FEEDBACK = "Feedback", + TRANSLATION = "Traduzione", + DONATION = "Donare", + RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", + RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", + RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", + RELOAD_DIALOG_RELOAD_BUTTON = "Ricarica", + RELOAD_DIALOG_DISCARD_BUTTON = "Annulla", + }, + fr = { -- provided by Ayantir + PANEL_NAME = "Extensions", + WEBSITE = "Visiter le site Web", + FEEDBACK = "Réaction", + TRANSLATION = "Traduction", + DONATION = "Donner", + RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", + RELOAD_DIALOG_TITLE = "Reload UI requis", + RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recharger", + RELOAD_DIALOG_DISCARD_BUTTON = "Annuler", + }, + de = { -- provided by sirinsidiator + PANEL_NAME = "Erweiterungen", + WEBSITE = "Webseite besuchen", + FEEDBACK = "Feedback", + TRANSLATION = "Übersetzung", + DONATION = "Spende", + RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", + RELOAD_DIALOG_TITLE = "Neuladen benötigt", + RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", + RELOAD_DIALOG_RELOAD_BUTTON = "Neu laden", + RELOAD_DIALOG_DISCARD_BUTTON = "Verwerfen", + }, + ru = { -- provided by TERAB1T + PANEL_NAME = "Дополнения", + VERSION = "Версия: <>", + WEBSITE = "Посетить сайт", + FEEDBACK = "отзыв", + TRANSLATION = "Перевод", + DONATION = "жертвовать", + PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", + RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", + RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", + RELOAD_DIALOG_TEXT = "Для применения некоторых изменений необходима перезагрузка интерфейса. Перезагрузить интерфейс сейчас или отменить изменения?", + RELOAD_DIALOG_RELOAD_BUTTON = "Перезагрузить", + RELOAD_DIALOG_DISCARD_BUTTON = "Отменить изменения", + }, + es = { -- provided by Morganlefai, checked by Kwisatz + PANEL_NAME = "Configuración", + VERSION = "Versión: <>", + WEBSITE = "Visita la página web", + FEEDBACK = "Reaccion", + TRANSLATION = "Traducción", + DONATION = "Donar", + RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", + RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", + RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recargar", + RELOAD_DIALOG_DISCARD_BUTTON = "Cancelar", + }, + jp = { -- provided by k0ta0uchi + PANEL_NAME = "アドオン設定", + WEBSITE = "ウェブサイトを見る", + FEEDBACK = "フィードバック", + TRANSLATION = "訳書", + DONATION = "寄贈する", + }, + zh = { -- provided by bssthu + PANEL_NAME = "插件", + VERSION = "版本: <>", + WEBSITE = "访问网站", + PANEL_INFO_FONT = "EsoZh/fonts/univers57.otf|14|soft-shadow-thin", + }, + pl = { -- provided by EmiruTegryfon + PANEL_NAME = "Dodatki", + VERSION = "Wersja: <>", + WEBSITE = "Odwiedź stronę", + RELOAD_UI_WARNING = "Zmiany będą widoczne po ponownym załadowaniu UI.", + RELOAD_DIALOG_TITLE = "Wymagane przeładowanie UI", + RELOAD_DIALOG_TEXT = "Niektóre zmiany wymagają ponownego załadowania UI. Czy chcesz teraz ponownie załadować, czy porzucić zmiany?", + RELOAD_DIALOG_RELOAD_BUTTON = "Przeładuj", + RELOAD_DIALOG_DISCARD_BUTTON = "Porzuć", + }, + kr = { -- provided by p.walker + PANEL_NAME = "蝠盜蠨", + VERSION = "纄訄: <>", + WEBSITE = "裹芬襴钸 縩紸", + PANEL_INFO_FONT = "EsoKR/fonts/Univers57.otf|14|soft-shadow-thin", + RELOAD_UI_WARNING = "襴 茤訕襄 绀溽靘籴 風滼筼 訁袩靘瀰褄靴 UI 苈穜滠遨襴 靄袔革瓈瓤.", + RELOAD_DIALOG_TITLE = "UI 苈穜滠遨 靄袔", + RELOAD_DIALOG_TEXT = "绀溽瘜 茤訕 謑 UI 苈穜滠遨襄 靄袔穜靘璔 芬靭襴 覈蒵瓈瓤. 诀瀈 苈穜滠遨靘蓜溠蒵瓈灌? 蝄瓈籴 绀溽襄 迨莌靘蓜溠蒵瓈灌?", + RELOAD_DIALOG_RELOAD_BUTTON = "苈穜滠遨", + RELOAD_DIALOG_DISCARD_BUTTON = "绀溽迨莌", + }, + br = { -- provided by mlsevero & FelipeS11 + PANEL_NAME = "Addons", + AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Autor: <>" + VERSION = "Versão: <>", + WEBSITE = "Visite o Website", + FEEDBACK = "Feedback", + TRANSLATION = "Tradução", + DONATION = "Doação", + RELOAD_UI_WARNING = "Mudanças nessa configuração requerem o recarregamento da UI para ter efeito.", + RELOAD_DIALOG_TITLE = "Recarregamento da UI requerida", + RELOAD_DIALOG_TEXT = "Algumas mudanças requerem o recarregamento da UI para ter efeito. Você deseja recarregar agora ou descartar as mudanças?", + RELOAD_DIALOG_RELOAD_BUTTON = "Recarregar", + RELOAD_DIALOG_DISCARD_BUTTON = "Descartar", + }, +} + +util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")] or {}, localization["en"]) +util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead +util.GetStringFromValue = GetStringFromValue +util.GetDefaultValue = GetDefaultValue +util.GetColorForState = GetColorForState +util.CreateBaseControl = CreateBaseControl +util.CreateLabelAndContainerControl = CreateLabelAndContainerControl +util.RequestRefreshIfNeeded = RequestRefreshIfNeeded +util.RegisterForRefreshIfNeeded = RegisterForRefreshIfNeeded +util.RegisterForReloadIfNeeded = RegisterForReloadIfNeeded +util.GetTopPanel = GetTopPanel +util.ShowConfirmationDialog = ShowConfirmationDialog +util.UpdateWarning = UpdateWarning + +local ADDON_DATA_TYPE = 1 +local RESELECTING_DURING_REBUILD = true +local USER_REQUESTED_OPEN = true + + +--INTERNAL FUNCTION +--scrolls ZO_ScrollList `list` to move the row corresponding to `data` +-- into view (does nothing if there is no such row in the list) +--unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for +-- fading near the list's edges - it avoids the fading area by scrolling +-- a little further than the ZO function +local function ScrollDataIntoView(list, data) + local targetIndex = data.sortIndex + if not targetIndex then return end + + local scrollMin, scrollMax = list.scrollbar:GetMinMax() + local scrollTop = list.scrollbar:GetValue() + local controlHeight = list.uniformControlHeight or list.controlHeight + local targetMin = controlHeight * (targetIndex - 1) - 64 + -- subtracting 64 ain't arbitrary, it's the maximum fading height + -- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade) + + if targetMin < scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin)) + else + local listHeight = ZO_ScrollList_GetHeight(list) + local targetMax = controlHeight * targetIndex + 64 - listHeight + + if targetMax > scrollTop then + ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax)) + end + end +end + + +--INTERNAL FUNCTION +--constructs a string pattern from the text in `searchEdit` control +-- * metacharacters are escaped, losing their special meaning +-- * whitespace matches anything (including empty substring) +--if there is nothing but whitespace, returns nil +--otherwise returns a filter function, which takes a `data` table argument +-- and returns true iff `data.filterText` matches the pattern +local function GetSearchFilterFunc(searchEdit) + local text = searchEdit:GetText():lower() + local pattern = text:match("(%S+.-)%s*$") + + if not pattern then -- nothing but whitespace + return nil + end + + -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de" + pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0") + + -- replace whitespace with "match shortest anything" + pattern = pattern:gsub("%s+", ".-") + + return function(data) + return data.filterText:lower():find(pattern) ~= nil + end +end + + +--INTERNAL FUNCTION +--populates `addonList` with entries from `addonsForList` +-- addonList = ZO_ScrollList control +-- filter = [optional] function(data) +local function PopulateAddonList(addonList, filter) + local entryList = ZO_ScrollList_GetDataList(addonList) + local numEntries = 0 + local selectedData = nil + local selectionIsFinal = false + + ZO_ScrollList_Clear(addonList) + + for i, data in ipairs(addonsForList) do + if not filter or filter(data) then + local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data) + numEntries = numEntries + 1 + data.sortIndex = numEntries + entryList[numEntries] = dataEntry + -- select the first panel passing the filter, or the currently + -- shown panel, but only if it passes the filter as well + if selectedData == nil or data.panel == lam.pendingAddonPanel or data.panel == lam.currentAddonPanel then + if not selectionIsFinal then + selectedData = data + end + if data.panel == lam.pendingAddonPanel then + lam.pendingAddonPanel = nil + selectionIsFinal = true + end + end + else + data.sortIndex = nil + end + end + + ZO_ScrollList_Commit(addonList) + + if selectedData then + if selectedData.panel == lam.currentAddonPanel then + ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD) + else + ZO_ScrollList_SelectData(addonList, selectedData, nil) + end + ScrollDataIntoView(addonList, selectedData) + end +end + + +--METHOD: REGISTER WIDGET-- +--each widget has its version checked before loading, +--so we only have the most recent one in memory +--Usage: +-- widgetType = "string"; the type of widget being registered +-- widgetVersion = integer; the widget's version number +LAMCreateControl = LAMCreateControl or {} +local lamcc = LAMCreateControl + +function lam:RegisterWidget(widgetType, widgetVersion) + if widgets[widgetType] and widgets[widgetType] >= widgetVersion then + return false + else + widgets[widgetType] = widgetVersion + return true + end +end + +-- INTERNAL METHOD: hijacks the handlers for the actions in the OptionsWindow layer if not already done +local function InitKeybindActions() + if not lam.keybindsInitialized then + lam.keybindsInitialized = true + ZO_PreHook(KEYBOARD_OPTIONS, "ApplySettings", function() + if lam.currentPanelOpened then + if not lam.applyButton:IsHidden() then + HandleReloadUIPressed() + end + return true + end + end) + ZO_PreHook("ZO_Dialogs_ShowDialog", function(dialogName) + if lam.currentPanelOpened and dialogName == "OPTIONS_RESET_TO_DEFAULTS" then + if not lam.defaultButton:IsHidden() then + HandleLoadDefaultsPressed() + end + return true + end + end) + end +end + +-- INTERNAL METHOD: fires the LAM-PanelOpened callback if not already done +local function OpenCurrentPanel() + if lam.currentAddonPanel and not lam.currentPanelOpened then + lam.currentPanelOpened = true + lam.defaultButton:SetHidden(not lam.currentAddonPanel.data.registerForDefaults) + cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel) + end +end + +-- INTERNAL METHOD: fires the LAM-PanelClosed callback if not already done +local function CloseCurrentPanel() + if lam.currentAddonPanel and lam.currentPanelOpened then + lam.currentPanelOpened = false + cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel) + end +end + +--METHOD: OPEN TO ADDON PANEL-- +--opens to a specific addon's option panel +--Usage: +-- panel = userdata; the panel returned by the :RegisterOptionsPanel method +local locSettings = GetString(SI_GAME_MENU_SETTINGS) +function lam:OpenToPanel(panel) + + -- find and select the panel's row in addon list + + local addonList = lam.addonList + local selectedData = nil + + for _, addonData in ipairs(addonsForList) do + if addonData.panel == panel then + selectedData = addonData + ScrollDataIntoView(addonList, selectedData) + lam.pendingAddonPanel = addonData.panel + break + end + end + + ZO_ScrollList_SelectData(addonList, selectedData) + ZO_ScrollList_RefreshVisible(addonList, selectedData) + + local srchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") + srchEdit:Clear() + + -- note that ZO_ScrollList doesn't require `selectedData` to be actually + -- present in the list, and that the list will only be populated once LAM + -- "Addon Settings" menu entry is selected for the first time + + local function openAddonSettingsMenu() + local gameMenu = ZO_GameMenu_InGame.gameMenu + local settingsMenu = gameMenu.headerControls[locSettings] + + if settingsMenu then -- an instance of ZO_TreeNode + local children = settingsMenu:GetChildren() + for i = 1, (children and #children or 0) do + local childNode = children[i] + local data = childNode:GetData() + if data and data.id == lam.panelId then + -- found LAM "Addon Settings" node, yay! + childNode:GetTree():SelectNode(childNode) + break + end + end + end + end + + if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then + openAddonSettingsMenu() + else + sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu) + sm:Show("gameMenuInGame") + end +end + +local TwinOptionsContainer_Index = 0 +local function TwinOptionsContainer(parent, leftWidget, rightWidget) + TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1 + local cParent = parent.scroll or parent + local panel = parent.panel or cParent + local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index), + cParent, CT_CONTROL) + container:SetResizeToFitDescendents(true) + container:SetAnchor(select(2, leftWidget:GetAnchor(0) )) + + leftWidget:ClearAnchors() + leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT) + rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0) + + leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls + rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 ) + + leftWidget:SetParent(container) + rightWidget:SetParent(container) + + container.data = {type = "container"} + container.panel = panel + return container +end + +--INTERNAL FUNCTION +--creates controls when options panel is first shown +--controls anchoring of these controls in the panel +local function CreateOptionsControls(panel) + local addonID = panel:GetName() + if(optionsState[addonID] == OPTIONS_CREATED) then + return false + elseif(optionsState[addonID] == OPTIONS_CREATION_RUNNING) then + return true + end + optionsState[addonID] = OPTIONS_CREATION_RUNNING + + local function CreationFinished() + optionsState[addonID] = OPTIONS_CREATED + cm:FireCallbacks("LAM-PanelControlsCreated", panel) + OpenCurrentPanel() + end + + local optionsTable = addonToOptionsMap[addonID] + if optionsTable then + local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf) + local widget + local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end) + if not status then + return err or true, offsetY, anchorTarget, wasHalf + else + local isHalf = (widgetData.width == "half") + if not anchorTarget then -- the first widget in a panel is just placed in the top left corner + widget:SetAnchor(TOPLEFT) + anchorTarget = widget + elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side + widget.lineControl = anchorTarget + isHalf = false + offsetY = 0 + anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget) + else -- otherwise we just put it below the previous one normally + widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15) + offsetY = 0 + anchorTarget = widget + end + return false, offsetY, anchorTarget, isHalf + end + end + + local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20 + local fifo = {} + local anchorOffset, lastAddedControl, wasHalf + local CreateWidgetsInPanel, err + + local function PrepareForNextPanel() + anchorOffset, lastAddedControl, wasHalf = 0, nil, false + end + + local function SetupCreationCalls(parent, widgetDataTable) + fifo[#fifo + 1] = PrepareForNextPanel + local count = #widgetDataTable + for i = 1, count, THROTTLE_COUNT do + fifo[#fifo + 1] = function() + CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count)) + end + end + return count ~= NonContiguousCount(widgetDataTable) + end + + CreateWidgetsInPanel = function(parent, widgetDataTable, startIndex, endIndex) + for i=startIndex,endIndex do + local widgetData = widgetDataTable[i] + if not widgetData then + PrintLater("Skipped creation of missing entry in the settings menu of " .. addonID .. ".") + else + local widgetType = widgetData.type + local offsetX = 0 + local isSubmenu = (widgetType == "submenu") + if isSubmenu then + wasHalf = false + offsetX = 5 + end + + err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) + if err then + PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) + if logger then + logger:Error(err) + end + end + + if isSubmenu then + if SetupCreationCalls(lastAddedControl, widgetData.controls) then + PrintLater(("The sub menu '%s' of %s is missing some entries."):format(GetStringFromValue(widgetData.name or "unnamed"), addonID)) + end + end + end + end + end + + local function DoCreateSettings() + if #fifo > 0 then + local nextCall = table.remove(fifo, 1) + nextCall() + if(nextCall == PrepareForNextPanel) then + DoCreateSettings() + else + zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT) + end + else + CreationFinished() + end + end + + if SetupCreationCalls(panel, optionsTable) then + PrintLater(("The settings menu of %s is missing some entries."):format(addonID)) + end + DoCreateSettings() + else + CreationFinished() + end + + return true +end + +--INTERNAL FUNCTION +--handles switching between panels +local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel + local currentlySelected = lam.currentAddonPanel + if currentlySelected and currentlySelected ~= panel then + currentlySelected:SetHidden(true) + CloseCurrentPanel() + end + lam.currentAddonPanel = panel + + -- refresh visible rows to reflect panel IsHidden status + ZO_ScrollList_RefreshVisible(lam.addonList) + + if not CreateOptionsControls(panel) then + OpenCurrentPanel() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) +end + +local CheckSafetyAndInitialize +local function ShowSetHandlerWarning(panel, handler) + local hint + if(handler == "OnShow" or handler == "OnEffectivelyShown") then + hint = "'LAM-PanelControlsCreated' or 'LAM-PanelOpened'" + elseif(handler == "OnHide" or handler == "OnEffectivelyHidden") then + hint = "'LAM-PanelClosed'" + end + + if hint then + local message = ("Setting a handler on a panel is not recommended. Use the global callback %s instead. (%s on %s)"):format(hint, handler, panel.data.name) + PrintLater(message) + if logger then + logger:Warn(message) + end + end +end + +--METHOD: REGISTER ADDON PANEL +--registers your addon with LibAddonMenu and creates a panel +--Usage: +-- addonID = "string"; unique ID which will be the global name of your panel +-- panelData = table; data object for your panel - see controls\panel.lua +function lam:RegisterAddonPanel(addonID, panelData) + CheckSafetyAndInitialize(addonID) + local container = lam:GetAddonPanelContainer() + local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel + panel:SetHidden(true) + panel:SetAnchorFill(container) + panel:SetHandler("OnEffectivelyShown", ToggleAddonPanels) + ZO_PreHook(panel, "SetHandler", ShowSetHandlerWarning) + + local function stripMarkup(str) + return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") + end + + local filterParts = {panelData.name, nil, nil} + -- append keywords and author separately, the may be nil + filterParts[#filterParts + 1] = panelData.keywords + filterParts[#filterParts + 1] = panelData.author + + local addonData = { + panel = panel, + name = stripMarkup(panelData.name), + filterText = stripMarkup(tconcat(filterParts, "\t")):lower(), + } + + tinsert(addonsForList, addonData) + + if panelData.slashCommand then + SLASH_COMMANDS[panelData.slashCommand] = function() + lam:OpenToPanel(panel) + end + end + + return panel --return for authors creating options manually +end + + +--METHOD: REGISTER OPTION CONTROLS +--registers the options you want shown for your addon +--these are stored in a table where each key-value pair is the order +--of the options in the panel and the data for that control, respectively +--see exampleoptions.lua for an example +--see controls\.lua for each widget type +--Usage: +-- addonID = "string"; the same string passed to :RegisterAddonPanel +-- optionsTable = table; the table containing all of the options controls and their data +function lam:RegisterOptionControls(addonID, optionsTable) --optionsTable = {sliderData, buttonData, etc} + addonToOptionsMap[addonID] = optionsTable +end + +--INTERNAL FUNCTION +--creates LAM's Addon Settings entry in ZO_GameMenu +local function CreateAddonSettingsMenuEntry() + local panelData = { + id = KEYBOARD_OPTIONS.currentPanelId, + name = util.L["PANEL_NAME"], + } + + KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1 + KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name + + lam.panelId = panelData.id + + local addonListSorted = false + + function panelData.callback() + sm:AddFragment(lam:GetAddonSettingsFragment()) + KEYBOARD_OPTIONS:ChangePanels(lam.panelId) + + local title = LAMAddonSettingsWindow:GetNamedChild("Title") + title:SetText(panelData.name) + + if not addonListSorted and #addonsForList > 0 then + local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") + --we're about to show our list for the first time - let's sort it + table.sort(addonsForList, function(a, b) return a.name < b.name end) + PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit)) + addonListSorted = true + end + end + + function panelData.unselectedCallback() + sm:RemoveFragment(lam:GetAddonSettingsFragment()) + if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011 + SetCameraOptionsPreviewModeEnabled(false) + end + end + + ZO_GameMenu_AddSettingPanel(panelData) +end + + +--INTERNAL FUNCTION +--creates the left-hand menu in LAM's window +local function CreateAddonList(name, parent) + local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList") + + local function addonListRow_OnMouseDown(control, button) + if button == 1 then + local data = ZO_ScrollList_GetData(control) + ZO_ScrollList_SelectData(addonList, data, control) + end + end + + local function addonListRow_OnMouseEnter(control) + ZO_ScrollList_MouseEnter(addonList, control) + end + + local function addonListRow_OnMouseExit(control) + ZO_ScrollList_MouseExit(addonList, control) + end + + local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild) + if not reselectingDuringRebuild then + if previouslySelectedData then + previouslySelectedData.panel:SetHidden(true) + end + if selectedData then + selectedData.panel:SetHidden(false) + PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION) + end + end + end + + local function addonListRow_Setup(control, data) + control:SetText(data.name) + control:SetSelected(not data.panel:IsHidden()) + end + + ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup) + -- I don't know how to make highlights clear properly; they often + -- get stuck and after a while the list is full of highlighted rows + --ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight") + ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select) + + local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE) + local addonListRow_CreateRaw = addonDataType.pool.m_Factory + + local function addonListRow_Create(pool) + local control = addonListRow_CreateRaw(pool) + control:SetHandler("OnMouseDown", addonListRow_OnMouseDown) + --control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter) + --control:SetHandler("OnMouseExit", addonListRow_OnMouseExit) + control:SetHeight(28) + control:SetFont("ZoFontHeader") + control:SetHorizontalAlignment(TEXT_ALIGN_LEFT) + control:SetVerticalAlignment(TEXT_ALIGN_CENTER) + control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + return control + end + + addonDataType.pool.m_Factory = addonListRow_Create + + return addonList +end + + +--INTERNAL FUNCTION +local function CreateSearchFilterBox(name, parent) + local boxControl = wm:CreateControl(name, parent, CT_CONTROL) + + local srchButton = wm:CreateControl("$(parent)Button", boxControl, CT_BUTTON) + srchButton:SetDimensions(32, 32) + srchButton:SetAnchor(LEFT, nil, LEFT, 2, 0) + srchButton:SetNormalTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_up.dds") + srchButton:SetPressedTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_down.dds") + srchButton:SetMouseOverTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_over.dds") + + local srchEdit = wm:CreateControlFromVirtual("$(parent)Edit", boxControl, "ZO_DefaultEdit") + srchEdit:SetAnchor(LEFT, srchButton, RIGHT, 4, 1) + srchEdit:SetAnchor(RIGHT, nil, RIGHT, -4, 1) + srchEdit:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) + + local srchBg = wm:CreateControl("$(parent)Bg", boxControl, CT_BACKDROP) + srchBg:SetAnchorFill() + srchBg:SetAlpha(0) + srchBg:SetCenterColor(0, 0, 0, 0.5) + srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) + srchBg:SetEdgeTexture("", 1, 1, 0, 0) + + -- search backdrop should appear whenever you hover over either + -- the magnifying glass button or the edit field (which is only + -- visible when it contains some text), and also while the edit + -- field has keyboard focus + + local srchActive = false + local srchHover = false + + local function srchBgUpdateAlpha() + if srchActive or srchEdit:HasFocus() then + srchBg:SetAlpha(srchHover and 0.8 or 0.6) + else + srchBg:SetAlpha(srchHover and 0.6 or 0.0) + end + end + + local function srchMouseEnter(control) + srchHover = true + srchBgUpdateAlpha() + end + + local function srchMouseExit(control) + srchHover = false + srchBgUpdateAlpha() + end + + boxControl:SetMouseEnabled(true) + boxControl:SetHitInsets(1, 1, -1, -1) + boxControl:SetHandler("OnMouseEnter", srchMouseEnter) + boxControl:SetHandler("OnMouseExit", srchMouseExit) + + srchButton:SetHandler("OnMouseEnter", srchMouseEnter) + srchButton:SetHandler("OnMouseExit", srchMouseExit) + + local focusLostTime = 0 + + srchButton:SetHandler("OnClicked", function(self) + srchEdit:Clear() + if GetFrameTimeMilliseconds() - focusLostTime < 100 then + -- re-focus the edit box if it lost focus due to this + -- button click (note that this handler may run a few + -- frames later) + srchEdit:TakeFocus() + end + end) + + srchEdit:SetHandler("OnMouseEnter", srchMouseEnter) + srchEdit:SetHandler("OnMouseExit", srchMouseExit) + srchEdit:SetHandler("OnFocusGained", srchBgUpdateAlpha) + + srchEdit:SetHandler("OnFocusLost", function() + focusLostTime = GetFrameTimeMilliseconds() + srchBgUpdateAlpha() + end) + + srchEdit:SetHandler("OnEscape", function(self) + self:Clear() + self:LoseFocus() + end) + + srchEdit:SetHandler("OnTextChanged", function(self) + local filterFunc = GetSearchFilterFunc(self) + if filterFunc then + srchActive = true + srchBg:SetEdgeColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA()) + srchButton:SetState(BSTATE_PRESSED) + else + srchActive = false + srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) + srchButton:SetState(BSTATE_NORMAL) + end + srchBgUpdateAlpha() + PopulateAddonList(lam.addonList, filterFunc) + PlaySound(SOUNDS.SPINNER_DOWN) + end) + + return boxControl +end + + +--INTERNAL FUNCTION +--creates LAM's Addon Settings top-level window +local function CreateAddonSettingsWindow() + local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow") + tlw:SetHidden(true) + tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow + + ZO_ReanchorControlForLeftSidePanel(tlw) + + -- create black background for the window (mimic ZO_RightFootPrintBackground) + + local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE) + bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds") + bgLeft:SetDimensions(1024, 1024) + bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT) + bgLeft:SetDrawLayer(DL_BACKGROUND) + bgLeft:SetExcludeFromResizeToFitExtents(true) + + local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE) + bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds") + bgRight:SetDimensions(64, 1024) + bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT) + bgRight:SetDrawLayer(DL_BACKGROUND) + bgRight:SetExcludeFromResizeToFitExtents(true) + + -- create gray background for addon list (mimic ZO_TreeUnderlay) + + local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE) + underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds") + underlayLeft:SetDimensions(256, 1024) + underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT) + underlayLeft:SetDrawLayer(DL_BACKGROUND) + underlayLeft:SetExcludeFromResizeToFitExtents(true) + + local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE) + underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds") + underlayRight:SetDimensions(128, 1024) + underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT) + underlayRight:SetDrawLayer(DL_BACKGROUND) + underlayRight:SetExcludeFromResizeToFitExtents(true) + + -- create title bar (mimic ZO_OptionsWindow) + + local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL) + title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70) + title:SetFont("ZoFontWinH1") + title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE) + + local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider") + divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108) + + -- create search filter box + + local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw) + srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120) + srchBox:SetDimensions(260, 30) + + -- create scrollable addon list + + local addonList = CreateAddonList("$(parent)AddonList", tlw) + addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160) + addonList:SetDimensions(285, 665) + + lam.addonList = addonList -- for easy access from elsewhere + + -- create container for option panels + + local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL) + panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120) + panelContainer:SetDimensions(645, 675) + + local defaultButton = wm:CreateControlFromVirtual("$(parent)ResetToDefaultButton", tlw, "ZO_DialogButton") + ZO_KeybindButtonTemplate_Setup(defaultButton, "OPTIONS_LOAD_DEFAULTS", HandleLoadDefaultsPressed, GetString(SI_OPTIONS_DEFAULTS)) + defaultButton:SetAnchor(TOPLEFT, panelContainer, BOTTOMLEFT, 0, 2) + lam.defaultButton = defaultButton + + local applyButton = wm:CreateControlFromVirtual("$(parent)ApplyButton", tlw, "ZO_DialogButton") + ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_ADDON_MANAGER_RELOAD)) + applyButton:SetAnchor(TOPRIGHT, panelContainer, BOTTOMRIGHT, 0, 2) + applyButton:SetHidden(true) + lam.applyButton = applyButton + + return tlw +end + + +--INITIALIZING +local safeToInitialize = false +local hasInitialized = false + +local eventHandle = table.concat({MAJOR, MINOR}, "r") +local function OnLoad(_, addonName) + -- wait for the first loaded event + em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED) + safeToInitialize = true +end +em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad) + +local function OnActivated(_, initial) + em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED) + FlushMessages() + + local reopenPanel = RetrievePanelForReopening() + if not initial and reopenPanel then + lam:OpenToPanel(reopenPanel) + end +end +em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated) + +function CheckSafetyAndInitialize(addonID) + if not safeToInitialize then + local msg = string.format("The panel with id '%s' was registered before addon loading has completed. This might break the AddOn Settings menu.", addonID) + PrintLater(msg) + end + if not hasInitialized then + hasInitialized = true + end +end + + +--TODO documentation +function lam:GetAddonPanelContainer() + local fragment = lam:GetAddonSettingsFragment() + local window = fragment:GetControl() + return window:GetNamedChild("PanelContainer") +end + + +--TODO documentation +function lam:GetAddonSettingsFragment() + assert(hasInitialized or safeToInitialize) + if not LAMAddonSettingsFragment then + local window = CreateAddonSettingsWindow() + LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100) + LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState) + if(newState == SCENE_FRAGMENT_SHOWN) then + InitKeybindActions() + PushActionLayerByName("OptionsWindow") + OpenCurrentPanel() + elseif(newState == SCENE_FRAGMENT_HIDDEN) then + CloseCurrentPanel() + RemoveActionLayerByName("OptionsWindow") + ShowReloadDialogIfNeeded() + end + end) + CreateAddonSettingsMenuEntry() + end + return LAMAddonSettingsFragment +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/button.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/button.lua new file mode 100644 index 0000000..17ecfef --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/button.lua @@ -0,0 +1,91 @@ +--[[buttonData = { + type = "button", + name = "My Button", -- string id or function returning a string + func = function() end, + tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + icon = "icon\\path.dds", -- (optional) + isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) + warning = "Will need to reload the UI.", -- (optional) + reference = "MyAddonButton", -- unique global reference to control (optional) +} ]] + +local widgetVersion = 11 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("button", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable = control.data.disabled + if type(disable) == "function" then + disable = disable() + end + control.button:SetEnabled(not disable) +end + +--controlName is optional +local MIN_HEIGHT = 28 -- default_button height +local HALF_WIDTH_LINE_SPACING = 2 +function LAMCreateControl.button(parent, buttonData, controlName) + local control = LAM.util.CreateBaseControl(parent, buttonData, controlName) + control:SetMouseEnabled(true) + + local width = control:GetWidth() + if control.isHalfWidth then + control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) + else + control:SetDimensions(width, MIN_HEIGHT) + end + + if buttonData.icon then + control.button = wm:CreateControl(nil, control, CT_BUTTON) + control.button:SetDimensions(26, 26) + control.button:SetNormalTexture(buttonData.icon) + control.button:SetPressedOffset(2, 2) + else + --control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton") + control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton") + control.button:SetWidth(width / 3) + control.button:SetText(LAM.util.GetStringFromValue(buttonData.name)) + if buttonData.isDangerous then control.button:SetNormalFontColor(ZO_ERROR_COLOR:UnpackRGBA()) end + end + local button = control.button + button:SetAnchor(control.isHalfWidth and CENTER or RIGHT) + button:SetClickSound("Click") + button.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.tooltip)} + button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + button:SetHandler("OnClicked", function(...) + local args = {...} + local function callback() + buttonData.func(unpack(args)) + LAM.util.RequestRefreshIfNeeded(control) + end + + if(buttonData.isDangerous) then + local title = LAM.util.GetStringFromValue(buttonData.name) + local body = LAM.util.GetStringFromValue(buttonData.warning) + LAM.util.ShowConfirmationDialog(title, body, callback) + else + callback() + end + end) + + if buttonData.warning ~= nil then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + if buttonData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/checkbox.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/checkbox.lua new file mode 100644 index 0000000..8f48b63 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/checkbox.lua @@ -0,0 +1,142 @@ +--[[checkboxData = { + type = "checkbox", + name = "My Checkbox", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- a boolean or function that returns a boolean (optional) + reference = "MyAddonCheckbox", -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("checkbox", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +--label +local enabledColor = ZO_DEFAULT_ENABLED_COLOR +local enabledHLcolor = ZO_HIGHLIGHT_TEXT +local disabledColor = ZO_DEFAULT_DISABLED_COLOR +local disabledHLcolor = ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR +--checkbox +local checkboxColor = ZO_NORMAL_TEXT +local checkboxHLcolor = ZO_HIGHLIGHT_TEXT + + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA()) + control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA()) + --control:SetMouseEnabled(not disable) + --control:SetMouseEnabled(true) + + control.isDisabled = disable +end + +local function ToggleCheckbox(control) + if control.value then + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.checkbox:SetText(control.checkedText) + else + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.checkbox:SetText(control.uncheckedText) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value ~= nil then --our value could be false + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + control.value = value + + ToggleCheckbox(control) +end + +local function OnMouseEnter(control) + ZO_Options_OnMouseEnter(control) + + if control.isDisabled then return end + + local label = control.label + if control.value then + label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) + else + label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + end + control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) +end + +local function OnMouseExit(control) + ZO_Options_OnMouseExit(control) + + if control.isDisabled then return end + + local label = control.label + if control.value then + label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + else + label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + end + control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) +end + +--controlName is optional +function LAMCreateControl.checkbox(parent, checkboxData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, checkboxData, controlName) + control:SetHandler("OnMouseEnter", OnMouseEnter) + control:SetHandler("OnMouseExit", OnMouseExit) + control:SetHandler("OnMouseUp", function(control) + if control.isDisabled then return end + PlaySound(SOUNDS.DEFAULT_CLICK) + control.value = not control.value + control:UpdateValue(false, control.value) + end) + + control.checkbox = wm:CreateControl(nil, control.container, CT_LABEL) + local checkbox = control.checkbox + checkbox:SetAnchor(LEFT, control.container, LEFT, 0, 0) + checkbox:SetFont("ZoFontGameBold") + checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) + control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper() + control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper() + + if checkboxData.warning ~= nil or checkboxData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if checkboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/colorpicker.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/colorpicker.lua new file mode 100644 index 0000000..b62cfba --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/colorpicker.lua @@ -0,0 +1,110 @@ +--[[colorpickerData = { + type = "colorpicker", + name = "My Color Picker", -- or string id or function returning a string + getFunc = function() return db.r, db.g, db.b, db.a end, -- (alpha is optional) + setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, -- (alpha is optional) + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, -- (optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color + reference = "MyAddonColorpicker" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end + + control.isDisabled = disable +end + +local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) + if forceDefault then --if we are forcing defaults + local color = LAM.util.GetDefaultValue(control.data.default) + valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a + control.data.setFunc(valueR, valueG, valueB, valueA) + elseif valueR and valueG and valueB then + control.data.setFunc(valueR, valueG, valueB, valueA or 1) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + valueR, valueG, valueB, valueA = control.data.getFunc() + end + + control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) +end + +function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName) + + control.color = control.container + local color = control.color + + control.thumb = wm:CreateControl(nil, color, CT_TEXTURE) + local thumb = control.thumb + thumb:SetDimensions(36, 18) + thumb:SetAnchor(LEFT, color, LEFT, 4, 0) + + color.border = wm:CreateControl(nil, color, CT_TEXTURE) + local border = color.border + border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds") + border:SetTextureCoords(0, .625, 0, .8125) + border:SetDimensions(40, 22) + border:SetAnchor(CENTER, thumb, CENTER, 0, 0) + + local function ColorPickerCallback(r, g, b, a) + control:UpdateValue(false, r, g, b, a) + end + + control:SetHandler("OnMouseUp", function(self, btn, upInside) + if self.isDisabled then return end + + if upInside then + local r, g, b, a = colorpickerData.getFunc() + if IsInGamepadPreferredMode() then + COLOR_PICKER_GAMEPAD:Show(ColorPickerCallback, r, g, b, a) + else + COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a) + end + end + end) + + if colorpickerData.warning ~= nil or colorpickerData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) + + control.UpdateValue = UpdateValue + control:UpdateValue() + if colorpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/custom.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/custom.lua new file mode 100644 index 0000000..eb6f26c --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/custom.lua @@ -0,0 +1,35 @@ +--[[customData = { + type = "custom", + reference = "MyAddonCustomControl", -- unique name for your control to use as reference (optional) + refreshFunc = function(customControl) end, -- function to call when panel/controls refresh (optional) + width = "full", -- or "half" (optional) +} ]] + +local widgetVersion = 7 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("custom", widgetVersion) then return end + +local function UpdateValue(control) + if control.data.refreshFunc then + control.data.refreshFunc(control) + end +end + +local MIN_HEIGHT = 26 +function LAMCreateControl.custom(parent, customData, controlName) + local control = LAM.util.CreateBaseControl(parent, customData, controlName) + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) + else + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) + end + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/description.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/description.lua new file mode 100644 index 0000000..a53c5b1 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/description.lua @@ -0,0 +1,80 @@ +--[[descriptionData = { + type = "description", + text = "My description text to display.", -- or string id or function returning a string + title = "My Title", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonDescription" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 9 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("description", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + control.desc:SetColor(color:UnpackRGBA()) + if control.title then + control.title:SetColor(color:UnpackRGBA()) + end + control.disabled = disable + end +end + +local function UpdateValue(control) + if control.title then + control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) + end + control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) +end + +function LAMCreateControl.description(parent, descriptionData, controlName) + local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if isHalfWidth then + control:SetDimensionConstraints(width / 2, 0, width / 2, 0) + else + control:SetDimensionConstraints(width, 0, width, 0) + end + + control.desc = wm:CreateControl(nil, control, CT_LABEL) + local desc = control.desc + desc:SetVerticalAlignment(TEXT_ALIGN_TOP) + desc:SetFont("ZoFontGame") + desc:SetText(LAM.util.GetStringFromValue(descriptionData.text)) + desc:SetWidth(isHalfWidth and width / 2 or width) + + if descriptionData.title then + control.title = wm:CreateControl(nil, control, CT_LABEL) + local title = control.title + title:SetWidth(isHalfWidth and width / 2 or width) + title:SetAnchor(TOPLEFT, control, TOPLEFT) + title:SetFont("ZoFontWinH4") + title:SetText(LAM.util.GetStringFromValue(descriptionData.title)) + desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT) + else + desc:SetAnchor(TOPLEFT) + end + + control.UpdateValue = UpdateValue + if descriptionData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control + +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/divider.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/divider.lua new file mode 100644 index 0000000..90ed6e8 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/divider.lua @@ -0,0 +1,45 @@ +--[[dividerData = { + type = "divider", + width = "full", -- or "half" (optional) + height = 10, -- (optional) + alpha = 0.25, -- (optional) + reference = "MyAddonDivider" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 2 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("divider", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local MIN_HEIGHT = 10 +local MAX_HEIGHT = 50 +local MIN_ALPHA = 0 +local MAX_ALPHA = 1 +local DEFAULT_ALPHA = 0.25 + +local function GetValueInRange(value, min, max, default) + if not value or type(value) ~= "number" then + return default + end + return math.min(math.max(min, value), max) +end + +function LAMCreateControl.divider(parent, dividerData, controlName) + local control = LAM.util.CreateBaseControl(parent, dividerData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + local height = GetValueInRange(dividerData.height, MIN_HEIGHT, MAX_HEIGHT, MIN_HEIGHT) + local alpha = GetValueInRange(dividerData.alpha, MIN_ALPHA, MAX_ALPHA, DEFAULT_ALPHA) + + control:SetDimensions(isHalfWidth and width / 2 or width, height) + + control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") + local divider = control.divider + divider:SetWidth(isHalfWidth and width / 2 or width) + divider:SetAnchor(TOPLEFT) + divider:SetAlpha(alpha) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/dropdown.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/dropdown.lua new file mode 100644 index 0000000..2f554cc --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/dropdown.lua @@ -0,0 +1,432 @@ +--[[dropdownData = { + type = "dropdown", + name = "My Dropdown", -- or string id or function returning a string + choices = {"table", "of", "choices"}, + choicesValues = {"foo", 2, "three"}, -- if specified, these values will get passed to setFunc instead (optional) + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + sort = "name-up", -- or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted + width = "full", -- or "half" (optional) + scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonDropdown" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 20 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("dropdown", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER +local SORT_BY_VALUE = { ["value"] = {} } +local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } +local SORT_TYPES = { + name = ZO_SORT_BY_NAME, + numeric = ZO_SORT_BY_NAME_NUMERIC, + value = SORT_BY_VALUE, + numericvalue = SORT_BY_VALUE_NUMERIC, +} +local SORT_ORDERS = { + up = ZO_SORT_ORDER_UP, + down = ZO_SORT_ORDER_DOWN, +} + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.dropdown:SetEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.dropdown:SetSelectedItem(control.choices[value]) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.dropdown:SetSelectedItem(control.choices[value]) + end +end + +local function DropdownCallback(control, choiceText, choice) + choice.control:UpdateValue(false, choice.value or choiceText) +end + +local function SetupTooltips(comboBox, choicesTooltips) + local function ShowTooltip(control) + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end + local function HideTooltip(control) + ClearTooltip(InformationTooltip) + end + + -- allow for tooltips on the drop down entries + local originalShow = comboBox.ShowDropdownInternal + comboBox.ShowDropdownInternal = function(comboBox) + originalShow(comboBox) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control.tooltip = choicesTooltips[i] + entry.onMouseEnter = control:GetHandler("OnMouseEnter") + entry.onMouseExit = control:GetHandler("OnMouseExit") + ZO_PreHookHandler(control, "OnMouseEnter", ShowTooltip) + ZO_PreHookHandler(control, "OnMouseExit", HideTooltip) + end + end + + local originalHide = comboBox.HideDropdownInternal + comboBox.HideDropdownInternal = function(self) + local entries = ZO_Menu.items + for i = 1, #entries do + local entry = entries[i] + local control = entries[i].item + control:SetHandler("OnMouseEnter", entry.onMouseEnter) + control:SetHandler("OnMouseExit", entry.onMouseExit) + control.tooltip = nil + end + originalHide(self) + end +end + +local function UpdateChoices(control, choices, choicesValues, choicesTooltips) + control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?) + ZO_ClearTable(control.choices) + + --build new list of choices + local choices = choices or control.data.choices + local choicesValues = choicesValues or control.data.choicesValues + local choicesTooltips = choicesTooltips or control.data.choicesTooltips + + if choicesValues then + assert(#choices == #choicesValues, "choices and choicesValues need to have the same size") + end + + if choicesTooltips then + assert(#choices == #choicesTooltips, "choices and choicesTooltips need to have the same size") + if not control.scrollHelper then -- only do this for non-scrollable + SetupTooltips(control.dropdown, choicesTooltips) + end + end + + for i = 1, #choices do + local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback) + entry.control = control + if choicesValues then + entry.value = choicesValues[i] + end + if choicesTooltips and control.scrollHelper then + entry.tooltip = choicesTooltips[i] + end + control.choices[entry.value or entry.name] = entry.name + control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort + end +end + +local function GrabSortingInfo(sortInfo) + local t, i = {}, 1 + for info in string.gmatch(sortInfo, "([^%-]+)") do + t[i] = info + i = i + 1 + end + + return t +end + +local ENTRY_ID = 1 +local LAST_ENTRY_ID = 2 +local OFFSET_X_INDEX = 4 +local DEFAULT_VISIBLE_ROWS = 10 +local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = ZO_SCROLLABLE_ENTRY_TEMPLATE_HEIGHT +local SCROLLBAR_PADDING = ZO_SCROLL_BAR_WIDTH +local PADDING_X = GetMenuPadding() +local PADDING_Y = ZO_SCROLLABLE_COMBO_BOX_LIST_PADDING_Y +local LABEL_OFFSET_X = 2 +local CONTENT_PADDING = PADDING_X * 4 +local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed +local ScrollableDropdownHelper = ZO_Object:Subclass() + +function ScrollableDropdownHelper:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function ScrollableDropdownHelper:Initialize(panel, control, visibleRows) + local combobox = control.combobox + local dropdown = control.dropdown + self.panel = panel + self.control = control + self.combobox = combobox + self.dropdown = dropdown + self.visibleRows = visibleRows + + -- clear anchors so we can adjust the width dynamically + dropdown.m_dropdown:ClearAnchors() + dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) + + -- handle dropdown or settingsmenu opening/closing + local function onShow() return self:OnShow() end + local function onHide() self:OnHide() end + local function doHide(closedPanel) + if closedPanel == panel then self:DoHide() end + end + + ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) + ZO_PreHook(dropdown, "HideDropdownInternal", onHide) + combobox:SetHandler("OnEffectivelyHidden", onHide) + cm:RegisterCallback("LAM-PanelClosed", doHide) + + -- dont fade entries near the edges + local scrollList = dropdown.m_scroll + scrollList.selectionTemplate = nil + scrollList.highlightTemplate = nil + ZO_ScrollList_EnableSelection(scrollList, "ZO_SelectionHighlight") + ZO_ScrollList_EnableHighlight(scrollList, "ZO_SelectionHighlight") + ZO_Scroll_SetUseFadeGradient(scrollList, false) + + -- adjust scroll content anchor to mimic menu padding + local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") + local anchor1 = {select(2, scroll:GetAnchor(0))} + local anchor2 = {select(2, scroll:GetAnchor(1))} + anchor1[OFFSET_X_INDEX] = PADDING_X - LABEL_OFFSET_X + anchor2[OFFSET_X_INDEX] = -anchor1[OFFSET_X_INDEX] + scroll:ClearAnchors() + scroll:SetAnchor(unpack(anchor1)) + scroll:SetAnchor(unpack(anchor2)) + ZO_ScrollList_Commit(scrollList) + + -- hook mouse enter/exit + local function onMouseEnter(control) self:OnMouseEnter(control) end + local function onMouseExit(control) self:OnMouseExit(control) end + + -- adjust row setup to mimic the highlight padding + local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, ENTRY_ID) + local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, LAST_ENTRY_ID) + local oSetup = dataType1.setupCallback -- both types have the same setup function + local function SetupEntry(control, data, list) + oSetup(control, data, list) + control.m_label:SetAnchor(LEFT, nil, nil, LABEL_OFFSET_X) + control.m_label:SetAnchor(RIGHT, nil, nil, -LABEL_OFFSET_X) + -- no need to store old ones since we have full ownership of our dropdown controls + if not control.hookedMouseHandlers then --only do it once per control + control.hookedMouseHandlers = true + ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) + ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) + end + end + dataType1.setupCallback = SetupEntry + dataType2.setupCallback = SetupEntry + + -- adjust dimensions based on entries + local scrollContent = scroll:GetNamedChild("Contents") + dropdown.AddMenuItems = ScrollableDropdownHelper.AddMenuItems + + dropdown.AdjustDimensions = function() + local numItems = #dropdown.m_sortedItems + local contentWidth = self:CalculateContentWidth() + CONTENT_PADDING + local anchorOffset = 0 + if(numItems > self.visibleRows) then + numItems = self.visibleRows + contentWidth = contentWidth + SCROLLBAR_PADDING + anchorOffset = -SCROLLBAR_PADDING + end + + local width = zo_max(contentWidth, dropdown.m_container:GetWidth()) + local height = dropdown:GetEntryTemplateHeightWithSpacing() * numItems - dropdown.m_spacing + (PADDING_Y * 2) + ROUNDING_MARGIN + + dropdown.m_dropdown:SetWidth(width) + dropdown.m_dropdown:SetHeight(height) + ZO_ScrollList_SetHeight(dropdown.m_scroll, height) + + scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) + end +end + +local function CreateScrollableComboBoxEntry(self, item, index, isLast) + item.m_index = index + item.m_owner = self + local entryType = isLast and LAST_ENTRY_ID or ENTRY_ID + local entry = ZO_ScrollList_CreateDataEntry(entryType, item) + + return entry +end + +function ScrollableDropdownHelper.AddMenuItems(self) -- self refers to the ZO_ScrollableComboBox here + ZO_ScrollList_Clear(self.m_scroll) + + local numItems = #self.m_sortedItems + local dataList = ZO_ScrollList_GetDataList(self.m_scroll) + + for i = 1, numItems do + local item = self.m_sortedItems[i] + local entry = CreateScrollableComboBoxEntry(self, item, i, i == numItems) + table.insert(dataList, entry) + end + + self:AdjustDimensions() + + ZO_ScrollList_Commit(self.m_scroll) +end + +function ScrollableDropdownHelper:OnShow() + local dropdown = self.dropdown + + -- don't show if there are no entries + if #dropdown.m_sortedItems == 0 then return true end + + if dropdown.m_lastParent ~= ZO_Menus then + dropdown.m_lastParent = dropdown.m_dropdown:GetParent() + dropdown.m_dropdown:SetParent(ZO_Menus) + ZO_Menus:BringWindowToTop() + end +end + +function ScrollableDropdownHelper:OnHide() + local dropdown = self.dropdown + if dropdown.m_lastParent then + dropdown.m_dropdown:SetParent(dropdown.m_lastParent) + dropdown.m_lastParent = nil + end +end + +function ScrollableDropdownHelper:DoHide() + local dropdown = self.dropdown + if dropdown:IsDropdownVisible() then + dropdown:HideDropdown() + end +end + +function ScrollableDropdownHelper:CalculateContentWidth() + local dropdown = self.dropdown + local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) + + local dummy = dataType.pool:AcquireObject() + dataType.setupCallback(dummy, { + m_owner = dropdown, + name = "Dummy" + }, dropdown) + + local maxWidth = 0 + local label = dummy.m_label + local entries = dropdown.m_sortedItems + local numItems = #entries + for index = 1, numItems do + label:SetText(entries[index].name) + local width = label:GetTextWidth() + if (width > maxWidth) then + maxWidth = width + end + end + + dataType.pool:ReleaseObject(dummy.key) + return maxWidth +end + +function ScrollableDropdownHelper:OnMouseEnter(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseEnter(control) + -- show tooltip + if control.m_data.tooltip then + InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.m_data.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() + end +end +function ScrollableDropdownHelper:OnMouseExit(control) + -- call original code if we replace instead of hook the handler + --ZO_ScrollableComboBox_Entry_OnMouseExit(control) + -- hide tooltip + if control.m_data.tooltip then + ClearTooltip(InformationTooltip) + end +end + +function LAMCreateControl.dropdown(parent, dropdownData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName) + control.choices = {} + + local countControl = parent + local name = parent:GetName() + if not name or #name == 0 then + countControl = LAMCreateControl + name = "LAM" + end + local comboboxCount = (countControl.comboboxCount or 0) + 1 + countControl.comboboxCount = comboboxCount + control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, dropdownData.scrollable and "ZO_ScrollableComboBox" or "ZO_ComboBox") + + local combobox = control.combobox + combobox:SetAnchor(TOPLEFT) + combobox:SetDimensions(control.container:GetDimensions()) + combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox) + local dropdown = control.dropdown + dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value + + if dropdownData.scrollable then + local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS + control.scrollHelper = ScrollableDropdownHelper:New(LAM.util.GetTopPanel(parent), control, visibleRows) + end + + ZO_PreHook(dropdown, "UpdateItems", function(self) + assert(not self.m_sortsItems, "built-in dropdown sorting was reactivated, sorting is handled by LAM") + if control.m_sortOrder ~= nil and control.m_sortType then + local sortKey = next(control.m_sortType) + local sortFunc = function(item1, item2) return ZO_TableOrderingFunction(item1, item2, sortKey, control.m_sortType, control.m_sortOrder) end + table.sort(self.m_sortedItems, sortFunc) + end + end) + + if dropdownData.sort then + local sortInfo = GrabSortingInfo(dropdownData.sort) + control.m_sortType, control.m_sortOrder = SORT_TYPES[sortInfo[1]], SORT_ORDERS[sortInfo[2]] + elseif dropdownData.choicesValues then + control.m_sortType, control.m_sortOrder = ZO_SORT_ORDER_UP, SORT_BY_VALUE + end + + if dropdownData.warning ~= nil or dropdownData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateChoices = UpdateChoices + control:UpdateChoices(dropdownData.choices, dropdownData.choicesValues) + control.UpdateValue = UpdateValue + control:UpdateValue() + if dropdownData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/editbox.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/editbox.lua new file mode 100644 index 0000000..f9f79ad --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/editbox.lua @@ -0,0 +1,156 @@ +--[[editboxData = { + type = "editbox", + name = "My Editbox", -- or string id or function returning a string + getFunc = function() return db.text end, + setFunc = function(text) db.text = text doStuff() end, + tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) + isMultiline = true, -- boolean (optional) + isExtraWide = true, -- boolean (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.text, -- default value or function that returns the default value (optional) + reference = "MyAddonEditbox" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 14 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("editbox", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.editbox:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end + --control.editbox:SetEditEnabled(not disable) + control.editbox:SetMouseEnabled(not disable) +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.editbox:SetText(value) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.editbox:SetText(value) + end +end + +local MIN_HEIGHT = 24 +local HALF_WIDTH_LINE_SPACING = 2 +function LAMCreateControl.editbox(parent, editboxData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, editboxData, controlName) + + local container = control.container + control.bg = wm:CreateControlFromVirtual(nil, container, "ZO_EditBackdrop") + local bg = control.bg + bg:SetAnchorFill() + + if editboxData.isMultiline then + control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditMultiLineForBackdrop") + control.editbox:SetHandler("OnMouseWheel", function(self, delta) + if self:HasFocus() then --only set focus to new spots if the editbox is currently in use + local cursorPos = self:GetCursorPosition() + local text = self:GetText() + local textLen = text:len() + local newPos + if delta > 0 then --scrolling up + local reverseText = text:reverse() + local revCursorPos = textLen - cursorPos + local revPos = reverseText:find("\n", revCursorPos+1) + newPos = revPos and textLen - revPos + else --scrolling down + newPos = text:find("\n", cursorPos+1) + end + if newPos then --if we found a new line, then scroll, otherwise don't + self:SetCursorPosition(newPos) + end + end + end) + else + control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop") + end + local editbox = control.editbox + editbox:SetText(editboxData.getFunc()) + editbox:SetMaxInputChars(3000) + editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end) + editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end) + editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0 + + control.label:ClearAnchors() + container:ClearAnchors() + + control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + + if control.isHalfWidth then + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) + end + + if editboxData.isExtraWide then + container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0) + else + container:SetWidth(MIN_WIDTH * 3.2) + end + + if editboxData.isMultiline then + container:SetHeight(MIN_HEIGHT * 3) + else + container:SetHeight(MIN_HEIGHT) + end + + if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then + control:SetHeight(container:GetHeight()) + else + control:SetHeight(container:GetHeight() + control.label:GetHeight()) + end + + editbox:ClearAnchors() + editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2) + editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2) + + if editboxData.warning ~= nil or editboxData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + if editboxData.isExtraWide then + control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0) + else + control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0) + end + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + if editboxData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/header.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/header.lua new file mode 100644 index 0000000..3eda1d7 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/header.lua @@ -0,0 +1,42 @@ +--[[headerData = { + type = "header", + name = "My Header", -- or string id or function returning a string + width = "full", -- or "half" (optional) + reference = "MyAddonHeader" -- unique global reference to control (optional) +} ]] + + +local widgetVersion = 8 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("header", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local function UpdateValue(control) + control.header:SetText(LAM.util.GetStringFromValue(control.data.name)) +end + +local MIN_HEIGHT = 30 +function LAMCreateControl.header(parent, headerData, controlName) + local control = LAM.util.CreateBaseControl(parent, headerData, controlName) + local isHalfWidth = control.isHalfWidth + local width = control:GetWidth() + control:SetDimensions(isHalfWidth and width / 2 or width, MIN_HEIGHT) + + control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") + local divider = control.divider + divider:SetWidth(isHalfWidth and width / 2 or width) + divider:SetAnchor(TOPLEFT) + + control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local header = control.header + header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT) + header:SetAnchor(BOTTOMRIGHT) + header:SetText(LAM.util.GetStringFromValue(headerData.name)) + + control.UpdateValue = UpdateValue + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/iconpicker.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/iconpicker.lua new file mode 100644 index 0000000..2cca460 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/iconpicker.lua @@ -0,0 +1,436 @@ +--[[iconpickerData = { + type = "iconpicker", + name = "My Icon Picker", -- or string id or function returning a string + choices = {"texture path 1", "texture path 2", "texture path 3"}, + getFunc = function() return db.var end, + setFunc = function(var) db.var = var doStuff() end, + tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) + choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) + maxColumns = 5, -- number of icons in one row (optional) + visibleRows = 4.5, -- number of visible rows (optional) + iconSize = 28, -- size of the icons (optional) + defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) + width = "full", --or "half" (optional) + beforeShow = function(control, iconPicker) return preventShow end, -- (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonIconPicker" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 8 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local IconPickerMenu = ZO_Object:Subclass() +local iconPicker +LAM.util.GetIconPickerMenu = function() + if not iconPicker then + iconPicker = IconPickerMenu:New("LAMIconPicker") + local sceneFragment = LAM:GetAddonSettingsFragment() + ZO_PreHook(sceneFragment, "OnHidden", function() + if not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + end) + end + return iconPicker +end + +function IconPickerMenu:New(...) + local object = ZO_Object.New(self) + object:Initialize(...) + return object +end + +function IconPickerMenu:Initialize(name) + local control = wm:CreateTopLevelWindow(name) + control:SetDrawTier(DT_HIGH) + control:SetHidden(true) + self.control = control + + local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer") + -- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count + scrollContainer:SetAnchorFill() + ZO_Scroll_SetUseFadeGradient(scrollContainer, false) + ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false) + ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value + local scroll = GetControl(scrollContainer, "ScrollChild") + self.scroll = scroll + self.scrollContainer = scrollContainer + + local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP) + bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE) + mouseOver:SetDrawLevel(2) + mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds") + mouseOver:SetHidden(true) + + local function IconFactory(pool) + local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE) + icon:SetMouseEnabled(true) + icon:SetDrawLevel(3) + icon:SetHandler("OnMouseEnter", function() + mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0) + mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0) + mouseOver:SetHidden(false) + if self.customOnMouseEnter then + self.customOnMouseEnter(icon) + else + self:OnMouseEnter(icon) + end + end) + icon:SetHandler("OnMouseExit", function() + mouseOver:ClearAnchors() + mouseOver:SetHidden(true) + if self.customOnMouseExit then + self.customOnMouseExit(icon) + else + self:OnMouseExit(icon) + end + end) + icon:SetHandler("OnMouseUp", function(control, ...) + PlaySound("Click") + icon.OnSelect(icon, icon.texture) + self:Clear() + end) + return icon + end + + local function ResetFunction(icon) + icon:ClearAnchors() + end + + self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction) + self:SetMaxColumns(1) + self.icons = {} + self.color = ZO_DEFAULT_ENABLED_COLOR + + EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function() + if self.refCount ~= nil then + local moc = wm:GetMouseOverControl() + if(moc:GetOwningWindow() ~= control) then + self.refCount = self.refCount - 1 + if self.refCount <= 0 then + self:Clear() + end + end + end + end) +end + +function IconPickerMenu:OnMouseEnter(icon) + InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT) + SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip)) + InformationTooltipTopLevel:BringWindowToTop() +end + +function IconPickerMenu:OnMouseExit(icon) + ClearTooltip(InformationTooltip) +end + +function IconPickerMenu:SetMaxColumns(value) + self.maxCols = value ~= nil and value or 5 +end + +local DEFAULT_SIZE = 28 +function IconPickerMenu:SetIconSize(value) + local iconSize = DEFAULT_SIZE + if value ~= nil then iconSize = math.max(iconSize, value) end + self.iconSize = iconSize +end + +function IconPickerMenu:SetVisibleRows(value) + self.visibleRows = value ~= nil and value or 4.5 +end + +function IconPickerMenu:SetMouseHandlers(onEnter, onExit) + self.customOnMouseEnter = onEnter + self.customOnMouseExit = onExit +end + +function IconPickerMenu:UpdateDimensions() + local iconSize = self.iconSize + local width = iconSize * self.maxCols + 20 + local height = iconSize * self.visibleRows + self.control:SetDimensions(width, height) + + local icons = self.icons + for i = 1, #icons do + local icon = icons[i] + icon:SetDimensions(iconSize, iconSize) + end +end + +function IconPickerMenu:UpdateAnchors() + local iconSize = self.iconSize + local col, maxCols = 1, self.maxCols + local previousCol, previousRow + local scroll = self.scroll + local icons = self.icons + + for i = 1, #icons do + local icon = icons[i] + icon:ClearAnchors() + if i == 1 then + icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0) + previousRow = icon + elseif col == 1 then + icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0) + previousRow = icon + else + icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0) + end + previousCol = icon + col = col >= maxCols and 1 or col + 1 + end +end + +function IconPickerMenu:Clear() + self.icons = {} + self.iconPool:ReleaseAllObjects() + self.control:SetHidden(true) + self.color = ZO_DEFAULT_ENABLED_COLOR + self.refCount = nil + self.parent = nil + self.customOnMouseEnter = nil + self.customOnMouseExit = nil +end + +function IconPickerMenu:AddIcon(texturePath, callback, tooltip) + local icon, key = self.iconPool:AcquireObject() + icon:SetTexture(texturePath) + icon:SetColor(self.color:UnpackRGBA()) + icon.texture = texturePath + icon.tooltip = tooltip + icon.OnSelect = callback + self.icons[#self.icons + 1] = icon +end + +function IconPickerMenu:Show(parent) + if #self.icons == 0 then return false end + if not self.control:IsHidden() then self:Clear() return false end + self:UpdateDimensions() + self:UpdateAnchors() + + local control = self.control + control:ClearAnchors() + control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8) + control:SetHidden(false) + control:BringWindowToTop() + self.parent = parent + self.refCount = 2 + + return true +end + +function IconPickerMenu:SetColor(color) + local icons = self.icons + self.color = color + for i = 1, #icons do + local icon = icons[i] + icon:SetColor(color:UnpackRGBA()) + end +end + +------------------------------------------------------------- + +local function UpdateChoices(control, choices, choicesTooltips) + local data = control.data + if not choices then + choices, choicesTooltips = data.choices, data.choicesTooltips or {} + end + local addedChoices = {} + + local iconPicker = LAM.util.GetIconPickerMenu() + iconPicker:Clear() + for i = 1, #choices do + local texture = choices[i] + if not addedChoices[texture] then -- remove duplicates + iconPicker:AddIcon(choices[i], function(self, texture) + control.icon:SetTexture(texture) + data.setFunc(texture) + LAM.util.RequestRefreshIfNeeded(control) + end, LAM.util.GetStringFromValue(choicesTooltips[i])) + addedChoices[texture] = true + end + end +end + +local function IsDisabled(control) + if type(control.data.disabled) == "function" then + return control.data.disabled() + else + return control.data.disabled + end +end + +local function SetColor(control, color) + local icon = control.icon + if IsDisabled(control) then + icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR + icon:SetColor(icon.color:UnpackRGBA()) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetColor(icon.color) + end +end + +local function UpdateDisabled(control) + local disable = IsDisabled(control) + + control.dropdown:SetMouseEnabled(not disable) + control.dropdownButton:SetEnabled(not disable) + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:Clear() + end + + SetColor(control, control.icon.color) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + control.icon:SetTexture(value) + elseif value then + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + control.icon:SetTexture(value) + end +end + +local MIN_HEIGHT = 26 +local HALF_WIDTH_LINE_SPACING = 2 +local function SetIconSize(control, size) + local icon = control.icon + icon.size = size + icon:SetDimensions(size, size) + + local height = size + 4 + control.dropdown:SetDimensions(size + 20, height) + height = math.max(height, MIN_HEIGHT) + control.container:SetHeight(height) + if control.lineControl then + control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING) + else + control:SetHeight(height) + end + + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then + iconPicker:SetIconSize(size) + iconPicker:UpdateDimensions() + iconPicker:UpdateAnchors() + end +end + +function LAMCreateControl.iconpicker(parent, iconpickerData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName) + + local function ShowIconPicker() + local iconPicker = LAM.util.GetIconPickerMenu() + if iconPicker.parent == control.container then + iconPicker:Clear() + else + iconPicker:SetMaxColumns(iconpickerData.maxColumns) + iconPicker:SetVisibleRows(iconpickerData.visibleRows) + iconPicker:SetIconSize(control.icon.size) + UpdateChoices(control) + iconPicker:SetColor(control.icon.color) + if iconpickerData.beforeShow then + if iconpickerData.beforeShow(control, iconPicker) then + iconPicker:Clear() + return + end + end + iconPicker:Show(control.container) + end + end + + local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE + control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL) + local dropdown = control.dropdown + dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0) + dropdown:SetMouseEnabled(true) + dropdown:SetHandler("OnMouseUp", ShowIconPicker) + dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE) + local icon = control.icon + icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0) + icon:SetDrawLevel(2) + + local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton") + dropdownButton:SetDimensions(16, 16) + dropdownButton:SetHandler("OnClicked", ShowIconPicker) + dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0) + control.dropdownButton = dropdownButton + + control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3) + bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5) + bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) + mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") + mungeOverlay:SetDrawLevel(1) + mungeOverlay:SetAddressMode(TEX_MODE_WRAP) + mungeOverlay:SetAnchorFill() + + if iconpickerData.warning ~= nil or iconpickerData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateChoices = UpdateChoices + control.UpdateValue = UpdateValue + control:UpdateValue() + control.SetColor = SetColor + control:SetColor() + control.SetIconSize = SetIconSize + control:SetIconSize(iconSize) + + if iconpickerData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/panel.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/panel.lua new file mode 100644 index 0000000..75bb904 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/panel.lua @@ -0,0 +1,168 @@ +--[[panelData = { + type = "panel", + name = "Window Title", -- or string id or function returning a string + displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) + author = "Seerah", -- or string id or function returning a string (optional) + version = "2.0", -- or string id or function returning a string (optional) + website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated or function (optional) + feedback = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where feedback/feature requests/bugs can be reported for the addon or function (optional) + translation = "https://www.esoui.com/portal.php?uid=5815", -- URL of website where translation texts of the addon can be helped with or function (optional) + donation = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where a donation for the addon author can be raised or function (optional) + keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) + slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) + registerForRefresh = true, -- boolean will refresh all options controls when a setting is changed and when the panel is shown (optional) + registerForDefaults = true, -- boolean will set all options controls back to default values (optional) + resetFunc = function() print("defaults reset") end, -- custom function to run after settings are reset to defaults (optional) +} ]] + + +local widgetVersion = 15 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("panel", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local cm = CALLBACK_MANAGER + +local function RefreshPanel(control) + local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu + if LAM.currentAddonPanel ~= panel or not LAM.currentPanelOpened then return end -- we refresh it later when the panel is opened + + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl ~= control and updateControl.UpdateValue then + updateControl:UpdateValue() + end + if updateControl.UpdateDisabled then + updateControl:UpdateDisabled() + end + if updateControl.UpdateWarning then + updateControl:UpdateWarning() + end + end +end + +local function ForceDefaults(panel) + local panelControls = panel.controlsToRefresh + + for i = 1, #panelControls do + local updateControl = panelControls[i] + if updateControl.UpdateValue and updateControl.data.default ~= nil then + updateControl:UpdateValue(true) + end + end + + if panel.data.resetFunc then + panel.data.resetFunc() + end + + cm:FireCallbacks("LAM-RefreshPanel", panel) +end + +local callbackRegistered = false +LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 +local SEPARATOR = " - " +local COLORED_SEPARATOR = ZO_WHITE:Colorize(SEPARATOR) +local LINK_COLOR = ZO_ColorDef:New("5959D5") +local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") +local LINK_COLOR_DONATE = ZO_ColorDef:New("FFD700") -- golden +local LINK_MOUSE_OVER_COLOR_DONATE = ZO_ColorDef:New("FFF6CC") + +local function CreateButtonControl(control, label, clickAction, relativeTo) + local button = wm:CreateControl(nil, control, CT_BUTTON) + button:SetClickSound("Click") + button:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + button:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) + button:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) + + local OnClicked + local actionType = type(clickAction) + if actionType == "string" then + OnClicked = function() RequestOpenUnsafeURL(clickAction) end + elseif actionType == "function" then + OnClicked = clickAction + end + button:SetHandler("OnClicked", OnClicked) + + if relativeTo then + button:SetAnchor(TOPLEFT, relativeTo, TOPRIGHT, 0, 0) + button:SetText(COLORED_SEPARATOR .. label) + else + button:SetAnchor(TOPLEFT, control.label, BOTTOMLEFT, 0, -2) + button:SetText(label) + end + button:SetDimensions(button:GetLabelControl():GetTextDimensions()) + + return button +end + +function LAMCreateControl.panel(parent, panelData, controlName) + local control = wm:CreateControl(controlName, parent, CT_CONTROL) + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) + label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) + + local previousInfoControl + if panelData.author or panelData.version then + control.info = wm:CreateControl(nil, control, CT_LABEL) + local info = control.info + info:SetFont(LAM.util.L["PANEL_INFO_FONT"]) + info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) + + local output = {} + if panelData.author then + output[#output + 1] = zo_strformat(LAM.util.L["AUTHOR"], LAM.util.GetStringFromValue(panelData.author)) + end + if panelData.version then + output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) + end + info:SetText(table.concat(output, SEPARATOR)) + previousInfoControl = info + end + + if panelData.website then + control.website = CreateButtonControl(control, LAM.util.L["WEBSITE"], panelData.website, previousInfoControl) + previousInfoControl = control.website + end + + if panelData.feedback then + control.feedback = CreateButtonControl(control, LAM.util.L["FEEDBACK"], panelData.feedback, previousInfoControl) + previousInfoControl = control.feedback + end + + if panelData.translation then + control.translation = CreateButtonControl(control, LAM.util.L["TRANSLATION"], panelData.translation, previousInfoControl) + previousInfoControl = control.translation + end + + if panelData.donation then + control.donation = CreateButtonControl(control, LAM.util.L["DONATION"], panelData.donation, previousInfoControl) + local donation = control.donation + previousInfoControl = donation + donation:SetNormalFontColor(LINK_COLOR_DONATE:UnpackRGBA()) + donation:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR_DONATE:UnpackRGBA()) + end + + control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") + LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1 + local container = control.container + container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20) + container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3) + control.scroll = GetControl(control.container, "ScrollChild") + control.scroll:SetResizeToFitPadding(0, 20) + + if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once + cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel) + callbackRegistered = true + end + + control.ForceDefaults = ForceDefaults + control.RefreshPanel = LAM.util.RequestRefreshIfNeeded + control.data = panelData + control.controlsToRefresh = {} + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/slider.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/slider.lua new file mode 100644 index 0000000..6c80968 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/slider.lua @@ -0,0 +1,220 @@ +--[[sliderData = { + type = "slider", + name = "My Slider", -- or string id or function returning a string + getFunc = function() return db.var end, + setFunc = function(value) db.var = value doStuff() end, + min = 0, + max = 20, + step = 1, -- (optional) + clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) + clampFunction = function(value, min, max) return math.max(math.min(value, max), min) end, -- function that is called to clamp the value (optional) + decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) + autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) + inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) + tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + disabled = function() return db.someBooleanSetting end, --or boolean (optional) + warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) + requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) + default = defaults.var, -- default value or function that returns the default value (optional) + reference = "MyAddonSlider" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("slider", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local strformat = string.format + +local function RoundDecimalToPlace(d, place) + return tonumber(strformat("%." .. tostring(place) .. "f", d)) +end + +local function ClampValue(value, min, max) + return math.max(math.min(value, max), min) +end + +local function UpdateDisabled(control) + local disable + if type(control.data.disabled) == "function" then + disable = control.data.disabled() + else + disable = control.data.disabled + end + + control.slider:SetEnabled(not disable) + control.slidervalue:SetEditEnabled(not disable) + if disable then + control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) + else + control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) + end +end + +local function UpdateValue(control, forceDefault, value) + if forceDefault then --if we are forcing defaults + value = LAM.util.GetDefaultValue(control.data.default) + control.data.setFunc(value) + elseif value then + if control.data.decimals then + value = RoundDecimalToPlace(value, control.data.decimals) + end + if control.data.clampInput ~= false then + local clamp = control.data.clampFunction or ClampValue + value = clamp(value, control.data.min, control.data.max) + end + control.data.setFunc(value) + --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed + LAM.util.RequestRefreshIfNeeded(control) + else + value = control.data.getFunc() + end + + control.slider:SetValue(value) + control.slidervalue:SetText(value) +end + +function LAMCreateControl.slider(parent, sliderData, controlName) + local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) + local isInputOnRight = sliderData.inputLocation == "right" + + --skipping creating the backdrop... Is this the actual slider texture? + control.slider = wm:CreateControl(nil, control.container, CT_SLIDER) + local slider = control.slider + slider:SetAnchor(TOPLEFT) + slider:SetHeight(14) + if(isInputOnRight) then + slider:SetAnchor(TOPRIGHT, nil, nil, -60) + else + slider:SetAnchor(TOPRIGHT) + end + slider:SetMouseEnabled(true) + slider:SetOrientation(ORIENTATION_HORIZONTAL) + --put nil for highlighted texture file path, and what look to be texture coords + slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16) + local minValue = sliderData.min + local maxValue = sliderData.max + slider:SetMinMax(minValue, maxValue) + slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) + slider:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) + + slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP) + local bg = slider.bg + bg:SetCenterColor(0, 0, 0) + bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4) + bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4) + + control.minText = wm:CreateControl(nil, slider, CT_LABEL) + local minText = control.minText + minText:SetFont("ZoFontGameSmall") + minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT) + minText:SetText(sliderData.min) + + control.maxText = wm:CreateControl(nil, slider, CT_LABEL) + local maxText = control.maxText + maxText:SetFont("ZoFontGameSmall") + maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT) + maxText:SetText(sliderData.max) + + control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop") + if(isInputOnRight) then + control.slidervalueBG:SetDimensions(60, 26) + control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0) + else + control.slidervalueBG:SetDimensions(50, 16) + control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0) + end + control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop") + local slidervalue = control.slidervalue + slidervalue:ClearAnchors() + slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1) + slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1) + slidervalue:SetTextType(TEXT_TYPE_NUMERIC) + if(isInputOnRight) then + slidervalue:SetFont("ZoFontGameLarge") + else + slidervalue:SetFont("ZoFontGameSmall") + end + + local isHandlingChange = false + local function HandleValueChanged(value) + if isHandlingChange then return end + if sliderData.decimals then + value = RoundDecimalToPlace(value, sliderData.decimals) + end + isHandlingChange = true + slider:SetValue(value) + slidervalue:SetText(value) + isHandlingChange = false + end + + slidervalue:SetHandler("OnEscape", function(self) + HandleValueChanged(sliderData.getFunc()) + self:LoseFocus() + end) + slidervalue:SetHandler("OnEnter", function(self) + self:LoseFocus() + end) + slidervalue:SetHandler("OnFocusLost", function(self) + local value = tonumber(self:GetText()) + control:UpdateValue(false, value) + end) + slidervalue:SetHandler("OnTextChanged", function(self) + local input = self:GetText() + if(#input > 1 and not input:sub(-1):match("[0-9]")) then return end + local value = tonumber(input) + if(value) then + HandleValueChanged(value) + end + end) + if(sliderData.autoSelect) then + ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self) + self:SelectAll() + end) + end + + local range = maxValue - minValue + slider:SetValueStep(sliderData.step or 1) + slider:SetHandler("OnValueChanged", function(self, value, eventReason) + if eventReason == EVENT_REASON_SOFTWARE then return end + HandleValueChanged(value) + end) + slider:SetHandler("OnSliderReleased", function(self, value) + if self:GetEnabled() then + control:UpdateValue(false, value) + end + end) + slider:SetHandler("OnMouseWheel", function(self, value) + if(not self:GetEnabled()) then return end + local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) + control:UpdateValue(false, new_value) + end) + + if sliderData.warning ~= nil or sliderData.requiresReload then + control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") + control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0) + control.UpdateWarning = LAM.util.UpdateWarning + control:UpdateWarning() + end + + control.UpdateValue = UpdateValue + control:UpdateValue() + + if sliderData.disabled ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + LAM.util.RegisterForReloadIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/submenu.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/submenu.lua new file mode 100644 index 0000000..d7bc8bf --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/submenu.lua @@ -0,0 +1,182 @@ +--[[submenuData = { + type = "submenu", + name = "Submenu Title", -- or string id or function returning a string + icon = "path/to/my/icon.dds", -- or function returning a string (optional) + iconTextureCoords = {left, right, top, bottom}, -- or function returning a table (optional) + tooltip = "My submenu tooltip", -- or string id or function returning a string (optional) + controls = {sliderData, buttonData} -- used by LAM (optional) + disabled = function() return db.someBooleanSetting end, -- or boolean (optional) + disabledLabel = function() return db.someBooleanSetting end, -- or boolean (optional) + reference = "MyAddonSubmenu" -- unique global reference to control (optional) +} ]] + +local widgetVersion = 13 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("submenu", widgetVersion) then return end + +local wm = WINDOW_MANAGER +local am = ANIMATION_MANAGER +local ICON_SIZE = 32 + +local GetDefaultValue = LAM.util.GetDefaultValue +local GetColorForState = LAM.util.GetColorForState + +local function UpdateDisabled(control) + local disable = GetDefaultValue(control.data.disabled) + if disable ~= control.disabled then + local color = GetColorForState(disable) + if disable and control.open then + control.open = false + control.animation:PlayFromStart() + end + + control.arrow:SetColor(color:UnpackRGBA()) + control.disabled = disable + end + + local disableLabel = control.disabled or GetDefaultValue(control.data.disabledLabel) + if disableLabel ~= control.disabledLabel then + local color = GetColorForState(disableLabel) + control.label:SetColor(color:UnpackRGBA()) + if(control.icon) then + control.icon:SetDesaturation(disableLabel and 1 or 0) + end + control.disabledLabel = disableLabel + end +end + +local function UpdateValue(control) + control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) + + if control.icon then + control.icon:SetTexture(GetDefaultValue(control.data.icon)) + if(control.data.iconTextureCoords) then + local coords = GetDefaultValue(control.data.iconTextureCoords) + control.icon:SetTextureCoords(unpack(coords)) + end + end + + if control.data.tooltip then + control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) + end +end + +local function AnimateSubmenu(clicked) + local control = clicked:GetParent() + if control.disabled then return end + + control.open = not control.open + if control.open then + control.animation:PlayFromStart() + else + control.animation:PlayFromEnd() + end +end + +function LAMCreateControl.submenu(parent, submenuData, controlName) + local width = parent:GetWidth() - 45 + local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL) + control.panel = parent + control.data = submenuData + + control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") + local label = control.label + label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) + label:SetText(LAM.util.GetStringFromValue(submenuData.name)) + label:SetMouseEnabled(true) + + if submenuData.icon then + control.icon = wm:CreateControl(nil, control, CT_TEXTURE) + local icon = control.icon + icon:SetTexture(GetDefaultValue(submenuData.icon)) + if(submenuData.iconTextureCoords) then + local coords = GetDefaultValue(submenuData.iconTextureCoords) + icon:SetTextureCoords(unpack(coords)) + end + icon:SetDimensions(ICON_SIZE, ICON_SIZE) + icon:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + icon:SetMouseEnabled(true) + icon:SetDrawLayer(DL_CONTROLS) + label:SetAnchor(TOP, control, TOP, 0, 5, ANCHOR_CONSTRAINS_Y) + label:SetAnchor(LEFT, icon, RIGHT, 10, 0, ANCHOR_CONSTRAINS_X) + label:SetDimensions(width - ICON_SIZE - 5, 30) + else + label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) + label:SetDimensions(width, 30) + end + + if submenuData.tooltip then + label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} + label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + if control.icon then + control.icon.data = label.data + control.icon:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + control.icon:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end + end + + control.scroll = wm:CreateControl(nil, control, CT_SCROLL) + local scroll = control.scroll + scroll:SetParent(control) + scroll:SetAnchor(TOPLEFT, control.icon or label, BOTTOMLEFT, 0, 10) + scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) + + control.bg = wm:CreateControl(nil, control.icon or label, CT_BACKDROP) + local bg = control.bg + bg:SetAnchor(TOPLEFT, control.icon or label, TOPLEFT, -5, -5) + bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) + bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) + bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") + bg:SetInsets(16, 16, -16, -16) + bg:SetDrawLayer(DL_BACKGROUND) + + control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) + local arrow = control.arrow + arrow:SetDimensions(28, 28) + arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way + arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5) + + --figure out the cool animation later... + control.animation = am:CreateTimeline() + local animation = control.animation + animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count + + control:SetResizeToFitDescendents(true) + control.open = false + label:SetHandler("OnMouseUp", AnimateSubmenu) + if(control.icon) then + control.icon:SetHandler("OnMouseUp", AnimateSubmenu) + end + animation:SetHandler("OnStop", function(self, completedPlaying) + scroll:SetResizeToFitDescendents(control.open) + if control.open then + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds") + scroll:SetResizeToFitPadding(5, 20) + else + control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") + scroll:SetResizeToFitPadding(5, 0) + scroll:SetHeight(0) + end + end) + + --small strip at the bottom of the submenu that you can click to close it + control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE) + local btmToggle = control.btmToggle + btmToggle:SetMouseEnabled(true) + btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT) + btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT) + btmToggle:SetHeight(15) + btmToggle:SetAlpha(0) + btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) + + control.UpdateValue = UpdateValue + if submenuData.disabled ~= nil or submenuData.disabledLabel ~= nil then + control.UpdateDisabled = UpdateDisabled + control:UpdateDisabled() + end + + LAM.util.RegisterForRefreshIfNeeded(control) + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/texture.lua b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/texture.lua new file mode 100644 index 0000000..6862ac2 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibAddonMenu-2.0/controls/texture.lua @@ -0,0 +1,45 @@ +--[[textureData = { + type = "texture", + image = "file/path.dds", + imageWidth = 64, -- max of 250 for half width, 510 for full + imageHeight = 32, -- max of 100 + tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) + width = "full", -- or "half" (optional) + reference = "MyAddonTexture" -- unique global reference to control (optional) +} ]] + +-- TODO: add texture coords support? + +local widgetVersion = 9 +local LAM = LibStub("LibAddonMenu-2.0") +if not LAM:RegisterWidget("texture", widgetVersion) then return end + +local wm = WINDOW_MANAGER + +local MIN_HEIGHT = 26 +function LAMCreateControl.texture(parent, textureData, controlName) + local control = LAM.util.CreateBaseControl(parent, textureData, controlName) + local width = control:GetWidth() + control:SetResizeToFitDescendents(true) + + if control.isHalfWidth then --note these restrictions + control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) + else + control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) + end + + control.texture = wm:CreateControl(nil, control, CT_TEXTURE) + local texture = control.texture + texture:SetAnchor(CENTER) + texture:SetDimensions(textureData.imageWidth, textureData.imageHeight) + texture:SetTexture(textureData.image) + + if textureData.tooltip then + texture:SetMouseEnabled(true) + texture.data = {tooltipText = LAM.util.GetStringFromValue(textureData.tooltip)} + texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) + texture:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) + end + + return control +end diff --git a/Elder Scrolls Online Addons/ShowMount/LibStub/LibStub.lua b/Elder Scrolls Online Addons/ShowMount/LibStub/LibStub.lua new file mode 100644 index 0000000..e6b8997 --- /dev/null +++ b/Elder Scrolls Online Addons/ShowMount/LibStub/LibStub.lua @@ -0,0 +1,38 @@ +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info +-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +-- LibStub developed for World of Warcraft by above members of the WowAce community. +-- Ported to Elder Scrolls Online by Seerah + +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 5 +local LibStub = _G[LIBSTUB_MAJOR] + +local strformat = string.format +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + if type(minor) ~= "number" then + minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.") + end + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(strformat("Cannot find a library instance of %q.", tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end + +LibStub.SILENT = true \ No newline at end of file diff --git a/ShowMount/Settings.lua b/Elder Scrolls Online Addons/ShowMount/Settings.lua similarity index 86% rename from ShowMount/Settings.lua rename to Elder Scrolls Online Addons/ShowMount/Settings.lua index 75d2405..d3b79c0 100644 --- a/ShowMount/Settings.lua +++ b/Elder Scrolls Online Addons/ShowMount/Settings.lua @@ -9,7 +9,6 @@ function ShowMount.LoadSettings() author = ShowMount.Colorize(ShowMount.author), slashCommand = "/sm", registerForRefresh = true, - -- registerForDefaults = true, } LAM:RegisterAddonPanel(ShowMount.menuName, panelData) @@ -54,6 +53,8 @@ function ShowMount.LoadSettings() ShowMount.SetMount("One", mount_id) end, width = "half", + scrollable = true, + sort = ShowMount.savedVariables.SortByName, }) table.insert(optionsTable, { @@ -74,6 +75,8 @@ function ShowMount.LoadSettings() ShowMount.SetMount("Two", mount_id) end, width = "half", + scrollable = true, + sort = ShowMount.savedVariables.SortByName, }) table.insert(optionsTable, { @@ -94,6 +97,8 @@ function ShowMount.LoadSettings() ShowMount.SetMount("Three", mount_id) end, width = "half", + scrollable = true, + sort = ShowMount.savedVariables.SortByName, }) table.insert(optionsTable, { @@ -114,6 +119,8 @@ function ShowMount.LoadSettings() ShowMount.SetMount("Four", mount_id) end, width = "half", + scrollable = true, + sort = ShowMount.savedVariables.SortByName, }) -- Other options category. -- @@ -133,6 +140,22 @@ function ShowMount.LoadSettings() width = "full", }) + table.insert(optionsTable, { + type = "checkbox", + name = "Sort mounts by name.", + tooltip = "A to Z.", + getFunc = function() return ShowMount.savedVariables.SortByName end, + setFunc = function(v) + if v then + ShowMount.savedVariables.SortByName = "name-up" + else + ShowMount.savedVariables.SortByName = nil + end + end, + width = "full", + requiresReload = true, + }) + table.insert(optionsTable, { type = "button", name = "Reset All Mounts", diff --git a/ShowMount/ShowMount.lua b/Elder Scrolls Online Addons/ShowMount/ShowMount.lua similarity index 96% rename from ShowMount/ShowMount.lua rename to Elder Scrolls Online Addons/ShowMount/ShowMount.lua index 3a361dc..d855181 100644 --- a/ShowMount/ShowMount.lua +++ b/Elder Scrolls Online Addons/ShowMount/ShowMount.lua @@ -12,6 +12,7 @@ ShowMount = { MountThree = 0, MountFour = 0, EnableChatCmds = true, + SortByName = false, }, -- Sounds. soundWarn = SOUNDS.QUICKSLOT_USE_EMPTY, -- Maybe SOUNDS.LOCKPICKING_BREAK instead? @@ -42,12 +43,7 @@ function ShowMount.Colorize(text, color) end -- Verbosity. -ShowMount.Instructions = ShowMount.Colorize("Press U", "ffa500") .. " to set an active mount," .. - " \nand then use " .. - ShowMount.Colorize("/qm1", "ffa500") .. - " and " .. - ShowMount.Colorize("/qm2", "ffa500") .. - " \nto set your Main and Secondary mounts." +ShowMount.Instructions = "Type " .. ShowMount.Colorize("/sm", "ffa500") .. " to select your mounts." ShowMount.NoneActive = "A mount must be Set Active first." -- Or EsoStrings[SI_COLLECTIBLEUSAGEBLOCKREASON9] -> "This collectible is not ready yet." ShowMount.CooldownMsg = ShowMount.Colorize("Can't switch mounts that fast.", "ffa500") -- Orange. diff --git a/ShowMount/ShowMount.txt b/Elder Scrolls Online Addons/ShowMount/ShowMount.txt similarity index 98% rename from ShowMount/ShowMount.txt rename to Elder Scrolls Online Addons/ShowMount/ShowMount.txt index 30fde58..b9a8bde 100644 --- a/ShowMount/ShowMount.txt +++ b/Elder Scrolls Online Addons/ShowMount/ShowMount.txt @@ -1,6 +1,6 @@ ## APIVersion: 100026 ## Title: ShowMount -## Version: 1.21 +## Version: 1.23 ## Author: phuein & Sponsored by ShadowOFMen from Tamriel Crown Exchange ## Description: Quickly toggle between two selected mounts with a chat /cmd or hotkey. ## SavedVariables: ShowMountSavedVariables diff --git a/ExtractSubtitles/ExtractSRT_MP4_MKV_AVI.reg b/ExtractSubtitles/ExtractSRT_MP4_MKV_AVI.reg new file mode 100644 index 0000000..113ca57 --- /dev/null +++ b/ExtractSubtitles/ExtractSRT_MP4_MKV_AVI.reg @@ -0,0 +1,10 @@ +Windows Registry Editor Version 5.00 + +[HKEY_CLASSES_ROOT\*\shell\Extract SRT] +@="Extract Subtitles" +"Icon"="\"%SystemRoot%\\System32\\shell32.dll,1\"" +"AppliesTo"="System.FileName: *.mkv OR System.FileName: *.avi OR System.FileName: *.mp4" + +[HKEY_CLASSES_ROOT\*\shell\Extract SRT\command] +@="\"C:\\extractsubs_srt.bat\",\"%L\"" + diff --git a/ExtractSubtitles/extractSubs.reg b/ExtractSubtitles/extractSubs.reg deleted file mode 100644 index 9c2138c..0000000 --- a/ExtractSubtitles/extractSubs.reg +++ /dev/null @@ -1,10 +0,0 @@ -Windows Registry Editor Version 5.00 - -[HKEY_CLASSES_ROOT\*\shell\ExtractSubs] -@="Extract Subtitles" -"Icon"="\"%SystemRoot%\\System32\\shell32.dll,38\"" -"AppliesTo"="System.FileName: *.mkv OR System.FileName: *.avi OR System.FileName: *.mp4" - -[HKEY_CLASSES_ROOT\*\shell\ExtractSubs\command] -@="\"C:\\extractsubs.bat\" \"%1\"" - diff --git a/ExtractSubtitles/extractsubs.bat b/ExtractSubtitles/extractsubs.bat deleted file mode 100644 index ceb5904..0000000 --- a/ExtractSubtitles/extractsubs.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo OFF -ffmpeg -i "%~1" -map 0:m:language:eng "%~n1.eng.srt" diff --git a/ExtractSubtitles/extractsubs_srt.bat b/ExtractSubtitles/extractsubs_srt.bat new file mode 100644 index 0000000..48e87bb --- /dev/null +++ b/ExtractSubtitles/extractsubs_srt.bat @@ -0,0 +1,12 @@ +@echo OFF +REM ffmpeg -i "%~1" -map 0:m:language:eng "%~n1.eng.srt" +REM ffmpeg -i "%~1" "%~n1.eng.srt" + +:LOOP +if "%~1"=="" goto :END + ffmpeg -i "%~1" -map 0:m:language:eng "%~n1.eng.srt" + shift + goto :LOOP +:END + +if %errorlevel% neq 0 pause diff --git a/2gif.bat b/File Converters/2gif.bat similarity index 100% rename from 2gif.bat rename to File Converters/2gif.bat diff --git a/mkv2mp4.bat b/File Converters/mkv2mp4.bat similarity index 97% rename from mkv2mp4.bat rename to File Converters/mkv2mp4.bat index d04fbed..00a65b3 100644 --- a/mkv2mp4.bat +++ b/File Converters/mkv2mp4.bat @@ -1,4 +1,4 @@ -@echo OFF -CD /D %~dp1 -ffmpeg -i %~nx1 -vf subtitles=%~nx1:si=0 -c:v libx264 -c:a copy -map 0:v -map 0:a:0 %~n1.mp4 +@echo OFF +CD /D %~dp1 +ffmpeg -i %~nx1 -vf subtitles=%~nx1:si=0 -c:v libx264 -c:a copy -map 0:v -map 0:a:0 %~n1.mp4 pause \ No newline at end of file diff --git a/Geoffrey/geoffrey.ico b/Geoffrey/geoffrey.ico new file mode 100644 index 0000000..13b46ab Binary files /dev/null and b/Geoffrey/geoffrey.ico differ diff --git a/Geoffrey/geoffrey.py b/Geoffrey/geoffrey.py new file mode 100644 index 0000000..144d40c --- /dev/null +++ b/Geoffrey/geoffrey.py @@ -0,0 +1,92 @@ +""" +Geoffrey - A very simple Discord server link remover for public channels. + +This bot expects an environment variable named DISCORD_TOKEN with your Discord user full-access token. + +--- + +IF the bot stops responding without any error, reinvite it to your server: + + https://discord.com/developers/applications + +Create an executable to run on Windows startup: + + pyinstaller --onefile --noconsole --icon=geoffrey.ico geoffrey.py + +More useful information: + + Module: https://github.com/Rapptz/discord.py + Guide: https://discordjs.guide/preparations/adding-your-bot-to-servers.html#bot-invite-links + Bot permissions: https://discord.com/developers/docs/topics/permissions +""" + +import logging, sys, os +import discord + +DISCORD_TOKEN = os.getenv('DISCORD_TOKEN') + +logging.basicConfig( + handlers=[ + logging.FileHandler('geoffrey.log', mode='w'), + logging.StreamHandler(sys.stdout) + ], + encoding='utf-8', + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%m/%d/%Y %I:%M:%S %p' +) + +logger = logging.getLogger(__name__) + +invite_links = [ + 'discord.gg/', + 'discordapp.com/invite/', + 'discord.me/server/join/', + 'discord.com/invite/' +] + +allowed_links = [] + +# Lower case for string matching, even though invites are case sensitive. +invite_links = [x.lower() for x in invite_links] +allowed_links = [x.lower() for x in allowed_links] + + +class MyClient(discord.Client): + async def on_ready(self): + logger.info(f'Logged on as {self.user}!') + + async def on_message(self, message): + words = message.content.lower().split() + + for word in words: + if any(link in word for link in allowed_links): + logger.info('Detected safe link:') + logger.info(message.author) + logger.info(message.created_at.astimezone().strftime('%Y-%m-%d %H:%M:%S')) + logger.info(message.content) + logger.info('Did nothing.') + continue + + if any(link in word for link in invite_links): + await message.delete() + + logger.warning('Detected invite link:') + logger.warning(message.author) + logger.warning(message.created_at.astimezone().strftime('%Y-%m-%d %H:%M:%S')) + logger.warning(message.content) + logger.warning('Deleted!') + + +intents = discord.Intents.default() +intents.message_content = True + +if __name__ == '__main__': + client = MyClient(intents=intents) + + if not DISCORD_TOKEN: + error_msg = 'Environment variable DISCORD_TOKEN is not defined! Quitting...' + logger.error(error_msg) + sys.exit(error_msg) + + client.run(DISCORD_TOKEN) diff --git a/Junkee2018/Junkee.lua b/Junkee2018/Junkee.lua deleted file mode 100644 index 0c9575f..0000000 --- a/Junkee2018/Junkee.lua +++ /dev/null @@ -1,326 +0,0 @@ -Junkee = Junkee or {} -Junkee.__index = Junkee -Junkee.name = "Junkee2018" - -local LAM = LibStub("LibAddonMenu-2.0") - -local em = EVENT_MANAGER - -local INVENTORIES_TO_HOOK = {INVENTORY_BACKPACK, INVENTORY_BANK} - -Junkee.slotControl = nil -- Reference for misc' properties. -Junkee.bagId = nil -Junkee.slotId = nil -Junkee.isJunk = false - --- Defaults. -Junkee.savedVars = { - visible = true, -- All items visible. - DestroyVisible = true, - LinkVisible = true, - LockVisible = true, - firstRun = true, - -- Each command name will have "/" prepended to it automatically. - slashCmds = { - GroupLeave = { - cmd = "/gl", - active = false, - f = function() - if IsUnitGrouped("player") then - GroupLeave() - end - end - }, - GroupDisband = { - cmd = "/gd", - active = false, - f = function() - if IsUnitGrouped("player") and IsUnitGroupLeader("player") then - GroupDisband() - end - end - }, - } -} - -Junkee.OnMouseEnter = function(control) - Junkee.slotControl = control - Junkee.bagId = control.dataEntry.data.bagId - Junkee.slotId = control.dataEntry.data.slotIndex - Junkee.isJunk = control.dataEntry.data.isJunk - if Junkee.savedVars.visible then - Junkee.AddJunkAction() - end -end - -Junkee.OnMouseExit = function(control) - Junkee.slotControl = nil - Junkee.bagId = nil - Junkee.slotId = nil - Junkee.isJunk = false - if Junkee.savedVars.visible then - Junkee.RemoveJunkAction() - end -end - -local function registerHook(inventory) - local listView = inventory.listView - if listView and listView.dataTypes and listView.dataTypes[1] then - local originalCallback = listView.dataTypes[1].setupCallback - listView.dataTypes[1].setupCallback = function(rowControl, slot) - originalCallback(rowControl, slot) - ZO_PreHookHandler(rowControl, "OnMouseEnter", Junkee.OnMouseEnter) - ZO_PreHookHandler(rowControl, "OnMouseExit", Junkee.OnMouseExit) - end - end -end - -local function registerHooks() - for _, index in pairs(INVENTORIES_TO_HOOK) do - registerHook(PLAYER_INVENTORY.inventories[index]) - end -end - --- Add menu with options. -local panelData = { - type = "panel", - name = "Junkee 2018", - displayName = "Junkee Settings", - registerForRefresh = true, - registerForDefaults = true, -} - -local optionsTable = { - [1] = { - type = "checkbox", - name = "Display Keybindings", - tooltip = "Display the addon's keybindings when opening the Inventory. " .. - "They appear on the bottom left.", - getFunc = function() return Junkee.savedVars.visible end, - setFunc = function(v) Junkee.savedVars.visible = v end, - width = "full", --or "half", - }, - [2] = { - type = "checkbox", - name = "Display the Destroy Keybinding", - tooltip = "Display the addon's keybinding for Destroy when opening the Inventory.", - getFunc = function() - return Junkee.savedVars.visible and Junkee.savedVars.DestroyVisible - end, - setFunc = function(v) Junkee.savedVars.DestroyVisible = v end, - width = "full", --or "half", - }, - [3] = { - type = "checkbox", - name = "Display the Link Keybinding", - tooltip = "Display the addon's keybinding for Link when opening the Inventory.", - getFunc = function() - return Junkee.savedVars.visible and Junkee.savedVars.LinkVisible - end, - setFunc = function(v) Junkee.savedVars.LinkVisible = v end, - width = "full", --or "half", - }, - [4] = { - type = "checkbox", - name = "Display the Lock Keybinding", - tooltip = "Display the addon's keybinding for Lock when opening the Inventory.", - getFunc = function() - return Junkee.savedVars.visible and Junkee.savedVars.LockVisible - end, - setFunc = function(v) Junkee.savedVars.LockVisible = v end, - width = "full", --or "half", - }, - [5] = { - type = "checkbox", - name = Junkee.savedVars.slashCmds["GroupLeave"].cmd, - tooltip = "Chat command to leave your group.", - getFunc = function() - return Junkee.savedVars.slashCmds["GroupLeave"].active - end, - setFunc = function(v) - local cmd = Junkee.savedVars.slashCmds["GroupLeave"].cmd - - Junkee.savedVars.slashCmds["GroupLeave"].active = v - if v then - SLASH_COMMANDS[cmd] = Junkee.savedVars.slashCmds["GroupLeave"].f - else - SLASH_COMMANDS[cmd] = nil - end - -- Reset autocomplete cache to update it. - SLASH_COMMAND_AUTO_COMPLETE:InvalidateSlashCommandCache() - end, - width = "full", --or "half", - }, - [6] = { - type = "checkbox", - name = Junkee.savedVars.slashCmds["GroupDisband"].cmd, - tooltip = "Chat command to disband your group.", - getFunc = function() - return Junkee.savedVars.slashCmds["GroupDisband"].active - end, - setFunc = function(v) - local cmd = Junkee.savedVars.slashCmds["GroupDisband"].cmd - - Junkee.savedVars.slashCmds["GroupDisband"].active = v - if v then - SLASH_COMMANDS[cmd] = Junkee.savedVars.slashCmds["GroupDisband"].f - else - SLASH_COMMANDS[cmd] = nil - end - -- Reset autocomplete cache to update it. - SLASH_COMMAND_AUTO_COMPLETE:InvalidateSlashCommandCache() - end, - width = "full", --or "half", - }, -} - -local function LoadMenu() - LAM:RegisterAddonPanel("Junkee 2018", panelData) - LAM:RegisterOptionControls("Junkee 2018", optionsTable) -end - -Junkee.Loaded = function(eventCode, addonName) - if (Junkee.name == addonName) then - em:UnregisterForEvent(Junkee.name, EVENT_ADD_ON_LOADED) - - registerHooks() - - -- Load saved variables. - Junkee.savedVars = ZO_SavedVars:New("JunkeeAddonSavedVars", 2, nil, Junkee.savedVars) - - -- Settings menu. - LoadMenu() - - -- Chat /slash commands. - local newCmds = false - for name, item in pairs(Junkee.savedVars.slashCmds) do - if item.active then - newCmds = true - SLASH_COMMANDS[item.cmd] = item.f - end - end - -- Reset autocomplete cache to update it. - if newCmds then - SLASH_COMMAND_AUTO_COMPLETE:InvalidateSlashCommandCache() - end - end -end -em:RegisterForEvent(Junkee.name, EVENT_ADD_ON_LOADED, Junkee.Loaded) - -Junkee.JunkIt = function() - if Junkee.bagId == nil then return end - local isJunk = IsItemJunk(Junkee.bagId, Junkee.slotId) - SetItemIsJunk(Junkee.bagId, Junkee.slotId, not isJunk) - if isJunk then - PlaySound(SOUNDS.INVENTORY_ITEM_UNJUNKED) - else - PlaySound(SOUNDS.INVENTORY_ITEM_JUNKED) - end -end - -Junkee.DeleteIt = function() - if Junkee.bagId == nil then return end - DestroyItem(Junkee.bagId, Junkee.slotId) -end - -local function createJunkStripDescriptor(name) - return JunkeeKeyStrip:New(name, "JUNKEE_JUNK_IT", Junkee.JunkIt) -end - -local junkStripDescriptor = createJunkStripDescriptor(Junkee.tr("JunkLabel")) -local unjunkStripDescriptor = createJunkStripDescriptor(Junkee.tr("UnjunkLabel")) -local deleteStripDescriptor = JunkeeKeyStrip:New(Junkee.tr("DeleteLabel"), "JUNKEE_DELETE_IT", Junkee.DeleteIt) -local linkStripDescriptor = JunkeeKeyStrip:New(Junkee.tr("LinkLabel"), "JUNKEE_LINK_IT", Junkee.LinkIt) -local lockStripDescriptor = JunkeeKeyStrip:New(Junkee.tr("LockLabel"), "JUNKEE_LOCK_IT", Junkee.LockIt) - -Junkee.AddJunkAction = function() - if (Junkee.isJunk) then - junkStripDescriptor:Remove() - unjunkStripDescriptor:Add(true) - else - unjunkStripDescriptor:Remove() - junkStripDescriptor:Add(true) - end - - if Junkee.savedVars.DestroyVisible then deleteStripDescriptor:Add(true) end - if Junkee.savedVars.LinkVisible then linkStripDescriptor:Add(true) end - if Junkee.savedVars.LockVisible then lockStripDescriptor:Add(true) end -end - -Junkee.RemoveJunkAction = function() - unjunkStripDescriptor:Remove() - junkStripDescriptor:Remove() - - deleteStripDescriptor:Remove() - linkStripDescriptor:Remove() - lockStripDescriptor:Remove() -end - --- Link item in chat. -Junkee.LinkIt = function() - if Junkee.bagId == nil then return end - - local link = GetItemLink(Junkee.bagId, Junkee.slotId, 1) - ZO_LinkHandler_InsertLink(link) -end - --- Un/Lock item. -Junkee.LockIt = function() - if Junkee.bagId == nil then return end - - local bag, index = Junkee.bagId, Junkee.slotId - local locking = not IsItemPlayerLocked(bag, index) -- The locking state to apply. - if CanItemBePlayerLocked(bag, index) then - SetItemIsPlayerLocked(bag, index, locking) - PlaySound(not locking and SOUNDS.INVENTORY_ITEM_LOCKED or SOUNDS.INVENTORY_ITEM_UNLOCKED) - end - - -- Below is taken from the game code for locking. - -- IsItemAlreadySlottedToCraft() errors, - -- so until that's solved I use the above code. Reference: - -- http://www.esoui.com/forums/showthread.php?p=34500 - - -- local inventorySlot = Junkee.slotControl - -- local bag, index = Junkee.bagId, Junkee.slotId -- ZO_Inventory_GetBagAndIndex(inventorySlot) - -- local locking = not IsItemPlayerLocked(bag, index) -- The locking state to apply. - -- local action - - -- if locking then - -- action = SI_ITEM_ACTION_MARK_AS_LOCKED - -- -- Can't lock these. - -- if IsItemAlreadySlottedToCraft(inventorySlot) then return end - -- else - -- action = SI_ITEM_ACTION_UNMARK_AS_LOCKED - -- end - - -- if CanItemBePlayerLocked(bag, index) and - -- not QUICKSLOT_WINDOW:AreQuickSlotsShowing() then - -- slotActions:AddSlotAction(action, - -- function() MarkAsPlayerLockedHelper(bag, index, locking) end, - -- "secondary") - -- end -end - --- Needed to bind CTRL/Shift+KEY. -function KEYBINDING_MANAGER:IsChordingAlwaysEnabled() - return true -end - -ZO_CreateStringId("SI_BINDING_NAME_JUNKEE_JUNK_IT", Junkee.tr("JunkBindingName")) -ZO_CreateStringId("SI_BINDING_NAME_JUNKEE_DELETE_IT", Junkee.tr("DeleteBindingName")) -ZO_CreateStringId("SI_BINDING_NAME_JUNKEE_LINK_IT", Junkee.tr("LinkBindingName")) -ZO_CreateStringId("SI_BINDING_NAME_JUNKEE_LOCK_IT", Junkee.tr("LockBindingName")) - --- Act when everything is ready, for sure, --- because player has acted. -local function OnActivated(eventCode, initial) - em:UnregisterForEvent(addonName, eventCode) - - if Junkee.savedVars.firstRun then - Junkee.savedVars.firstRun = false - -- Do on first run of addon. - d("Junkee recommends these keybindings:\n" .. - "Junk/UnJunk = Z, Destroy = Shift+Z, Link = F2, Lock = Tab.") - end -end -em:RegisterForEvent(Junkee.name, EVENT_PLAYER_ACTIVATED, OnActivated) \ No newline at end of file diff --git a/Junkee2018/LibAddonMenu-2.0/controls/checkbox.lua b/Junkee2018/LibAddonMenu-2.0/controls/checkbox.lua deleted file mode 100644 index 84710de..0000000 --- a/Junkee2018/LibAddonMenu-2.0/controls/checkbox.lua +++ /dev/null @@ -1,142 +0,0 @@ ---[[checkboxData = { - type = "checkbox", - name = "My Checkbox", -- or string id or function returning a string - getFunc = function() return db.var end, - setFunc = function(value) db.var = value doStuff() end, - tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) - width = "full", -- or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- a boolean or function that returns a boolean (optional) - reference = "MyAddonCheckbox", -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 14 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("checkbox", widgetVersion) then return end - -local wm = WINDOW_MANAGER - ---label -local enabledColor = ZO_DEFAULT_ENABLED_COLOR -local enabledHLcolor = ZO_HIGHLIGHT_TEXT -local disabledColor = ZO_DEFAULT_DISABLED_COLOR -local disabledHLcolor = ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR ---checkbox -local checkboxColor = ZO_NORMAL_TEXT -local checkboxHLcolor = ZO_HIGHLIGHT_TEXT - - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA()) - control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA()) - --control:SetMouseEnabled(not disable) - --control:SetMouseEnabled(true) - - control.isDisabled = disable -end - -local function ToggleCheckbox(control) - if control.value then - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.checkbox:SetText(control.checkedText) - else - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.checkbox:SetText(control.uncheckedText) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - elseif value ~= nil then --our value could be false - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - end - control.value = value - - ToggleCheckbox(control) -end - -local function OnMouseEnter(control) - ZO_Options_OnMouseEnter(control) - - if control.isDisabled then return end - - local label = control.label - if control.value then - label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) - else - label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) - end - control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) -end - -local function OnMouseExit(control) - ZO_Options_OnMouseExit(control) - - if control.isDisabled then return end - - local label = control.label - if control.value then - label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - else - label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - end - control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) -end - ---controlName is optional -function LAMCreateControl.checkbox(parent, checkboxData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, checkboxData, controlName) - control:SetHandler("OnMouseEnter", OnMouseEnter) - control:SetHandler("OnMouseExit", OnMouseExit) - control:SetHandler("OnMouseUp", function(control) - if control.isDisabled then return end - PlaySound(SOUNDS.DEFAULT_CLICK) - control.value = not control.value - control:UpdateValue(false, control.value) - end) - - control.checkbox = wm:CreateControl(nil, control.container, CT_LABEL) - local checkbox = control.checkbox - checkbox:SetAnchor(LEFT, control.container, LEFT, 0, 0) - checkbox:SetFont("ZoFontGameBold") - checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) - control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper() - control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper() - - if checkboxData.warning ~= nil or checkboxData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip) - - control.UpdateValue = UpdateValue - control:UpdateValue() - if checkboxData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/Junkee2018/LibAddonMenu-2.0/controls/custom.lua b/Junkee2018/LibAddonMenu-2.0/controls/custom.lua deleted file mode 100644 index 5d6111c..0000000 --- a/Junkee2018/LibAddonMenu-2.0/controls/custom.lua +++ /dev/null @@ -1,35 +0,0 @@ ---[[customData = { - type = "custom", - reference = "MyAddonCustomControl", --(optional) unique name for your control to use as reference - refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh - width = "full", --or "half" (optional) -} ]] - -local widgetVersion = 7 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("custom", widgetVersion) then return end - -local function UpdateValue(control) - if control.data.refreshFunc then - control.data.refreshFunc(control) - end -end - -local MIN_HEIGHT = 26 -function LAMCreateControl.custom(parent, customData, controlName) - local control = LAM.util.CreateBaseControl(parent, customData, controlName) - local width = control:GetWidth() - control:SetResizeToFitDescendents(true) - - if control.isHalfWidth then --note these restrictions - control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) - else - control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) - end - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control -end diff --git a/Junkee2018/LibAddonMenu-2.0/controls/divider.lua b/Junkee2018/LibAddonMenu-2.0/controls/divider.lua deleted file mode 100644 index b24e2fc..0000000 --- a/Junkee2018/LibAddonMenu-2.0/controls/divider.lua +++ /dev/null @@ -1,45 +0,0 @@ ---[[dividerData = { - type = "divider", - width = "full", --or "half" (optional) - height = 10, (optional) - alpha = 0.25, (optional) - reference = "MyAddonDivider" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 2 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("divider", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local MIN_HEIGHT = 10 -local MAX_HEIGHT = 50 -local MIN_ALPHA = 0 -local MAX_ALPHA = 1 -local DEFAULT_ALPHA = 0.25 - -local function GetValueInRange(value, min, max, default) - if not value or type(value) ~= "number" then - return default - end - return math.min(math.max(min, value), max) -end - -function LAMCreateControl.divider(parent, dividerData, controlName) - local control = LAM.util.CreateBaseControl(parent, dividerData, controlName) - local isHalfWidth = control.isHalfWidth - local width = control:GetWidth() - local height = GetValueInRange(dividerData.height, MIN_HEIGHT, MAX_HEIGHT, MIN_HEIGHT) - local alpha = GetValueInRange(dividerData.alpha, MIN_ALPHA, MAX_ALPHA, DEFAULT_ALPHA) - - control:SetDimensions(isHalfWidth and width / 2 or width, height) - - control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") - local divider = control.divider - divider:SetWidth(isHalfWidth and width / 2 or width) - divider:SetAnchor(TOPLEFT) - divider:SetAlpha(alpha) - - return control -end diff --git a/Junkee2018/LibAddonMenu-2.0/controls/editbox.lua b/Junkee2018/LibAddonMenu-2.0/controls/editbox.lua deleted file mode 100644 index bcc6a7c..0000000 --- a/Junkee2018/LibAddonMenu-2.0/controls/editbox.lua +++ /dev/null @@ -1,156 +0,0 @@ ---[[editboxData = { - type = "editbox", - name = "My Editbox", -- or string id or function returning a string - getFunc = function() return db.text end, - setFunc = function(text) db.text = text doStuff() end, - tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) - isMultiline = true, --boolean (optional) - isExtraWide = true, --boolean (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.text, -- default value or function that returns the default value (optional) - reference = "MyAddonEditbox" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 14 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("editbox", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.editbox:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end - --control.editbox:SetEditEnabled(not disable) - control.editbox:SetMouseEnabled(not disable) -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - control.editbox:SetText(value) - elseif value then - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - control.editbox:SetText(value) - end -end - -local MIN_HEIGHT = 24 -local HALF_WIDTH_LINE_SPACING = 2 -function LAMCreateControl.editbox(parent, editboxData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, editboxData, controlName) - - local container = control.container - control.bg = wm:CreateControlFromVirtual(nil, container, "ZO_EditBackdrop") - local bg = control.bg - bg:SetAnchorFill() - - if editboxData.isMultiline then - control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditMultiLineForBackdrop") - control.editbox:SetHandler("OnMouseWheel", function(self, delta) - if self:HasFocus() then --only set focus to new spots if the editbox is currently in use - local cursorPos = self:GetCursorPosition() - local text = self:GetText() - local textLen = text:len() - local newPos - if delta > 0 then --scrolling up - local reverseText = text:reverse() - local revCursorPos = textLen - cursorPos - local revPos = reverseText:find("\n", revCursorPos+1) - newPos = revPos and textLen - revPos - else --scrolling down - newPos = text:find("\n", cursorPos+1) - end - if newPos then --if we found a new line, then scroll, otherwise don't - self:SetCursorPosition(newPos) - end - end - end) - else - control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop") - end - local editbox = control.editbox - editbox:SetText(editboxData.getFunc()) - editbox:SetMaxInputChars(3000) - editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end) - editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end) - editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - - local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0 - - control.label:ClearAnchors() - container:ClearAnchors() - - control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) - container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) - - if control.isHalfWidth then - container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) - end - - if editboxData.isExtraWide then - container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0) - else - container:SetWidth(MIN_WIDTH * 3.2) - end - - if editboxData.isMultiline then - container:SetHeight(MIN_HEIGHT * 3) - else - container:SetHeight(MIN_HEIGHT) - end - - if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then - control:SetHeight(container:GetHeight()) - else - control:SetHeight(container:GetHeight() + control.label:GetHeight()) - end - - editbox:ClearAnchors() - editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2) - editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2) - - if editboxData.warning ~= nil or editboxData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - if editboxData.isExtraWide then - control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0) - else - control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0) - end - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateValue = UpdateValue - control:UpdateValue() - if editboxData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/Junkee2018/LibAddonMenu-2.0/controls/header.lua b/Junkee2018/LibAddonMenu-2.0/controls/header.lua deleted file mode 100644 index 3290c89..0000000 --- a/Junkee2018/LibAddonMenu-2.0/controls/header.lua +++ /dev/null @@ -1,42 +0,0 @@ ---[[headerData = { - type = "header", - name = "My Header", -- or string id or function returning a string - width = "full", --or "half" (optional) - reference = "MyAddonHeader" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 8 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("header", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateValue(control) - control.header:SetText(LAM.util.GetStringFromValue(control.data.name)) -end - -local MIN_HEIGHT = 30 -function LAMCreateControl.header(parent, headerData, controlName) - local control = LAM.util.CreateBaseControl(parent, headerData, controlName) - local isHalfWidth = control.isHalfWidth - local width = control:GetWidth() - control:SetDimensions(isHalfWidth and width / 2 or width, MIN_HEIGHT) - - control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") - local divider = control.divider - divider:SetWidth(isHalfWidth and width / 2 or width) - divider:SetAnchor(TOPLEFT) - - control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") - local header = control.header - header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT) - header:SetAnchor(BOTTOMRIGHT) - header:SetText(LAM.util.GetStringFromValue(headerData.name)) - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control -end diff --git a/Junkee2018/LibAddonMenu-2.0/controls/iconpicker.lua b/Junkee2018/LibAddonMenu-2.0/controls/iconpicker.lua deleted file mode 100644 index 3485740..0000000 --- a/Junkee2018/LibAddonMenu-2.0/controls/iconpicker.lua +++ /dev/null @@ -1,436 +0,0 @@ ---[[iconpickerData = { - type = "iconpicker", - name = "My Icon Picker", -- or string id or function returning a string - choices = {"texture path 1", "texture path 2", "texture path 3"}, - getFunc = function() return db.var end, - setFunc = function(var) db.var = var doStuff() end, - tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) - maxColumns = 5, -- number of icons in one row (optional) - visibleRows = 4.5, -- number of visible rows (optional) - iconSize = 28, -- size of the icons (optional) - defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) - width = "full", --or "half" (optional) - beforeShow = function(control, iconPicker) return preventShow end, --(optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonIconPicker" -- unique global reference to control (optional) -} ]] - -local widgetVersion = 8 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local IconPickerMenu = ZO_Object:Subclass() -local iconPicker -LAM.util.GetIconPickerMenu = function() - if not iconPicker then - iconPicker = IconPickerMenu:New("LAMIconPicker") - local sceneFragment = LAM:GetAddonSettingsFragment() - ZO_PreHook(sceneFragment, "OnHidden", function() - if not iconPicker.control:IsHidden() then - iconPicker:Clear() - end - end) - end - return iconPicker -end - -function IconPickerMenu:New(...) - local object = ZO_Object.New(self) - object:Initialize(...) - return object -end - -function IconPickerMenu:Initialize(name) - local control = wm:CreateTopLevelWindow(name) - control:SetDrawTier(DT_HIGH) - control:SetHidden(true) - self.control = control - - local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer") - -- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count - scrollContainer:SetAnchorFill() - ZO_Scroll_SetUseFadeGradient(scrollContainer, false) - ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false) - ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value - local scroll = GetControl(scrollContainer, "ScrollChild") - self.scroll = scroll - self.scrollContainer = scrollContainer - - local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP) - bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3) - bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5) - bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) - bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") - bg:SetInsets(16, 16, -16, -16) - - local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) - mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") - mungeOverlay:SetDrawLevel(1) - mungeOverlay:SetAddressMode(TEX_MODE_WRAP) - mungeOverlay:SetAnchorFill() - - local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE) - mouseOver:SetDrawLevel(2) - mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds") - mouseOver:SetHidden(true) - - local function IconFactory(pool) - local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE) - icon:SetMouseEnabled(true) - icon:SetDrawLevel(3) - icon:SetHandler("OnMouseEnter", function() - mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0) - mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0) - mouseOver:SetHidden(false) - if self.customOnMouseEnter then - self.customOnMouseEnter(icon) - else - self:OnMouseEnter(icon) - end - end) - icon:SetHandler("OnMouseExit", function() - mouseOver:ClearAnchors() - mouseOver:SetHidden(true) - if self.customOnMouseExit then - self.customOnMouseExit(icon) - else - self:OnMouseExit(icon) - end - end) - icon:SetHandler("OnMouseUp", function(control, ...) - PlaySound("Click") - icon.OnSelect(icon, icon.texture) - self:Clear() - end) - return icon - end - - local function ResetFunction(icon) - icon:ClearAnchors() - end - - self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction) - self:SetMaxColumns(1) - self.icons = {} - self.color = ZO_DEFAULT_ENABLED_COLOR - - EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function() - if self.refCount ~= nil then - local moc = wm:GetMouseOverControl() - if(moc:GetOwningWindow() ~= control) then - self.refCount = self.refCount - 1 - if self.refCount <= 0 then - self:Clear() - end - end - end - end) -end - -function IconPickerMenu:OnMouseEnter(icon) - InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT) - SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip)) - InformationTooltipTopLevel:BringWindowToTop() -end - -function IconPickerMenu:OnMouseExit(icon) - ClearTooltip(InformationTooltip) -end - -function IconPickerMenu:SetMaxColumns(value) - self.maxCols = value ~= nil and value or 5 -end - -local DEFAULT_SIZE = 28 -function IconPickerMenu:SetIconSize(value) - local iconSize = DEFAULT_SIZE - if value ~= nil then iconSize = math.max(iconSize, value) end - self.iconSize = iconSize -end - -function IconPickerMenu:SetVisibleRows(value) - self.visibleRows = value ~= nil and value or 4.5 -end - -function IconPickerMenu:SetMouseHandlers(onEnter, onExit) - self.customOnMouseEnter = onEnter - self.customOnMouseExit = onExit -end - -function IconPickerMenu:UpdateDimensions() - local iconSize = self.iconSize - local width = iconSize * self.maxCols + 20 - local height = iconSize * self.visibleRows - self.control:SetDimensions(width, height) - - local icons = self.icons - for i = 1, #icons do - local icon = icons[i] - icon:SetDimensions(iconSize, iconSize) - end -end - -function IconPickerMenu:UpdateAnchors() - local iconSize = self.iconSize - local col, maxCols = 1, self.maxCols - local previousCol, previousRow - local scroll = self.scroll - local icons = self.icons - - for i = 1, #icons do - local icon = icons[i] - icon:ClearAnchors() - if i == 1 then - icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0) - previousRow = icon - elseif col == 1 then - icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0) - previousRow = icon - else - icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0) - end - previousCol = icon - col = col >= maxCols and 1 or col + 1 - end -end - -function IconPickerMenu:Clear() - self.icons = {} - self.iconPool:ReleaseAllObjects() - self.control:SetHidden(true) - self.color = ZO_DEFAULT_ENABLED_COLOR - self.refCount = nil - self.parent = nil - self.customOnMouseEnter = nil - self.customOnMouseExit = nil -end - -function IconPickerMenu:AddIcon(texturePath, callback, tooltip) - local icon, key = self.iconPool:AcquireObject() - icon:SetTexture(texturePath) - icon:SetColor(self.color:UnpackRGBA()) - icon.texture = texturePath - icon.tooltip = tooltip - icon.OnSelect = callback - self.icons[#self.icons + 1] = icon -end - -function IconPickerMenu:Show(parent) - if #self.icons == 0 then return false end - if not self.control:IsHidden() then self:Clear() return false end - self:UpdateDimensions() - self:UpdateAnchors() - - local control = self.control - control:ClearAnchors() - control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8) - control:SetHidden(false) - control:BringWindowToTop() - self.parent = parent - self.refCount = 2 - - return true -end - -function IconPickerMenu:SetColor(color) - local icons = self.icons - self.color = color - for i = 1, #icons do - local icon = icons[i] - icon:SetColor(color:UnpackRGBA()) - end -end - -------------------------------------------------------------- - -local function UpdateChoices(control, choices, choicesTooltips) - local data = control.data - if not choices then - choices, choicesTooltips = data.choices, data.choicesTooltips or {} - end - local addedChoices = {} - - local iconPicker = LAM.util.GetIconPickerMenu() - iconPicker:Clear() - for i = 1, #choices do - local texture = choices[i] - if not addedChoices[texture] then -- remove duplicates - iconPicker:AddIcon(choices[i], function(self, texture) - control.icon:SetTexture(texture) - data.setFunc(texture) - LAM.util.RequestRefreshIfNeeded(control) - end, LAM.util.GetStringFromValue(choicesTooltips[i])) - addedChoices[texture] = true - end - end -end - -local function IsDisabled(control) - if type(control.data.disabled) == "function" then - return control.data.disabled() - else - return control.data.disabled - end -end - -local function SetColor(control, color) - local icon = control.icon - if IsDisabled(control) then - icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR - icon:SetColor(icon.color:UnpackRGBA()) - end - - local iconPicker = LAM.util.GetIconPickerMenu() - if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then - iconPicker:SetColor(icon.color) - end -end - -local function UpdateDisabled(control) - local disable = IsDisabled(control) - - control.dropdown:SetMouseEnabled(not disable) - control.dropdownButton:SetEnabled(not disable) - - local iconPicker = LAM.util.GetIconPickerMenu() - if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then - iconPicker:Clear() - end - - SetColor(control, control.icon.color) - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - control.icon:SetTexture(value) - elseif value then - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - control.icon:SetTexture(value) - end -end - -local MIN_HEIGHT = 26 -local HALF_WIDTH_LINE_SPACING = 2 -local function SetIconSize(control, size) - local icon = control.icon - icon.size = size - icon:SetDimensions(size, size) - - local height = size + 4 - control.dropdown:SetDimensions(size + 20, height) - height = math.max(height, MIN_HEIGHT) - control.container:SetHeight(height) - if control.lineControl then - control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING) - else - control:SetHeight(height) - end - - local iconPicker = LAM.util.GetIconPickerMenu() - if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then - iconPicker:SetIconSize(size) - iconPicker:UpdateDimensions() - iconPicker:UpdateAnchors() - end -end - -function LAMCreateControl.iconpicker(parent, iconpickerData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName) - - local function ShowIconPicker() - local iconPicker = LAM.util.GetIconPickerMenu() - if iconPicker.parent == control.container then - iconPicker:Clear() - else - iconPicker:SetMaxColumns(iconpickerData.maxColumns) - iconPicker:SetVisibleRows(iconpickerData.visibleRows) - iconPicker:SetIconSize(control.icon.size) - UpdateChoices(control) - iconPicker:SetColor(control.icon.color) - if iconpickerData.beforeShow then - if iconpickerData.beforeShow(control, iconPicker) then - iconPicker:Clear() - return - end - end - iconPicker:Show(control.container) - end - end - - local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE - control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL) - local dropdown = control.dropdown - dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0) - dropdown:SetMouseEnabled(true) - dropdown:SetHandler("OnMouseUp", ShowIconPicker) - dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - - control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE) - local icon = control.icon - icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0) - icon:SetDrawLevel(2) - - local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton") - dropdownButton:SetDimensions(16, 16) - dropdownButton:SetHandler("OnClicked", ShowIconPicker) - dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0) - control.dropdownButton = dropdownButton - - control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP) - local bg = control.bg - bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3) - bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5) - bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16) - bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds") - bg:SetInsets(16, 16, -16, -16) - local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) - mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") - mungeOverlay:SetDrawLevel(1) - mungeOverlay:SetAddressMode(TEX_MODE_WRAP) - mungeOverlay:SetAnchorFill() - - if iconpickerData.warning ~= nil or iconpickerData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateChoices = UpdateChoices - control.UpdateValue = UpdateValue - control:UpdateValue() - control.SetColor = SetColor - control:SetColor() - control.SetIconSize = SetIconSize - control:SetIconSize(iconSize) - - if iconpickerData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/Junkee2018/LibAddonMenu-2.0/controls/texture.lua b/Junkee2018/LibAddonMenu-2.0/controls/texture.lua deleted file mode 100644 index 4604fea..0000000 --- a/Junkee2018/LibAddonMenu-2.0/controls/texture.lua +++ /dev/null @@ -1,45 +0,0 @@ ---[[textureData = { - type = "texture", - image = "file/path.dds", - imageWidth = 64, --max of 250 for half width, 510 for full - imageHeight = 32, --max of 100 - tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonTexture" --(optional) unique global reference to control -} ]] - ---add texture coords support? - -local widgetVersion = 9 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("texture", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local MIN_HEIGHT = 26 -function LAMCreateControl.texture(parent, textureData, controlName) - local control = LAM.util.CreateBaseControl(parent, textureData, controlName) - local width = control:GetWidth() - control:SetResizeToFitDescendents(true) - - if control.isHalfWidth then --note these restrictions - control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) - else - control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) - end - - control.texture = wm:CreateControl(nil, control, CT_TEXTURE) - local texture = control.texture - texture:SetAnchor(CENTER) - texture:SetDimensions(textureData.imageWidth, textureData.imageHeight) - texture:SetTexture(textureData.image) - - if textureData.tooltip then - texture:SetMouseEnabled(true) - texture.data = {tooltipText = LAM.util.GetStringFromValue(textureData.tooltip)} - texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - texture:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - end - - return control -end diff --git a/PvPFPS2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua b/PvPFPS2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua deleted file mode 100644 index 50696f4..0000000 --- a/PvPFPS2018/LibAddonMenu-2.0/LibAddonMenu-2.0.lua +++ /dev/null @@ -1,1226 +0,0 @@ --- LibAddonMenu-2.0 & its files © Ryan Lakanen (Seerah) -- --- Distributed under The Artistic License 2.0 (see LICENSE) -- ------------------------------------------------------------------- - - ---Register LAM with LibStub -local MAJOR, MINOR = "LibAddonMenu-2.0", _LAM2_VERSION_NUMBER or -1 -local lam, oldminor = LibStub:NewLibrary(MAJOR, MINOR) -if not lam then return end --the same or newer version of this lib is already loaded into memory - -local messages = {} -local MESSAGE_PREFIX = "[LAM2] " -local function PrintLater(msg) - if CHAT_SYSTEM.primaryContainer then - d(MESSAGE_PREFIX .. msg) - else - messages[#messages + 1] = msg - end -end - -local function FlushMessages() - for i = 1, #messages do - d(MESSAGE_PREFIX .. messages[i]) - end - messages = {} -end - -if LAMSettingsPanelCreated and not LAMCompatibilityWarning then - PrintLater("An old version of LibAddonMenu with compatibility issues was detected. For more information on how to proceed search for LibAddonMenu on esoui.com") - LAMCompatibilityWarning = true -end - ---UPVALUES-- -local wm = WINDOW_MANAGER -local em = EVENT_MANAGER -local sm = SCENE_MANAGER -local cm = CALLBACK_MANAGER -local tconcat = table.concat -local tinsert = table.insert - -local MIN_HEIGHT = 26 -local HALF_WIDTH_LINE_SPACING = 2 -local OPTIONS_CREATION_RUNNING = 1 -local OPTIONS_CREATED = 2 -local LAM_CONFIRM_DIALOG = "LAM_CONFIRM_DIALOG" -local LAM_DEFAULTS_DIALOG = "LAM_DEFAULTS" -local LAM_RELOAD_DIALOG = "LAM_RELOAD_DIALOG" - -local addonsForList = {} -local addonToOptionsMap = {} -local optionsState = {} -lam.widgets = lam.widgets or {} -local widgets = lam.widgets -lam.util = lam.util or {} -local util = lam.util -lam.controlsForReload = lam.controlsForReload or {} -local controlsForReload = lam.controlsForReload - -local function GetDefaultValue(default) - if type(default) == "function" then - return default() - end - return default -end - -local function GetStringFromValue(value) - if type(value) == "function" then - return value() - elseif type(value) == "number" then - return GetString(value) - end - return value -end - -local function CreateBaseControl(parent, controlData, controlName) - local control = wm:CreateControl(controlName or controlData.reference, parent.scroll or parent, CT_CONTROL) - control.panel = parent.panel or parent -- if this is in a submenu, panel is the submenu's parent - control.data = controlData - - control.isHalfWidth = controlData.width == "half" - local width = 510 -- set default width in case a custom parent object is passed - if control.panel.GetWidth ~= nil then width = control.panel:GetWidth() - 60 end - control:SetWidth(width) - return control -end - -local function CreateLabelAndContainerControl(parent, controlData, controlName) - local control = CreateBaseControl(parent, controlData, controlName) - local width = control:GetWidth() - - local container = wm:CreateControl(nil, control, CT_CONTROL) - container:SetDimensions(width / 3, MIN_HEIGHT) - control.container = container - - local label = wm:CreateControl(nil, control, CT_LABEL) - label:SetFont("ZoFontWinH4") - label:SetHeight(MIN_HEIGHT) - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetText(GetStringFromValue(controlData.name)) - control.label = label - - if control.isHalfWidth then - control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) - label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) - label:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) - container:SetAnchor(TOPRIGHT, control.label, BOTTOMRIGHT, 0, HALF_WIDTH_LINE_SPACING) - else - control:SetDimensions(width, MIN_HEIGHT) - container:SetAnchor(TOPRIGHT, control, TOPRIGHT, 0, 0) - label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) - label:SetAnchor(TOPRIGHT, container, TOPLEFT, 5, 0) - end - - control.data.tooltipText = GetStringFromValue(control.data.tooltip) - control:SetMouseEnabled(true) - control:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - control:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - return control -end - -local function GetTopPanel(panel) - while panel.panel and panel.panel ~= panel do - panel = panel.panel - end - return panel -end - -local function IsSame(objA, objB) - if #objA ~= #objB then return false end - for i = 1, #objA do - if objA[i] ~= objB[i] then return false end - end - return true -end - -local function RefreshReloadUIButton() - lam.requiresReload = false - - for i = 1, #controlsForReload do - local reloadControl = controlsForReload[i] - if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then - lam.requiresReload = true - break - end - end - - lam.applyButton:SetHidden(not lam.requiresReload) -end - -local function RequestRefreshIfNeeded(control) - -- if our parent window wants to refresh controls, then fire the callback - local panel = GetTopPanel(control.panel) - local panelData = panel.data - if panelData.registerForRefresh then - cm:FireCallbacks("LAM-RefreshPanel", control) - end - RefreshReloadUIButton() -end - -local function RegisterForRefreshIfNeeded(control) - -- if our parent window wants to refresh controls, then add this to the list - local panel = GetTopPanel(control.panel) - local panelData = panel.data - if panelData.registerForRefresh or panelData.registerForDefaults then - tinsert(panel.controlsToRefresh or {}, control) -- prevent errors on custom panels - end -end - -local function RegisterForReloadIfNeeded(control) - if control.data.requiresReload then - tinsert(controlsForReload, control) - control.startValue = {control.data.getFunc()} - end -end - -local function GetConfirmDialog() - if(not ESO_Dialogs[LAM_CONFIRM_DIALOG]) then - ESO_Dialogs[LAM_CONFIRM_DIALOG] = { - canQueue = true, - title = { - text = "", - }, - mainText = { - text = "", - }, - buttons = { - [1] = { - text = SI_DIALOG_CONFIRM, - callback = function(dialog) end, - }, - [2] = { - text = SI_DIALOG_CANCEL, - } - } - } - end - return ESO_Dialogs[LAM_CONFIRM_DIALOG] -end - -local function ShowConfirmationDialog(title, body, callback) - local dialog = GetConfirmDialog() - dialog.title.text = title - dialog.mainText.text = body - dialog.buttons[1].callback = callback - ZO_Dialogs_ShowDialog(LAM_CONFIRM_DIALOG) -end - -local function GetDefaultsDialog() - if(not ESO_Dialogs[LAM_DEFAULTS_DIALOG]) then - ESO_Dialogs[LAM_DEFAULTS_DIALOG] = { - canQueue = true, - title = { - text = SI_INTERFACE_OPTIONS_RESET_TO_DEFAULT_TOOLTIP, - }, - mainText = { - text = SI_OPTIONS_RESET_PROMPT, - }, - buttons = { - [1] = { - text = SI_OPTIONS_RESET, - callback = function(dialog) end, - }, - [2] = { - text = SI_DIALOG_CANCEL, - } - } - } - end - return ESO_Dialogs[LAM_DEFAULTS_DIALOG] -end - -local function ShowDefaultsDialog(panel) - local dialog = GetDefaultsDialog() - dialog.buttons[1].callback = function() - panel:ForceDefaults() - RefreshReloadUIButton() - end - ZO_Dialogs_ShowDialog(LAM_DEFAULTS_DIALOG) -end - -local function DiscardChangesOnReloadControls() - for i = 1, #controlsForReload do - local reloadControl = controlsForReload[i] - if not IsSame(reloadControl.startValue, {reloadControl.data.getFunc()}) then - reloadControl:UpdateValue(false, unpack(reloadControl.startValue)) - end - end - lam.requiresReload = false - lam.applyButton:SetHidden(true) -end - -local function StorePanelForReopening() - local saveData = ZO_Ingame_SavedVariables["LAM"] or {} - saveData.reopenPanel = lam.currentAddonPanel:GetName() - ZO_Ingame_SavedVariables["LAM"] = saveData -end - -local function RetrievePanelForReopening() - local saveData = ZO_Ingame_SavedVariables["LAM"] - if(saveData) then - ZO_Ingame_SavedVariables["LAM"] = nil - return _G[saveData.reopenPanel] - end -end - -local function HandleReloadUIPressed() - StorePanelForReopening() - ReloadUI() -end - -local function HandleLoadDefaultsPressed() - ShowDefaultsDialog(lam.currentAddonPanel) -end - -local function GetReloadDialog() - if(not ESO_Dialogs[LAM_RELOAD_DIALOG]) then - ESO_Dialogs[LAM_RELOAD_DIALOG] = { - canQueue = true, - title = { - text = util.L["RELOAD_DIALOG_TITLE"], - }, - mainText = { - text = util.L["RELOAD_DIALOG_TEXT"], - }, - buttons = { - [1] = { - text = util.L["RELOAD_DIALOG_RELOAD_BUTTON"], - callback = function() ReloadUI() end, - }, - [2] = { - text = util.L["RELOAD_DIALOG_DISCARD_BUTTON"], - callback = DiscardChangesOnReloadControls, - } - }, - noChoiceCallback = DiscardChangesOnReloadControls, - } - end - return ESO_Dialogs[LAM_CONFIRM_DIALOG] -end - -local function ShowReloadDialogIfNeeded() - if lam.requiresReload then - local dialog = GetReloadDialog() - ZO_Dialogs_ShowDialog(LAM_RELOAD_DIALOG) - end -end - -local function UpdateWarning(control) - local warning - if control.data.warning ~= nil then - warning = util.GetStringFromValue(control.data.warning) - end - - if control.data.requiresReload then - if not warning then - warning = string.format("|cff0000%s", util.L["RELOAD_UI_WARNING"]) - else - warning = string.format("%s\n\n|cff0000%s", warning, util.L["RELOAD_UI_WARNING"]) - end - end - - if not warning then - control.warning:SetHidden(true) - else - control.warning.data = {tooltipText = warning} - control.warning:SetHidden(false) - end -end - -local localization = { - en = { - PANEL_NAME = "Addons", - AUTHOR = string.format("%s: <>", GetString(SI_ADDON_MANAGER_AUTHOR)), -- "Author: <>" - VERSION = "Version: <>", - WEBSITE = "Visit Website", - PANEL_INFO_FONT = "$(CHAT_FONT)|14|soft-shadow-thin", - RELOAD_UI_WARNING = "Changes to this setting require an UI reload in order to take effect.", - RELOAD_DIALOG_TITLE = "UI Reload required", - RELOAD_DIALOG_TEXT = "Some changes require an UI reload in order to take effect. Do you want to reload now or discard the changes?", - RELOAD_DIALOG_RELOAD_BUTTON = "Reload", - RELOAD_DIALOG_DISCARD_BUTTON = "Discard", - }, - it = { -- provided by JohnnyKing - PANEL_NAME = "Addon", - VERSION = "Versione: <>", - WEBSITE = "Visita il Sitoweb", - RELOAD_UI_WARNING = "Cambiare questa impostazione richiede un Ricarica UI al fine che faccia effetto.", - RELOAD_DIALOG_TITLE = "Ricarica UI richiesto", - RELOAD_DIALOG_TEXT = "Alcune modifiche richiedono un Ricarica UI al fine che facciano effetto. Sei sicuro di voler ricaricare ora o di voler annullare le modifiche?", - RELOAD_DIALOG_RELOAD_BUTTON = "Ricarica", - RELOAD_DIALOG_DISCARD_BUTTON = "Annulla", - }, - fr = { -- provided by Ayantir - PANEL_NAME = "Extensions", - WEBSITE = "Visiter le site Web", - RELOAD_UI_WARNING = "La modification de ce paramètre requiert un rechargement de l'UI pour qu'il soit pris en compte.", - RELOAD_DIALOG_TITLE = "Reload UI requis", - RELOAD_DIALOG_TEXT = "Certaines modifications requièrent un rechargement de l'UI pour qu'ils soient pris en compte. Souhaitez-vous recharger l'interface maintenant ou annuler les modifications ?", - RELOAD_DIALOG_RELOAD_BUTTON = "Recharger", - RELOAD_DIALOG_DISCARD_BUTTON = "Annuler", - }, - de = { -- provided by sirinsidiator - PANEL_NAME = "Erweiterungen", - WEBSITE = "Webseite besuchen", - RELOAD_UI_WARNING = "Änderungen an dieser Option werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird.", - RELOAD_DIALOG_TITLE = "Neuladen benötigt", - RELOAD_DIALOG_TEXT = "Einige Änderungen werden erst übernommen nachdem die Benutzeroberfläche neu geladen wird. Wollt Ihr sie jetzt neu laden oder die Änderungen verwerfen?", - RELOAD_DIALOG_RELOAD_BUTTON = "Neu laden", - RELOAD_DIALOG_DISCARD_BUTTON = "Verwerfen", - }, - ru = { -- provided by TERAB1T - PANEL_NAME = "Дополнения", - VERSION = "Версия: <>", - WEBSITE = "Посетить сайт", - PANEL_INFO_FONT = "RuESO/fonts/Univers57.otf|14|soft-shadow-thin", - RELOAD_UI_WARNING = "Для применения этой настройки необходима перезагрузка интерфейса.", - RELOAD_DIALOG_TITLE = "Необходима перезагрузка интерфейса", - RELOAD_DIALOG_TEXT = "Для применения некоторых изменений необходима перезагрузка интерфейса. Перезагрузить интерфейс сейчас или отменить изменения?", - RELOAD_DIALOG_RELOAD_BUTTON = "Перезагрузить", - RELOAD_DIALOG_DISCARD_BUTTON = "Отменить изменения", - }, - es = { -- provided by Morganlefai, checked by Kwisatz - PANEL_NAME = "Configuración", - VERSION = "Versión: <>", - WEBSITE = "Visita la página web", - RELOAD_UI_WARNING = "Cambiar este ajuste recargará la interfaz del usuario.", - RELOAD_DIALOG_TITLE = "Requiere recargar la interfaz", - RELOAD_DIALOG_TEXT = "Algunos cambios requieren recargar la interfaz para poder aplicarse. Quieres aplicar los cambios y recargar la interfaz?", - RELOAD_DIALOG_RELOAD_BUTTON = "Recargar", - RELOAD_DIALOG_DISCARD_BUTTON = "Cancelar", - }, - jp = { -- provided by k0ta0uchi - PANEL_NAME = "アドオン設定", - WEBSITE = "ウェブサイトを見る", - }, - zh = { -- provided by bssthu - PANEL_NAME = "插件", - VERSION = "版本: <>", - WEBSITE = "访问网站", - PANEL_INFO_FONT = "EsoZh/fonts/univers57.otf|14|soft-shadow-thin", - }, - pl = { -- provided by EmiruTegryfon - PANEL_NAME = "Dodatki", - VERSION = "Wersja: <>", - WEBSITE = "Odwiedź stronę", - RELOAD_UI_WARNING = "Zmiany będą widoczne po ponownym załadowaniu UI.", - RELOAD_DIALOG_TITLE = "Wymagane przeładowanie UI", - RELOAD_DIALOG_TEXT = "Niektóre zmiany wymagają ponownego załadowania UI. Czy chcesz teraz ponownie załadować, czy porzucić zmiany?", - RELOAD_DIALOG_RELOAD_BUTTON = "Przeładuj", - RELOAD_DIALOG_DISCARD_BUTTON = "Porzuć", - }, -} - -util.L = ZO_ShallowTableCopy(localization[GetCVar("Language.2")], localization["en"]) -util.GetTooltipText = GetStringFromValue -- deprecated, use util.GetStringFromValue instead -util.GetStringFromValue = GetStringFromValue -util.GetDefaultValue = GetDefaultValue -util.CreateBaseControl = CreateBaseControl -util.CreateLabelAndContainerControl = CreateLabelAndContainerControl -util.RequestRefreshIfNeeded = RequestRefreshIfNeeded -util.RegisterForRefreshIfNeeded = RegisterForRefreshIfNeeded -util.RegisterForReloadIfNeeded = RegisterForReloadIfNeeded -util.GetTopPanel = GetTopPanel -util.ShowConfirmationDialog = ShowConfirmationDialog -util.UpdateWarning = UpdateWarning - -local ADDON_DATA_TYPE = 1 -local RESELECTING_DURING_REBUILD = true -local USER_REQUESTED_OPEN = true - - ---INTERNAL FUNCTION ---scrolls ZO_ScrollList `list` to move the row corresponding to `data` --- into view (does nothing if there is no such row in the list) ---unlike ZO_ScrollList_ScrollDataIntoView, this function accounts for --- fading near the list's edges - it avoids the fading area by scrolling --- a little further than the ZO function -local function ScrollDataIntoView(list, data) - local targetIndex = data.sortIndex - if not targetIndex then return end - - local scrollMin, scrollMax = list.scrollbar:GetMinMax() - local scrollTop = list.scrollbar:GetValue() - local controlHeight = list.uniformControlHeight or list.controlHeight - local targetMin = controlHeight * (targetIndex - 1) - 64 - -- subtracting 64 ain't arbitrary, it's the maximum fading height - -- (libraries/zo_templates/scrolltemplates.lua/UpdateScrollFade) - - if targetMin < scrollTop then - ZO_ScrollList_ScrollAbsolute(list, zo_max(targetMin, scrollMin)) - else - local listHeight = ZO_ScrollList_GetHeight(list) - local targetMax = controlHeight * targetIndex + 64 - listHeight - - if targetMax > scrollTop then - ZO_ScrollList_ScrollAbsolute(list, zo_min(targetMax, scrollMax)) - end - end -end - - ---INTERNAL FUNCTION ---constructs a string pattern from the text in `searchEdit` control --- * metacharacters are escaped, losing their special meaning --- * whitespace matches anything (including empty substring) ---if there is nothing but whitespace, returns nil ---otherwise returns a filter function, which takes a `data` table argument --- and returns true iff `data.filterText` matches the pattern -local function GetSearchFilterFunc(searchEdit) - local text = searchEdit:GetText():lower() - local pattern = text:match("(%S+.-)%s*$") - - if not pattern then -- nothing but whitespace - return nil - end - - -- escape metacharacters, e.g. "ESO-Datenbank.de" => "ESO%-Datenbank%.de" - pattern = pattern:gsub("[-*+?^$().[%]%%]", "%%%0") - - -- replace whitespace with "match shortest anything" - pattern = pattern:gsub("%s+", ".-") - - return function(data) - return data.filterText:lower():find(pattern) ~= nil - end -end - - ---INTERNAL FUNCTION ---populates `addonList` with entries from `addonsForList` --- addonList = ZO_ScrollList control --- filter = [optional] function(data) -local function PopulateAddonList(addonList, filter) - local entryList = ZO_ScrollList_GetDataList(addonList) - local numEntries = 0 - local selectedData = nil - local selectionIsFinal = false - - ZO_ScrollList_Clear(addonList) - - for i, data in ipairs(addonsForList) do - if not filter or filter(data) then - local dataEntry = ZO_ScrollList_CreateDataEntry(ADDON_DATA_TYPE, data) - numEntries = numEntries + 1 - data.sortIndex = numEntries - entryList[numEntries] = dataEntry - -- select the first panel passing the filter, or the currently - -- shown panel, but only if it passes the filter as well - if selectedData == nil or data.panel == lam.pendingAddonPanel or data.panel == lam.currentAddonPanel then - if not selectionIsFinal then - selectedData = data - end - if data.panel == lam.pendingAddonPanel then - lam.pendingAddonPanel = nil - selectionIsFinal = true - end - end - else - data.sortIndex = nil - end - end - - ZO_ScrollList_Commit(addonList) - - if selectedData then - if selectedData.panel == lam.currentAddonPanel then - ZO_ScrollList_SelectData(addonList, selectedData, nil, RESELECTING_DURING_REBUILD) - else - ZO_ScrollList_SelectData(addonList, selectedData, nil) - end - ScrollDataIntoView(addonList, selectedData) - end -end - - ---METHOD: REGISTER WIDGET-- ---each widget has its version checked before loading, ---so we only have the most recent one in memory ---Usage: --- widgetType = "string"; the type of widget being registered --- widgetVersion = integer; the widget's version number -LAMCreateControl = LAMCreateControl or {} -local lamcc = LAMCreateControl - -function lam:RegisterWidget(widgetType, widgetVersion) - if widgets[widgetType] and widgets[widgetType] >= widgetVersion then - return false - else - widgets[widgetType] = widgetVersion - return true - end -end - --- INTERNAL METHOD: hijacks the handlers for the actions in the OptionsWindow layer if not already done -local function InitKeybindActions() - if not lam.keybindsInitialized then - lam.keybindsInitialized = true - ZO_PreHook(KEYBOARD_OPTIONS, "ApplySettings", function() - if lam.currentPanelOpened then - if not lam.applyButton:IsHidden() then - HandleReloadUIPressed() - end - return true - end - end) - ZO_PreHook("ZO_Dialogs_ShowDialog", function(dialogName) - if lam.currentPanelOpened and dialogName == "OPTIONS_RESET_TO_DEFAULTS" then - if not lam.defaultButton:IsHidden() then - HandleLoadDefaultsPressed() - end - return true - end - end) - end -end - --- INTERNAL METHOD: fires the LAM-PanelOpened callback if not already done -local function OpenCurrentPanel() - if lam.currentAddonPanel and not lam.currentPanelOpened then - lam.currentPanelOpened = true - lam.defaultButton:SetHidden(not lam.currentAddonPanel.data.registerForDefaults) - cm:FireCallbacks("LAM-PanelOpened", lam.currentAddonPanel) - end -end - --- INTERNAL METHOD: fires the LAM-PanelClosed callback if not already done -local function CloseCurrentPanel() - if lam.currentAddonPanel and lam.currentPanelOpened then - lam.currentPanelOpened = false - cm:FireCallbacks("LAM-PanelClosed", lam.currentAddonPanel) - end -end - ---METHOD: OPEN TO ADDON PANEL-- ---opens to a specific addon's option panel ---Usage: --- panel = userdata; the panel returned by the :RegisterOptionsPanel method -local locSettings = GetString(SI_GAME_MENU_SETTINGS) -function lam:OpenToPanel(panel) - - -- find and select the panel's row in addon list - - local addonList = lam.addonList - local selectedData = nil - - for _, addonData in ipairs(addonsForList) do - if addonData.panel == panel then - selectedData = addonData - ScrollDataIntoView(addonList, selectedData) - lam.pendingAddonPanel = addonData.panel - break - end - end - - ZO_ScrollList_SelectData(addonList, selectedData) - ZO_ScrollList_RefreshVisible(addonList, selectedData) - - local srchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") - srchEdit:Clear() - - -- note that ZO_ScrollList doesn't require `selectedData` to be actually - -- present in the list, and that the list will only be populated once LAM - -- "Addon Settings" menu entry is selected for the first time - - local function openAddonSettingsMenu() - local gameMenu = ZO_GameMenu_InGame.gameMenu - local settingsMenu = gameMenu.headerControls[locSettings] - - if settingsMenu then -- an instance of ZO_TreeNode - local children = settingsMenu:GetChildren() - for i = 1, (children and #children or 0) do - local childNode = children[i] - local data = childNode:GetData() - if data and data.id == lam.panelId then - -- found LAM "Addon Settings" node, yay! - childNode:GetTree():SelectNode(childNode) - break - end - end - end - end - - if sm:GetScene("gameMenuInGame"):GetState() == SCENE_SHOWN then - openAddonSettingsMenu() - else - sm:CallWhen("gameMenuInGame", SCENE_SHOWN, openAddonSettingsMenu) - sm:Show("gameMenuInGame") - end -end - -local TwinOptionsContainer_Index = 0 -local function TwinOptionsContainer(parent, leftWidget, rightWidget) - TwinOptionsContainer_Index = TwinOptionsContainer_Index + 1 - local cParent = parent.scroll or parent - local panel = parent.panel or cParent - local container = wm:CreateControl("$(parent)TwinContainer" .. tostring(TwinOptionsContainer_Index), - cParent, CT_CONTROL) - container:SetResizeToFitDescendents(true) - container:SetAnchor(select(2, leftWidget:GetAnchor(0) )) - - leftWidget:ClearAnchors() - leftWidget:SetAnchor(TOPLEFT, container, TOPLEFT) - rightWidget:SetAnchor(TOPLEFT, leftWidget, TOPRIGHT, 5, 0) - - leftWidget:SetWidth( leftWidget:GetWidth() - 2.5 ) -- fixes bad alignment with 'full' controls - rightWidget:SetWidth( rightWidget:GetWidth() - 2.5 ) - - leftWidget:SetParent(container) - rightWidget:SetParent(container) - - container.data = {type = "container"} - container.panel = panel - return container -end - ---INTERNAL FUNCTION ---creates controls when options panel is first shown ---controls anchoring of these controls in the panel -local function CreateOptionsControls(panel) - local addonID = panel:GetName() - if(optionsState[addonID] == OPTIONS_CREATED) then - return false - elseif(optionsState[addonID] == OPTIONS_CREATION_RUNNING) then - return true - end - optionsState[addonID] = OPTIONS_CREATION_RUNNING - - local function CreationFinished() - optionsState[addonID] = OPTIONS_CREATED - cm:FireCallbacks("LAM-PanelControlsCreated", panel) - OpenCurrentPanel() - end - - local optionsTable = addonToOptionsMap[addonID] - if optionsTable then - local function CreateAndAnchorWidget(parent, widgetData, offsetX, offsetY, anchorTarget, wasHalf) - local widget - local status, err = pcall(function() widget = LAMCreateControl[widgetData.type](parent, widgetData) end) - if not status then - return err or true, offsetY, anchorTarget, wasHalf - else - local isHalf = (widgetData.width == "half") - if not anchorTarget then -- the first widget in a panel is just placed in the top left corner - widget:SetAnchor(TOPLEFT) - anchorTarget = widget - elseif wasHalf and isHalf then -- when the previous widget was only half width and this one is too, we place it on the right side - widget.lineControl = anchorTarget - isHalf = false - offsetY = 0 - anchorTarget = TwinOptionsContainer(parent, anchorTarget, widget) - else -- otherwise we just put it below the previous one normally - widget:SetAnchor(TOPLEFT, anchorTarget, BOTTOMLEFT, 0, 15) - offsetY = 0 - anchorTarget = widget - end - return false, offsetY, anchorTarget, isHalf - end - end - - local THROTTLE_TIMEOUT, THROTTLE_COUNT = 10, 20 - local fifo = {} - local anchorOffset, lastAddedControl, wasHalf - local CreateWidgetsInPanel, err - - local function PrepareForNextPanel() - anchorOffset, lastAddedControl, wasHalf = 0, nil, false - end - - local function SetupCreationCalls(parent, widgetDataTable) - fifo[#fifo + 1] = PrepareForNextPanel - local count = #widgetDataTable - for i = 1, count, THROTTLE_COUNT do - fifo[#fifo + 1] = function() - CreateWidgetsInPanel(parent, widgetDataTable, i, zo_min(i + THROTTLE_COUNT - 1, count)) - end - end - return count ~= NonContiguousCount(widgetDataTable) - end - - CreateWidgetsInPanel = function(parent, widgetDataTable, startIndex, endIndex) - for i=startIndex,endIndex do - local widgetData = widgetDataTable[i] - if not widgetData then - PrintLater("Skipped creation of missing entry in the settings menu of " .. addonID .. ".") - else - local widgetType = widgetData.type - local offsetX = 0 - local isSubmenu = (widgetType == "submenu") - if isSubmenu then - wasHalf = false - offsetX = 5 - end - - err, anchorOffset, lastAddedControl, wasHalf = CreateAndAnchorWidget(parent, widgetData, offsetX, anchorOffset, lastAddedControl, wasHalf) - if err then - PrintLater(("Could not create %s '%s' of %s."):format(widgetData.type, GetStringFromValue(widgetData.name or "unnamed"), addonID)) - end - - if isSubmenu then - if SetupCreationCalls(lastAddedControl, widgetData.controls) then - PrintLater(("The sub menu '%s' of %s is missing some entries."):format(GetStringFromValue(widgetData.name or "unnamed"), addonID)) - end - end - end - end - end - - local function DoCreateSettings() - if #fifo > 0 then - local nextCall = table.remove(fifo, 1) - nextCall() - if(nextCall == PrepareForNextPanel) then - DoCreateSettings() - else - zo_callLater(DoCreateSettings, THROTTLE_TIMEOUT) - end - else - CreationFinished() - end - end - - if SetupCreationCalls(panel, optionsTable) then - PrintLater(("The settings menu of %s is missing some entries."):format(addonID)) - end - DoCreateSettings() - else - CreationFinished() - end - - return true -end - ---INTERNAL FUNCTION ---handles switching between panels -local function ToggleAddonPanels(panel) --called in OnShow of newly shown panel - local currentlySelected = lam.currentAddonPanel - if currentlySelected and currentlySelected ~= panel then - currentlySelected:SetHidden(true) - CloseCurrentPanel() - end - lam.currentAddonPanel = panel - - -- refresh visible rows to reflect panel IsHidden status - ZO_ScrollList_RefreshVisible(lam.addonList) - - if not CreateOptionsControls(panel) then - OpenCurrentPanel() - end - - cm:FireCallbacks("LAM-RefreshPanel", panel) -end - -local CheckSafetyAndInitialize - ---METHOD: REGISTER ADDON PANEL ---registers your addon with LibAddonMenu and creates a panel ---Usage: --- addonID = "string"; unique ID which will be the global name of your panel --- panelData = table; data object for your panel - see controls\panel.lua -function lam:RegisterAddonPanel(addonID, panelData) - CheckSafetyAndInitialize(addonID) - local container = lam:GetAddonPanelContainer() - local panel = lamcc.panel(container, panelData, addonID) --addonID==global name of panel - panel:SetHidden(true) - panel:SetAnchorFill(container) - panel:SetHandler("OnShow", ToggleAddonPanels) - - local function stripMarkup(str) - return str:gsub("|[Cc]%x%x%x%x%x%x", ""):gsub("|[Rr]", "") - end - - local filterParts = {panelData.name, nil, nil} - -- append keywords and author separately, the may be nil - filterParts[#filterParts + 1] = panelData.keywords - filterParts[#filterParts + 1] = panelData.author - - local addonData = { - panel = panel, - name = stripMarkup(panelData.name), - filterText = stripMarkup(tconcat(filterParts, "\t")):lower(), - } - - tinsert(addonsForList, addonData) - - if panelData.slashCommand then - SLASH_COMMANDS[panelData.slashCommand] = function() - lam:OpenToPanel(panel) - end - end - - return panel --return for authors creating options manually -end - - ---METHOD: REGISTER OPTION CONTROLS ---registers the options you want shown for your addon ---these are stored in a table where each key-value pair is the order ---of the options in the panel and the data for that control, respectively ---see exampleoptions.lua for an example ---see controls\.lua for each widget type ---Usage: --- addonID = "string"; the same string passed to :RegisterAddonPanel --- optionsTable = table; the table containing all of the options controls and their data -function lam:RegisterOptionControls(addonID, optionsTable) --optionsTable = {sliderData, buttonData, etc} - addonToOptionsMap[addonID] = optionsTable -end - ---INTERNAL FUNCTION ---creates LAM's Addon Settings entry in ZO_GameMenu -local function CreateAddonSettingsMenuEntry() - local panelData = { - id = KEYBOARD_OPTIONS.currentPanelId, - name = util.L["PANEL_NAME"], - } - - KEYBOARD_OPTIONS.currentPanelId = panelData.id + 1 - KEYBOARD_OPTIONS.panelNames[panelData.id] = panelData.name - - lam.panelId = panelData.id - - local addonListSorted = false - - function panelData.callback() - sm:AddFragment(lam:GetAddonSettingsFragment()) - KEYBOARD_OPTIONS:ChangePanels(lam.panelId) - - local title = LAMAddonSettingsWindow:GetNamedChild("Title") - title:SetText(panelData.name) - - if not addonListSorted and #addonsForList > 0 then - local searchEdit = LAMAddonSettingsWindow:GetNamedChild("SearchFilterEdit") - --we're about to show our list for the first time - let's sort it - table.sort(addonsForList, function(a, b) return a.name < b.name end) - PopulateAddonList(lam.addonList, GetSearchFilterFunc(searchEdit)) - addonListSorted = true - end - end - - function panelData.unselectedCallback() - sm:RemoveFragment(lam:GetAddonSettingsFragment()) - if SetCameraOptionsPreviewModeEnabled then -- available since API version 100011 - SetCameraOptionsPreviewModeEnabled(false) - end - end - - ZO_GameMenu_AddSettingPanel(panelData) -end - - ---INTERNAL FUNCTION ---creates the left-hand menu in LAM's window -local function CreateAddonList(name, parent) - local addonList = wm:CreateControlFromVirtual(name, parent, "ZO_ScrollList") - - local function addonListRow_OnMouseDown(control, button) - if button == 1 then - local data = ZO_ScrollList_GetData(control) - ZO_ScrollList_SelectData(addonList, data, control) - end - end - - local function addonListRow_OnMouseEnter(control) - ZO_ScrollList_MouseEnter(addonList, control) - end - - local function addonListRow_OnMouseExit(control) - ZO_ScrollList_MouseExit(addonList, control) - end - - local function addonListRow_Select(previouslySelectedData, selectedData, reselectingDuringRebuild) - if not reselectingDuringRebuild then - if previouslySelectedData then - previouslySelectedData.panel:SetHidden(true) - end - if selectedData then - selectedData.panel:SetHidden(false) - PlaySound(SOUNDS.MENU_SUBCATEGORY_SELECTION) - end - end - end - - local function addonListRow_Setup(control, data) - control:SetText(data.name) - control:SetSelected(not data.panel:IsHidden()) - end - - ZO_ScrollList_AddDataType(addonList, ADDON_DATA_TYPE, "ZO_SelectableLabel", 28, addonListRow_Setup) - -- I don't know how to make highlights clear properly; they often - -- get stuck and after a while the list is full of highlighted rows - --ZO_ScrollList_EnableHighlight(addonList, "ZO_ThinListHighlight") - ZO_ScrollList_EnableSelection(addonList, "ZO_ThinListHighlight", addonListRow_Select) - - local addonDataType = ZO_ScrollList_GetDataTypeTable(addonList, ADDON_DATA_TYPE) - local addonListRow_CreateRaw = addonDataType.pool.m_Factory - - local function addonListRow_Create(pool) - local control = addonListRow_CreateRaw(pool) - control:SetHandler("OnMouseDown", addonListRow_OnMouseDown) - --control:SetHandler("OnMouseEnter", addonListRow_OnMouseEnter) - --control:SetHandler("OnMouseExit", addonListRow_OnMouseExit) - control:SetHeight(28) - control:SetFont("ZoFontHeader") - control:SetHorizontalAlignment(TEXT_ALIGN_LEFT) - control:SetVerticalAlignment(TEXT_ALIGN_CENTER) - control:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - return control - end - - addonDataType.pool.m_Factory = addonListRow_Create - - return addonList -end - - ---INTERNAL FUNCTION -local function CreateSearchFilterBox(name, parent) - local boxControl = wm:CreateControl(name, parent, CT_CONTROL) - - local srchButton = wm:CreateControl("$(parent)Button", boxControl, CT_BUTTON) - srchButton:SetDimensions(32, 32) - srchButton:SetAnchor(LEFT, nil, LEFT, 2, 0) - srchButton:SetNormalTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_up.dds") - srchButton:SetPressedTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_down.dds") - srchButton:SetMouseOverTexture("EsoUI/Art/LFG/LFG_tabIcon_groupTools_over.dds") - - local srchEdit = wm:CreateControlFromVirtual("$(parent)Edit", boxControl, "ZO_DefaultEdit") - srchEdit:SetAnchor(LEFT, srchButton, RIGHT, 4, 1) - srchEdit:SetAnchor(RIGHT, nil, RIGHT, -4, 1) - srchEdit:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) - - local srchBg = wm:CreateControl("$(parent)Bg", boxControl, CT_BACKDROP) - srchBg:SetAnchorFill() - srchBg:SetAlpha(0) - srchBg:SetCenterColor(0, 0, 0, 0.5) - srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) - srchBg:SetEdgeTexture("", 1, 1, 0, 0) - - -- search backdrop should appear whenever you hover over either - -- the magnifying glass button or the edit field (which is only - -- visible when it contains some text), and also while the edit - -- field has keyboard focus - - local srchActive = false - local srchHover = false - - local function srchBgUpdateAlpha() - if srchActive or srchEdit:HasFocus() then - srchBg:SetAlpha(srchHover and 0.8 or 0.6) - else - srchBg:SetAlpha(srchHover and 0.6 or 0.0) - end - end - - local function srchMouseEnter(control) - srchHover = true - srchBgUpdateAlpha() - end - - local function srchMouseExit(control) - srchHover = false - srchBgUpdateAlpha() - end - - boxControl:SetMouseEnabled(true) - boxControl:SetHitInsets(1, 1, -1, -1) - boxControl:SetHandler("OnMouseEnter", srchMouseEnter) - boxControl:SetHandler("OnMouseExit", srchMouseExit) - - srchButton:SetHandler("OnMouseEnter", srchMouseEnter) - srchButton:SetHandler("OnMouseExit", srchMouseExit) - - local focusLostTime = 0 - - srchButton:SetHandler("OnClicked", function(self) - srchEdit:Clear() - if GetFrameTimeMilliseconds() - focusLostTime < 100 then - -- re-focus the edit box if it lost focus due to this - -- button click (note that this handler may run a few - -- frames later) - srchEdit:TakeFocus() - end - end) - - srchEdit:SetHandler("OnMouseEnter", srchMouseEnter) - srchEdit:SetHandler("OnMouseExit", srchMouseExit) - srchEdit:SetHandler("OnFocusGained", srchBgUpdateAlpha) - - srchEdit:SetHandler("OnFocusLost", function() - focusLostTime = GetFrameTimeMilliseconds() - srchBgUpdateAlpha() - end) - - srchEdit:SetHandler("OnEscape", function(self) - self:Clear() - self:LoseFocus() - end) - - srchEdit:SetHandler("OnTextChanged", function(self) - local filterFunc = GetSearchFilterFunc(self) - if filterFunc then - srchActive = true - srchBg:SetEdgeColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA()) - srchButton:SetState(BSTATE_PRESSED) - else - srchActive = false - srchBg:SetEdgeColor(ZO_DISABLED_TEXT:UnpackRGBA()) - srchButton:SetState(BSTATE_NORMAL) - end - srchBgUpdateAlpha() - PopulateAddonList(lam.addonList, filterFunc) - PlaySound(SOUNDS.SPINNER_DOWN) - end) - - return boxControl -end - - ---INTERNAL FUNCTION ---creates LAM's Addon Settings top-level window -local function CreateAddonSettingsWindow() - local tlw = wm:CreateTopLevelWindow("LAMAddonSettingsWindow") - tlw:SetHidden(true) - tlw:SetDimensions(1010, 914) -- same height as ZO_OptionsWindow - - ZO_ReanchorControlForLeftSidePanel(tlw) - - -- create black background for the window (mimic ZO_RightFootPrintBackground) - - local bgLeft = wm:CreateControl("$(parent)BackgroundLeft", tlw, CT_TEXTURE) - bgLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_left.dds") - bgLeft:SetDimensions(1024, 1024) - bgLeft:SetAnchor(TOPLEFT, nil, TOPLEFT) - bgLeft:SetDrawLayer(DL_BACKGROUND) - bgLeft:SetExcludeFromResizeToFitExtents(true) - - local bgRight = wm:CreateControl("$(parent)BackgroundRight", tlw, CT_TEXTURE) - bgRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_right.dds") - bgRight:SetDimensions(64, 1024) - bgRight:SetAnchor(TOPLEFT, bgLeft, TOPRIGHT) - bgRight:SetDrawLayer(DL_BACKGROUND) - bgRight:SetExcludeFromResizeToFitExtents(true) - - -- create gray background for addon list (mimic ZO_TreeUnderlay) - - local underlayLeft = wm:CreateControl("$(parent)UnderlayLeft", tlw, CT_TEXTURE) - underlayLeft:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_left.dds") - underlayLeft:SetDimensions(256, 1024) - underlayLeft:SetAnchor(TOPLEFT, bgLeft, TOPLEFT) - underlayLeft:SetDrawLayer(DL_BACKGROUND) - underlayLeft:SetExcludeFromResizeToFitExtents(true) - - local underlayRight = wm:CreateControl("$(parent)UnderlayRight", tlw, CT_TEXTURE) - underlayRight:SetTexture("EsoUI/Art/Miscellaneous/centerscreen_indexArea_right.dds") - underlayRight:SetDimensions(128, 1024) - underlayRight:SetAnchor(TOPLEFT, underlayLeft, TOPRIGHT) - underlayRight:SetDrawLayer(DL_BACKGROUND) - underlayRight:SetExcludeFromResizeToFitExtents(true) - - -- create title bar (mimic ZO_OptionsWindow) - - local title = wm:CreateControl("$(parent)Title", tlw, CT_LABEL) - title:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 70) - title:SetFont("ZoFontWinH1") - title:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE) - - local divider = wm:CreateControlFromVirtual("$(parent)Divider", tlw, "ZO_Options_Divider") - divider:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 108) - - -- create search filter box - - local srchBox = CreateSearchFilterBox("$(parent)SearchFilter", tlw) - srchBox:SetAnchor(TOPLEFT, nil, TOPLEFT, 63, 120) - srchBox:SetDimensions(260, 30) - - -- create scrollable addon list - - local addonList = CreateAddonList("$(parent)AddonList", tlw) - addonList:SetAnchor(TOPLEFT, nil, TOPLEFT, 65, 160) - addonList:SetDimensions(285, 665) - - lam.addonList = addonList -- for easy access from elsewhere - - -- create container for option panels - - local panelContainer = wm:CreateControl("$(parent)PanelContainer", tlw, CT_CONTROL) - panelContainer:SetAnchor(TOPLEFT, nil, TOPLEFT, 365, 120) - panelContainer:SetDimensions(645, 675) - - local defaultButton = wm:CreateControlFromVirtual("$(parent)ResetToDefaultButton", tlw, "ZO_DialogButton") - ZO_KeybindButtonTemplate_Setup(defaultButton, "OPTIONS_LOAD_DEFAULTS", HandleLoadDefaultsPressed, GetString(SI_OPTIONS_DEFAULTS)) - defaultButton:SetAnchor(TOPLEFT, panelContainer, BOTTOMLEFT, 0, 2) - lam.defaultButton = defaultButton - - local applyButton = wm:CreateControlFromVirtual("$(parent)ApplyButton", tlw, "ZO_DialogButton") - ZO_KeybindButtonTemplate_Setup(applyButton, "OPTIONS_APPLY_CHANGES", HandleReloadUIPressed, GetString(SI_ADDON_MANAGER_RELOAD)) - applyButton:SetAnchor(TOPRIGHT, panelContainer, BOTTOMRIGHT, 0, 2) - applyButton:SetHidden(true) - lam.applyButton = applyButton - - return tlw -end - - ---INITIALIZING -local safeToInitialize = false -local hasInitialized = false - -local eventHandle = table.concat({MAJOR, MINOR}, "r") -local function OnLoad(_, addonName) - -- wait for the first loaded event - em:UnregisterForEvent(eventHandle, EVENT_ADD_ON_LOADED) - safeToInitialize = true -end -em:RegisterForEvent(eventHandle, EVENT_ADD_ON_LOADED, OnLoad) - -local function OnActivated(_, initial) - em:UnregisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED) - FlushMessages() - - local reopenPanel = RetrievePanelForReopening() - if not initial and reopenPanel then - lam:OpenToPanel(reopenPanel) - end -end -em:RegisterForEvent(eventHandle, EVENT_PLAYER_ACTIVATED, OnActivated) - -function CheckSafetyAndInitialize(addonID) - if not safeToInitialize then - local msg = string.format("The panel with id '%s' was registered before addon loading has completed. This might break the AddOn Settings menu.", addonID) - PrintLater(msg) - end - if not hasInitialized then - hasInitialized = true - end -end - - ---TODO documentation -function lam:GetAddonPanelContainer() - local fragment = lam:GetAddonSettingsFragment() - local window = fragment:GetControl() - return window:GetNamedChild("PanelContainer") -end - - ---TODO documentation -function lam:GetAddonSettingsFragment() - assert(hasInitialized or safeToInitialize) - if not LAMAddonSettingsFragment then - local window = CreateAddonSettingsWindow() - LAMAddonSettingsFragment = ZO_FadeSceneFragment:New(window, true, 100) - LAMAddonSettingsFragment:RegisterCallback("StateChange", function(oldState, newState) - if(newState == SCENE_FRAGMENT_SHOWN) then - InitKeybindActions() - PushActionLayerByName("OptionsWindow") - OpenCurrentPanel() - elseif(newState == SCENE_FRAGMENT_HIDDEN) then - CloseCurrentPanel() - RemoveActionLayerByName("OptionsWindow") - ShowReloadDialogIfNeeded() - end - end) - CreateAddonSettingsMenuEntry() - end - return LAMAddonSettingsFragment -end diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/button.lua b/PvPFPS2018/LibAddonMenu-2.0/controls/button.lua deleted file mode 100644 index 82b5032..0000000 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/button.lua +++ /dev/null @@ -1,91 +0,0 @@ ---[[buttonData = { - type = "button", - name = "My Button", -- string id or function returning a string - func = function() end, - tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - icon = "icon\\path.dds", --(optional) - isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) - warning = "Will need to reload the UI.", --(optional) - reference = "MyAddonButton", -- unique global reference to control (optional) -} ]] - -local widgetVersion = 11 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("button", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateDisabled(control) - local disable = control.data.disabled - if type(disable) == "function" then - disable = disable() - end - control.button:SetEnabled(not disable) -end - ---controlName is optional -local MIN_HEIGHT = 28 -- default_button height -local HALF_WIDTH_LINE_SPACING = 2 -function LAMCreateControl.button(parent, buttonData, controlName) - local control = LAM.util.CreateBaseControl(parent, buttonData, controlName) - control:SetMouseEnabled(true) - - local width = control:GetWidth() - if control.isHalfWidth then - control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) - else - control:SetDimensions(width, MIN_HEIGHT) - end - - if buttonData.icon then - control.button = wm:CreateControl(nil, control, CT_BUTTON) - control.button:SetDimensions(26, 26) - control.button:SetNormalTexture(buttonData.icon) - control.button:SetPressedOffset(2, 2) - else - --control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton") - control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton") - control.button:SetWidth(width / 3) - control.button:SetText(LAM.util.GetStringFromValue(buttonData.name)) - if buttonData.isDangerous then control.button:SetNormalFontColor(ZO_ERROR_COLOR:UnpackRGBA()) end - end - local button = control.button - button:SetAnchor(control.isHalfWidth and CENTER or RIGHT) - button:SetClickSound("Click") - button.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.tooltip)} - button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - button:SetHandler("OnClicked", function(...) - local args = {...} - local function callback() - buttonData.func(unpack(args)) - LAM.util.RequestRefreshIfNeeded(control) - end - - if(buttonData.isDangerous) then - local title = LAM.util.GetStringFromValue(buttonData.name) - local body = LAM.util.GetStringFromValue(buttonData.warning) - LAM.util.ShowConfirmationDialog(title, body, callback) - else - callback() - end - end) - - if buttonData.warning ~= nil then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - if buttonData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control -end diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/colorpicker.lua b/PvPFPS2018/LibAddonMenu-2.0/controls/colorpicker.lua deleted file mode 100644 index a57aab0..0000000 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/colorpicker.lua +++ /dev/null @@ -1,106 +0,0 @@ ---[[colorpickerData = { - type = "colorpicker", - name = "My Color Picker", -- or string id or function returning a string - getFunc = function() return db.r, db.g, db.b, db.a end, --(alpha is optional) - setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, --(alpha is optional) - tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, --(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color - reference = "MyAddonColorpicker" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 13 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end - - control.isDisabled = disable -end - -local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) - if forceDefault then --if we are forcing defaults - local color = LAM.util.GetDefaultValue(control.data.default) - valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a - control.data.setFunc(valueR, valueG, valueB, valueA) - elseif valueR and valueG and valueB then - control.data.setFunc(valueR, valueG, valueB, valueA or 1) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - valueR, valueG, valueB, valueA = control.data.getFunc() - end - - control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) -end - -function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName) - - control.color = control.container - local color = control.color - - control.thumb = wm:CreateControl(nil, color, CT_TEXTURE) - local thumb = control.thumb - thumb:SetDimensions(36, 18) - thumb:SetAnchor(LEFT, color, LEFT, 4, 0) - - color.border = wm:CreateControl(nil, color, CT_TEXTURE) - local border = color.border - border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds") - border:SetTextureCoords(0, .625, 0, .8125) - border:SetDimensions(40, 22) - border:SetAnchor(CENTER, thumb, CENTER, 0, 0) - - local function ColorPickerCallback(r, g, b, a) - control:UpdateValue(false, r, g, b, a) - end - - control:SetHandler("OnMouseUp", function(self, btn, upInside) - if self.isDisabled then return end - - if upInside then - local r, g, b, a = colorpickerData.getFunc() - COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, LAM.util.GetStringFromValue(colorpickerData.name)) - end - end) - - if colorpickerData.warning ~= nil or colorpickerData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) - - control.UpdateValue = UpdateValue - control:UpdateValue() - if colorpickerData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/description.lua b/PvPFPS2018/LibAddonMenu-2.0/controls/description.lua deleted file mode 100644 index da207a0..0000000 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/description.lua +++ /dev/null @@ -1,60 +0,0 @@ ---[[descriptionData = { - type = "description", - text = "My description text to display.", -- or string id or function returning a string - title = "My Title", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonDescription" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 8 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("description", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateValue(control) - if control.title then - control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) - end - control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) -end - -function LAMCreateControl.description(parent, descriptionData, controlName) - local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName) - local isHalfWidth = control.isHalfWidth - local width = control:GetWidth() - control:SetResizeToFitDescendents(true) - - if isHalfWidth then - control:SetDimensionConstraints(width / 2, 0, width / 2, 0) - else - control:SetDimensionConstraints(width, 0, width, 0) - end - - control.desc = wm:CreateControl(nil, control, CT_LABEL) - local desc = control.desc - desc:SetVerticalAlignment(TEXT_ALIGN_TOP) - desc:SetFont("ZoFontGame") - desc:SetText(LAM.util.GetStringFromValue(descriptionData.text)) - desc:SetWidth(isHalfWidth and width / 2 or width) - - if descriptionData.title then - control.title = wm:CreateControl(nil, control, CT_LABEL) - local title = control.title - title:SetWidth(isHalfWidth and width / 2 or width) - title:SetAnchor(TOPLEFT, control, TOPLEFT) - title:SetFont("ZoFontWinH4") - title:SetText(LAM.util.GetStringFromValue(descriptionData.title)) - desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT) - else - desc:SetAnchor(TOPLEFT) - end - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control - -end diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/dropdown.lua b/PvPFPS2018/LibAddonMenu-2.0/controls/dropdown.lua deleted file mode 100644 index 70e23bb..0000000 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/dropdown.lua +++ /dev/null @@ -1,387 +0,0 @@ ---[[dropdownData = { - type = "dropdown", - name = "My Dropdown", -- or string id or function returning a string - choices = {"table", "of", "choices"}, - choicesValues = {"foo", 2, "three"}, -- if specified, these values will get passed to setFunc instead (optional) - getFunc = function() return db.var end, - setFunc = function(var) db.var = var doStuff() end, - tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) - choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) - sort = "name-up", --or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted - width = "full", --or "half" (optional) - scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonDropdown" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 18 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("dropdown", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local SORT_BY_VALUE = { ["value"] = {} } -local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } -local SORT_TYPES = { - name = ZO_SORT_BY_NAME, - numeric = ZO_SORT_BY_NAME_NUMERIC, - value = SORT_BY_VALUE, - numericvalue = SORT_BY_VALUE_NUMERIC, -} -local SORT_ORDERS = { - up = ZO_SORT_ORDER_UP, - down = ZO_SORT_ORDER_DOWN, -} - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - control.dropdown:SetEnabled(not disable) - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - control.dropdown:SetSelectedItem(control.choices[value]) - elseif value then - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - control.dropdown:SetSelectedItem(control.choices[value]) - end -end - -local function DropdownCallback(control, choiceText, choice) - choice.control:UpdateValue(false, choice.value or choiceText) -end - -local function SetupTooltips(comboBox, choicesTooltips) - local function ShowTooltip(control) - InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) - SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.tooltip)) - InformationTooltipTopLevel:BringWindowToTop() - end - local function HideTooltip(control) - ClearTooltip(InformationTooltip) - end - - -- allow for tooltips on the drop down entries - local originalShow = comboBox.ShowDropdownInternal - comboBox.ShowDropdownInternal = function(comboBox) - originalShow(comboBox) - local entries = ZO_Menu.items - for i = 1, #entries do - local entry = entries[i] - local control = entries[i].item - control.tooltip = choicesTooltips[i] - entry.onMouseEnter = control:GetHandler("OnMouseEnter") - entry.onMouseExit = control:GetHandler("OnMouseExit") - ZO_PreHookHandler(control, "OnMouseEnter", ShowTooltip) - ZO_PreHookHandler(control, "OnMouseExit", HideTooltip) - end - end - - local originalHide = comboBox.HideDropdownInternal - comboBox.HideDropdownInternal = function(self) - local entries = ZO_Menu.items - for i = 1, #entries do - local entry = entries[i] - local control = entries[i].item - control:SetHandler("OnMouseEnter", entry.onMouseEnter) - control:SetHandler("OnMouseExit", entry.onMouseExit) - control.tooltip = nil - end - originalHide(self) - end -end - -local function UpdateChoices(control, choices, choicesValues, choicesTooltips) - control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?) - ZO_ClearTable(control.choices) - - --build new list of choices - local choices = choices or control.data.choices - local choicesValues = choicesValues or control.data.choicesValues - local choicesTooltips = choicesTooltips or control.data.choicesTooltips - - if choicesValues then - assert(#choices == #choicesValues, "choices and choicesValues need to have the same size") - end - - if choicesTooltips then - assert(#choices == #choicesTooltips, "choices and choicesTooltips need to have the same size") - if not control.scrollHelper then -- only do this for non-scrollable - SetupTooltips(control.dropdown, choicesTooltips) - end - end - - for i = 1, #choices do - local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback) - entry.control = control - if choicesValues then - entry.value = choicesValues[i] - end - if choicesTooltips and control.scrollHelper then - entry.tooltip = choicesTooltips[i] - end - control.choices[entry.value or entry.name] = entry.name - control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort - end -end - -local function GrabSortingInfo(sortInfo) - local t, i = {}, 1 - for info in string.gmatch(sortInfo, "([^%-]+)") do - t[i] = info - i = i + 1 - end - - return t -end - -local DEFAULT_VISIBLE_ROWS = 10 -local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = 25 -- same as in zo_combobox.lua -local CONTENT_PADDING = 24 -local SCROLLBAR_PADDING = 16 -local PADDING = GetMenuPadding() / 2 -- half the amount looks closer to the regular dropdown -local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed -local ScrollableDropdownHelper = ZO_Object:Subclass() - -function ScrollableDropdownHelper:New(...) - local object = ZO_Object.New(self) - object:Initialize(...) - return object -end - -function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) - local combobox = control.combobox - local dropdown = control.dropdown - self.parent = parent - self.control = control - self.combobox = combobox - self.dropdown = dropdown - self.visibleRows = visibleRows - - -- clear anchors so we can adjust the width dynamically - dropdown.m_dropdown:ClearAnchors() - dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) - - -- handle dropdown or settingsmenu opening/closing - local function onShow() self:OnShow() end - local function onHide() self:OnHide() end - local function doHide() self:DoHide() end - - ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) - ZO_PreHook(dropdown, "HideDropdownInternal", onHide) - combobox:SetHandler("OnEffectivelyHidden", onHide) - parent:SetHandler("OnEffectivelyHidden", doHide) - - -- dont fade entries near the edges - local scrollList = dropdown.m_scroll - scrollList.selectionTemplate = nil - scrollList.highlightTemplate = nil - ZO_ScrollList_EnableSelection(scrollList, "ZO_SelectionHighlight") - ZO_ScrollList_EnableHighlight(scrollList, "ZO_SelectionHighlight") - ZO_Scroll_SetUseFadeGradient(scrollList, false) - - -- adjust scroll content anchor to mimic menu padding - local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") - local anchor1 = {scroll:GetAnchor(0)} - local anchor2 = {scroll:GetAnchor(1)} - scroll:ClearAnchors() - scroll:SetAnchor(anchor1[2], anchor1[3], anchor1[4], anchor1[5] + PADDING, anchor1[6] + PADDING) - scroll:SetAnchor(anchor2[2], anchor2[3], anchor2[4], anchor2[5] - PADDING, anchor2[6] - PADDING) - ZO_ScrollList_Commit(scrollList) - - -- hook mouse enter/exit - local function onMouseEnter(control) self:OnMouseEnter(control) end - local function onMouseExit(control) self:OnMouseExit(control) end - - -- adjust row setup to mimic the highlight padding - local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) - local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 2) - local oSetup = dataType1.setupCallback -- both types have the same setup function - local function SetupEntry(control, data, list) - oSetup(control, data, list) - control.m_label:SetAnchor(LEFT, nil, nil, 2) - -- no need to store old ones since we have full ownership of our dropdown controls - if not control.hookedMouseHandlers then --only do it once per control - control.hookedMouseHandlers = true - ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) - ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) - -- we could also just replace the handlers - --control:SetHandler("OnMouseEnter", onMouseEnter) - --control:SetHandler("OnMouseExit", onMouseExit) - end - end - dataType1.setupCallback = SetupEntry - dataType2.setupCallback = SetupEntry - - -- adjust dimensions based on entries - local scrollContent = scroll:GetNamedChild("Contents") - ZO_PreHook(dropdown, "AddMenuItems", function() - local width = PADDING * 2 + zo_max(self:GetMaxWidth(), combobox:GetWidth()) - local numItems = #dropdown.m_sortedItems - local anchorOffset = 0 - if(numItems > self.visibleRows) then - width = width + CONTENT_PADDING + SCROLLBAR_PADDING - anchorOffset = -SCROLLBAR_PADDING - numItems = self.visibleRows - end - scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) - local height = PADDING * 2 + numItems * (SCROLLABLE_ENTRY_TEMPLATE_HEIGHT + dropdown.m_spacing) - dropdown.m_spacing + ROUNDING_MARGIN - dropdown.m_dropdown:SetWidth(width) - dropdown.m_dropdown:SetHeight(height) - end) -end - -function ScrollableDropdownHelper:OnShow() - local dropdown = self.dropdown - if dropdown.m_lastParent ~= ZO_Menus then - dropdown.m_lastParent = dropdown.m_dropdown:GetParent() - dropdown.m_dropdown:SetParent(ZO_Menus) - ZO_Menus:BringWindowToTop() - end -end - -function ScrollableDropdownHelper:OnHide() - local dropdown = self.dropdown - if dropdown.m_lastParent then - dropdown.m_dropdown:SetParent(dropdown.m_lastParent) - dropdown.m_lastParent = nil - end -end - -function ScrollableDropdownHelper:DoHide() - local dropdown = self.dropdown - if dropdown:IsDropdownVisible() then - dropdown:HideDropdown() - end -end - -function ScrollableDropdownHelper:GetMaxWidth() - local dropdown = self.dropdown - local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) - - local dummy = dataType.pool:AcquireObject() - dataType.setupCallback(dummy, { - m_owner = dropdown, - name = "Dummy" - }, dropdown) - - local maxWidth = 0 - local label = dummy.m_label - local entries = dropdown.m_sortedItems - local numItems = #entries - for index = 1, numItems do - label:SetText(entries[index].name) - local width = label:GetTextWidth() - if (width > maxWidth) then - maxWidth = width - end - end - - dataType.pool:ReleaseObject(dummy.key) - return maxWidth -end - -function ScrollableDropdownHelper:OnMouseEnter(control) - -- call original code if we replace instead of hook the handler - --ZO_ScrollableComboBox_Entry_OnMouseEnter(control) - -- show tooltip - if control.m_data.tooltip then - InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) - SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.m_data.tooltip)) - InformationTooltipTopLevel:BringWindowToTop() - end -end -function ScrollableDropdownHelper:OnMouseExit(control) - -- call original code if we replace instead of hook the handler - --ZO_ScrollableComboBox_Entry_OnMouseExit(control) - -- hide tooltip - if control.m_data.tooltip then - ClearTooltip(InformationTooltip) - end -end - -function LAMCreateControl.dropdown(parent, dropdownData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName) - control.choices = {} - - local countControl = parent - local name = parent:GetName() - if not name or #name == 0 then - countControl = LAMCreateControl - name = "LAM" - end - local comboboxCount = (countControl.comboboxCount or 0) + 1 - countControl.comboboxCount = comboboxCount - control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, dropdownData.scrollable and "ZO_ScrollableComboBox" or "ZO_ComboBox") - - local combobox = control.combobox - combobox:SetAnchor(TOPLEFT) - combobox:SetDimensions(control.container:GetDimensions()) - combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox) - local dropdown = control.dropdown - dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value - - if dropdownData.scrollable then - local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS - control.scrollHelper = ScrollableDropdownHelper:New(parent, control, visibleRows) - end - - ZO_PreHook(dropdown, "UpdateItems", function(self) - assert(not self.m_sortsItems, "built-in dropdown sorting was reactivated, sorting is handled by LAM") - if control.m_sortOrder ~= nil and control.m_sortType then - local sortKey = next(control.m_sortType) - local sortFunc = function(item1, item2) return ZO_TableOrderingFunction(item1, item2, sortKey, control.m_sortType, control.m_sortOrder) end - table.sort(self.m_sortedItems, sortFunc) - end - end) - - if dropdownData.sort then - local sortInfo = GrabSortingInfo(dropdownData.sort) - control.m_sortType, control.m_sortOrder = SORT_TYPES[sortInfo[1]], SORT_ORDERS[sortInfo[2]] - elseif dropdownData.choicesValues then - control.m_sortType, control.m_sortOrder = ZO_SORT_ORDER_UP, SORT_BY_VALUE - end - - if dropdownData.warning ~= nil or dropdownData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateChoices = UpdateChoices - control:UpdateChoices(dropdownData.choices, dropdownData.choicesValues) - control.UpdateValue = UpdateValue - control:UpdateValue() - if dropdownData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/panel.lua b/PvPFPS2018/LibAddonMenu-2.0/controls/panel.lua deleted file mode 100644 index 1404686..0000000 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/panel.lua +++ /dev/null @@ -1,126 +0,0 @@ ---[[panelData = { - type = "panel", - name = "Window Title", -- or string id or function returning a string - displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) - author = "Seerah", -- or string id or function returning a string (optional) - version = "2.0", -- or string id or function returning a string (optional) - website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated (optional) - keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) - slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) - registerForRefresh = true, --boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown) - registerForDefaults = true, --boolean (optional) (will set all options controls back to default values) - resetFunc = function() print("defaults reset") end, --(optional) custom function to run after settings are reset to defaults -} ]] - - -local widgetVersion = 13 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("panel", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local cm = CALLBACK_MANAGER - -local function RefreshPanel(control) - local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu - local panelControls = panel.controlsToRefresh - - for i = 1, #panelControls do - local updateControl = panelControls[i] - if updateControl ~= control and updateControl.UpdateValue then - updateControl:UpdateValue() - end - if updateControl.UpdateDisabled then - updateControl:UpdateDisabled() - end - if updateControl.UpdateWarning then - updateControl:UpdateWarning() - end - end -end - -local function ForceDefaults(panel) - local panelControls = panel.controlsToRefresh - - for i = 1, #panelControls do - local updateControl = panelControls[i] - if updateControl.UpdateValue and updateControl.data.default ~= nil then - updateControl:UpdateValue(true) - end - end - - if panel.data.resetFunc then - panel.data.resetFunc() - end - - cm:FireCallbacks("LAM-RefreshPanel", panel) -end - -local callbackRegistered = false -LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 -local SEPARATOR = " - " -local LINK_COLOR = ZO_ColorDef:New("5959D5") -local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") - -function LAMCreateControl.panel(parent, panelData, controlName) - local control = wm:CreateControl(controlName, parent, CT_CONTROL) - - control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") - local label = control.label - label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) - label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) - - if panelData.author or panelData.version then - control.info = wm:CreateControl(nil, control, CT_LABEL) - local info = control.info - info:SetFont(LAM.util.L["PANEL_INFO_FONT"]) - info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) - - local output = {} - if panelData.author then - output[#output + 1] = zo_strformat(LAM.util.L["AUTHOR"], LAM.util.GetStringFromValue(panelData.author)) - end - if panelData.version then - output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) - end - info:SetText(table.concat(output, SEPARATOR)) - end - - if panelData.website then - control.website = wm:CreateControl(nil, control, CT_BUTTON) - local website = control.website - website:SetClickSound("Click") - website:SetFont(LAM.util.L["PANEL_INFO_FONT"]) - website:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) - website:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) - if(control.info) then - website:SetAnchor(TOPLEFT, control.info, TOPRIGHT, 0, 0) - website:SetText(string.format("|cffffff%s|r%s", SEPARATOR, LAM.util.L["WEBSITE"])) - else - website:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) - website:SetText(LAM.util.L["WEBSITE"]) - end - website:SetDimensions(website:GetLabelControl():GetTextDimensions()) - website:SetHandler("OnClicked", function() - RequestOpenUnsafeURL(panelData.website) - end) - end - - control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") - LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1 - local container = control.container - container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20) - container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3) - control.scroll = GetControl(control.container, "ScrollChild") - control.scroll:SetResizeToFitPadding(0, 20) - - if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once - cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel) - callbackRegistered = true - end - - control.ForceDefaults = ForceDefaults - control.data = panelData - control.controlsToRefresh = {} - - return control -end diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/slider.lua b/PvPFPS2018/LibAddonMenu-2.0/controls/slider.lua deleted file mode 100644 index bd721c5..0000000 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/slider.lua +++ /dev/null @@ -1,212 +0,0 @@ ---[[sliderData = { - type = "slider", - name = "My Slider", -- or string id or function returning a string - getFunc = function() return db.var end, - setFunc = function(value) db.var = value doStuff() end, - min = 0, - max = 20, - step = 1, --(optional) - clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) - decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) - autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) - inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) - tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonSlider" -- unique global reference to control (optional) -} ]] - -local widgetVersion = 12 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("slider", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local strformat = string.format - -local function RoundDecimalToPlace(d, place) - return tonumber(strformat("%." .. tostring(place) .. "f", d)) -end - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - control.slider:SetEnabled(not disable) - control.slidervalue:SetEditEnabled(not disable) - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - elseif value then - if control.data.decimals then - value = RoundDecimalToPlace(value, control.data.decimals) - end - if control.data.clampInput ~= false then - value = math.max(math.min(value, control.data.max), control.data.min) - end - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - end - - control.slider:SetValue(value) - control.slidervalue:SetText(value) -end - -function LAMCreateControl.slider(parent, sliderData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) - local isInputOnRight = sliderData.inputLocation == "right" - - --skipping creating the backdrop... Is this the actual slider texture? - control.slider = wm:CreateControl(nil, control.container, CT_SLIDER) - local slider = control.slider - slider:SetAnchor(TOPLEFT) - slider:SetHeight(14) - if(isInputOnRight) then - slider:SetAnchor(TOPRIGHT, nil, nil, -60) - else - slider:SetAnchor(TOPRIGHT) - end - slider:SetMouseEnabled(true) - slider:SetOrientation(ORIENTATION_HORIZONTAL) - --put nil for highlighted texture file path, and what look to be texture coords - slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16) - local minValue = sliderData.min - local maxValue = sliderData.max - slider:SetMinMax(minValue, maxValue) - slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - slider:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - - slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP) - local bg = slider.bg - bg:SetCenterColor(0, 0, 0) - bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4) - bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4) - bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4) - - control.minText = wm:CreateControl(nil, slider, CT_LABEL) - local minText = control.minText - minText:SetFont("ZoFontGameSmall") - minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT) - minText:SetText(sliderData.min) - - control.maxText = wm:CreateControl(nil, slider, CT_LABEL) - local maxText = control.maxText - maxText:SetFont("ZoFontGameSmall") - maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT) - maxText:SetText(sliderData.max) - - control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop") - if(isInputOnRight) then - control.slidervalueBG:SetDimensions(60, 26) - control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0) - else - control.slidervalueBG:SetDimensions(50, 16) - control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0) - end - control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop") - local slidervalue = control.slidervalue - slidervalue:ClearAnchors() - slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1) - slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1) - slidervalue:SetTextType(TEXT_TYPE_NUMERIC) - if(isInputOnRight) then - slidervalue:SetFont("ZoFontGameLarge") - else - slidervalue:SetFont("ZoFontGameSmall") - end - - local isHandlingChange = false - local function HandleValueChanged(value) - if isHandlingChange then return end - if sliderData.decimals then - value = RoundDecimalToPlace(value, sliderData.decimals) - end - isHandlingChange = true - slider:SetValue(value) - slidervalue:SetText(value) - isHandlingChange = false - end - - slidervalue:SetHandler("OnEscape", function(self) - HandleValueChanged(sliderData.getFunc()) - self:LoseFocus() - end) - slidervalue:SetHandler("OnEnter", function(self) - self:LoseFocus() - end) - slidervalue:SetHandler("OnFocusLost", function(self) - local value = tonumber(self:GetText()) - control:UpdateValue(false, value) - end) - slidervalue:SetHandler("OnTextChanged", function(self) - local input = self:GetText() - if(#input > 1 and not input:sub(-1):match("[0-9]")) then return end - local value = tonumber(input) - if(value) then - HandleValueChanged(value) - end - end) - if(sliderData.autoSelect) then - ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self) - self:SelectAll() - end) - end - - local range = maxValue - minValue - slider:SetValueStep(sliderData.step or 1) - slider:SetHandler("OnValueChanged", function(self, value, eventReason) - if eventReason == EVENT_REASON_SOFTWARE then return end - HandleValueChanged(value) - end) - slider:SetHandler("OnSliderReleased", function(self, value) - control:UpdateValue(false, value) - end) - slider:SetHandler("OnMouseWheel", function(self, value) - if(not self:GetEnabled()) then return end - local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) - control:UpdateValue(false, new_value) - end) - - if sliderData.warning ~= nil or sliderData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateValue = UpdateValue - control:UpdateValue() - - if sliderData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/PvPFPS2018/LibAddonMenu-2.0/controls/submenu.lua b/PvPFPS2018/LibAddonMenu-2.0/controls/submenu.lua deleted file mode 100644 index 1766a1f..0000000 --- a/PvPFPS2018/LibAddonMenu-2.0/controls/submenu.lua +++ /dev/null @@ -1,108 +0,0 @@ ---[[submenuData = { - type = "submenu", - name = "Submenu Title", -- or string id or function returning a string - tooltip = "My submenu tooltip", -- -- or string id or function returning a string (optional) - controls = {sliderData, buttonData} --(optional) used by LAM - reference = "MyAddonSubmenu" --(optional) unique global reference to control -} ]] - -local widgetVersion = 11 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("submenu", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local am = ANIMATION_MANAGER - -local function UpdateValue(control) - control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) - if control.data.tooltip then - control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) - end -end - -local function AnimateSubmenu(clicked) - local control = clicked:GetParent() - control.open = not control.open - - if control.open then - control.animation:PlayFromStart() - else - control.animation:PlayFromEnd() - end -end - -function LAMCreateControl.submenu(parent, submenuData, controlName) - local width = parent:GetWidth() - 45 - local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL) - control.panel = parent - control.data = submenuData - - control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") - local label = control.label - label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) - label:SetDimensions(width, 30) - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetText(LAM.util.GetStringFromValue(submenuData.name)) - label:SetMouseEnabled(true) - if submenuData.tooltip then - label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} - label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - end - - control.scroll = wm:CreateControl(nil, control, CT_SCROLL) - local scroll = control.scroll - scroll:SetParent(control) - scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10) - scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) - - control.bg = wm:CreateControl(nil, label, CT_BACKDROP) - local bg = control.bg - bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5) - bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) - bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) - bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") - bg:SetInsets(16, 16, -16, -16) - - control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) - local arrow = control.arrow - arrow:SetDimensions(28, 28) - arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way - arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5) - - --figure out the cool animation later... - control.animation = am:CreateTimeline() - local animation = control.animation - animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count - - control:SetResizeToFitDescendents(true) - control.open = false - label:SetHandler("OnMouseUp", AnimateSubmenu) - animation:SetHandler("OnStop", function(self, completedPlaying) - scroll:SetResizeToFitDescendents(control.open) - if control.open then - control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds") - scroll:SetResizeToFitPadding(5, 20) - else - control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") - scroll:SetResizeToFitPadding(5, 0) - scroll:SetHeight(0) - end - end) - - --small strip at the bottom of the submenu that you can click to close it - control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE) - local btmToggle = control.btmToggle - btmToggle:SetMouseEnabled(true) - btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT) - btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT) - btmToggle:SetHeight(15) - btmToggle:SetAlpha(0) - btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control -end diff --git a/PvPFPS2018/LibStub/LibStub.lua b/PvPFPS2018/LibStub/LibStub.lua deleted file mode 100644 index 0e6bf67..0000000 --- a/PvPFPS2018/LibStub/LibStub.lua +++ /dev/null @@ -1,38 +0,0 @@ --- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info --- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke --- LibStub developed for World of Warcraft by above members of the WowAce community. --- Ported to Elder Scrolls Online by Seerah - -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 4 -local LibStub = _G[LIBSTUB_MAJOR] - -local strformat = string.format -if not LibStub or LibStub.minor < LIBSTUB_MINOR then - LibStub = LibStub or {libs = {}, minors = {} } - _G[LIBSTUB_MAJOR] = LibStub - LibStub.minor = LIBSTUB_MINOR - - function LibStub:NewLibrary(major, minor) - assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") - if type(minor) ~= "number" then - minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.") - end - - local oldminor = self.minors[major] - if oldminor and oldminor >= minor then return nil end - self.minors[major], self.libs[major] = minor, self.libs[major] or {} - return self.libs[major], oldminor - end - - function LibStub:GetLibrary(major, silent) - if not self.libs[major] and not silent then - error(strformat("Cannot find a library instance of %q.", tostring(major)), 2) - end - return self.libs[major], self.minors[major] - end - - function LibStub:IterateLibraries() return pairs(self.libs) end - setmetatable(LibStub, { __call = LibStub.GetLibrary }) -end - -LibStub.SILENT = true \ No newline at end of file diff --git a/README.md b/README.md index cc01b7c..b09d46c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ # UserScripts A collection of all my varied userscripts and scripts. -http://www.esoui.com/downloads/author-38690.html - -https://www.patreon.com/jameskoss +Elder Scrolls Online addons list: http://www.esoui.com/downloads/author-38690.html diff --git a/ShowMount/LibAddonMenu-2.0/controls/button.lua b/ShowMount/LibAddonMenu-2.0/controls/button.lua deleted file mode 100644 index 82b5032..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/button.lua +++ /dev/null @@ -1,91 +0,0 @@ ---[[buttonData = { - type = "button", - name = "My Button", -- string id or function returning a string - func = function() end, - tooltip = "Button's tooltip text.", -- string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - icon = "icon\\path.dds", --(optional) - isDangerous = false, -- boolean, if set to true, the button text will be red and a confirmation dialog with the button label and warning text will show on click before the callback is executed (optional) - warning = "Will need to reload the UI.", --(optional) - reference = "MyAddonButton", -- unique global reference to control (optional) -} ]] - -local widgetVersion = 11 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("button", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateDisabled(control) - local disable = control.data.disabled - if type(disable) == "function" then - disable = disable() - end - control.button:SetEnabled(not disable) -end - ---controlName is optional -local MIN_HEIGHT = 28 -- default_button height -local HALF_WIDTH_LINE_SPACING = 2 -function LAMCreateControl.button(parent, buttonData, controlName) - local control = LAM.util.CreateBaseControl(parent, buttonData, controlName) - control:SetMouseEnabled(true) - - local width = control:GetWidth() - if control.isHalfWidth then - control:SetDimensions(width / 2, MIN_HEIGHT * 2 + HALF_WIDTH_LINE_SPACING) - else - control:SetDimensions(width, MIN_HEIGHT) - end - - if buttonData.icon then - control.button = wm:CreateControl(nil, control, CT_BUTTON) - control.button:SetDimensions(26, 26) - control.button:SetNormalTexture(buttonData.icon) - control.button:SetPressedOffset(2, 2) - else - --control.button = wm:CreateControlFromVirtual(controlName.."Button", control, "ZO_DefaultButton") - control.button = wm:CreateControlFromVirtual(nil, control, "ZO_DefaultButton") - control.button:SetWidth(width / 3) - control.button:SetText(LAM.util.GetStringFromValue(buttonData.name)) - if buttonData.isDangerous then control.button:SetNormalFontColor(ZO_ERROR_COLOR:UnpackRGBA()) end - end - local button = control.button - button:SetAnchor(control.isHalfWidth and CENTER or RIGHT) - button:SetClickSound("Click") - button.data = {tooltipText = LAM.util.GetStringFromValue(buttonData.tooltip)} - button:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - button:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - button:SetHandler("OnClicked", function(...) - local args = {...} - local function callback() - buttonData.func(unpack(args)) - LAM.util.RequestRefreshIfNeeded(control) - end - - if(buttonData.isDangerous) then - local title = LAM.util.GetStringFromValue(buttonData.name) - local body = LAM.util.GetStringFromValue(buttonData.warning) - LAM.util.ShowConfirmationDialog(title, body, callback) - else - callback() - end - end) - - if buttonData.warning ~= nil then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, button, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - if buttonData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/checkbox.lua b/ShowMount/LibAddonMenu-2.0/controls/checkbox.lua deleted file mode 100644 index 6696dd7..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/checkbox.lua +++ /dev/null @@ -1,142 +0,0 @@ ---[[checkboxData = { - type = "checkbox", - name = "My Checkbox", -- or string id or function returning a string - getFunc = function() return db.var end, - setFunc = function(value) db.var = value doStuff() end, - tooltip = "Checkbox's tooltip text.", -- or string id or function returning a string (optional) - width = "full", -- or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- a boolean or function that returns a boolean (optional) - reference = "MyAddonCheckbox", -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 14 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("checkbox", widgetVersion) then return end - -local wm = WINDOW_MANAGER - ---label -local enabledColor = ZO_DEFAULT_ENABLED_COLOR -local enabledHLcolor = ZO_HIGHLIGHT_TEXT -local disabledColor = ZO_DEFAULT_DISABLED_COLOR -local disabledHLcolor = ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR ---checkbox -local checkboxColor = ZO_NORMAL_TEXT -local checkboxHLcolor = ZO_HIGHLIGHT_TEXT - - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - control.label:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or control.value and ZO_DEFAULT_ENABLED_COLOR or ZO_DEFAULT_DISABLED_COLOR):UnpackRGBA()) - control.checkbox:SetColor((disable and ZO_DEFAULT_DISABLED_COLOR or ZO_NORMAL_TEXT):UnpackRGBA()) - --control:SetMouseEnabled(not disable) - --control:SetMouseEnabled(true) - - control.isDisabled = disable -end - -local function ToggleCheckbox(control) - if control.value then - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.checkbox:SetText(control.checkedText) - else - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.checkbox:SetText(control.uncheckedText) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - elseif value ~= nil then --our value could be false - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - end - control.value = value - - ToggleCheckbox(control) -end - -local function OnMouseEnter(control) - ZO_Options_OnMouseEnter(control) - - if control.isDisabled then return end - - local label = control.label - if control.value then - label:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) - else - label:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) - end - control.checkbox:SetColor(ZO_HIGHLIGHT_TEXT:UnpackRGBA()) -end - -local function OnMouseExit(control) - ZO_Options_OnMouseExit(control) - - if control.isDisabled then return end - - local label = control.label - if control.value then - label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - else - label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - end - control.checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) -end - ---controlName is optional -function LAMCreateControl.checkbox(parent, checkboxData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, checkboxData, controlName) - control:SetHandler("OnMouseEnter", OnMouseEnter) - control:SetHandler("OnMouseExit", OnMouseExit) - control:SetHandler("OnMouseUp", function(control) - if control.isDisabled then return end - PlaySound(SOUNDS.DEFAULT_CLICK) - control.value = not control.value - control:UpdateValue(false, control.value) - end) - - control.checkbox = wm:CreateControl(nil, control.container, CT_LABEL) - local checkbox = control.checkbox - checkbox:SetAnchor(LEFT, control.container, LEFT, 0, 0) - checkbox:SetFont("ZoFontGameBold") - checkbox:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) - control.checkedText = GetString(SI_CHECK_BUTTON_ON):upper() - control.uncheckedText = GetString(SI_CHECK_BUTTON_OFF):upper() - - if checkboxData.warning ~= nil or checkboxData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, checkbox, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.data.tooltipText = LAM.util.GetStringFromValue(checkboxData.tooltip) - - control.UpdateValue = UpdateValue - control:UpdateValue() - if checkboxData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/colorpicker.lua b/ShowMount/LibAddonMenu-2.0/controls/colorpicker.lua deleted file mode 100644 index a57aab0..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/colorpicker.lua +++ /dev/null @@ -1,106 +0,0 @@ ---[[colorpickerData = { - type = "colorpicker", - name = "My Color Picker", -- or string id or function returning a string - getFunc = function() return db.r, db.g, db.b, db.a end, --(alpha is optional) - setFunc = function(r,g,b,a) db.r=r, db.g=g, db.b=b, db.a=a end, --(alpha is optional) - tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = {r = defaults.r, g = defaults.g, b = defaults.b, a = defaults.a}, --(optional) table of default color values (or default = defaultColor, where defaultColor is a table with keys of r, g, b[, a]) or a function that returns the color - reference = "MyAddonColorpicker" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 13 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("colorpicker", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end - - control.isDisabled = disable -end - -local function UpdateValue(control, forceDefault, valueR, valueG, valueB, valueA) - if forceDefault then --if we are forcing defaults - local color = LAM.util.GetDefaultValue(control.data.default) - valueR, valueG, valueB, valueA = color.r, color.g, color.b, color.a - control.data.setFunc(valueR, valueG, valueB, valueA) - elseif valueR and valueG and valueB then - control.data.setFunc(valueR, valueG, valueB, valueA or 1) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - valueR, valueG, valueB, valueA = control.data.getFunc() - end - - control.thumb:SetColor(valueR, valueG, valueB, valueA or 1) -end - -function LAMCreateControl.colorpicker(parent, colorpickerData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, colorpickerData, controlName) - - control.color = control.container - local color = control.color - - control.thumb = wm:CreateControl(nil, color, CT_TEXTURE) - local thumb = control.thumb - thumb:SetDimensions(36, 18) - thumb:SetAnchor(LEFT, color, LEFT, 4, 0) - - color.border = wm:CreateControl(nil, color, CT_TEXTURE) - local border = color.border - border:SetTexture("EsoUI\\Art\\ChatWindow\\chatOptions_bgColSwatch_frame.dds") - border:SetTextureCoords(0, .625, 0, .8125) - border:SetDimensions(40, 22) - border:SetAnchor(CENTER, thumb, CENTER, 0, 0) - - local function ColorPickerCallback(r, g, b, a) - control:UpdateValue(false, r, g, b, a) - end - - control:SetHandler("OnMouseUp", function(self, btn, upInside) - if self.isDisabled then return end - - if upInside then - local r, g, b, a = colorpickerData.getFunc() - COLOR_PICKER:Show(ColorPickerCallback, r, g, b, a, LAM.util.GetStringFromValue(colorpickerData.name)) - end - end) - - if colorpickerData.warning ~= nil or colorpickerData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, control.color, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.data.tooltipText = LAM.util.GetStringFromValue(colorpickerData.tooltip) - - control.UpdateValue = UpdateValue - control:UpdateValue() - if colorpickerData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/custom.lua b/ShowMount/LibAddonMenu-2.0/controls/custom.lua deleted file mode 100644 index 40a7c42..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/custom.lua +++ /dev/null @@ -1,35 +0,0 @@ ---[[customData = { - type = "custom", - reference = "MyAddonCustomControl", --(optional) unique name for your control to use as reference - refreshFunc = function(customControl) end, --(optional) function to call when panel/controls refresh - width = "full", --or "half" (optional) -} ]] - -local widgetVersion = 7 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("custom", widgetVersion) then return end - -local function UpdateValue(control) - if control.data.refreshFunc then - control.data.refreshFunc(control) - end -end - -local MIN_HEIGHT = 26 -function LAMCreateControl.custom(parent, customData, controlName) - local control = LAM.util.CreateBaseControl(parent, customData, controlName) - local width = control:GetWidth() - control:SetResizeToFitDescendents(true) - - if control.isHalfWidth then --note these restrictions - control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) - else - control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) - end - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/description.lua b/ShowMount/LibAddonMenu-2.0/controls/description.lua deleted file mode 100644 index da207a0..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/description.lua +++ /dev/null @@ -1,60 +0,0 @@ ---[[descriptionData = { - type = "description", - text = "My description text to display.", -- or string id or function returning a string - title = "My Title", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonDescription" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 8 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("description", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateValue(control) - if control.title then - control.title:SetText(LAM.util.GetStringFromValue(control.data.title)) - end - control.desc:SetText(LAM.util.GetStringFromValue(control.data.text)) -end - -function LAMCreateControl.description(parent, descriptionData, controlName) - local control = LAM.util.CreateBaseControl(parent, descriptionData, controlName) - local isHalfWidth = control.isHalfWidth - local width = control:GetWidth() - control:SetResizeToFitDescendents(true) - - if isHalfWidth then - control:SetDimensionConstraints(width / 2, 0, width / 2, 0) - else - control:SetDimensionConstraints(width, 0, width, 0) - end - - control.desc = wm:CreateControl(nil, control, CT_LABEL) - local desc = control.desc - desc:SetVerticalAlignment(TEXT_ALIGN_TOP) - desc:SetFont("ZoFontGame") - desc:SetText(LAM.util.GetStringFromValue(descriptionData.text)) - desc:SetWidth(isHalfWidth and width / 2 or width) - - if descriptionData.title then - control.title = wm:CreateControl(nil, control, CT_LABEL) - local title = control.title - title:SetWidth(isHalfWidth and width / 2 or width) - title:SetAnchor(TOPLEFT, control, TOPLEFT) - title:SetFont("ZoFontWinH4") - title:SetText(LAM.util.GetStringFromValue(descriptionData.title)) - desc:SetAnchor(TOPLEFT, title, BOTTOMLEFT) - else - desc:SetAnchor(TOPLEFT) - end - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control - -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/divider.lua b/ShowMount/LibAddonMenu-2.0/controls/divider.lua deleted file mode 100644 index 8089539..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/divider.lua +++ /dev/null @@ -1,45 +0,0 @@ ---[[dividerData = { - type = "divider", - width = "full", --or "half" (optional) - height = 10, (optional) - alpha = 0.25, (optional) - reference = "MyAddonDivider" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 2 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("divider", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local MIN_HEIGHT = 10 -local MAX_HEIGHT = 50 -local MIN_ALPHA = 0 -local MAX_ALPHA = 1 -local DEFAULT_ALPHA = 0.25 - -local function GetValueInRange(value, min, max, default) - if not value or type(value) ~= "number" then - return default - end - return math.min(math.max(min, value), max) -end - -function LAMCreateControl.divider(parent, dividerData, controlName) - local control = LAM.util.CreateBaseControl(parent, dividerData, controlName) - local isHalfWidth = control.isHalfWidth - local width = control:GetWidth() - local height = GetValueInRange(dividerData.height, MIN_HEIGHT, MAX_HEIGHT, MIN_HEIGHT) - local alpha = GetValueInRange(dividerData.alpha, MIN_ALPHA, MAX_ALPHA, DEFAULT_ALPHA) - - control:SetDimensions(isHalfWidth and width / 2 or width, height) - - control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") - local divider = control.divider - divider:SetWidth(isHalfWidth and width / 2 or width) - divider:SetAnchor(TOPLEFT) - divider:SetAlpha(alpha) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/dropdown.lua b/ShowMount/LibAddonMenu-2.0/controls/dropdown.lua deleted file mode 100644 index 70e23bb..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/dropdown.lua +++ /dev/null @@ -1,387 +0,0 @@ ---[[dropdownData = { - type = "dropdown", - name = "My Dropdown", -- or string id or function returning a string - choices = {"table", "of", "choices"}, - choicesValues = {"foo", 2, "three"}, -- if specified, these values will get passed to setFunc instead (optional) - getFunc = function() return db.var end, - setFunc = function(var) db.var = var doStuff() end, - tooltip = "Dropdown's tooltip text.", -- or string id or function returning a string (optional) - choicesTooltips = {"tooltip 1", "tooltip 2", "tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) - sort = "name-up", --or "name-down", "numeric-up", "numeric-down", "value-up", "value-down", "numericvalue-up", "numericvalue-down" (optional) - if not provided, list will not be sorted - width = "full", --or "half" (optional) - scrollable = true, -- boolean or number, if set the dropdown will feature a scroll bar if there are a large amount of choices and limit the visible lines to the specified number or 10 if true is used (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonDropdown" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 18 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("dropdown", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local SORT_BY_VALUE = { ["value"] = {} } -local SORT_BY_VALUE_NUMERIC = { ["value"] = { isNumeric = true } } -local SORT_TYPES = { - name = ZO_SORT_BY_NAME, - numeric = ZO_SORT_BY_NAME_NUMERIC, - value = SORT_BY_VALUE, - numericvalue = SORT_BY_VALUE_NUMERIC, -} -local SORT_ORDERS = { - up = ZO_SORT_ORDER_UP, - down = ZO_SORT_ORDER_DOWN, -} - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - control.dropdown:SetEnabled(not disable) - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - control.dropdown:SetSelectedItem(control.choices[value]) - elseif value then - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - control.dropdown:SetSelectedItem(control.choices[value]) - end -end - -local function DropdownCallback(control, choiceText, choice) - choice.control:UpdateValue(false, choice.value or choiceText) -end - -local function SetupTooltips(comboBox, choicesTooltips) - local function ShowTooltip(control) - InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) - SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.tooltip)) - InformationTooltipTopLevel:BringWindowToTop() - end - local function HideTooltip(control) - ClearTooltip(InformationTooltip) - end - - -- allow for tooltips on the drop down entries - local originalShow = comboBox.ShowDropdownInternal - comboBox.ShowDropdownInternal = function(comboBox) - originalShow(comboBox) - local entries = ZO_Menu.items - for i = 1, #entries do - local entry = entries[i] - local control = entries[i].item - control.tooltip = choicesTooltips[i] - entry.onMouseEnter = control:GetHandler("OnMouseEnter") - entry.onMouseExit = control:GetHandler("OnMouseExit") - ZO_PreHookHandler(control, "OnMouseEnter", ShowTooltip) - ZO_PreHookHandler(control, "OnMouseExit", HideTooltip) - end - end - - local originalHide = comboBox.HideDropdownInternal - comboBox.HideDropdownInternal = function(self) - local entries = ZO_Menu.items - for i = 1, #entries do - local entry = entries[i] - local control = entries[i].item - control:SetHandler("OnMouseEnter", entry.onMouseEnter) - control:SetHandler("OnMouseExit", entry.onMouseExit) - control.tooltip = nil - end - originalHide(self) - end -end - -local function UpdateChoices(control, choices, choicesValues, choicesTooltips) - control.dropdown:ClearItems() --remove previous choices --(need to call :SetSelectedItem()?) - ZO_ClearTable(control.choices) - - --build new list of choices - local choices = choices or control.data.choices - local choicesValues = choicesValues or control.data.choicesValues - local choicesTooltips = choicesTooltips or control.data.choicesTooltips - - if choicesValues then - assert(#choices == #choicesValues, "choices and choicesValues need to have the same size") - end - - if choicesTooltips then - assert(#choices == #choicesTooltips, "choices and choicesTooltips need to have the same size") - if not control.scrollHelper then -- only do this for non-scrollable - SetupTooltips(control.dropdown, choicesTooltips) - end - end - - for i = 1, #choices do - local entry = control.dropdown:CreateItemEntry(choices[i], DropdownCallback) - entry.control = control - if choicesValues then - entry.value = choicesValues[i] - end - if choicesTooltips and control.scrollHelper then - entry.tooltip = choicesTooltips[i] - end - control.choices[entry.value or entry.name] = entry.name - control.dropdown:AddItem(entry, not control.data.sort and ZO_COMBOBOX_SUPRESS_UPDATE) --if sort type/order isn't specified, then don't sort - end -end - -local function GrabSortingInfo(sortInfo) - local t, i = {}, 1 - for info in string.gmatch(sortInfo, "([^%-]+)") do - t[i] = info - i = i + 1 - end - - return t -end - -local DEFAULT_VISIBLE_ROWS = 10 -local SCROLLABLE_ENTRY_TEMPLATE_HEIGHT = 25 -- same as in zo_combobox.lua -local CONTENT_PADDING = 24 -local SCROLLBAR_PADDING = 16 -local PADDING = GetMenuPadding() / 2 -- half the amount looks closer to the regular dropdown -local ROUNDING_MARGIN = 0.01 -- needed to avoid rare issue with too many anchors processed -local ScrollableDropdownHelper = ZO_Object:Subclass() - -function ScrollableDropdownHelper:New(...) - local object = ZO_Object.New(self) - object:Initialize(...) - return object -end - -function ScrollableDropdownHelper:Initialize(parent, control, visibleRows) - local combobox = control.combobox - local dropdown = control.dropdown - self.parent = parent - self.control = control - self.combobox = combobox - self.dropdown = dropdown - self.visibleRows = visibleRows - - -- clear anchors so we can adjust the width dynamically - dropdown.m_dropdown:ClearAnchors() - dropdown.m_dropdown:SetAnchor(TOPLEFT, combobox, BOTTOMLEFT) - - -- handle dropdown or settingsmenu opening/closing - local function onShow() self:OnShow() end - local function onHide() self:OnHide() end - local function doHide() self:DoHide() end - - ZO_PreHook(dropdown, "ShowDropdownOnMouseUp", onShow) - ZO_PreHook(dropdown, "HideDropdownInternal", onHide) - combobox:SetHandler("OnEffectivelyHidden", onHide) - parent:SetHandler("OnEffectivelyHidden", doHide) - - -- dont fade entries near the edges - local scrollList = dropdown.m_scroll - scrollList.selectionTemplate = nil - scrollList.highlightTemplate = nil - ZO_ScrollList_EnableSelection(scrollList, "ZO_SelectionHighlight") - ZO_ScrollList_EnableHighlight(scrollList, "ZO_SelectionHighlight") - ZO_Scroll_SetUseFadeGradient(scrollList, false) - - -- adjust scroll content anchor to mimic menu padding - local scroll = dropdown.m_dropdown:GetNamedChild("Scroll") - local anchor1 = {scroll:GetAnchor(0)} - local anchor2 = {scroll:GetAnchor(1)} - scroll:ClearAnchors() - scroll:SetAnchor(anchor1[2], anchor1[3], anchor1[4], anchor1[5] + PADDING, anchor1[6] + PADDING) - scroll:SetAnchor(anchor2[2], anchor2[3], anchor2[4], anchor2[5] - PADDING, anchor2[6] - PADDING) - ZO_ScrollList_Commit(scrollList) - - -- hook mouse enter/exit - local function onMouseEnter(control) self:OnMouseEnter(control) end - local function onMouseExit(control) self:OnMouseExit(control) end - - -- adjust row setup to mimic the highlight padding - local dataType1 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) - local dataType2 = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 2) - local oSetup = dataType1.setupCallback -- both types have the same setup function - local function SetupEntry(control, data, list) - oSetup(control, data, list) - control.m_label:SetAnchor(LEFT, nil, nil, 2) - -- no need to store old ones since we have full ownership of our dropdown controls - if not control.hookedMouseHandlers then --only do it once per control - control.hookedMouseHandlers = true - ZO_PreHookHandler(control, "OnMouseEnter", onMouseEnter) - ZO_PreHookHandler(control, "OnMouseExit", onMouseExit) - -- we could also just replace the handlers - --control:SetHandler("OnMouseEnter", onMouseEnter) - --control:SetHandler("OnMouseExit", onMouseExit) - end - end - dataType1.setupCallback = SetupEntry - dataType2.setupCallback = SetupEntry - - -- adjust dimensions based on entries - local scrollContent = scroll:GetNamedChild("Contents") - ZO_PreHook(dropdown, "AddMenuItems", function() - local width = PADDING * 2 + zo_max(self:GetMaxWidth(), combobox:GetWidth()) - local numItems = #dropdown.m_sortedItems - local anchorOffset = 0 - if(numItems > self.visibleRows) then - width = width + CONTENT_PADDING + SCROLLBAR_PADDING - anchorOffset = -SCROLLBAR_PADDING - numItems = self.visibleRows - end - scrollContent:SetAnchor(BOTTOMRIGHT, nil, nil, anchorOffset) - local height = PADDING * 2 + numItems * (SCROLLABLE_ENTRY_TEMPLATE_HEIGHT + dropdown.m_spacing) - dropdown.m_spacing + ROUNDING_MARGIN - dropdown.m_dropdown:SetWidth(width) - dropdown.m_dropdown:SetHeight(height) - end) -end - -function ScrollableDropdownHelper:OnShow() - local dropdown = self.dropdown - if dropdown.m_lastParent ~= ZO_Menus then - dropdown.m_lastParent = dropdown.m_dropdown:GetParent() - dropdown.m_dropdown:SetParent(ZO_Menus) - ZO_Menus:BringWindowToTop() - end -end - -function ScrollableDropdownHelper:OnHide() - local dropdown = self.dropdown - if dropdown.m_lastParent then - dropdown.m_dropdown:SetParent(dropdown.m_lastParent) - dropdown.m_lastParent = nil - end -end - -function ScrollableDropdownHelper:DoHide() - local dropdown = self.dropdown - if dropdown:IsDropdownVisible() then - dropdown:HideDropdown() - end -end - -function ScrollableDropdownHelper:GetMaxWidth() - local dropdown = self.dropdown - local dataType = ZO_ScrollList_GetDataTypeTable(dropdown.m_scroll, 1) - - local dummy = dataType.pool:AcquireObject() - dataType.setupCallback(dummy, { - m_owner = dropdown, - name = "Dummy" - }, dropdown) - - local maxWidth = 0 - local label = dummy.m_label - local entries = dropdown.m_sortedItems - local numItems = #entries - for index = 1, numItems do - label:SetText(entries[index].name) - local width = label:GetTextWidth() - if (width > maxWidth) then - maxWidth = width - end - end - - dataType.pool:ReleaseObject(dummy.key) - return maxWidth -end - -function ScrollableDropdownHelper:OnMouseEnter(control) - -- call original code if we replace instead of hook the handler - --ZO_ScrollableComboBox_Entry_OnMouseEnter(control) - -- show tooltip - if control.m_data.tooltip then - InitializeTooltip(InformationTooltip, control, TOPLEFT, 0, 0, BOTTOMRIGHT) - SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(control.m_data.tooltip)) - InformationTooltipTopLevel:BringWindowToTop() - end -end -function ScrollableDropdownHelper:OnMouseExit(control) - -- call original code if we replace instead of hook the handler - --ZO_ScrollableComboBox_Entry_OnMouseExit(control) - -- hide tooltip - if control.m_data.tooltip then - ClearTooltip(InformationTooltip) - end -end - -function LAMCreateControl.dropdown(parent, dropdownData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, dropdownData, controlName) - control.choices = {} - - local countControl = parent - local name = parent:GetName() - if not name or #name == 0 then - countControl = LAMCreateControl - name = "LAM" - end - local comboboxCount = (countControl.comboboxCount or 0) + 1 - countControl.comboboxCount = comboboxCount - control.combobox = wm:CreateControlFromVirtual(zo_strjoin(nil, name, "Combobox", comboboxCount), control.container, dropdownData.scrollable and "ZO_ScrollableComboBox" or "ZO_ComboBox") - - local combobox = control.combobox - combobox:SetAnchor(TOPLEFT) - combobox:SetDimensions(control.container:GetDimensions()) - combobox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - combobox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - control.dropdown = ZO_ComboBox_ObjectFromContainer(combobox) - local dropdown = control.dropdown - dropdown:SetSortsItems(false) -- need to sort ourselves in order to be able to sort by value - - if dropdownData.scrollable then - local visibleRows = type(dropdownData.scrollable) == "number" and dropdownData.scrollable or DEFAULT_VISIBLE_ROWS - control.scrollHelper = ScrollableDropdownHelper:New(parent, control, visibleRows) - end - - ZO_PreHook(dropdown, "UpdateItems", function(self) - assert(not self.m_sortsItems, "built-in dropdown sorting was reactivated, sorting is handled by LAM") - if control.m_sortOrder ~= nil and control.m_sortType then - local sortKey = next(control.m_sortType) - local sortFunc = function(item1, item2) return ZO_TableOrderingFunction(item1, item2, sortKey, control.m_sortType, control.m_sortOrder) end - table.sort(self.m_sortedItems, sortFunc) - end - end) - - if dropdownData.sort then - local sortInfo = GrabSortingInfo(dropdownData.sort) - control.m_sortType, control.m_sortOrder = SORT_TYPES[sortInfo[1]], SORT_ORDERS[sortInfo[2]] - elseif dropdownData.choicesValues then - control.m_sortType, control.m_sortOrder = ZO_SORT_ORDER_UP, SORT_BY_VALUE - end - - if dropdownData.warning ~= nil or dropdownData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, combobox, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateChoices = UpdateChoices - control:UpdateChoices(dropdownData.choices, dropdownData.choicesValues) - control.UpdateValue = UpdateValue - control:UpdateValue() - if dropdownData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/editbox.lua b/ShowMount/LibAddonMenu-2.0/controls/editbox.lua deleted file mode 100644 index d6baf11..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/editbox.lua +++ /dev/null @@ -1,156 +0,0 @@ ---[[editboxData = { - type = "editbox", - name = "My Editbox", -- or string id or function returning a string - getFunc = function() return db.text end, - setFunc = function(text) db.text = text doStuff() end, - tooltip = "Editbox's tooltip text.", -- or string id or function returning a string (optional) - isMultiline = true, --boolean (optional) - isExtraWide = true, --boolean (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.text, -- default value or function that returns the default value (optional) - reference = "MyAddonEditbox" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 14 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("editbox", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.editbox:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.editbox:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end - --control.editbox:SetEditEnabled(not disable) - control.editbox:SetMouseEnabled(not disable) -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - control.editbox:SetText(value) - elseif value then - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - control.editbox:SetText(value) - end -end - -local MIN_HEIGHT = 24 -local HALF_WIDTH_LINE_SPACING = 2 -function LAMCreateControl.editbox(parent, editboxData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, editboxData, controlName) - - local container = control.container - control.bg = wm:CreateControlFromVirtual(nil, container, "ZO_EditBackdrop") - local bg = control.bg - bg:SetAnchorFill() - - if editboxData.isMultiline then - control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditMultiLineForBackdrop") - control.editbox:SetHandler("OnMouseWheel", function(self, delta) - if self:HasFocus() then --only set focus to new spots if the editbox is currently in use - local cursorPos = self:GetCursorPosition() - local text = self:GetText() - local textLen = text:len() - local newPos - if delta > 0 then --scrolling up - local reverseText = text:reverse() - local revCursorPos = textLen - cursorPos - local revPos = reverseText:find("\n", revCursorPos+1) - newPos = revPos and textLen - revPos - else --scrolling down - newPos = text:find("\n", cursorPos+1) - end - if newPos then --if we found a new line, then scroll, otherwise don't - self:SetCursorPosition(newPos) - end - end - end) - else - control.editbox = wm:CreateControlFromVirtual(nil, bg, "ZO_DefaultEditForBackdrop") - end - local editbox = control.editbox - editbox:SetText(editboxData.getFunc()) - editbox:SetMaxInputChars(3000) - editbox:SetHandler("OnFocusLost", function(self) control:UpdateValue(false, self:GetText()) end) - editbox:SetHandler("OnEscape", function(self) self:LoseFocus() control:UpdateValue(false, self:GetText()) end) - editbox:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - editbox:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - - local MIN_WIDTH = (parent.GetWidth and (parent:GetWidth() / 10)) or (parent.panel.GetWidth and (parent.panel:GetWidth() / 10)) or 0 - - control.label:ClearAnchors() - container:ClearAnchors() - - control.label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 0) - container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) - - if control.isHalfWidth then - container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, 0, 0) - end - - if editboxData.isExtraWide then - container:SetAnchor(BOTTOMLEFT, control, BOTTOMLEFT, 0, 0) - else - container:SetWidth(MIN_WIDTH * 3.2) - end - - if editboxData.isMultiline then - container:SetHeight(MIN_HEIGHT * 3) - else - container:SetHeight(MIN_HEIGHT) - end - - if control.isHalfWidth ~= true and editboxData.isExtraWide ~= true then - control:SetHeight(container:GetHeight()) - else - control:SetHeight(container:GetHeight() + control.label:GetHeight()) - end - - editbox:ClearAnchors() - editbox:SetAnchor(TOPLEFT, container, TOPLEFT, 2, 2) - editbox:SetAnchor(BOTTOMRIGHT, container, BOTTOMRIGHT, -2, -2) - - if editboxData.warning ~= nil or editboxData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - if editboxData.isExtraWide then - control.warning:SetAnchor(BOTTOMRIGHT, control.bg, TOPRIGHT, 2, 0) - else - control.warning:SetAnchor(TOPRIGHT, control.bg, TOPLEFT, -5, 0) - end - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateValue = UpdateValue - control:UpdateValue() - if editboxData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/header.lua b/ShowMount/LibAddonMenu-2.0/controls/header.lua deleted file mode 100644 index eadff38..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/header.lua +++ /dev/null @@ -1,42 +0,0 @@ ---[[headerData = { - type = "header", - name = "My Header", -- or string id or function returning a string - width = "full", --or "half" (optional) - reference = "MyAddonHeader" -- unique global reference to control (optional) -} ]] - - -local widgetVersion = 8 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("header", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local function UpdateValue(control) - control.header:SetText(LAM.util.GetStringFromValue(control.data.name)) -end - -local MIN_HEIGHT = 30 -function LAMCreateControl.header(parent, headerData, controlName) - local control = LAM.util.CreateBaseControl(parent, headerData, controlName) - local isHalfWidth = control.isHalfWidth - local width = control:GetWidth() - control:SetDimensions(isHalfWidth and width / 2 or width, MIN_HEIGHT) - - control.divider = wm:CreateControlFromVirtual(nil, control, "ZO_Options_Divider") - local divider = control.divider - divider:SetWidth(isHalfWidth and width / 2 or width) - divider:SetAnchor(TOPLEFT) - - control.header = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") - local header = control.header - header:SetAnchor(TOPLEFT, divider, BOTTOMLEFT) - header:SetAnchor(BOTTOMRIGHT) - header:SetText(LAM.util.GetStringFromValue(headerData.name)) - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/iconpicker.lua b/ShowMount/LibAddonMenu-2.0/controls/iconpicker.lua deleted file mode 100644 index 65c7782..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/iconpicker.lua +++ /dev/null @@ -1,436 +0,0 @@ ---[[iconpickerData = { - type = "iconpicker", - name = "My Icon Picker", -- or string id or function returning a string - choices = {"texture path 1", "texture path 2", "texture path 3"}, - getFunc = function() return db.var end, - setFunc = function(var) db.var = var doStuff() end, - tooltip = "Color Picker's tooltip text.", -- or string id or function returning a string (optional) - choicesTooltips = {"icon tooltip 1", "icon tooltip 2", "icon tooltip 3"}, -- or array of string ids or array of functions returning a string (optional) - maxColumns = 5, -- number of icons in one row (optional) - visibleRows = 4.5, -- number of visible rows (optional) - iconSize = 28, -- size of the icons (optional) - defaultColor = ZO_ColorDef:New("FFFFFF"), -- default color of the icons (optional) - width = "full", --or "half" (optional) - beforeShow = function(control, iconPicker) return preventShow end, --(optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonIconPicker" -- unique global reference to control (optional) -} ]] - -local widgetVersion = 8 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("iconpicker", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local IconPickerMenu = ZO_Object:Subclass() -local iconPicker -LAM.util.GetIconPickerMenu = function() - if not iconPicker then - iconPicker = IconPickerMenu:New("LAMIconPicker") - local sceneFragment = LAM:GetAddonSettingsFragment() - ZO_PreHook(sceneFragment, "OnHidden", function() - if not iconPicker.control:IsHidden() then - iconPicker:Clear() - end - end) - end - return iconPicker -end - -function IconPickerMenu:New(...) - local object = ZO_Object.New(self) - object:Initialize(...) - return object -end - -function IconPickerMenu:Initialize(name) - local control = wm:CreateTopLevelWindow(name) - control:SetDrawTier(DT_HIGH) - control:SetHidden(true) - self.control = control - - local scrollContainer = wm:CreateControlFromVirtual(name .. "ScrollContainer", control, "ZO_ScrollContainer") - -- control:SetDimensions(control.container:GetWidth(), height) -- adjust to icon size / col count - scrollContainer:SetAnchorFill() - ZO_Scroll_SetUseFadeGradient(scrollContainer, false) - ZO_Scroll_SetHideScrollbarOnDisable(scrollContainer, false) - ZO_VerticalScrollbarBase_OnMouseExit(scrollContainer:GetNamedChild("ScrollBar")) -- scrollbar initialization seems to be broken so we force it to update the correct alpha value - local scroll = GetControl(scrollContainer, "ScrollChild") - self.scroll = scroll - self.scrollContainer = scrollContainer - - local bg = wm:CreateControl(nil, scrollContainer, CT_BACKDROP) - bg:SetAnchor(TOPLEFT, scrollContainer, TOPLEFT, 0, -3) - bg:SetAnchor(BOTTOMRIGHT, scrollContainer, BOTTOMRIGHT, 2, 5) - bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) - bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") - bg:SetInsets(16, 16, -16, -16) - - local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) - mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") - mungeOverlay:SetDrawLevel(1) - mungeOverlay:SetAddressMode(TEX_MODE_WRAP) - mungeOverlay:SetAnchorFill() - - local mouseOver = wm:CreateControl(nil, scrollContainer, CT_TEXTURE) - mouseOver:SetDrawLevel(2) - mouseOver:SetTexture("EsoUI/Art/Buttons/minmax_mouseover.dds") - mouseOver:SetHidden(true) - - local function IconFactory(pool) - local icon = wm:CreateControl(name .. "Entry" .. pool:GetNextControlId(), scroll, CT_TEXTURE) - icon:SetMouseEnabled(true) - icon:SetDrawLevel(3) - icon:SetHandler("OnMouseEnter", function() - mouseOver:SetAnchor(TOPLEFT, icon, TOPLEFT, 0, 0) - mouseOver:SetAnchor(BOTTOMRIGHT, icon, BOTTOMRIGHT, 0, 0) - mouseOver:SetHidden(false) - if self.customOnMouseEnter then - self.customOnMouseEnter(icon) - else - self:OnMouseEnter(icon) - end - end) - icon:SetHandler("OnMouseExit", function() - mouseOver:ClearAnchors() - mouseOver:SetHidden(true) - if self.customOnMouseExit then - self.customOnMouseExit(icon) - else - self:OnMouseExit(icon) - end - end) - icon:SetHandler("OnMouseUp", function(control, ...) - PlaySound("Click") - icon.OnSelect(icon, icon.texture) - self:Clear() - end) - return icon - end - - local function ResetFunction(icon) - icon:ClearAnchors() - end - - self.iconPool = ZO_ObjectPool:New(IconFactory, ResetFunction) - self:SetMaxColumns(1) - self.icons = {} - self.color = ZO_DEFAULT_ENABLED_COLOR - - EVENT_MANAGER:RegisterForEvent(name .. "_OnGlobalMouseUp", EVENT_GLOBAL_MOUSE_UP, function() - if self.refCount ~= nil then - local moc = wm:GetMouseOverControl() - if(moc:GetOwningWindow() ~= control) then - self.refCount = self.refCount - 1 - if self.refCount <= 0 then - self:Clear() - end - end - end - end) -end - -function IconPickerMenu:OnMouseEnter(icon) - InitializeTooltip(InformationTooltip, icon, TOPLEFT, 0, 0, BOTTOMRIGHT) - SetTooltipText(InformationTooltip, LAM.util.GetStringFromValue(icon.tooltip)) - InformationTooltipTopLevel:BringWindowToTop() -end - -function IconPickerMenu:OnMouseExit(icon) - ClearTooltip(InformationTooltip) -end - -function IconPickerMenu:SetMaxColumns(value) - self.maxCols = value ~= nil and value or 5 -end - -local DEFAULT_SIZE = 28 -function IconPickerMenu:SetIconSize(value) - local iconSize = DEFAULT_SIZE - if value ~= nil then iconSize = math.max(iconSize, value) end - self.iconSize = iconSize -end - -function IconPickerMenu:SetVisibleRows(value) - self.visibleRows = value ~= nil and value or 4.5 -end - -function IconPickerMenu:SetMouseHandlers(onEnter, onExit) - self.customOnMouseEnter = onEnter - self.customOnMouseExit = onExit -end - -function IconPickerMenu:UpdateDimensions() - local iconSize = self.iconSize - local width = iconSize * self.maxCols + 20 - local height = iconSize * self.visibleRows - self.control:SetDimensions(width, height) - - local icons = self.icons - for i = 1, #icons do - local icon = icons[i] - icon:SetDimensions(iconSize, iconSize) - end -end - -function IconPickerMenu:UpdateAnchors() - local iconSize = self.iconSize - local col, maxCols = 1, self.maxCols - local previousCol, previousRow - local scroll = self.scroll - local icons = self.icons - - for i = 1, #icons do - local icon = icons[i] - icon:ClearAnchors() - if i == 1 then - icon:SetAnchor(TOPLEFT, scroll, TOPLEFT, 0, 0) - previousRow = icon - elseif col == 1 then - icon:SetAnchor(TOPLEFT, previousRow, BOTTOMLEFT, 0, 0) - previousRow = icon - else - icon:SetAnchor(TOPLEFT, previousCol, TOPRIGHT, 0, 0) - end - previousCol = icon - col = col >= maxCols and 1 or col + 1 - end -end - -function IconPickerMenu:Clear() - self.icons = {} - self.iconPool:ReleaseAllObjects() - self.control:SetHidden(true) - self.color = ZO_DEFAULT_ENABLED_COLOR - self.refCount = nil - self.parent = nil - self.customOnMouseEnter = nil - self.customOnMouseExit = nil -end - -function IconPickerMenu:AddIcon(texturePath, callback, tooltip) - local icon, key = self.iconPool:AcquireObject() - icon:SetTexture(texturePath) - icon:SetColor(self.color:UnpackRGBA()) - icon.texture = texturePath - icon.tooltip = tooltip - icon.OnSelect = callback - self.icons[#self.icons + 1] = icon -end - -function IconPickerMenu:Show(parent) - if #self.icons == 0 then return false end - if not self.control:IsHidden() then self:Clear() return false end - self:UpdateDimensions() - self:UpdateAnchors() - - local control = self.control - control:ClearAnchors() - control:SetAnchor(TOPLEFT, parent, BOTTOMLEFT, 0, 8) - control:SetHidden(false) - control:BringWindowToTop() - self.parent = parent - self.refCount = 2 - - return true -end - -function IconPickerMenu:SetColor(color) - local icons = self.icons - self.color = color - for i = 1, #icons do - local icon = icons[i] - icon:SetColor(color:UnpackRGBA()) - end -end - -------------------------------------------------------------- - -local function UpdateChoices(control, choices, choicesTooltips) - local data = control.data - if not choices then - choices, choicesTooltips = data.choices, data.choicesTooltips or {} - end - local addedChoices = {} - - local iconPicker = LAM.util.GetIconPickerMenu() - iconPicker:Clear() - for i = 1, #choices do - local texture = choices[i] - if not addedChoices[texture] then -- remove duplicates - iconPicker:AddIcon(choices[i], function(self, texture) - control.icon:SetTexture(texture) - data.setFunc(texture) - LAM.util.RequestRefreshIfNeeded(control) - end, LAM.util.GetStringFromValue(choicesTooltips[i])) - addedChoices[texture] = true - end - end -end - -local function IsDisabled(control) - if type(control.data.disabled) == "function" then - return control.data.disabled() - else - return control.data.disabled - end -end - -local function SetColor(control, color) - local icon = control.icon - if IsDisabled(control) then - icon:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - icon.color = color or control.data.defaultColor or ZO_DEFAULT_ENABLED_COLOR - icon:SetColor(icon.color:UnpackRGBA()) - end - - local iconPicker = LAM.util.GetIconPickerMenu() - if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then - iconPicker:SetColor(icon.color) - end -end - -local function UpdateDisabled(control) - local disable = IsDisabled(control) - - control.dropdown:SetMouseEnabled(not disable) - control.dropdownButton:SetEnabled(not disable) - - local iconPicker = LAM.util.GetIconPickerMenu() - if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then - iconPicker:Clear() - end - - SetColor(control, control.icon.color) - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - control.icon:SetTexture(value) - elseif value then - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - control.icon:SetTexture(value) - end -end - -local MIN_HEIGHT = 26 -local HALF_WIDTH_LINE_SPACING = 2 -local function SetIconSize(control, size) - local icon = control.icon - icon.size = size - icon:SetDimensions(size, size) - - local height = size + 4 - control.dropdown:SetDimensions(size + 20, height) - height = math.max(height, MIN_HEIGHT) - control.container:SetHeight(height) - if control.lineControl then - control.lineControl:SetHeight(MIN_HEIGHT + size + HALF_WIDTH_LINE_SPACING) - else - control:SetHeight(height) - end - - local iconPicker = LAM.util.GetIconPickerMenu() - if iconPicker.parent == control.container and not iconPicker.control:IsHidden() then - iconPicker:SetIconSize(size) - iconPicker:UpdateDimensions() - iconPicker:UpdateAnchors() - end -end - -function LAMCreateControl.iconpicker(parent, iconpickerData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, iconpickerData, controlName) - - local function ShowIconPicker() - local iconPicker = LAM.util.GetIconPickerMenu() - if iconPicker.parent == control.container then - iconPicker:Clear() - else - iconPicker:SetMaxColumns(iconpickerData.maxColumns) - iconPicker:SetVisibleRows(iconpickerData.visibleRows) - iconPicker:SetIconSize(control.icon.size) - UpdateChoices(control) - iconPicker:SetColor(control.icon.color) - if iconpickerData.beforeShow then - if iconpickerData.beforeShow(control, iconPicker) then - iconPicker:Clear() - return - end - end - iconPicker:Show(control.container) - end - end - - local iconSize = iconpickerData.iconSize ~= nil and iconpickerData.iconSize or DEFAULT_SIZE - control.dropdown = wm:CreateControl(nil, control.container, CT_CONTROL) - local dropdown = control.dropdown - dropdown:SetAnchor(LEFT, control.container, LEFT, 0, 0) - dropdown:SetMouseEnabled(true) - dropdown:SetHandler("OnMouseUp", ShowIconPicker) - dropdown:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - dropdown:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - - control.icon = wm:CreateControl(nil, dropdown, CT_TEXTURE) - local icon = control.icon - icon:SetAnchor(LEFT, dropdown, LEFT, 3, 0) - icon:SetDrawLevel(2) - - local dropdownButton = wm:CreateControlFromVirtual(nil, dropdown, "ZO_DropdownButton") - dropdownButton:SetDimensions(16, 16) - dropdownButton:SetHandler("OnClicked", ShowIconPicker) - dropdownButton:SetAnchor(RIGHT, dropdown, RIGHT, -3, 0) - control.dropdownButton = dropdownButton - - control.bg = wm:CreateControl(nil, dropdown, CT_BACKDROP) - local bg = control.bg - bg:SetAnchor(TOPLEFT, dropdown, TOPLEFT, 0, -3) - bg:SetAnchor(BOTTOMRIGHT, dropdown, BOTTOMRIGHT, 2, 5) - bg:SetEdgeTexture("EsoUI/Art/Tooltips/UI-Border.dds", 128, 16) - bg:SetCenterTexture("EsoUI/Art/Tooltips/UI-TooltipCenter.dds") - bg:SetInsets(16, 16, -16, -16) - local mungeOverlay = wm:CreateControl(nil, bg, CT_TEXTURE) - mungeOverlay:SetTexture("EsoUI/Art/Tooltips/munge_overlay.dds") - mungeOverlay:SetDrawLevel(1) - mungeOverlay:SetAddressMode(TEX_MODE_WRAP) - mungeOverlay:SetAnchorFill() - - if iconpickerData.warning ~= nil or iconpickerData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, control.container, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateChoices = UpdateChoices - control.UpdateValue = UpdateValue - control:UpdateValue() - control.SetColor = SetColor - control:SetColor() - control.SetIconSize = SetIconSize - control:SetIconSize(iconSize) - - if iconpickerData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/panel.lua b/ShowMount/LibAddonMenu-2.0/controls/panel.lua deleted file mode 100644 index 1404686..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/panel.lua +++ /dev/null @@ -1,126 +0,0 @@ ---[[panelData = { - type = "panel", - name = "Window Title", -- or string id or function returning a string - displayName = "My Longer Window Title", -- or string id or function returning a string (optional) (can be useful for long addon names or if you want to colorize it) - author = "Seerah", -- or string id or function returning a string (optional) - version = "2.0", -- or string id or function returning a string (optional) - website = "http://www.esoui.com/downloads/info7-LibAddonMenu.html", -- URL of website where the addon can be updated (optional) - keywords = "settings", -- additional keywords for search filter (it looks for matches in name..keywords..author) (optional) - slashCommand = "/myaddon", -- will register a keybind to open to this panel (don't forget to include the slash!) (optional) - registerForRefresh = true, --boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown) - registerForDefaults = true, --boolean (optional) (will set all options controls back to default values) - resetFunc = function() print("defaults reset") end, --(optional) custom function to run after settings are reset to defaults -} ]] - - -local widgetVersion = 13 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("panel", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local cm = CALLBACK_MANAGER - -local function RefreshPanel(control) - local panel = LAM.util.GetTopPanel(control) --callback can be fired by a single control, by the panel showing or by a nested submenu - local panelControls = panel.controlsToRefresh - - for i = 1, #panelControls do - local updateControl = panelControls[i] - if updateControl ~= control and updateControl.UpdateValue then - updateControl:UpdateValue() - end - if updateControl.UpdateDisabled then - updateControl:UpdateDisabled() - end - if updateControl.UpdateWarning then - updateControl:UpdateWarning() - end - end -end - -local function ForceDefaults(panel) - local panelControls = panel.controlsToRefresh - - for i = 1, #panelControls do - local updateControl = panelControls[i] - if updateControl.UpdateValue and updateControl.data.default ~= nil then - updateControl:UpdateValue(true) - end - end - - if panel.data.resetFunc then - panel.data.resetFunc() - end - - cm:FireCallbacks("LAM-RefreshPanel", panel) -end - -local callbackRegistered = false -LAMCreateControl.scrollCount = LAMCreateControl.scrollCount or 1 -local SEPARATOR = " - " -local LINK_COLOR = ZO_ColorDef:New("5959D5") -local LINK_MOUSE_OVER_COLOR = ZO_ColorDef:New("B8B8D3") - -function LAMCreateControl.panel(parent, panelData, controlName) - local control = wm:CreateControl(controlName, parent, CT_CONTROL) - - control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") - local label = control.label - label:SetAnchor(TOPLEFT, control, TOPLEFT, 0, 4) - label:SetText(LAM.util.GetStringFromValue(panelData.displayName or panelData.name)) - - if panelData.author or panelData.version then - control.info = wm:CreateControl(nil, control, CT_LABEL) - local info = control.info - info:SetFont(LAM.util.L["PANEL_INFO_FONT"]) - info:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) - - local output = {} - if panelData.author then - output[#output + 1] = zo_strformat(LAM.util.L["AUTHOR"], LAM.util.GetStringFromValue(panelData.author)) - end - if panelData.version then - output[#output + 1] = zo_strformat(LAM.util.L["VERSION"], LAM.util.GetStringFromValue(panelData.version)) - end - info:SetText(table.concat(output, SEPARATOR)) - end - - if panelData.website then - control.website = wm:CreateControl(nil, control, CT_BUTTON) - local website = control.website - website:SetClickSound("Click") - website:SetFont(LAM.util.L["PANEL_INFO_FONT"]) - website:SetNormalFontColor(LINK_COLOR:UnpackRGBA()) - website:SetMouseOverFontColor(LINK_MOUSE_OVER_COLOR:UnpackRGBA()) - if(control.info) then - website:SetAnchor(TOPLEFT, control.info, TOPRIGHT, 0, 0) - website:SetText(string.format("|cffffff%s|r%s", SEPARATOR, LAM.util.L["WEBSITE"])) - else - website:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, -2) - website:SetText(LAM.util.L["WEBSITE"]) - end - website:SetDimensions(website:GetLabelControl():GetTextDimensions()) - website:SetHandler("OnClicked", function() - RequestOpenUnsafeURL(panelData.website) - end) - end - - control.container = wm:CreateControlFromVirtual("LAMAddonPanelContainer"..LAMCreateControl.scrollCount, control, "ZO_ScrollContainer") - LAMCreateControl.scrollCount = LAMCreateControl.scrollCount + 1 - local container = control.container - container:SetAnchor(TOPLEFT, control.info or label, BOTTOMLEFT, 0, 20) - container:SetAnchor(BOTTOMRIGHT, control, BOTTOMRIGHT, -3, -3) - control.scroll = GetControl(control.container, "ScrollChild") - control.scroll:SetResizeToFitPadding(0, 20) - - if panelData.registerForRefresh and not callbackRegistered then --don't want to register our callback more than once - cm:RegisterCallback("LAM-RefreshPanel", RefreshPanel) - callbackRegistered = true - end - - control.ForceDefaults = ForceDefaults - control.data = panelData - control.controlsToRefresh = {} - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/slider.lua b/ShowMount/LibAddonMenu-2.0/controls/slider.lua deleted file mode 100644 index bd721c5..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/slider.lua +++ /dev/null @@ -1,212 +0,0 @@ ---[[sliderData = { - type = "slider", - name = "My Slider", -- or string id or function returning a string - getFunc = function() return db.var end, - setFunc = function(value) db.var = value doStuff() end, - min = 0, - max = 20, - step = 1, --(optional) - clampInput = true, -- boolean, if set to false the input won't clamp to min and max and allow any number instead (optional) - decimals = 0, -- when specified the input value is rounded to the specified number of decimals (optional) - autoSelect = false, -- boolean, automatically select everything in the text input field when it gains focus (optional) - inputLocation = "below", -- or "right", determines where the input field is shown. This should not be used within the addon menu and is for custom sliders (optional) - tooltip = "Slider's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - disabled = function() return db.someBooleanSetting end, --or boolean (optional) - warning = "May cause permanent awesomeness.", -- or string id or function returning a string (optional) - requiresReload = false, -- boolean, if set to true, the warning text will contain a notice that changes are only applied after an UI reload and any change to the value will make the "Apply Settings" button appear on the panel which will reload the UI when pressed (optional) - default = defaults.var, -- default value or function that returns the default value (optional) - reference = "MyAddonSlider" -- unique global reference to control (optional) -} ]] - -local widgetVersion = 12 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("slider", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local strformat = string.format - -local function RoundDecimalToPlace(d, place) - return tonumber(strformat("%." .. tostring(place) .. "f", d)) -end - -local function UpdateDisabled(control) - local disable - if type(control.data.disabled) == "function" then - disable = control.data.disabled() - else - disable = control.data.disabled - end - - control.slider:SetEnabled(not disable) - control.slidervalue:SetEditEnabled(not disable) - if disable then - control.label:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.minText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.maxText:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGBA()) - control.slidervalue:SetColor(ZO_DEFAULT_DISABLED_MOUSEOVER_COLOR:UnpackRGBA()) - else - control.label:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.minText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.maxText:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - control.slidervalue:SetColor(ZO_DEFAULT_ENABLED_COLOR:UnpackRGBA()) - end -end - -local function UpdateValue(control, forceDefault, value) - if forceDefault then --if we are forcing defaults - value = LAM.util.GetDefaultValue(control.data.default) - control.data.setFunc(value) - elseif value then - if control.data.decimals then - value = RoundDecimalToPlace(value, control.data.decimals) - end - if control.data.clampInput ~= false then - value = math.max(math.min(value, control.data.max), control.data.min) - end - control.data.setFunc(value) - --after setting this value, let's refresh the others to see if any should be disabled or have their settings changed - LAM.util.RequestRefreshIfNeeded(control) - else - value = control.data.getFunc() - end - - control.slider:SetValue(value) - control.slidervalue:SetText(value) -end - -function LAMCreateControl.slider(parent, sliderData, controlName) - local control = LAM.util.CreateLabelAndContainerControl(parent, sliderData, controlName) - local isInputOnRight = sliderData.inputLocation == "right" - - --skipping creating the backdrop... Is this the actual slider texture? - control.slider = wm:CreateControl(nil, control.container, CT_SLIDER) - local slider = control.slider - slider:SetAnchor(TOPLEFT) - slider:SetHeight(14) - if(isInputOnRight) then - slider:SetAnchor(TOPRIGHT, nil, nil, -60) - else - slider:SetAnchor(TOPRIGHT) - end - slider:SetMouseEnabled(true) - slider:SetOrientation(ORIENTATION_HORIZONTAL) - --put nil for highlighted texture file path, and what look to be texture coords - slider:SetThumbTexture("EsoUI\\Art\\Miscellaneous\\scrollbox_elevator.dds", "EsoUI\\Art\\Miscellaneous\\scrollbox_elevator_disabled.dds", nil, 8, 16) - local minValue = sliderData.min - local maxValue = sliderData.max - slider:SetMinMax(minValue, maxValue) - slider:SetHandler("OnMouseEnter", function() ZO_Options_OnMouseEnter(control) end) - slider:SetHandler("OnMouseExit", function() ZO_Options_OnMouseExit(control) end) - - slider.bg = wm:CreateControl(nil, slider, CT_BACKDROP) - local bg = slider.bg - bg:SetCenterColor(0, 0, 0) - bg:SetAnchor(TOPLEFT, slider, TOPLEFT, 0, 4) - bg:SetAnchor(BOTTOMRIGHT, slider, BOTTOMRIGHT, 0, -4) - bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-SliderBackdrop.dds", 32, 4) - - control.minText = wm:CreateControl(nil, slider, CT_LABEL) - local minText = control.minText - minText:SetFont("ZoFontGameSmall") - minText:SetAnchor(TOPLEFT, slider, BOTTOMLEFT) - minText:SetText(sliderData.min) - - control.maxText = wm:CreateControl(nil, slider, CT_LABEL) - local maxText = control.maxText - maxText:SetFont("ZoFontGameSmall") - maxText:SetAnchor(TOPRIGHT, slider, BOTTOMRIGHT) - maxText:SetText(sliderData.max) - - control.slidervalueBG = wm:CreateControlFromVirtual(nil, slider, "ZO_EditBackdrop") - if(isInputOnRight) then - control.slidervalueBG:SetDimensions(60, 26) - control.slidervalueBG:SetAnchor(LEFT, slider, RIGHT, 5, 0) - else - control.slidervalueBG:SetDimensions(50, 16) - control.slidervalueBG:SetAnchor(TOP, slider, BOTTOM, 0, 0) - end - control.slidervalue = wm:CreateControlFromVirtual(nil, control.slidervalueBG, "ZO_DefaultEditForBackdrop") - local slidervalue = control.slidervalue - slidervalue:ClearAnchors() - slidervalue:SetAnchor(TOPLEFT, control.slidervalueBG, TOPLEFT, 3, 1) - slidervalue:SetAnchor(BOTTOMRIGHT, control.slidervalueBG, BOTTOMRIGHT, -3, -1) - slidervalue:SetTextType(TEXT_TYPE_NUMERIC) - if(isInputOnRight) then - slidervalue:SetFont("ZoFontGameLarge") - else - slidervalue:SetFont("ZoFontGameSmall") - end - - local isHandlingChange = false - local function HandleValueChanged(value) - if isHandlingChange then return end - if sliderData.decimals then - value = RoundDecimalToPlace(value, sliderData.decimals) - end - isHandlingChange = true - slider:SetValue(value) - slidervalue:SetText(value) - isHandlingChange = false - end - - slidervalue:SetHandler("OnEscape", function(self) - HandleValueChanged(sliderData.getFunc()) - self:LoseFocus() - end) - slidervalue:SetHandler("OnEnter", function(self) - self:LoseFocus() - end) - slidervalue:SetHandler("OnFocusLost", function(self) - local value = tonumber(self:GetText()) - control:UpdateValue(false, value) - end) - slidervalue:SetHandler("OnTextChanged", function(self) - local input = self:GetText() - if(#input > 1 and not input:sub(-1):match("[0-9]")) then return end - local value = tonumber(input) - if(value) then - HandleValueChanged(value) - end - end) - if(sliderData.autoSelect) then - ZO_PreHookHandler(slidervalue, "OnFocusGained", function(self) - self:SelectAll() - end) - end - - local range = maxValue - minValue - slider:SetValueStep(sliderData.step or 1) - slider:SetHandler("OnValueChanged", function(self, value, eventReason) - if eventReason == EVENT_REASON_SOFTWARE then return end - HandleValueChanged(value) - end) - slider:SetHandler("OnSliderReleased", function(self, value) - control:UpdateValue(false, value) - end) - slider:SetHandler("OnMouseWheel", function(self, value) - if(not self:GetEnabled()) then return end - local new_value = (tonumber(slidervalue:GetText()) or sliderData.min or 0) + ((sliderData.step or 1) * value) - control:UpdateValue(false, new_value) - end) - - if sliderData.warning ~= nil or sliderData.requiresReload then - control.warning = wm:CreateControlFromVirtual(nil, control, "ZO_Options_WarningIcon") - control.warning:SetAnchor(RIGHT, slider, LEFT, -5, 0) - control.UpdateWarning = LAM.util.UpdateWarning - control:UpdateWarning() - end - - control.UpdateValue = UpdateValue - control:UpdateValue() - - if sliderData.disabled ~= nil then - control.UpdateDisabled = UpdateDisabled - control:UpdateDisabled() - end - - LAM.util.RegisterForRefreshIfNeeded(control) - LAM.util.RegisterForReloadIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/submenu.lua b/ShowMount/LibAddonMenu-2.0/controls/submenu.lua deleted file mode 100644 index 1766a1f..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/submenu.lua +++ /dev/null @@ -1,108 +0,0 @@ ---[[submenuData = { - type = "submenu", - name = "Submenu Title", -- or string id or function returning a string - tooltip = "My submenu tooltip", -- -- or string id or function returning a string (optional) - controls = {sliderData, buttonData} --(optional) used by LAM - reference = "MyAddonSubmenu" --(optional) unique global reference to control -} ]] - -local widgetVersion = 11 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("submenu", widgetVersion) then return end - -local wm = WINDOW_MANAGER -local am = ANIMATION_MANAGER - -local function UpdateValue(control) - control.label:SetText(LAM.util.GetStringFromValue(control.data.name)) - if control.data.tooltip then - control.label.data.tooltipText = LAM.util.GetStringFromValue(control.data.tooltip) - end -end - -local function AnimateSubmenu(clicked) - local control = clicked:GetParent() - control.open = not control.open - - if control.open then - control.animation:PlayFromStart() - else - control.animation:PlayFromEnd() - end -end - -function LAMCreateControl.submenu(parent, submenuData, controlName) - local width = parent:GetWidth() - 45 - local control = wm:CreateControl(controlName or submenuData.reference, parent.scroll or parent, CT_CONTROL) - control.panel = parent - control.data = submenuData - - control.label = wm:CreateControlFromVirtual(nil, control, "ZO_Options_SectionTitleLabel") - local label = control.label - label:SetAnchor(TOPLEFT, control, TOPLEFT, 5, 5) - label:SetDimensions(width, 30) - label:SetWrapMode(TEXT_WRAP_MODE_ELLIPSIS) - label:SetText(LAM.util.GetStringFromValue(submenuData.name)) - label:SetMouseEnabled(true) - if submenuData.tooltip then - label.data = {tooltipText = LAM.util.GetStringFromValue(submenuData.tooltip)} - label:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - label:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - end - - control.scroll = wm:CreateControl(nil, control, CT_SCROLL) - local scroll = control.scroll - scroll:SetParent(control) - scroll:SetAnchor(TOPLEFT, label, BOTTOMLEFT, 0, 10) - scroll:SetDimensionConstraints(width + 5, 0, width + 5, 0) - - control.bg = wm:CreateControl(nil, label, CT_BACKDROP) - local bg = control.bg - bg:SetAnchor(TOPLEFT, label, TOPLEFT, -5, -5) - bg:SetAnchor(BOTTOMRIGHT, scroll, BOTTOMRIGHT, -7, 0) - bg:SetEdgeTexture("EsoUI\\Art\\Tooltips\\UI-Border.dds", 128, 16) - bg:SetCenterTexture("EsoUI\\Art\\Tooltips\\UI-TooltipCenter.dds") - bg:SetInsets(16, 16, -16, -16) - - control.arrow = wm:CreateControl(nil, bg, CT_TEXTURE) - local arrow = control.arrow - arrow:SetDimensions(28, 28) - arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") --list_sortup for the other way - arrow:SetAnchor(TOPRIGHT, bg, TOPRIGHT, -5, 5) - - --figure out the cool animation later... - control.animation = am:CreateTimeline() - local animation = control.animation - animation:SetPlaybackType(ANIMATION_SIZE, 0) --2nd arg = loop count - - control:SetResizeToFitDescendents(true) - control.open = false - label:SetHandler("OnMouseUp", AnimateSubmenu) - animation:SetHandler("OnStop", function(self, completedPlaying) - scroll:SetResizeToFitDescendents(control.open) - if control.open then - control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortup.dds") - scroll:SetResizeToFitPadding(5, 20) - else - control.arrow:SetTexture("EsoUI\\Art\\Miscellaneous\\list_sortdown.dds") - scroll:SetResizeToFitPadding(5, 0) - scroll:SetHeight(0) - end - end) - - --small strip at the bottom of the submenu that you can click to close it - control.btmToggle = wm:CreateControl(nil, control, CT_TEXTURE) - local btmToggle = control.btmToggle - btmToggle:SetMouseEnabled(true) - btmToggle:SetAnchor(BOTTOMLEFT, control.scroll, BOTTOMLEFT) - btmToggle:SetAnchor(BOTTOMRIGHT, control.scroll, BOTTOMRIGHT) - btmToggle:SetHeight(15) - btmToggle:SetAlpha(0) - btmToggle:SetHandler("OnMouseUp", AnimateSubmenu) - - control.UpdateValue = UpdateValue - - LAM.util.RegisterForRefreshIfNeeded(control) - - return control -end diff --git a/ShowMount/LibAddonMenu-2.0/controls/texture.lua b/ShowMount/LibAddonMenu-2.0/controls/texture.lua deleted file mode 100644 index 29dda7c..0000000 --- a/ShowMount/LibAddonMenu-2.0/controls/texture.lua +++ /dev/null @@ -1,45 +0,0 @@ ---[[textureData = { - type = "texture", - image = "file/path.dds", - imageWidth = 64, --max of 250 for half width, 510 for full - imageHeight = 32, --max of 100 - tooltip = "Image's tooltip text.", -- or string id or function returning a string (optional) - width = "full", --or "half" (optional) - reference = "MyAddonTexture" --(optional) unique global reference to control -} ]] - ---add texture coords support? - -local widgetVersion = 9 -local LAM = LibStub("LibAddonMenu-2.0") -if not LAM:RegisterWidget("texture", widgetVersion) then return end - -local wm = WINDOW_MANAGER - -local MIN_HEIGHT = 26 -function LAMCreateControl.texture(parent, textureData, controlName) - local control = LAM.util.CreateBaseControl(parent, textureData, controlName) - local width = control:GetWidth() - control:SetResizeToFitDescendents(true) - - if control.isHalfWidth then --note these restrictions - control:SetDimensionConstraints(width / 2, MIN_HEIGHT, width / 2, MIN_HEIGHT * 4) - else - control:SetDimensionConstraints(width, MIN_HEIGHT, width, MIN_HEIGHT * 4) - end - - control.texture = wm:CreateControl(nil, control, CT_TEXTURE) - local texture = control.texture - texture:SetAnchor(CENTER) - texture:SetDimensions(textureData.imageWidth, textureData.imageHeight) - texture:SetTexture(textureData.image) - - if textureData.tooltip then - texture:SetMouseEnabled(true) - texture.data = {tooltipText = LAM.util.GetStringFromValue(textureData.tooltip)} - texture:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter) - texture:SetHandler("OnMouseExit", ZO_Options_OnMouseExit) - end - - return control -end diff --git a/ShowMount/LibStub/LibStub.lua b/ShowMount/LibStub/LibStub.lua deleted file mode 100644 index 0e6bf67..0000000 --- a/ShowMount/LibStub/LibStub.lua +++ /dev/null @@ -1,38 +0,0 @@ --- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info --- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke --- LibStub developed for World of Warcraft by above members of the WowAce community. --- Ported to Elder Scrolls Online by Seerah - -local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 4 -local LibStub = _G[LIBSTUB_MAJOR] - -local strformat = string.format -if not LibStub or LibStub.minor < LIBSTUB_MINOR then - LibStub = LibStub or {libs = {}, minors = {} } - _G[LIBSTUB_MAJOR] = LibStub - LibStub.minor = LIBSTUB_MINOR - - function LibStub:NewLibrary(major, minor) - assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") - if type(minor) ~= "number" then - minor = assert(tonumber(zo_strmatch(minor, "%d+%.?%d*")), "Minor version must either be a number or contain a number.") - end - - local oldminor = self.minors[major] - if oldminor and oldminor >= minor then return nil end - self.minors[major], self.libs[major] = minor, self.libs[major] or {} - return self.libs[major], oldminor - end - - function LibStub:GetLibrary(major, silent) - if not self.libs[major] and not silent then - error(strformat("Cannot find a library instance of %q.", tostring(major)), 2) - end - return self.libs[major], self.minors[major] - end - - function LibStub:IterateLibraries() return pairs(self.libs) end - setmetatable(LibStub, { __call = LibStub.GetLibrary }) -end - -LibStub.SILENT = true \ No newline at end of file diff --git a/StartConsole.py b/StartConsole.py index cb6b290..f1b2e51 100644 --- a/StartConsole.py +++ b/StartConsole.py @@ -1,84 +1,108 @@ -""" -This script idles in the background, -listening to gamepad (XBox One Controller) button presses, -to activate or bring-to-front RetroArch in Windows 10. -""" - -import inputs -from time import sleep, time -import os -import win32gui - -DEBUG = False - -delay = 3 # Don't repeat anything faster than this in seconds. -t = 0 - -# Press down all four front buttons to activate. -toggles = { - "BTN_TR": 0, - "BTN_TL": 0, - "ABS_RZ": 0, - "ABS_Z": 0, -} - -windowName = "RetroArch" -processName = "retroarch.exe" -handle = None - -if DEBUG: - windowName = "Untitled - Notepad" - processName = "notepad.exe" - - -# Return hwnd or None. -def enumHandler(hwnd, lParam): - global handle - - if "RetroArch" in win32gui.GetWindowText(hwnd): - handle = hwnd - - -while True: - # No gamepads connected. Must have one. - if len(inputs.devices.gamepads) == 0: - DEBUG and print('No gamepads connected.') - sleep(delay) - inputs.devices._detect_gamepads() - continue - - # Only the first gamepad to register will catch. - try: - gamepad = inputs.devices.gamepads[0] - events = gamepad.read() - except Exception as e: - DEBUG and print(e) - # Try again. - continue - - for e in events: - if e.code in toggles: - toggles[e.code] = e.state - - # Check if all 4 are down. - if all(v != 0 for v in toggles.values()): - # Don't retry too fast. - if time() - t < 3: - continue - - # Check if RetroArch isn't running. - lst = os.popen("tasklist").read() # Long string of all procs. - - if processName not in lst: - os.startfile(processName) - else: - # Find window. - win32gui.EnumWindows(enumHandler, None) - # Bring to front. - if handle: - win32gui.SetForegroundWindow(handle) - # Reset hwnd. - handle = None - - # Reset timer. - t = time() +""" +This script idles in the background, +listening to gamepad (XBox One Controller) button presses, +to activate or bring-to-front RetroArch in Windows 10. +""" + +import inputs +from time import sleep, time +import os +import win32gui + +DEBUG = False + +delay = 5 # Don't repeat anything faster than this in seconds. +t = 0 + +# Press down all four front buttons to activate. +toggles = { + "BTN_TR": 0, + "BTN_TL": 0, + "ABS_RZ": 0, + "ABS_Z": 0, +} + +windowName = "RetroArch" +processName = "retroarch.exe" +handle = None +activated = False + +if DEBUG: + windowName = "Untitled - Notepad" + processName = "notepad.exe" + + +# Return hwnd or None. +def enumHandler(hwnd, lParam): + global handle + + if "RetroArch" in win32gui.GetWindowText(hwnd): + handle = hwnd + +# Load or bring process forward. + + +def getProcess(): + global processName, handle + + # Check if RetroArch isn't running. + # Long string of all procs. + lst = os.popen("tasklist").read() + + if processName not in lst: + os.startfile(processName) + else: + try: + # Find window. + win32gui.EnumWindows(enumHandler, None) + # Bring to front. + if handle: + win32gui.SetForegroundWindow(handle) + # Reset hwnd. + handle = None + except Exception as e: + print(e) + +# Check if the corrent button combination is pressed on a gamepad, +# and start or bring the process forward. + + +def checkGamepads(events): + for e in events: + if e.code in toggles: + print(e.code, e.state) + toggles[e.code] = e.state + + # Check if all 4 are down. + if all(v != 0 for v in toggles.values()): + # Avoid repetition by resetting the tracker. + for k, v in toggles.items(): + toggles[k] = 0 + print('starting!') + getProcess() + + +# Track pressed gamepad buttons. +# Refresh tracker every interval. +while True: + # No gamepads connected. Wait and retry. + if len(inputs.devices.gamepads) == 0: + DEBUG and print('No gamepads connected.') + sleep(delay) + inputs.devices._detect_gamepads() + continue + + # Reduce CPU usage. + sleep(0.01) + + # Check every gamepad. + for gamepad in inputs.devices.gamepads: + try: + events = gamepad.read() + except Exception as e: + DEBUG and print(e) + # Reset detected gamepads. + inputs.devices.gamepads = [] + break + + checkGamepads(events) diff --git a/cleanup.bat b/cleanup.bat index 779178d..3802119 100644 --- a/cleanup.bat +++ b/cleanup.bat @@ -1,2 +1,4 @@ +REM Deletes files older than 7 days, in my security video recording folder. + CD /D "%userprofile%\Videos\Captures\video\C615" -start cmd /c for %%G in (.mp4, .jpg) do forfiles -s -m *%%G -d -0 -c "cmd /c del @path" +start cmd /c for %%G in (.mp4, .jpg) do forfiles -s -m *%%G -d -7 -c "cmd /c del @path" diff --git a/click.ahk b/click.ahk new file mode 100644 index 0000000..ba71bcd --- /dev/null +++ b/click.ahk @@ -0,0 +1,45 @@ +#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. +; #Warn ; Enable warnings to assist with detecting common errors. +SendMode Input ; Recommended for new scripts due to its superior speed and reliability. +SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. + +#MaxThreadsPerHotkey 2 + +MsgBox, 0, Functions, F1 - Click`nF2 - Hold Click`nF3 - Random E Key`nF4 - Random Clicking, 3 + +F1::Click +;F2::RButton +F2::Click down + +F3:: +ToggleE := !ToggleE +Loop +{ + If not ToggleE + break + + Random,rand, 838, 2292 + Sleep rand + Send e +} +return + +F4:: +Toggle := !Toggle +Loop +{ + If not Toggle + break + + Random,rand, 348, 1492 + Sleep rand + Click +} +return + +F5::ExitApp + +;New World +;ahk_class CryENGINE +;ahk_exe Javelin_x64.exe +;ahk_pid 4220 \ No newline at end of file diff --git a/lock_at_night.bat b/lock_at_night.bat new file mode 100644 index 0000000..7c9217e --- /dev/null +++ b/lock_at_night.bat @@ -0,0 +1,13 @@ +@echo off + +title LockAtNight +nircmd.exe win hide ititle "LockAtNight" + +SET hour=%time:~0,2% +SET shouldrun=False + +IF %hour% GEQ 0 IF %hour% LEQ 08 SET shouldrun=True + +IF "%shouldrun%"=="True" ( + C:\nircmd-x64\nircmd.exe monitor off +) diff --git a/mac_copypaste.ahk b/mac_copypaste.ahk new file mode 100644 index 0000000..ba34400 --- /dev/null +++ b/mac_copypaste.ahk @@ -0,0 +1,12 @@ +#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. +; #Warn ; Enable warnings to assist with detecting common errors. +SendMode Input ; Recommended for new scripts due to its superior speed and reliability. +SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. + +#MaxThreadsPerHotkey 2 + +MsgBox, 0, Functions, Copy Paste Cut with the Alt key, 3 + +!c::Send, ^c +!v::Send, ^v +!x::Send, ^x \ No newline at end of file diff --git a/~nwn2_camera_hold_x.ahk b/~nwn2_camera_hold_x.ahk new file mode 100644 index 0000000..b5bbc5b --- /dev/null +++ b/~nwn2_camera_hold_x.ahk @@ -0,0 +1,28 @@ +#Requires AutoHotkey v2.0 + +SendMode('Event') + +toggle := 0 + +ToggleX() +{ + global toggle + + Click 'X ' ((toggle := !toggle) ? 'down' : 'up') +} + +#HotIf WinActive("ahk_exe nwn2.exe") +; Override clicking X with a hold toggle of X +X:: +{ + ToggleX() +} + +; Release the toggle on Left Mouse Button click +~LButton:: +{ + if (toggle) { + ToggleX() + } +} +#HotIf