diff CrossRealmAssist.lua @ 32:7b7b3ca996fd

CrossRealmAssist beta 0.75 release-candidate
author ShadowTheAge
date Mon, 26 Oct 2015 00:47:27 +0300
parents 7267ae761cb9
children f39b5803b4c1
line wrap: on
line diff
--- a/CrossRealmAssist.lua	Sun Sep 27 16:06:18 2015 +0300
+++ b/CrossRealmAssist.lua	Mon Oct 26 00:47:27 2015 +0300
@@ -1,6 +1,7 @@
 CrossRealmAssist = LibStub("AceAddon-3.0"):NewAddon("CrossRealmAssist", "AceEvent-3.0", "AceConsole-3.0", "AceTimer-3.0")
 local addon = CrossRealmAssist;
 local wholib = LibStub:GetLibrary('LibWho-2.0'):Library()
+local realmInfo = LibStub:GetLibrary('LibRealmInfo')
 local ScrollingTable = LibStub("ScrollingTable");
 local ldb = LibStub("LibDataBroker-1.1")
 local minimapIcon = LibStub("LibDBIcon-1.0")
@@ -9,7 +10,7 @@
 local homeRealm, realmSep, gui, btRefresh, btSettings, btQuick, btManual, lbRealm, lbStatus, playerName, lfgui, lfgTabSelected, lfgTable, lbThrottle, curLfgGroup, sheduledScan, wasInGroup, inInstance
 local settingsMenu
 local hintShown
-local cbHideGroups, cbHideRaids, cbHideNoAutoinv
+local btFilterCount, cbHideNoAutoinv, edFilterText
 
 local tabs = {}
 local curRealmStat
@@ -19,8 +20,12 @@
 local autoScanGroups={}
 local active=false
 local allLanguageTable={}
+local extraColumns
+local tableTemplate
+local filterString
+local filterByCountId=1
 
-local lfgGroups={
+addon.lfgGroups={
     6, -- Custom
     10, -- Ashran
     1, -- Quests
@@ -46,13 +51,34 @@
         quickJoinHint = true,
         quickJoin={[6]=1},
         allLanguages = true,
-        stoplist = {"no hop","kick"}
+        stoplist = {"no hop","nohop","no realm","kick"},
+        priorityList = {"realm hop","realmhop","garrison"},
+        lfgPanelScale = 1.0, uiScale = 1.0, listItemCount=15,
+        extraColumns = {}
     }
 }
+local filterByCountList = {
+    {text="Any number of players",min=1,max=40},
+    {text="Groups (1-5)",min=1,max=5},
+    {text="Raids (6-40)",min=6,max=40},
+    {text="Non-full groups (1-4)",min=1,max=4},
+    {text="Non-full raids (6-35)",min=6,max=35}
+}
 
 
 -- Utils functions
 
+
+local function searchInList(name, list)
+    if list and name then
+        local lname = string.lower(name);
+        for i=1, #list do
+            if string.find(lname, list[i], 1, true) then return true end
+        end
+    end
+    return false;
+end
+
 local function PlayerName(fullname)
     fullname = fullname or "???-???"
     local name, realm = strsplit(realmSep, fullname)
@@ -64,8 +90,12 @@
     return (not IsInGroup()) or (UnitIsGroupLeader('player') and not IsInRaid())
 end
 
-local function sortByWeight(a,b)
-    return b.weight < a.weight
+local function sortByTypeAndName(a,b)
+    if a.type == b.type then
+		return a.name < b.name
+	else 
+		return a.type < b.type;
+	end
 end
 
 
@@ -162,16 +192,19 @@
     end
 end
 
+local function getJoinedAgo(name)
+    if recentgroups[name] then
+        return GetTime() - recentgroups[name].time
+    end
+end
+
 local function WeightLfgItem(id, forAutoJoin)
     local _, action, caption, desc, voice, ilvl, time, bnetfr, charfr, guild, delisted, fullname, pcount, autoinv = C_LFGList.GetSearchResultInfo(id)
     if delisted then return 0 end
     local name,realm = PlayerName(fullname);
