-------------------------------------------------------------------------- -- MobileFrames.lua -------------------------------------------------------------------------- --[[ Mobile Minimap Buttons By: AnduinLothar Makes the Minimap Buttons draggable around the minimap with adjustable angle. Control-Drag to change angle. Control-Right-Click to bring up menu. Menu: Reset, Reset All, Disable. Possible ToDo: Shift-Ctrl-Drag to change radius. Change Log: v1.71 -Changed the radius calculation to make compatible with AddOns that allow changes to the radius setting of their buttons e.g. Gatherer, AlphaMap -Updated the API.txt v1.7 -Now automaticly makes mobile the following addon buttons: Soundtrack, Cirk's Blessings, CritLine, AlphaMap, and Natur EnemyCastBar. v1.6 -Changed dragging and reset menu to control click to avoid conflict with battlegrounds button -Fixed bug that wasn't saving posistions of icons unless you tapped them v1.52 -Updated TOC to 11100 -Fixed Census button mask. v1.51 -New Buttons are now Anchored when first made mobile. (Fixed OnLoad error with Atlas) -Updated German Localization v1.5 (1/15/06) -Fixed Shift-OnClick option overridding to still work for clicks under half a second. (Fixes battleground minimap) -Now automaticly makes mobile the following addon buttons: Atlas, CTRA, Wardrobe, Yatlas, Gatherer, Earth, IEF, CTA. (Addon Buttons are only on English client until localized.) v1.4 (1/4/06) -Disabled OnDrag events of registered addon buttons (Wardrobe now correctly stops dragging) -Fixed nil OnLoad bug by delaying frame loading until after PLAYER_ENTERING_WORLD on a fresh load -Updated TOC to 10900 v1.3 (11/24/05) -Dynamicly added buttons now save accross sessions Demo additions: /script MobileMinimapButtons_AddButton("AtlasButton","Atlas Button"); /script MobileMinimapButtons_AddButton("CT_RASets_Button","CT Raid Assist Button"); /script MobileMinimapButtons_AddButton("Wardrobe.IconFrame","Wardrobe Button"); /script MobileMinimapButtons_AddButton("TheYatlasButton","Yatlas Button"); /script MobileMinimapButtons_AddButton("GathererUI_IconFrame","Gatherer Button"); /script MobileMinimapButtons_AddButton("EarthMinimapButton","Earth Button"); /script MobileMinimapButtons_AddButton("IEFMinimapButton","Improved Error Frame Button"); /script MobileMinimapButtons_AddButton("CTA_MinimapIcon","Call To Arms Button"); v1.2 (10/27/05) -Chnaged OnClick handling to allow for Casting via OnClick -Implimented HasScript so that you no longer have to pass weather the frame is a button or not. v1.11 (10/25/05) -Fixed an obscure OnClick bug involving Khaos v1.1 (10/18/05) -Added dynamic button adding using MobileMinimapButtons_AddButton at any time. -See API.txt for details on how to make your addon's button mobile. v1.0 (9/30/05) -Initial Release $Id: MobileMinimapButtons.lua 2025 2005-07-02 23:51:34Z KarlKFI $ $Rev: 2025 $ $LastChangedBy: KarlKFI $ $Date: 2005-07-02 16:51:34 -0700 (Sat, 02 Jul 2005) $ ]]-- --Update +1 if you change the list of frames in the localization! local tempListVersion = MOBILE_MINIMAP_BUTTONS_LIST_VERSION; local tempFrameList = MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS; MobileMinimapButtons_Debug = false; MobileMinimapButtons_Coords = {}; MobileMinimapButtons_Enabled = true; MobileMinimapButtons_CurrentlyEnabled = {}; MobileMinimapButtons_NextClickDisabled = nil; MobileMinimapButtons_FullSizeButtons = { --Fullsize buttons use the 1/2 width offset rather than the normal 1/4 width ["MiniMapTrackingFrame"] = true, }; MobileMinimapButtons_MaskParentButtons = { --Parents that aren't attached hinder dragging, attach them. ["AtlasButton"] = "AtlasButtonFrame", ["CensusButton"] = "CensusButtonFrame", ["CT_RASets_Button"] = "CT_RASetsFrame", ["TheYatlasButton"] = "YatlasButtonFrame", ["AM_MinimapButton"] = "AM_MinimapFrame", }; function MobileMinimapButtons_OnLoad() this:RegisterEvent("VARIABLES_LOADED"); this:RegisterEvent("PLAYER_ENTERING_WORLD"); if (Khaos) then MobileMinimapButtons_RegisterForKhaos(); end end function MobileMinimapButtons_OnEvent(event) if (event == "VARIABLES_LOADED") then --Make sure list has new frames, but don't remove added ones if (MOBILE_MINIMAP_BUTTONS_LIST_VERSION) and (tempListVersion > MOBILE_MINIMAP_BUTTONS_LIST_VERSION) then for frameName, localizedFrameName in tempFrameList do if (not MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS[frameName]) then MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS[frameName] = localizedFrameName; end end MOBILE_MINIMAP_BUTTONS_LIST_VERSION = tempListVersion; end tempFrameList = nil; tempListVersion = nil MobileMinimapButtons_EnteringWorldFromFullLoad = true; elseif (event == "PLAYER_ENTERING_WORLD") then if (MobileMinimapButtons_EnteringWorldFromFullLoad) then --Loop Through Minimap Buttons for frameName, localizedFrameName in MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS do if (Sea.util.getValue(frameName)) then MobileMinimapButtons_MakeMobile(frameName, localizedFrameName); end end MobileMinimapButtons_EnteringWorldFromFullLoad = nil; MobileMinimapButtons_FramesLoaded = true; end end end function MobileMinimapButtons_AddButton(frameName, localizedFrameName) if (not frameName) or (not Sea.util.getValue(frameName)) then Sea.io.print("MobileMinimapButtons Error: Cannot add ", frameName, " (", localizedFrameName, ") called from ", this:GetName(), ". The button does not exist."); return; elseif (MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS[frameName]) then if (MobileMinimapButtons_FramesLoaded) then Sea.io.print("MobileMinimapButtons Error: Cannot add ", frameName, " (", localizedFrameName, ") called from ", this:GetName(), ". Duplicate already registered."); end return; end MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS[frameName] = localizedFrameName; if (MobileMinimapButtons_FramesLoaded) then MobileMinimapButtons_MakeMobile(frameName, localizedFrameName); if (not MobileMinimapButtons_Enabled) then --Override Disable to redisable MobileMinimapButtons_Enabled = true; MobileMinimapButtons_Disable(); end end end function MobileMinimapButtons_MakeMobile(frameName, localizedFrameName) if (MobileMinimapButtons_CurrentlyEnabled[frameName]) then -- Already Mobile return; end local frame = Sea.util.getValue(frameName); --Store the current position as the reset coords MobileMinimapButtons_StoreResetPosition(frameName); --Load Frame Script Element Hooks Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnEvent", "replace", "OnEvent" ); if (frame:HasScript("OnClick")) then --Enable Click events --frame:RegisterForClicks("LeftButton", "RightButton"); Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnClick", "replace", "OnClick" ); end Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnMouseDown", "replace", "OnMouseDown" ); Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnMouseUp", "replace", "OnMouseUp" ); Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnHide", "replace", "OnHide" ); Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnUpdate", "replace", "OnUpdate" ); --Make sure all the Buttons are Mobile if (not frame:IsMovable()) then frame:SetMovable(1); end --Disable OnDrag events by passing no arguments frame:RegisterForDrag(); --Reposition Buttons to Saved Coords local coords = MobileMinimapButtons_Coords[frameName]; frame:ClearAllPoints(); if (coords) and (coords.x) and (coords.y) then frame:SetPoint("CENTER", "Minimap", "CENTER", coords.x, coords.y); else frame:SetPoint("CENTER", "Minimap", "CENTER", frame.resetX, frame.resetY); end --Set as enabled for this session MobileMinimapButtons_CurrentlyEnabled[frameName] = localizedFrameName; --Save for later MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS[frameName] = localizedFrameName; --Elevate Buttons Above the MiniMap frame:SetFrameLevel(frame:GetFrameLevel()+1); --Attach Parent Buttons local maskFrame = Sea.util.getValue(MobileMinimapButtons_MaskParentButtons[frameName]) if (maskFrame) then maskFrame:SetAllPoints(frame); end end function MobileMinimapButtons_StoreResetPosition(frameName) local frame = Sea.util.getValue(frameName); local centerX, centerY = Minimap:GetCenter(); local thisX, thisY = frame:GetCenter(); local radius; local diffX = centerX - thisX; local diffY = centerY - thisY; local dist = (diffX * diffX) + (diffY * diffY); radius = math.sqrt(dist); local x = math.abs(thisX - centerX); local y = math.abs(thisY - centerY); local xSign = 1; local ySign = 1; if not (thisX >= centerX) then xSign = -1; end if not (thisY >= centerY) then ySign = -1; end --Sea.io.print(xSign*x,", ",ySign*y); local angle = math.atan(x/y); x = math.sin(angle)*radius; y = math.cos(angle)*radius; frame.resetX = xSign*x; frame.resetY = ySign*y; end function MobileMinimapButtons_Reset(frame) if (frame) then frame.isMoving = false; frame:ClearAllPoints(); frame:SetPoint("CENTER", "Minimap", "CENTER", frame.resetX, frame.resetY); frame:SetUserPlaced(false); MobileMinimapButtons_Coords[frame:GetName()] = nil; end end function MobileMinimapButtons_ResetAll() for frameName, localizedFrameName in MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS do local frame = Sea.util.getValue(frameName); MobileMinimapButtons_Reset(frame); end end function MobileMinimapButtons_Disable() if (not MobileMinimapButtons_Enabled) then return; end for frameName, localizedFrameName in MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS do --Reset Location without forgetting coords local frame = Sea.util.getValue(frameName); if (frame) then frame.isMoving = false; frame:ClearAllPoints(); frame:SetPoint("CENTER", "Minimap", "CENTER", frame.resetX, frame.resetY); frame:SetUserPlaced(false); --Unload Frame Script Element Hooks Sea.util.unhook( frameName, "MobileMinimapButtons_Master_OnEvent", "replace", "OnEvent" ); if (frame:HasScript("OnClick")) then Sea.util.unhook( frameName, "MobileMinimapButtons_Master_OnClick", "replace", "OnClick" ); end Sea.util.unhook( frameName, "MobileMinimapButtons_Master_OnMouseDown", "replace", "OnMouseDown" ); Sea.util.unhook( frameName, "MobileMinimapButtons_Master_OnMouseUp", "replace", "OnMouseUp" ); Sea.util.unhook( frameName, "MobileMinimapButtons_Master_OnHide", "replace", "OnHide" ); Sea.util.unhook( frameName, "MobileMinimapButtons_Master_OnUpdate", "replace", "OnUpdate" ); end end MobileMinimapButtons_Enabled = nil; end function MobileMinimapButtons_ReEnable() if (MobileMinimapButtons_Enabled) then return; end for frameName, localizedFrameName in MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS do --Load Frame Script Element Hooks local frame = Sea.util.getValue(frameName); if (frame) then Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnEvent", "replace", "OnEvent" ); if (frame:HasScript("OnClick")) then Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnClick", "replace", "OnClick" ); end Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnMouseDown", "replace", "OnMouseDown" ); Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnMouseUp", "replace", "OnMouseUp" ); Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnHide", "replace", "OnHide" ); Sea.util.hook( frameName, "MobileMinimapButtons_Master_OnUpdate", "replace", "OnUpdate" ); --Reposition Buttons to Saved Coords local coords = MobileMinimapButtons_Coords[frameName]; if (coords) and (coords.x) and (coords.y) then local frame = Sea.util.getValue(frameName); frame:ClearAllPoints(); frame:SetPoint("CENTER", "Minimap", "CENTER", coords.x, coords.y); end end end MobileMinimapButtons_Enabled = true; end function MobileMinimapButtons_Master_OnMouseDown() Sea.io.dprint("MobileMinimapButtons_Debug", "MobileMinimapButtons_Master_OnMouseDown(", arg1, ")"); if (IsControlKeyDown()) then if (arg1 == "LeftButton") then this.isMoving = 0; local centerX, centerY = Minimap:GetCenter(); local thisX, thisY = this:GetCenter(); local diffX = centerX - thisX; local diffY = centerY - thisY; local dist = (diffX * diffX) + (diffY * diffY); this.radius = math.sqrt(dist); end else return true; end end function MobileMinimapButtons_Master_OnMouseUp() Sea.io.dprint("MobileMinimapButtons_Debug", "MobileMinimapButtons_Master_OnMouseUp(", arg1, ")"); local frameName = this:GetName(); if (this.isMoving) then if (MouseIsOver(this)) and (this.isMoving > GetFramerate()) then --Only disable OnClick if it was dragging longer than 1 second (accounts for shift-OnClicking) MobileMinimapButtons_NextClickDisabled = true; end if (not MobileMinimapButtons_Coords[frameName]) then MobileMinimapButtons_Coords[frameName] = {}; end MobileMinimapButtons_Coords[frameName].x = this.currentX; MobileMinimapButtons_Coords[frameName].y = this.currentY; this.isMoving = false; this.radius = nil; elseif (MouseIsOver(this)) then if (IsControlKeyDown()) and (arg1 == "RightButton") then --MobileMinimapButtons_Reset(this); MobileMinimapButtonsDropDown.displayMode = "MENU"; ToggleDropDownMenu(1, frameName, MobileMinimapButtonsDropDown, frameName); --MobileMinimapButtonsDropDown_Reposition(frameName); MobileMinimapButtons_NextClickDisabled = true; else --MobileMinimapButtons_NextClickDisabled = nil; return true; end else return true; end end function MobileMinimapButtons_Master_OnClick() if (not MobileMinimapButtons_NextClickDisabled) then Sea.io.dprint("MobileMinimapButtons_Debug", "MobileMinimapButtons_Master_OnClick(", arg1, ") Orig Called."); return true; else Sea.io.dprint("MobileMinimapButtons_Debug", "MobileMinimapButtons_Master_OnClick(", arg1, ") Orig Not Called."); MobileMinimapButtons_NextClickDisabled = nil; end end function MobileMinimapButtons_Master_OnHide() this.isMoving = false; return true; end function MobileMinimapButtons_Master_OnUpdate() if (this.isMoving) then this.isMoving = this.isMoving+1; local mouseX, mouseY = GetCursorPosition(); local centerX, centerY = Minimap:GetCenter(); local scale = Minimap:GetEffectiveScale(); mouseX = mouseX / scale; mouseY = mouseY / scale; local radius; if ( not this.radius ) then if (MobileMinimapButtons_FullSizeButtons[this:GetName()]) then radius = ((Minimap:GetRight()-Minimap:GetLeft())/2) + ((this:GetRight()-this:GetLeft())/2); else radius = ((Minimap:GetRight()-Minimap:GetLeft())/2) + ((this:GetRight()-this:GetLeft())/4); end else radius = this.radius; end local x = math.abs(mouseX - centerX); local y = math.abs(mouseY - centerY); local xSign = 1; local ySign = 1; if not (mouseX >= centerX) then xSign = -1; end if not (mouseY >= centerY) then ySign = -1; end --Sea.io.print(xSign*x,", ",ySign*y); local angle = math.atan(x/y); x = math.sin(angle)*radius; y = math.cos(angle)*radius; this.currentX = xSign*x; this.currentY = ySign*y; this:ClearAllPoints(); this:SetPoint("CENTER", "Minimap", "CENTER", this.currentX, this.currentY); else return true; end end -- <= == == == == == == == == == == == == => -- => Menu -- <= == == == == == == == == == == == == => function MobileMinimapButtons_LoadDropDownMenu() --Title local info = {}; info.text = MOBILE_MINIMAP_BUTTONS_DESCRIPTIONS[UIDROPDOWNMENU_MENU_VALUE]; info.notClickable = 1; info.isTitle = 1; UIDropDownMenu_AddButton(info, 1); --Reset local info = {}; info.text = RESET; info.value = "Reset"; info.func = function() MobileMinimapButtons_Reset(Sea.util.getValue(UIDROPDOWNMENU_MENU_VALUE)) end; --info.notCheckable = 1; UIDropDownMenu_AddButton(info, 1); --Reset All local info = {}; info.text = RESET_ALL; info.value = "ResetAll"; info.func = MobileMinimapButtons_ResetAll; --info.notCheckable = 1; UIDropDownMenu_AddButton(info, 1); MobileMinimapButtonsDropDown_Reposition(UIDROPDOWNMENU_MENU_VALUE); end function MobileMinimapButtonsDropDown_OnLoad() UIDropDownMenu_Initialize(this, MobileMinimapButtons_LoadDropDownMenu, "MENU"); end function MobileMinimapButtonsDropDown_Reposition(anchorName) local customPoint = "TOPLEFT"; --Default Anchor local offscreenY, offscreenX, anchorPoint, relativePoint, offsetX, offsetY; local listFrame = getglobal("DropDownList"..UIDROPDOWNMENU_MENU_LEVEL); -- Determine whether the menu is off the screen or not local offscreenY, offscreenX; --Hack for built in bug if ( not listFrame:GetRight() ) then return; end if ( listFrame:GetBottom() < WorldFrame:GetBottom() ) then offscreenY = 1; end if ( listFrame:GetRight() > WorldFrame:GetRight() ) then offscreenX = 1; end local anchorPoint, relativePoint, offsetX, offsetY; if ( offscreenY == 1 ) then if ( offscreenX == 1 ) then anchorPoint = string.gsub(customPoint, "TOP(.*)", "BOTTOM%1"); anchorPoint = string.gsub(anchorPoint, "(.*)LEFT", "%1RIGHT"); relativePoint = "TOPRIGHT"; offsetX = 0; offsetY = 14; else anchorPoint = string.gsub(customPoint, "TOP(.*)", "BOTTOM%1"); relativePoint = "TOPLEFT"; offsetX = 0; offsetY = 14; end else if ( offscreenX == 1 ) then anchorPoint = string.gsub(customPoint, "(.*)LEFT", "%1RIGHT"); relativePoint = "BOTTOMRIGHT"; offsetX = 0; offsetY = -14; else anchorPoint = customPoint; relativePoint = "BOTTOMLEFT"; offsetX = 0; offsetY = -14; end end listFrame:ClearAllPoints(); listFrame:SetPoint(anchorPoint, anchorName, relativePoint, offsetX, offsetY); -- Reshow the "MENU" border getglobal(listFrame:GetName().."Backdrop"):Hide(); getglobal(listFrame:GetName().."MenuBackdrop"):Show(); --getglobal(listFrame:GetName().."Backdrop"):Show(); --getglobal(listFrame:GetName().."MenuBackdrop"):Hide(); end -- <= == == == == == == == == == == == == => -- => Khaos Registration -- <= == == == == == == == == == == == == => function MobileMinimapButtons_RegisterForKhaos() local optionSet = { id="MobileMinimapButtons"; text=MOBILE_MINIMAP_BUTTONS_HEADER; helptext=MOBILE_MINIMAP_BUTTONS_HEADER_INFO; difficulty=1; default = {checked = true}; callback = function(checked) if (checked) then MobileMinimapButtons_ReEnable(); else MobileMinimapButtons_Disable(); end end; options={ { id="Header"; text=MOBILE_MINIMAP_BUTTONS_HEADER; helptext=MOBILE_MINIMAP_BUTTONS_HEADER_INFO; type=K_HEADER; }; { id="ResetAll"; type=K_BUTTON; text=MOBILE_MINIMAP_BUTTONS_RESET_ALL_TEXT; helptext=MOBILE_MINIMAP_BUTTONS_RESET_ALL_TEXT_INFO; callback=MobileMinimapButtons_ResetAll; setup={buttonText=RESET_ALL}; }; }; }; Khaos.registerOptionSet( "frames", optionSet ); end