local sets = {}; local frames = {}; -- state function local current_locx_xact, current_locy_xact; local current_frame, current_viewframe; local binsert; local nilfunc = function () end local emptylist = {}; function YAPoints_RegisterSet(set) sets[set.name] = set; end function YAPoints_RegisterFrame(...) frames[arg[1]] = 0; end function YAPoints_ForceUpdate(frame) if( not frame) then for h,v in pairs(frames) do YAPoints_OnMapChange(getglobal(h)); end else YAPoints_OnMapChange(frame); end end function YAPoints_OnMapChange(frame) local lm = frame:GetName(); -- clear all points local h = 1; while h > 0 do local point = getglobal(lm.."Point"..h); if(point) then point:Clear(); h = h + 1; else h = 0; end end local pd_resetlist = getglobal(frame.YA_PD_ResetList); if(pd_resetlist) then pd_resetlist(); end -- store all points for this map frame.points = {}; current_frame = frame; for h,v in pairs(sets) do if(v.getpoints) then v.getpoints(h, YatlasOptions.Frames[lm].Map); end end -- handle mobile points here to. -- Keep in mind, mobile points shouldn't be updated here specifically, -- but it gets the job done. frame.mobilepoints = {}; frame.nextmobilepoint = 1; if(frame.mobilepointframes == nil) then frame.mobilepointframes = {} end for h,v in pairs(sets) do if(v.getmobilepoints) then v.getmobilepoints(h); end end for id,mp in pairs(frame.mobilepoints) do if(mp.locMap ~= map or not mp.locMap) then mp:Hide(); end end -- force update frame.yap_lastx = nil; YAPoints_OnMove(frame, unpack(YatlasOptions.Frames[lm].Location)); end function YAPoints_OnMove(frame, x, y) local lm = frame:GetName(); if(frames[lm] == 0) then frames[lm] = 1; return YAPoints_OnMapChange(frame); end -- if we have run at this x, y coord recently, don't do it again if(frame.yap_lastx == x and frame.yap_lasty == y) then -- no change return; end -- update normal points and unit points YAPoints_Update(frame, x, y); -- YAPoints_UpdateP(frame); -- hide/update mobile points as needed for id,mp in pairs(frame.mobilepoints) do if(mp:IsShown()) then mp:Update(frame); end end frame.yap_lasty = y; frame.yap_lastx = x; end function YAPoints_OnUpdate(frame, ela) local lm = frame:GetName(); for h,v in pairs(sets) do if(v.OnUpdate) then v.OnUpdate(h, frame, ela); end end end function YAPoints_Update(frame, x, y) local lm = frame:GetName(); local flr,cei=math.floor,math.ceil; local z = frame:GetZoom(); local hpoint = 1; local legend = {}; if(x == nil) then x = YatlasOptions.Frames[lm].Location[1]; y = YatlasOptions.Frames[lm].Location[2]; end current_locx_xact = x; current_locy_xact = y; current_frame = frame; current_viewframe = getglobal(lm.."ViewFrame"); -- ensure that we have loaded the points already if(frame.points == nil) then return YAPoints_OnMapChange(frame); end -- clear all points for h, point in ipairs(frame.pointframes) do if(point and point:IsShown()) then point:Clear(); end end -- init vispoints frame.vispoints = {}; for h,v in pairs(sets) do frame.vispoints[h] = {}; end -- fill vispoints for xv = flr(x),cei(x+current_viewframe:GetWidth()/z),1 do if(frame.points[xv] ~= nil) then for yv = flr(y),cei(y+current_viewframe:GetHeight()/z),1 do if(frame.points[xv][yv] ~= nil) then for k,vv in pairs(frame.points[xv][yv]) do if(vv.x > x and vv.y > y and vv.x < x+current_viewframe:GetWidth()/z and vv.y < y+current_viewframe:GetHeight()/z) then binsert(frame.vispoints[vv.setname], vv); end end end end end end local env = { current_lm = lm, current_frame = current_frame, zoom = z, iconsize = YatlasOptions.Frames[lm].IconSize }; -- draw visible points frame._common_pd = {}; local id = 1; for hset,set in pairs(frame.vispoints) do local showornotfunc = sets[hset].showme; local pointfunc = sets[hset].setuppoint; local legendfunc = sets[hset].setuplegend; for hval,val in pairs(set) do local point = YAPoints_GetPoint(frame, hpoint); local showmemaybe = (not showornotfunc and not YatlasOptions.Frames[lm].PointCfg[val.setsubname]) or (showornotfunc and showornotfunc(val, lm) ); if(point and showmemaybe) then if(not val.options.commonpd) then val.id = id; id = id + 1; end point:Clear(); point:Show(); -- this gets changed around a lot env.iconsize = YatlasOptions.Frames[lm].IconSize; -- call functions point.dat = val; if(pointfunc) then pointfunc(point, env, val); end elseif(point) then hpoint = hpoint-1; end hpoint = hpoint + 1; end end end function YAPoints_GetPoint(frame, id) -- does point exist?? if(frame.pointframes[id]) then return frame.pointframes[id]; end if(id > 4096) then -- this is too big by far return; end -- create local viewframe = getglobal(frame:GetName().."ViewFrame"); local f = CreateFrame("Button"); f:SetHeight(16); f:SetWidth(16); f:SetParent(viewframe); f:EnableMouse(true); f.Icon = f:CreateTexture(nil, "OVERLAY"); f.Icon:SetPoint("TOPLEFT", f); f.Foreground = f:CreateFontString(nil, "ARTWORK"); f.Foreground:SetFontObject(GameFontHighlight); f.Foreground:SetTextColor(0, 0, 0); f.Foreground:SetShadowOffset(-1, 0); f.Foreground:SetPoint("TOPLEFT", f); f:SetFrameLevel(f:GetFrameLevel() + 4); f.Clear = YP_Clear; f.SetOffset = YP_SetOffset; f:SetScript("OnEnter", YP_OnEnter); frame.pointframes[id] = f; return f; end function YAPoints_AllocMobilePoint(frame, id) -- does point exist?? if(frame.mobilepointframes[id]) then return frame.mobilepointframes[id]; end if(id > 1024) then -- this is too big by far return; end -- create local viewframe = getglobal(frame:GetName().."ViewFrame"); local f = CreateFrame("Button"); f:SetHeight(16); f:SetWidth(16); f:SetParent(viewframe); f:EnableMouse(true); f.Icon = f:CreateTexture(nil, "OVERLAY"); f.Icon:SetPoint("TOPLEFT", f); f.Foreground = f:CreateFontString(nil, "ARTWORK"); f.Foreground:SetFontObject(GameFontHighlight); f.Foreground:SetTextColor(0, 0, 0); f.Foreground:SetShadowOffset(-1, 0); f.Foreground:SetPoint("TOPLEFT", f); f:SetFrameLevel(f:GetFrameLevel() + 4); f.Clear = YP_Clear; f.SetOffset = YP_SetOffset; f.Update = YMP_Update; f:SetScript("OnEnter", YP_OnEnter); frame.mobilepointframes[id] = f; return f; end function YAPoints_UpdateTooltip(frame, tooltip, point, op) local dat = point.dat; local lm = frame:GetName(); if(not tooltip.points) then tooltip.points = {}; end if(op == "add") then if(point.intooltip == nil) then tinsert(tooltip.points, point); point.intooltip = 1; end elseif(op == "remove") then for h,v in ipairs(tooltip.points) do if(v == point) then tremove(tooltip.points, h); break; end end point.intooltip = nil; else -- ??? end local env = { current_lm = lm, current_frame = frame, zoom = frame:GetZoom(), iconsize = 14, islegend = true, }; if(tooltip.points[1]) then local vf = getglobal(lm.."ViewFrame"); tooltip:Clear(); for h,point in ipairs(tooltip.points) do local legendfunc = sets[point.dat.setname].setuplegend; if(legendfunc) then local legend = tooltip:GetNext(); legendfunc(legend, env, point.dat); end -- tooltip:AddDataPoint(point.dat.name); end tooltip:Show(); else tooltip:Hide(); end end function YAPoints_showmeornot(frame, val) local showornotfunc = sets[val.setname].showme; if(type(frame) ~= "string") then frame = frame:GetName(); end return (not showornotfunc and not YatlasOptions.Frames[frame].PointCfg[val.setsubname]) or (showornotfunc and showornotfunc(val, frame) ); end --- --- point OO implementation --- function YP_Clear(point) point:Hide(); point:ClearAllPoints(); point:SetPoint("TOPLEFT", point:GetParent()); point.Icon:SetTexture(nil); point.Icon:SetTexCoord(0, 1, 0, 1); point.Foreground:SetText(""); end function YP_SetOffset(point, x, y) local z = current_frame:GetZoom(); local lm = current_frame:GetName(); local iconsz = YatlasOptions.Frames[lm].IconSize; point:ClearAllPoints(); point:SetPoint("TOPLEFT", current_viewframe, "TOPLEFT", -(current_locx_xact - x)*z - iconsz/2, (current_locy_xact - y)*z + iconsz/2); end function YP_OnEnter() local vf = this:GetParent(); local f = vf:GetParent(); local tp = getglobal(f.hoverTooltip); vf.inpoint = true; if(tp and tp.knownshownlines == nil) then tp.knownshownlines = 0; end end function YatlasFrameViewFrame_UpdatePointTooltip() local f = this:GetParent(); local tp = getglobal(f.hoverTooltip); for h,v in pairs(f.pointframes) do if(v.intooltip and not MouseIsOver(v)) then YAPoints_UpdateTooltip(f, tp, v, "remove"); tp.knownshownlines = tp.knownshownlines - 1; elseif(not v.intooltip and MouseIsOver(v)) then YAPoints_UpdateTooltip(f, tp, v, "add"); tp.knownshownlines = tp.knownshownlines + 1; end end for h,v in pairs(f.mobilepointframes) do if(v.intooltip and not MouseIsOver(v)) then YAPoints_UpdateTooltip(f, tp, v, "remove"); tp.knownshownlines = tp.knownshownlines - 1; elseif(not v.intooltip and MouseIsOver(v) and v:IsShown()) then YAPoints_UpdateTooltip(f, tp, v, "add"); tp.knownshownlines = tp.knownshownlines + 1; end end if(tp.knownshownlines == 0) then this.inpoint = nil; end end --- --- --- function YAPoints_AddPoint(frame, setname, name, x, y, options, userdat) local tab = { setname = setname, name = name, x = x, y = y, options = options, userdat = userdat }; if(tab.options == nil) then tab.options = emptylist; end if(options and options.setsubname) then tab.setsubname = options.setsubname; else tab.setsubname = tab.setname; end if(type(frame) ~= "table") then frame = current_frame; end local fx = math.floor(x); local fy = math.floor(y); if(frame.points[fx] == nil) then frame.points[fx] = {}; end if(frame.points[fx][fy] == nil) then frame.points[fx][fy] = {}; end tinsert(frame.points[fx][fy], tab); end function YAPoints_AddMobilePoint(frame, setname, name, opt, userdat) local tab = { setname = setname, name = name, options = opt, userdat = userdat }; if(tab.options == nil) then tab.options = emptylist; end if(options and options.setsubname) then tab.setsubname = options.setsubname; else tab.setsubname = tab.setname; end if(type(frame) ~= "table") then frame = current_frame; end point = YAPoints_AllocMobilePoint(frame, frame.nextmobilepoint); point.dat = tab; frame.nextmobilepoint = frame.nextmobilepoint + 1; frame.mobilepoints[setname..":"..name] = point; return getn(frame.mobilepoints); end function YAPoints_Mobile_SetLocation(setname, name, map, x, y) for framename,v in pairs(frames) do local frame = getglobal(framename); if(frame:IsVisible()) then local d = frame.mobilepoints[setname..":"..name]; d.locx = x; d.locy = y; d.locmap = map; d:Update(frame); end end end function YAPoints_SetupMobilePoint(setname, name, itahm, prop, ...) local whut; for framename,v in pairs(frames) do local frame = getglobal(framename); whut = frame.mobilepoints[setname..":"..name][itahm]; whut[prop](whut, unpack(arg)); end end function YAPoints_SetupMobilePointF(frame, setname, name, itahm, prop, ...) local whut; if(type(frame) ~= "table") then frame = current_frame; end whut = frame.mobilepoints[setname..":"..name][itahm]; whut[prop](whut, unpack(arg)); end function YAPoints_HideMobile(setname, name) for framename,v in pairs(frames) do local frame = getglobal(framename); if(frame:IsVisible()) then local d = frame.mobilepoints[setname..":"..name]; d.locmap = nil; d:Update(frame); end end end function YMP_Update(point, frame) local zoom = frame:GetZoom(); local vf = getglobal(frame:GetName().."ViewFrame") local map = frame:GetMap(); local minx, miny = frame:GetLocation(); local maxx, maxy = minx + vf:GetWidth()/zoom, miny + vf:GetHeight()/zoom; if(map == point.locmap and point.locx > minx and point.locx < maxx and point.locy > miny and point.locy < maxy) then point:SetOffset(point.locx, point.locy); point:Show(); else point:Hide(); end end --- --- YFOO: pulldown to control what points are shown. name has some --- historical significance --- function YFOO_Init(frame) if(not frame) then frame = this; end UIDropDownMenu_Initialize(frame, YFOODropDown_Initialize, "MENU"); UIDropDownMenu_SetButtonWidth(50,frame); UIDropDownMenu_SetWidth(50,frame); end function YFOODropDown_Initialize() local func; if(current_frame == nil) then return; end local lm = current_frame:GetName(); if(UIDROPDOWNMENU_MENU_LEVEL == 1) then local info = {}; info.text = YATLAS_POINTS_SHOWPOINTS_TITLE; info.notClickable = 1; info.isTitle = 1; info.notCheckable = 1; UIDropDownMenu_AddButton(info); end if(YatlasOptions.Frames and YatlasOptions.Frames[lm]) then for h,v in pairs(sets) do func = v.configmenu; if(func) then func(h, lm); end end end end function YFOO_OnClick() current_frame = this; while(current_frame and not current_frame.SetLocation) do current_frame = current_frame:GetParent() end if(current_frame:GetName() == "BigYatlasFrame") then BigYatlasTooltip:Hide(); end ToggleDropDownMenu(1, nil, getglobal(this:GetName().."DropDown"), this:GetName(), 0, 0); end function YFOODropDown_do_toggle_normal() YatlasOptions.Frames[current_frame:GetName()].PointCfg[this.value] = UIDropDownMenuButton_GetChecked() YAPoints_ForceUpdate(current_frame) end --- --- misc --- -- based on code by ??? binsert = function( t, val) local iStart, iEnd, iMid, iState = 1, table.getn( t ), 1, 0 -- Get Insertposition while iStart <= iEnd do -- calculate middle iMid = math.floor( ( iStart + iEnd )/2 ) -- compare if val.name <= t[iMid].name then iEnd = iMid - 1 iState = 0 else iStart = iMid + 1 iState = 1 end end table.insert( t, ( iMid+iState ), val ) end