-    local stoplist = db.global.stoplist or {}
-    local ldesc = string.lower(caption) .. "|" .. string.lower(desc);
-    local isHopGroup = string.find(ldesc, "realm hop")
-    for i=1, #stoplist do
-        if string.find(ldesc, stoplist[i], 1, true) then return 0 end
-    end
+    local ldesc = caption .. "|" .. desc;
+    if searchInList(ldesc, db.global.stoplist) then return 0 end
+    local isHopGroup = searchInList(ldesc, db.global.priorityList);
     if forAutoJoin then
         if not autoinv or recentgroups[fullname] or (not isHopGroup and (pcount >= 35 or pcount <= 5)) then return 0 end
     end
@@ -181,7 +214,7 @@
 
     local visCoef = 1
     if recentgroups[fullname] then
-        local ago = GetTime() - recentgroups[fullname].time;
+        local ago = getJoinedAgo(fullname)
         visCoef = math.min(1,ago/600)
     end
 
@@ -227,7 +260,7 @@
         addTooltipLineIcon(ilvl > 0, "Min. ilvl: "..ilvl, READY_CHECK_WAITING_TEXTURE, 1, 1, 0)
         addTooltipLineIcon(voice ~= "", "Voice: "..voice, READY_CHECK_WAITING_TEXTURE, 1, 1, 0)
         addTooltipLineIcon(friends > 0, "Friends: "..friends, READY_CHECK_WAITING_TEXTURE, 1, 1, 0)
-        addTooltipLineIcon(autoinv, "Autoinvite!", READY_CHECK_READY_TEXTURE, 0, 1, 0)
+        addTooltipLineIcon(autoinv, "Autoaccept!", READY_CHECK_READY_TEXTURE, 0, 1, 0)
         local visitinfo = recentgroups[fullname]
         if visitinfo then
             local ago = GetTime() - visitinfo.time;
@@ -268,6 +301,63 @@
     return select(3, C_LFGList.GetSearchResultInfo(id))
 end
 
+local function updateRealmType(id)
+    local name = select(12, C_LFGList.GetSearchResultInfo(id))
+    local pname, realm = PlayerName(name);
+    return select(4, realmInfo:GetRealmInfo(realm)) or "???"
+end
+
+local function updateGroupAge(id)
+    local age = select(7, C_LFGList.GetSearchResultInfo(id))
+    return SecondsToTime(age, false, false, 1, false)
+end
+
+local function sortBase(col, value)
+    local column = lfgTable.cols[col];
+    local direction = column.sort or column.defaultsort or "asc"
+    if direction == "asc" then
+        return value
+    else
+        return not value;
+    end
+end
+
+
+local function sortByAge(self, rowa, rowb, sortbycol)
+    if rowa == nil or rowb == nil then return false end; -- wtf ScrollingTable???
+    local row1 = lfgTable:GetRow(rowa);
+    local row2 = lfgTable:GetRow(rowb);
+    local age1 = select(7, C_LFGList.GetSearchResultInfo(row1.id));
+    local age2 = select(7, C_LFGList.GetSearchResultInfo(row2.id));
+    return sortBase(sortbycol, age1<age2);
+end
+
+local function updateJoinAge(id)
+    local name = select(12, C_LFGList.GetSearchResultInfo(id))
+    local ago = getJoinedAgo(name);
+    if ago then
+        return SecondsToTime(ago, false, false, 1, false)
+    else
+        return ""
+    end
+end
+
+local function sortByJoinAge(self, rowa, rowb, sortbycol)
+    if rowa == nil or rowb == nil then return false end; -- wtf ScrollingTable???
+    local row1 = lfgTable:GetRow(rowa);
+    local row2 = lfgTable:GetRow(rowb);
+    local joinAge1 = getJoinedAgo(select(12, C_LFGList.GetSearchResultInfo(row1.id))) or 1e10;
+    local joinAge2 = getJoinedAgo(select(12, C_LFGList.GetSearchResultInfo(row2.id))) or 1e10;
+    return sortBase(sortbycol, joinAge1<joinAge2);
+end
+
+local function sortByScore(self, rowa, rowb, sortbycol)
+    if rowa == nil or rowb == nil then return false end; -- wtf ScrollingTable???
+    local row1 = lfgTable:GetRow(rowa);
+    local row2 = lfgTable:GetRow(rowb);
+    return row1.weight > row2.weight;
+end
+
 local function updateGroupCount(id)
     return select(13, C_LFGList.GetSearchResultInfo(id))
 end
