--------------------------------------------------------------- -- Intellisense --------------------------------------------------------------- -- Context-aware bridge module for other internal modules, -- processing based on multiple factors in an isolated sandbox. local _, db = ...; local L = db.Locale; local Intellisense = db:Register('Intellisense', {}) local Intellinode = {}; function Intellisense:OnHintsFocus() if db('mouseHandlingEnabled') then db.Mouse:SetCameraControl() end end function Intellisense:OnNodeLeave() self.dressupItem = nil; self.bagLocation = nil; self.itemLocation = nil; self.inventorySlotID = nil; end db:RegisterCallback('OnHintsFocus', Intellisense.OnHintsFocus, Intellisense) function Intellisense:ProcessInterfaceCursorEvent(button, down, node) if (down == false) then if node and node:IsObjectType('EditBox') then if node:HasFocus() then node:ClearFocus() else node:SetFocus() end elseif self.inventorySlotID then Intellinode.OnInventoryButtonModifiedClick(node, 'LeftButton') return true; elseif self.dressupItem then Intellinode.OnDressupButtonModifiedClick(node, 'LeftButton') return true; elseif self.itemLocation then db.ItemMenu:SetItem(self.itemLocation:GetBagAndSlot()) elseif self.bagLocation then PickupBagFromSlot(self.bagLocation) elseif db.Utility:HasPendingAction() then return db.Utility:PostPendingAction() end end end function Intellisense:ProcessInterfaceClickEvent(script, node) if (script == 'OnMouseUp') then if GetCursorInfo() then local isActionButton = (node:IsProtected() and node:GetAttribute('type') == 'action') local actionID = isActionButton and (node.CalculateAction and node:CalculateAction() or node:GetAttribute('action')) if actionID then PlaceAction(actionID) return true; end elseif self:IsModifiedClick() then -- HACK: identify a container slot button if (node.UpdateTooltip and node.UpdateTooltip == ContainerFrameItemButton_OnUpdate) then Intellinode.OnContainerButtonModifiedClick(node, 'LeftButton') return true; end end end end function Intellisense:IsModifiedClick() return next(db.Gamepad:GetModifiersHeld()) ~= nil; end --------------------------------------------------------------- -- Special handling for container item buttons --------------------------------------------------------------- do local IsWidget, GetID, GetParent, GetScript = C_Widget.IsFrameWidget, UIParent.GetID, UIParent.GetParent, UIParent.GetScript; local TryIdentifyContainerSlot = CPAPI.IsRetailVersion and function(node) return node.UpdateTooltip == ContainerFrameItemButton_OnUpdate; end or function(node) return node.UpdateTooltip == ContainerFrameItemButton_OnEnter; end local TryIdentifyContainerBag = function(node) return GetScript(node, 'OnEnter') == ContainerFramePortraitButton_OnEnter and GetID(node) ~= 0; end function Intellisense:GetItemLocationFromNode(node) return IsWidget(node) and TryIdentifyContainerSlot(node) and ItemLocation:CreateFromBagAndSlot(GetID(GetParent(node)), GetID(node)) or nil; end function Intellisense:GetBagLocationFromNode(node) return IsWidget(node) and TryIdentifyContainerBag(node) and ContainerIDToInventoryID(node:GetID()); end end --------------------------------------------------------------- -- Prompts --------------------------------------------------------------- function Intellisense:GetSpecialActionPrompt(text) local device = db('Gamepad/Active') return device and device:GetTooltipButtonPrompt( db('Settings/UICursorSpecial'), L(text), 64 ); end function Intellisense:SetPendingItemMenu(tooltip, itemLocation) self.itemLocation = itemLocation; local prompt = self:GetSpecialActionPrompt(OPTIONS) if prompt then tooltip:AddLine(prompt) tooltip:Show() end end function Intellisense:SetPendingBagPickup(tooltip, bagLocation) self.bagLocation = bagLocation; local prompt = self:GetSpecialActionPrompt(L'Pickup') if prompt then tooltip:AddLine(prompt) tooltip:Show() end end function Intellisense:SetPendingActionToUtilityRing(tooltip, owner, action) if owner.ignoreUtilityRing then return end self.pendingAction = action; if db.Utility:SetPendingAction(1, action) then if tooltip then local prompt = self:GetSpecialActionPrompt('Add to Utility Ring') if prompt then tooltip:AddLine(prompt) tooltip:Show() end end else local _, existingIndex = db.Utility:IsUniqueAction(1, action) if existingIndex then db.Utility:SetPendingRemove(1, action) if tooltip then local prompt = self:GetSpecialActionPrompt('Remove from Utility Ring') if prompt then tooltip:AddLine(prompt) tooltip:Show() end end end end end function Intellisense:SetPendingDressupItem(tooltip, item) self.dressupItem = item; if tooltip then local prompt = self:GetSpecialActionPrompt(INSPECT) if prompt then tooltip:AddLine(prompt) tooltip:Show() end end end function Intellisense:SetPendingInspectItem(tooltip, item) if tonumber(item) then self.inventorySlotID = item; if tooltip then local prompt = self:GetSpecialActionPrompt(('%s / %s'):format(INSPECT, SOCKET_GEMS)) if prompt then tooltip:AddLine(prompt) tooltip:Show() end end return end end GameTooltip:HookScript('OnTooltipSetItem', function(self) local owner = self:GetOwner() if not InCombatLockdown() and db.Cursor:IsCurrentNode(owner) then local itemLocation = Intellisense:GetItemLocationFromNode(owner) if itemLocation then return Intellisense:SetPendingItemMenu(self, itemLocation) end local bagLocation = Intellisense:GetBagLocationFromNode(owner) if bagLocation then return Intellisense:SetPendingBagPickup(self, bagLocation) end local name, link = self:GetItem() local numOwned = GetItemCount(link) local isEquipped = IsEquippedItem(link) local isEquippable = IsEquippableItem(link) if ( GetItemSpell(link) and numOwned > 0 ) then Intellisense:SetPendingActionToUtilityRing(self, owner, { type = 'item', item = link, link = link }); elseif isEquippable and not isEquipped then Intellisense:SetPendingDressupItem(self, link); elseif isEquippable and isEquipped then Intellisense:SetPendingInspectItem(self, owner:GetID()) end end end) GameTooltip:HookScript('OnTooltipSetSpell', function(self) local owner = self:GetOwner() if not InCombatLockdown() and db.Cursor:IsCurrentNode(owner) then local name, spellID = self:GetSpell() if spellID and not IsPassiveSpell(spellID) then local isKnown = IsSpellKnown(spellID) if not isKnown then local mountID = CPAPI.GetMountFromSpell(spellID) if mountID then isKnown = (select(11, CPAPI.GetMountInfoByID(mountID))) spellID = name; end end if isKnown then Intellisense:SetPendingActionToUtilityRing(self, owner, { type = 'spell', spell = spellID, link = GetSpellLink(spellID) }); end end end end) GameTooltip:HookScript('OnHide', function(self) if self.pendingAction then db.Utility:ClearPendingAction() self.pendingAction = nil; end end) --------------------------------------------------------------- -- Node --------------------------------------------------------------- local function WrappedExecute(func, execEnv, ...) local env = getfenv(func) setfenv(func, setmetatable(execEnv, {__index = env})) func(...) setfenv(func, env) end function Intellinode:OnContainerButtonModifiedClick(...) WrappedExecute(ContainerFrameItemButton_OnModifiedClick, { IsModifiedClick = function(action) return db.Gamepad:GetModifierHeld(GetModifiedClick(action)) end; }, self, ...) end function Intellinode:OnDressupButtonModifiedClick() WrappedExecute(HandleModifiedItemClick, { IsModifiedClick = function(action) if (action == 'CHATLINK') then return false; elseif (action == 'DRESSUP') then return true; end end; }, Intellisense.dressupItem) Intellisense.dressupItem = nil; end function Intellinode:OnInventoryButtonModifiedClick() WrappedExecute(PaperDollItemSlotButton_OnModifiedClick, { IsModifiedClick = function(action) if (action == 'EXPANDITEM') then return true; end end; }, self) if not GetSocketItemInfo() then WrappedExecute(HandleModifiedItemClick, { IsModifiedClick = function(action) if (action == 'CHATLINK') then return false; elseif (action == 'DRESSUP') then return true; end end; }, GetInventoryItemLink('player', self:GetID())) end end