@@ -275,23 +365,41 @@
 local function updateGroupRealm(id)
     local name = select(12, C_LFGList.GetSearchResultInfo(id))
     local pname, realm = PlayerName(name);
-    return realm
+    return realm;
 end
 
 local COLOR_YELLOW = {r=1,g=1,b=0,a=1}
+local COLOR_WHITE = {r=1,g=1,b=1,a=1}
 local COLOR_GREEN = {r=0,g=1,b=0,a=1}
+local COLOR_RED = {r=1,g=0,b=0,a=1}
+local COLOR_GREY = {r=0.5,g=0.5,b=0.5,a=1}
 local function updateRealmColor(id)
     local name = select(12, C_LFGList.GetSearchResultInfo(id))
     local pname, realm = PlayerName(name);
     return recentRealms[realm] and COLOR_YELLOW or COLOR_GREEN;
 end
 
+local function updateNameColor(id)
+    local name = select(3, C_LFGList.GetSearchResultInfo(id))
+    if searchInList(name, db.global.highlightList) then return COLOR_GREEN end;
+    if searchInList(name, db.global.stoplist) then return COLOR_GREY end;
+    if searchInList(name, db.global.priorityList) then return COLOR_YELLOW end;
+    return COLOR_WHITE;
+end
+
 local function filterTable(self, row)
-    local _, _, _, _, _, _, _, _, _, _, delisted, _, pcount, autoinv = C_LFGList.GetSearchResultInfo(row.id)
+    local _, _, caption, desc, _, _, _, _, _, _, delisted, _, pcount, autoinv = C_LFGList.GetSearchResultInfo(row.id)
     if delisted then return false end;
-    if pcount > 5 and cbHideRaids:GetChecked() then return false end;
-    if pcount <= 5 and cbHideGroups:GetChecked() then return false end;
+    if filterByCountId > 1 then
+        local fobj = filterByCountList[filterByCountId];
+        if pcount < fobj.min or pcount > fobj.max then return false end;
+    end
     if not autoinv and cbHideNoAutoinv:GetChecked() then return false end;
+    if filterString then
+        caption = string.lower(caption);
+        desc = string.lower(desc);
+        if not (string.find(caption, filterString, 1, true) or string.find(desc, filterString, 1, true))then return false end
+    end
     return true;
 end
 
@@ -307,19 +415,25 @@
     if lfgScanInProgress or not lfgTable then return end
     local count, list = C_LFGList.GetSearchResults()
     local tableData = {}
+    local extraColumnId = 4;
+
     for i = 1,count do
         local rid = list[i];
         if not rid then break end
         local data = list[i];
         local cols = {}
         local row = {rid}
-        cols[1] = {value=updateGroupName,args=row}
-        cols[2] = {value=updateGroupCount,args=row}
-        cols[3] = {value=updateGroupRealm,args=row,color=updateRealmColor,colorargs=row}
-        cols[4] = {}
+        for i=1, #tableTemplate do
+            local item = tableTemplate[i];
+            local cell = {value=item.value, args=row }
+            if item.color then
+                cell.color = item.color;
+                cell.colorargs = row;
+            end
+            cols[i] = cell
+        end
         table.insert(tableData, {cols=cols,id=rid,weight=WeightLfgItem(rid)})
     end
-    table.sort(tableData, sortByWeight);
     lfgTable:SetData(tableData)
     if #tableData == 0 then
         lbThrottle:SetText("No groups found")
@@ -334,9 +448,13 @@
 end
 
 local function TableCellClick(rowFrame, cellFrame, data, cols, row, realrow, column, scrollingTable, ...)
-    if not realrow or not canJoinGroup() then return end
+    if not realrow then return end
     local rowdata = scrollingTable:GetRow(realrow);
-    JoinGroup(rowdata.id)
+    if canJoinGroup() then
+        JoinGroup(rowdata.id)
+    else
+        LeaveParty()
+    end
 end
 
 
@@ -353,6 +471,7 @@
 
 function addon:OnInitialize()
     db = LibStub("AceDB-3.0"):New("CrossRealmAssistDB", SettingsDefaults)
+    addon.db = db;
     local minimapData = ldb:NewDataObject("CrossRealmAssistMinimapIcon",{
         type = "data source",
         text = "Cross Realm Assist",
@@ -428,7 +547,8 @@
 end
 
 function addon:CreateUI()
-    gui = setupWidget(CreateFrame("Frame","CrossRealmAssistMainUI",nil,"InsetFrameTemplate3"), {SetFrameStrata="LOW",SetWidth=208,SetHeight=60,EnableMouse=true,SetMovable=true,SetClampedToScreen=true})
+    local scale = db.global.uiScale or 1.0;
+    gui = setupWidget(CreateFrame("Frame","CrossRealmAssistMainUI",nil,"InsetFrameTemplate3"), {SetFrameStrata="LOW",SetWidth=208,SetHeight=60,EnableMouse=true,SetMovable=true,SetClampedToScreen=true,SetScale=scale})
     local title = setupWidget(CreateFrame("Frame",nil,gui), {SetWidth=190,SetHeight=18,EnableMouse=true,RegisterForDrag="LeftButton"}, 0, 6);
     title:SetScript("OnDragStart", function() gui:StartMoving() end)
     title:SetScript("OnDragStop", stopMovingWidget)
@@ -482,20 +602,57 @@
     lfgTable:SetFilter(filterTable)
 end
 
+local function updateFilter(self)
+    SearchBoxTemplate_OnTextChanged(self)
+    filterString = string.lower(edFilterText:GetText());
+    if filterString == "" then filterString = nil end;
+    addon.refreshList()
+end
+
+local function updateFilterByCount(btn, arg1, arg2, checked)
+    filterByCountId = arg1;
+    local filterObj = filterByCountList[arg1];
+    UIDropDownMenu_SetText(btFilterCount, "Count: "..filterObj.min.."-"..filterObj.max);
+    addon.refreshList()
+end
+
+local function numberFilter(self, level, menuList)
+    for i=1,#filterByCountList do
+        UIDropDownMenu_AddButton({text=filterByCountList[i].text, arg1=i,checked=(i==filterByCountId), func=updateFilterByCount}, level)
+    end
+end
+
 function addon:CreateLFGUI()
-    lfgui = setupWidget(CreateFrame("Frame","CrossRealmAssistJoinUI",nil,"UIPanelDialogTemplate"), {SetFrameStrata="DIALOG",SetWidth=405,SetHeight=323,EnableMouse=true,SetMovable=true})
+    local scale = db.global.lfgPanelScale or 1.0;
+    local itemCount = db.global.listItemCount;
+    local shift = itemCount * 16;
+
+    tableTemplate = {
+        {name="Title",width=160, value = updateGroupName, color = updateNameColor},
+        {name="#",width=30,align="CENTER",value = updateGroupCount},
+        {name="Realm",width=120,align="RIGHT",value = updateGroupRealm, color = updateRealmColor}
+    }
+
+    extraColumns = db.global.extraColumns;
+    if extraColumns.rtype then table.insert(tableTemplate, {name="Type",width=40,align="CENTER", value = updateRealmType}) end;
+    if extraColumns.groupAge then table.insert(tableTemplate, {name="Age",width=45,align="CENTER",comparesort=sortByAge, value = updateGroupAge}) end;
+    if extraColumns.joinTime then table.insert(tableTemplate, {name="Joined",width=45,align="CENTER",comparesort=sortByJoinAge, value = updateJoinAge}) end;
+    table.insert(tableTemplate, {name="Misc",width=50,DoCellUpdate=updateTableData,comparesort=sortByScore,align="RIGHT",sort="asc"})
+
+    local tableWidth = 0;
+    for i=1,#tableTemplate do
+        tableWidth = tableWidth + tableTemplate[i].width;
+    end
+
+
+    lfgui = setupWidget(CreateFrame("Frame","CrossRealmAssistJoinUI",nil,"UIPanelDialogTemplate"), {SetFrameStrata="DIALOG",SetWidth=tableWidth+45,SetHeight=shift+95,EnableMouse=true,SetMovable=true,SetScale=scale})
     lfgui.title:SetText("Click to join group")
     lfgui:SetScript("OnUpdate",addon.lfgUpdate)
     local titlereg = lfgui:CreateTitleRegion()
     titlereg:SetAllPoints(lfgui.title)
     addon:CreateTabs()
 
-    lfgTable = ScrollingTable:CreateST({
-        {name="Title",width=160},
-        {name="#",width=30,align="CENTER"},
-        {name="Realm",width=120,align="RIGHT"},
-        {name="",width=50,DoCellUpdate=updateTableData}
-    },15,16,nil,lfgui);
+    lfgTable = ScrollingTable:CreateST(tableTemplate,itemCount,16,nil,lfgui);
 
     lfgTable:RegisterEvents({OnEnter=ShowLfgInfo,OnLeave=HideTooltip,OnClick=TableCellClick})
 
@@ -504,19 +661,36 @@
     lfgui:SetPoint("CENTER",0,0)
     refreshLFGList()
 
-    lbThrottle = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetWidth=300}, 50, 100)
+    lbThrottle = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetWidth=tableWidth}, 0, 100)
     lbThrottle:Hide();
 
-    local btRefresh = setupWidget(CreateFrame("Button",nil,lfgui,"UIPanelSquareButton"),{SetWidth=22,SetHeight=22},379,27)
+    local btRefresh = setupWidget(CreateFrame("Button",nil,lfgui,"UIPanelSquareButton"),{SetWidth=22,SetHeight=22},tableWidth+19,27)
     btRefresh.icon:SetTexture("Interface/BUTTONS/UI-RefreshButton")
     btRefresh.icon:SetTexCoord(0,1,0,1);
     btRefresh:SetScript("OnClick",addon.refreshLfgCurrent)
 
-    setupWidget(CreateFrame("Frame",nil,lfgui,"HorizontalBarTemplate"),{SetWidth=392,SetHeight=2}, 8, 294)
-    local text = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetText="Hide:"}, 20, 302)
+    setupWidget(CreateFrame("Frame",nil,lfgui,"HorizontalBarTemplate"),{SetWidth=tableWidth+32,SetHeight=2}, 8, shift+54)
+    local text = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetText="Filters:"}, 20, shift+68)
 
-    cbHideGroups = setupWidget(CreateFrame("CheckButton",nil,lfgui,"UICheckButtonTemplate"),{SetWidth=22,SetHeight=22})
-    cbHideGroups:SetPoint("TOPLEFT",text,"TOPRIGHT",5,7)
+    btFilterCount = CreateFrame("FRAME", "CrossRealmAssistCountFilter", lfgui, "UIDropDownMenuTemplate")
+    UIDropDownMenu_SetWidth(btFilterCount, 90)
+    UIDropDownMenu_SetText(btFilterCount, "By count")
+    UIDropDownMenu_Initialize(btFilterCount, numberFilter)
+    btFilterCount:SetPoint("TOPLEFT",text,"TOPRIGHT",-10,10)
+
+    cbHideNoAutoinv = setupWidget(CreateFrame("CheckButton",nil,lfgui,"UICheckButtonTemplate"),{SetWidth=22,SetHeight=22})
+    cbHideNoAutoinv:SetPoint("TOPLEFT",btFilterCount,"TOPRIGHT",-10,-3)
+    cbHideNoAutoinv:SetScript("OnClick",addon.refreshList)
+    text = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetText="Autoaccept only"})
+    text:SetPoint("TOPLEFT",cbHideNoAutoinv,"TOPRIGHT",0,-7)
+
+    edFilterText = setupWidget(CreateFrame("EditBox",nil,lfgui,"SearchBoxTemplate"),{SetHeight=22})
+    edFilterText:SetPoint("TOPLEFT",text,"TOPRIGHT",10,7)
+    edFilterText:SetPoint("TOPRIGHT",lfgui,"BOTTOMRIGHT",-10,0)
+    edFilterText:SetScript("OnTextChanged",updateFilter)
+
+    --[[cbHideGroups = setupWidget(CreateFrame("CheckButton",nil,lfgui,"UICheckButtonTemplate"),{SetWidth=22,SetHeight=22})
+    cbHideGroups:SetPoint("TOPLEFT",btFilterCount,"TOPRIGHT",5,7)
     cbHideGroups:SetScript("OnClick",addon.refreshList)
     text = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetText="5p Groups"})
     text:SetPoint("TOPLEFT",cbHideGroups,"TOPRIGHT",0,-7)
@@ -531,14 +705,14 @@
     cbHideNoAutoinv:SetPoint("TOPLEFT",text,"TOPRIGHT",5,7)
     cbHideNoAutoinv:SetScript("OnClick",addon.refreshList)
     text = setupWidget(lfgui:CreateFontString(nil,"BACKGROUND", "GameFontHighlightSmall"), {SetText="Groups w/o Autoinvite"})
-    text:SetPoint("TOPLEFT",cbHideNoAutoinv,"TOPRIGHT",0,-7)
+    text:SetPoint("TOPLEFT",cbHideNoAutoinv,"TOPRIGHT",0,-7)]]
 end
 
 function addon:CreateTabs()
     local prevTab
-    for i=1,#lfgGroups do
+    for i=1,#addon.lfgGroups do
         local tab = CreateFrame("Button","$parentTab"..i,lfgui,"CharacterFrameTabButtonTemplate")
-        tab:SetText((C_LFGList.GetCategoryInfo(lfgGroups[i])));
+        tab:SetText((C_LFGList.GetCategoryInfo(addon.lfgGroups[i])));
         tab.searchID = i;
         tab:SetID(i);
         PanelTemplates_TabResize(tab, 0)
@@ -566,8 +740,8 @@
 end
 
 function addon.GetNextAutoScanCategory()
-    for i=1,#lfgGroups do
-        if not autoScanGroups[i] and db.global.quickJoin[lfgGroups[i]] and i ~= curLfgGroup then return i end
+    for i=1,#addon.lfgGroups do
+        if not autoScanGroups[i] and db.global.quickJoin[addon.lfgGroups[i]] and i ~= curLfgGroup then return i end
     end
     return nil
 end
@@ -580,7 +754,7 @@
     lfgScanInProgress = true
     curLfgGroup = group
     local languages = db.global.allLanguages and allLanguageTable or C_LFGList.GetLanguageSearchFilter();
-    C_LFGList.Search(lfgGroups[curLfgGroup],"",nil,nil,languages)
+    C_LFGList.Search(addon.lfgGroups[curLfgGroup],"",nil,nil,languages)
 end
 
 function addon:LfgScanFailed(event, reason)
@@ -854,7 +1028,7 @@
         addon.LfgScan(self.category)
     end,
     tooltip = function(self)
-        GameTooltip:AddLine("Scan "..(C_LFGList.GetCategoryInfo(lfgGroups[self.category])))
+        GameTooltip:AddLine("Scan "..(C_LFGList.GetCategoryInfo(addon.lfgGroups[self.category])))
     end,
     text = "Scan more"
 }
@@ -881,7 +1055,7 @@
     text = "Quick Join",
     func = function()
         StaticPopupDialogs["CROSS_REALM_ASSIST"] = {
-            text = "Quick Join button will automatically join you to a random group with autoinvite and medium number of players. You never join same group twice, you need to clear join history to do so. This message can be disabled in options.",
+            text = "Quick Join button will automatically join you to a random group with autoaccept and medium number of players. You never join same group twice, you need to clear join history to do so. This message can be disabled in options.",
             button1 = OKAY,
             hideOnEscape = true,
             preferredIndex = 3,
@@ -960,9 +1134,7 @@
 
 -- Settings
 
-local function toggleMinimapIcon(btn, arg1, arg2, checked)
-    local hidden = not checked;
-    db.global.minimap.hide = hidden;
+function addon.toggleMinimapIcon(hidden)
     if hidden then
         DEFAULT_CHAT_FRAME:AddMessage("|cffff0000Type |cffffffff/cra |cffff0000in chat to open Cross Realm Assist without minimap button");
         minimapIcon:Hide("CrossRealmAssistMinimapIcon")
@@ -971,6 +1143,14 @@
     end
 end
 
+function addon.updateLfgScale(scale)
+    if lfgui then lfgui:SetScale(scale) end;
+end
+
+function addon.updateUIScale(scale)
+    if gui then gui:SetScale(scale) end;
+end
+
 local function toggleQuickJoinHint(btn, arg1, arg2, checked)
     db.global.quickJoinHint = checked
 end
@@ -992,6 +1172,10 @@
     if checked then addon:RegisterEvent("PLAYER_FLAGS_CHANGED", "PlayerFlagsUpdate") end
 end
 
+local function joinFriendGroup(btn, rid)
+	JoinGroup(rid);
+end
+
 local function ClearJoinHistory()
     recentgroups = {}
     addon:UpdateAutoButtonStatus()
@@ -1024,38 +1208,41 @@
 local function initMenu(self, level)
     if not level then return end
     if level == 1 then
+		UIDropDownMenu_AddButton({text="Clear join history",notCheckable=1,func=ClearJoinHistory}, level)
         UIDropDownMenu_AddButton({text="Clear realm history",notCheckable=1,func=ClearRealmHistory}, level)
-        UIDropDownMenu_AddButton({text="Clear join history",notCheckable=1,func=ClearJoinHistory}, level)
+        UIDropDownMenu_AddButton({disabled=1,notCheckable=1}, level)
 
-        if canJoinGroup() then
-            UIDropDownMenu_AddButton({disabled=1,notCheckable=1}, level)
+        UIDropDownMenu_AddButton({text="Cross Realm Assist Toolbox",notCheckable=1,func=CreateHopGroup,isTitle=1}, level)
+        UIDropDownMenu_AddButton({text="Show Quick Join Hint",checked=db.global.quickJoinHint, func=toggleQuickJoinHint,keepShownOnClick=true,isNotRadio=true}, level)
+		if canJoinGroup() then
             UIDropDownMenu_AddButton({text="Create a group for realm hoppers",notCheckable=1,func=CreateHopGroup}, level)
+			UIDropDownMenu_AddButton({text="Join to a friend",notCheckable=1,hasArrow=1,value="jtf",keepShownOnClick=true}, level)
         end
 
         UIDropDownMenu_AddButton({disabled=1,notCheckable=1}, level)
-        UIDropDownMenu_AddButton({text="Show Quick Join Hint",checked=db.global.quickJoinHint, func=toggleQuickJoinHint,keepShownOnClick=true,isNotRadio=true}, level)
-        UIDropDownMenu_AddButton({text="Settings",notCheckable=1,hasArrow=1,value="settings",keepShownOnClick=true}, level)
+        UIDropDownMenu_AddButton({text="Settings...",notCheckable=1,func=addon.showSettings}, level)
     elseif level == 2 then
-        if UIDROPDOWNMENU_MENU_VALUE == "settings" then
-            UIDropDownMenu_AddButton({text="Show Minimap Button",checked=not db.global.minimap.hide, func=toggleMinimapIcon,keepShownOnClick=true,isNotRadio=true}, level)
-            UIDropDownMenu_AddButton({text="All language groups",checked=db.global.allLanguages, func=toggleAllLanguages,keepShownOnClick=true,isNotRadio=true}, level)
-            UIDropDownMenu_AddButton({text="Apply to groups as DD only",checked=db.global.applyAsDD, func=toggleApplyAsDD,keepShownOnClick=true,isNotRadio=true}, level)
-            UIDropDownMenu_AddButton({disabled=1,notCheckable=1}, level)
-            UIDropDownMenu_AddButton({text="Quick join categories",notCheckable=1,hasArrow=1,value="qjc",keepShownOnClick=true}, level)
-            UIDropDownMenu_AddButton({text="Edit Quick Join Stoplist",notCheckable=1,func=QuickJoinStoplist}, level)
-            UIDropDownMenu_AddButton({disabled=1,notCheckable=1}, level)
-            UIDropDownMenu_AddButton({text="Experimental features",notCheckable=1,hasArrow=1,value="experimental",keepShownOnClick=true}, level)
-        end
-    elseif level == 3 then
-        if UIDROPDOWNMENU_MENU_VALUE == "qjc" then
-            for i=1,#lfgGroups do
-                local groupId = lfgGroups[i]
-                UIDropDownMenu_AddButton({text=(C_LFGList.GetCategoryInfo(groupId)),checked=db.global.quickJoin[groupId],arg1=groupId,func=toggleQuickJoin,keepShownOnClick=true,isNotRadio=true}, level)
-            end
-        elseif UIDROPDOWNMENU_MENU_VALUE == "experimental" then
-            UIDropDownMenu_AddButton({isTitle=1,text="Use at your own risk!",notCheckable=1}, level)
-            UIDropDownMenu_AddButton({text="Auto create group for realm hopping when AFK at garrison",checked=db.global.autoCreateHopGroup,keepShownOnClick=true,isNotRadio=true,func=toggleCreateHopGroup}, level)
-        end
+        if UIDROPDOWNMENU_MENU_VALUE == "jtf" then
+			local count, list = C_LFGList.GetSearchResults()
+			local friends = {}
+			for i = 1,count do
+				local rid = list[i];
+				if not rid then break end
+				local bnf, chf, gf = C_LFGList.GetSearchResultFriends(rid)
+				for j=1,#bnf do	table.insert(friends,{name="|cFF00B1F0"..bnf[j],type=0,id=rid}) end
+				for j=1,#chf do	table.insert(friends,{name="|cFFFF80FF"..chf[j],type=1,id=rid}) end
+				for j=1,#gf do table.insert(friends,{name="|cFF40FF40"..gf[j],type=2,id=rid}) end
+			end
+			if #friends==0 then
+				UIDropDownMenu_AddButton({text="No friends found (click to refresh)",notCheckable=1,func=addon.refreshLfgCurrent}, level)
+			else
+				UIDropDownMenu_AddButton({text="Refresh",notCheckable=1,func=addon.refreshLfgCurrent}, level)
+				table.sort(friends, sortByTypeAndName);
+				for i=1,#friends do
+					UIDropDownMenu_AddButton({text=friends[i].name,notCheckable=1,func=joinFriendGroup,arg1=friends[i].id}, level)
+				end
+			end
+		end
     end
 end