UI Rewrite to put as tab

Sasky [09-16-14 - 09:16]
UI Rewrite to put as tab
- Rewrite UI elements as actual fragments
- Tie into scene manager and tabs
- Add mini group listing
- Initial localization
Filename
AutoInvite.txt
AutoInviteUI.lua
lang/en.lua
ui/ai_enabled_fragment.lua
ui/ai_options_fragment.lua
ui/autoinvitescene.lua
ui/half_grouplist.lua
ui/half_grouplist.xml
diff --git a/AutoInvite.txt b/AutoInvite.txt
index c326407..08e1311 100644
--- a/AutoInvite.txt
+++ b/AutoInvite.txt
@@ -20,9 +20,19 @@ lib/LibAddonMenu-2.0/controls/header.lua
 lib/LibAddonMenu-2.0/controls/slider.lua
 lib/LibAddonMenu-2.0/controls/texture.lua

+lang/en.lua
+lang/$(language).lua
+
 lua/cli.lua
 lua/guild.lua
 lua/kick.lua
 lua/queue.lua
+
 AutoInviteUI.lua
+ui/half_grouplist.lua
+ui/half_grouplist.xml
+ui/ai_enabled_fragment.lua
+ui/ai_options_fragment.lua
+ui/autoinvitescene.lua
+
 AutoInvite.lua
diff --git a/AutoInviteUI.lua b/AutoInviteUI.lua
index d7bc5f1..c6ca912 100644
--- a/AutoInviteUI.lua
+++ b/AutoInviteUI.lua
@@ -15,157 +15,74 @@
 -- You should have received a copy of the GNU General Public License
 -- along with this program.  If not, see <http://www.gnu.org/licenses/>.

-AutoInviteUI = {}
+AutoInviteUI = AutoInviteUI or {}
 local ui = AutoInviteUI
 local wm = WINDOW_MANAGER

 function AutoInviteUI.create()
-    local pre = "AutoInviteUI"
-    ui.main = wm:CreateControl(nil, ZO_GroupList, CT_CONTROL)
-    ui.main:SetAnchor(TOPRIGHT, ZO_SharedRightBackground, TOPLEFT, -50, 50)
-    ui.main:SetDimensions(280,450)
-
-    ui.scroll = ui.main -- For using LAM controls
-    ui.data = {}
-
-    ui.bg = wm:CreateControl(pre .. "bg", ui.main, CT_BACKDROP)
-    ui.bg:SetDimensions(280,450)
-    ui.bg:SetAnchor(TOPLEFT, ui.main, TOPLEFT, 0, 0)
-    ui.bg:SetCenterColor( 0, 0, 0, .7 )
-    ui.bg:SetEdgeColor( 1, 1, 1, 0 )
-
-    ui.title = LAMCreateControl.header(ui, {
-        type = "header",
-        name = "AutoInvite Options",
-        width = "half"
-    })
-    ui.title:SetAnchor(TOPLEFT, ui.main, TOPLEFT, 5, 5)
-    ui.title:SetWidth(270)
-    ui.title.divider:ClearAnchors()
-    ui.title.divider:SetAnchor(BOTTOM)
-    ui.title.header:ClearAnchors()
-    ui.title.header:SetAnchor(TOPLEFT)
-
-    ui.enabled = LAMCreateControl.checkbox(ui, {
-        type = "checkbox",
-        name = "Enabled",
-        tooltip = "Whether to enable AutoInvite",
-        getFunc = function() return AutoInvite.listening end,
-        setFunc = function(val)
-            if val then AutoInvite.startListening() else AutoInvite.disable() end
-        end,
-        width = "half"
-    })
-    ui.enabled:SetDimensions(250, 26)
-    ui.enabled:SetAnchor(TOPLEFT, ui.title, BOTTOMLEFT, 10, 5)
-
-    ui.text = LAMCreateControl.editbox(ui, {
-        type = "editbox",
-        name = "Invite String",
-        tooltip = "Text to check messages to auto-invite for",
-        getFunc = function() return AutoInvite.cfg.watchStr end,
-        setFunc = function(val) AutoInvite.cfg.watchStr = val end,
-        width = "half"
-    })
-    ui.text:SetWidth(260)
-    ui.text:SetAnchor(TOPLEFT, ui.enabled, BOTTOMLEFT, 0, 5)
-
-    ui.max = LAMCreateControl.slider(ui, {
-        type = "slider",
-        name = "Max group size",
-        tooltip = "Maximum number of players to invite to group",
-        min = 4,
-        max = 24,
-        getFunc = function() return AutoInvite.cfg.maxSize end,
-        setFunc = function(val) AutoInvite.cfg.maxSize = val end,
-        default = 24,
-        width = "half"
-    })
-    ui.max:SetAnchor(TOPLEFT, ui.text, BOTTOMLEFT, 0, 10)
-
-    ui.restart = LAMCreateControl.checkbox(ui, {
-        type = "checkbox",
-        name = "Restart",
-        tooltip = "Restart AutoInvite if drop below max",
-        getFunc = function() return AutoInvite.cfg.restart end,
-        setFunc = function(val) AutoInvite.cfg.restart = val  end,
-        width = "half"
-    })
-    ui.restart:SetDimensions(250, 26)
-    ui.restart:SetAnchor(TOPLEFT, ui.max, BOTTOMLEFT, 0, 12)
-
-    ui.cyr = LAMCreateControl.checkbox(ui, {
-        type = "checkbox",
-        name = "Cyrodiil Check",
-        tooltip = "Only invite players that are in Cyrodiil.\n(This only runs if you are in Cyrodiil yourself.)",
-        getFunc = function() return AutoInvite.cfg.cyrCheck end,
-        setFunc = function(val) AutoInvite.cfg.cyrCheck = val end,
-        width = "half"
-    })
-    ui.cyr:SetDimensions(250, 26)
-    ui.cyr:SetAnchor(TOPLEFT, ui.restart, BOTTOMLEFT, 0, 5)
-
-    ui.kick = LAMCreateControl.checkbox(ui, {
-        type = "checkbox",
-        name = "Auto kick",
-        tooltip = "Kick players that go offline",
-        getFunc = function() return AutoInvite.cfg.autoKick end,
-        setFunc = function(val) AutoInvite.cfg.autoKick = val  end,
-        width = "half"
-    })
-    ui.kick:SetDimensions(250, 26)
-    ui.kick:SetAnchor(TOPLEFT, ui.cyr, BOTTOMLEFT, 0, 5)
-
-    ui.kickTime = LAMCreateControl.slider(ui, {
-        type = "slider",
-        name = "Time before kick",
-        tooltip = "Number of seconds to wait before kicking an offline player",
-        min = 5,
-        max = 600,
-        getFunc = function() return AutoInvite.cfg.kickDelay end,
-        setFunc = function(val) AutoInvite.cfg.kickDelay = val end,
-        default = 300,
-        width = "half"
-    })
-    ui.kickTime:SetAnchor(TOPLEFT, ui.kick, BOTTOMLEFT, 0, 5)
-
-    ui.note = LAMCreateControl.description(ui, {
-        type = "description",
-        title = "Slash Commands",
-        text = "/ai foo - start listening on 'foo'\n/ai - stop listening",
-        width = "half"
-    })
-    ui.note:SetAnchor(TOPLEFT, ui.kickTime, BOTTOMLEFT, 0, 25)
-    ui.note.desc:SetColor(.7,.7,.7,1)
-
-    ui.hide = wm:CreateControlFromVirtual(nil, ui.main, "ZO_DefaultButton")
-    ui.hide:SetAnchor(TOPRIGHT, ui.main, TOPRIGHT, 7, 2)
-    ui.hide:SetWidth(40)
-    ui.hide:SetText("X")
-    ui.hide:SetScale(0.8)
-    ui.hide:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-    ui.hide:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-    ui.hide:SetHandler("OnClicked", AutoInviteUI.menuHide)
+--    local pre = "AutoInviteUI"
+--    ui.main = wm:CreateControl(nil, ZO_GroupList, CT_CONTROL)
+--    ui.main:SetAnchor(TOPRIGHT, ZO_SharedRightBackground, TOPLEFT, -50, 50)
+--    ui.main:SetDimensions(280,450)
+--
+--    ui.bg = wm:CreateControl(pre .. "bg", ui.main, CT_BACKDROP)
+--    ui.bg:SetDimensions(280,450)
+--    ui.bg:SetAnchor(TOPLEFT, ui.main, TOPLEFT, 0, 0)
+--    ui.bg:SetCenterColor( 0, 0, 0, .7 )
+--    ui.bg:SetEdgeColor( 1, 1, 1, 0 )
+--
+--    AutoInviteUI.addControls(ui, pre)
+end

-    ui.show = wm:CreateControlFromVirtual(nil, ZO_GroupList, "ZO_DefaultButton")
-    ui.show:SetAnchor(TOPLEFT, ZO_GroupList, TOPLEFT, 120, -40)
-    ui.show:SetWidth(160)
-    ui.show:SetText("AutoInvite Settings")
-    ui.show:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
-    ui.show:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
-    ui.show:SetHandler("OnClicked", AutoInviteUI.menuShow)
+function AutoInviteUI.addControls(ui)
+--    ui.main:SetDimensions(280,450)
+--    ui.scroll = ui.main -- For using LAM controls
+--    ui.data = {}
+--
+--    ui.title = LAMCreateControl.header(ui, {
+--        type = "header",
+--        name = "AutoInvite Options",
+--        width = "half"
+--    })
+--    ui.title:SetAnchor(TOPLEFT, ui.main, TOPLEFT, 5, 5)
+--    ui.title:SetWidth(270)
+--    ui.title.divider:ClearAnchors()
+--    ui.title.divider:SetAnchor(BOTTOM)
+--    ui.title.header:ClearAnchors()
+--    ui.title.header:SetAnchor(TOPLEFT)
+
+
+
+
+
+--    ui.hide = wm:CreateControlFromVirtual(nil, ui.main, "ZO_DefaultButton")
+--    ui.hide:SetAnchor(TOPRIGHT, ui.main, TOPRIGHT, 7, 2)
+--    ui.hide:SetWidth(40)
+--    ui.hide:SetText("X")
+--    ui.hide:SetScale(0.8)
+--    ui.hide:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+--    ui.hide:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+--    ui.hide:SetHandler("OnClicked", AutoInviteUI.menuHide)
+--
+--    ui.show = wm:CreateControlFromVirtual(nil, ZO_GroupList, "ZO_DefaultButton")
+--    ui.show:SetAnchor(TOPLEFT, ZO_GroupList, TOPLEFT, 120, -40)
+--    ui.show:SetWidth(160)
+--    ui.show:SetText("AutoInvite Settings")
+--    ui.show:SetHandler("OnMouseEnter", ZO_Options_OnMouseEnter)
+--    ui.show:SetHandler("OnMouseExit", ZO_Options_OnMouseExit)
+--    ui.show:SetHandler("OnClicked", AutoInviteUI.menuShow)
 end

 function AutoInviteUI.menuShow()
-    ui.main:SetHidden(false)
-    ui.show:SetHidden(true)
-    AutoInvite.cfg.showPanel = true
+--    ui.main:SetHidden(false)
+--    ui.show:SetHidden(true)
+--    AutoInvite.cfg.showPanel = true
 end

 function AutoInviteUI.menuHide()
-    ui.main:SetHidden(true)
-    ui.show:SetHidden(false)
-    AutoInvite.cfg.showPanel = false
+--    ui.main:SetHidden(true)
+--    ui.show:SetHidden(false)
+--    AutoInvite.cfg.showPanel = false
 end

 function AutoInviteUI.refresh()
@@ -179,12 +96,9 @@ end
 function AutoInviteUI.init()
     if ui.created then return end
     ui.created = true
-    AutoInviteUI.create()
-    if AutoInvite.cfg.showPanel then
-        ui.show:SetHidden(true)
-    else
-        ui.main:SetHidden(true)
-    end
+    AutoInviteUI:CreateEnabledFragment()
+    AutoInviteUI:CreateOptionFragment()
+    AutoInviteUI:CreateScene()
 end

 SLASH_COMMANDS["/zzg"] = function()
diff --git a/lang/en.lua b/lang/en.lua
new file mode 100644
index 0000000..f57ca0e
--- /dev/null
+++ b/lang/en.lua
@@ -0,0 +1,20 @@
+-- This file is part of AutoInvite
+--
+-- (C) 2014 Scott Yeskie (Sasky)
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+ZO_CreateStringId("SI_AUTO_INVITE", "Auto Invite")
+ZO_CreateStringId("SI_AUTO_INVITE_STOP", "Stop AutoInvite")
+--ZO_CreateStringId("", "")
\ No newline at end of file
diff --git a/ui/ai_enabled_fragment.lua b/ui/ai_enabled_fragment.lua
new file mode 100644
index 0000000..0bd13a5
--- /dev/null
+++ b/ui/ai_enabled_fragment.lua
@@ -0,0 +1,53 @@
+-- This file is part of AutoInvite
+--
+-- (C) 2014 Scott Yeskie (Sasky)
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+AutoInviteUI = AutoInviteUI or {}
+local ui = {}
+local wm = WINDOW_MANAGER
+
+function AutoInviteUI:CreateEnabledFragment()
+    ui.main = wm:CreateTopLevelWindow("AutoInviteEnabledFragment")
+    ui.main:SetHidden(true)
+    ui.scroll = ui.main -- For using LAM controls
+    ui.data = {}
+
+    ui.enabled = LAMCreateControl.checkbox(ui, {
+        type = "checkbox",
+        name = "Enabled",
+        tooltip = "Whether to enable AutoInvite",
+        getFunc = function() return AutoInvite.listening end,
+        setFunc = function(val)
+            if val then AutoInvite.startListening() else AutoInvite.disable() end
+        end,
+        width = "half"
+    })
+    ui.enabled:SetDimensions(250, 26)
+    ui.enabled:SetAnchor(TOP, ZO_GroupList, TOP, 0, 20)
+
+    ui.text = LAMCreateControl.editbox(ui, {
+        type = "editbox",
+        name = "Invite String",
+        tooltip = "Text to check messages to auto-invite for",
+        getFunc = function() return AutoInvite.cfg.watchStr end,
+        setFunc = function(val) AutoInvite.cfg.watchStr = val end,
+        --width = "half"
+    })
+    ui.text:SetWidth(260)
+    ui.text:SetAnchor(TOPRIGHT, ZO_GroupList, TOPRIGHT, -40, 20)
+
+    AUTO_INVITE_ENABLED_FRAGMENT = ZO_FadeSceneFragment:New(ui.main)
+end
diff --git a/ui/ai_options_fragment.lua b/ui/ai_options_fragment.lua
new file mode 100644
index 0000000..f28f050
--- /dev/null
+++ b/ui/ai_options_fragment.lua
@@ -0,0 +1,95 @@
+-- This file is part of AutoInvite
+--
+-- (C) 2014 Scott Yeskie (Sasky)
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+AutoInviteUI = AutoInviteUI or {}
+local ui = {}
+local wm = WINDOW_MANAGER
+
+function AutoInviteUI:CreateOptionFragment()
+    ui.main = wm:CreateTopLevelWindow("AutoInviteOptionsFragment")
+    ui.main:SetAnchor(TOPRIGHT, ZO_GroupList, TOPRIGHT, -40, 60)
+    ui.main:SetHidden(true)
+    ui.scroll = ui.main -- For using LAM controls
+    ui.data = {}
+
+    ui.max = LAMCreateControl.slider(ui, {
+        type = "slider",
+        name = "Max group size",
+        tooltip = "Maximum number of players to invite to group",
+        min = 4,
+        max = 24,
+        getFunc = function() return AutoInvite.cfg.maxSize end,
+        setFunc = function(val) AutoInvite.cfg.maxSize = val end,
+        default = 24,
+        --width = "half"
+    })
+    ui.max:SetAnchor(TOPRIGHT, ui.main, TOPRIGHT, 0, 25)
+
+    ui.restart = LAMCreateControl.checkbox(ui, {
+        type = "checkbox",
+        name = "Restart",
+        tooltip = "Restart AutoInvite if drop below max",
+        getFunc = function() return AutoInvite.cfg.restart end,
+        setFunc = function(val) AutoInvite.cfg.restart = val  end,
+        --width = "half"
+    })
+    ui.restart:SetAnchor(TOPLEFT, ui.max, BOTTOMLEFT, 0, 25)
+
+    ui.cyr = LAMCreateControl.checkbox(ui, {
+        type = "checkbox",
+        name = "Cyrodiil Check",
+        tooltip = "Only invite players that are in Cyrodiil.\n(This only runs if you are in Cyrodiil yourself.)",
+        getFunc = function() return AutoInvite.cfg.cyrCheck end,
+        setFunc = function(val) AutoInvite.cfg.cyrCheck = val end,
+        --width = "half"
+    })
+    ui.cyr:SetAnchor(TOPLEFT, ui.restart, BOTTOMLEFT, 0, 25)
+
+    ui.kick = LAMCreateControl.checkbox(ui, {
+        type = "checkbox",
+        name = "Auto kick",
+        tooltip = "Kick players that go offline",
+        getFunc = function() return AutoInvite.cfg.autoKick end,
+        setFunc = function(val) AutoInvite.cfg.autoKick = val  end,
+        --width = "half"
+    })
+    ui.kick:SetAnchor(TOPLEFT, ui.cyr, BOTTOMLEFT, 0, 25)
+
+    ui.kickTime = LAMCreateControl.slider(ui, {
+        type = "slider",
+        name = "Time before kick",
+        tooltip = "Number of seconds to wait before kicking an offline player",
+        min = 5,
+        max = 600,
+        getFunc = function() return AutoInvite.cfg.kickDelay end,
+        setFunc = function(val) AutoInvite.cfg.kickDelay = val end,
+        default = 300,
+        --width = "half"
+    })
+    ui.kickTime:SetAnchor(TOPLEFT, ui.kick, BOTTOMLEFT, 0, 25)
+
+    ui.note = LAMCreateControl.description(ui, {
+        type = "description",
+        title = "Slash Commands",
+        text = "/ai foo - start listening on 'foo'\n/ai - stop listening",
+        --width = "half"
+    })
+    ui.note:SetAnchor(BOTTOMRIGHT, ZO_GroupList, BOTTOMRIGHT, -40, -40)
+    ui.note.desc:SetColor(.7,.7,.7,1)
+
+    AUTO_INVITE_OPTIONS_FRAGMENT = ZO_FadeSceneFragment:New(ui.main)
+end
\ No newline at end of file
diff --git a/ui/autoinvitescene.lua b/ui/autoinvitescene.lua
new file mode 100644
index 0000000..67bc4b3
--- /dev/null
+++ b/ui/autoinvitescene.lua
@@ -0,0 +1,117 @@
+-- This file is part of AutoInvite
+--
+-- (C) 2014 Scott Yeskie (Sasky)
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+AutoInviteUI = AutoInviteUI or {}
+
+local keybindStripDescriptor =
+{
+    alignment = KEYBIND_STRIP_ALIGN_CENTER,
+
+    -- Invite to Group
+    {
+        name = GetString(SI_GROUP_WINDOW_INVITE_PLAYER),
+        keybind = "UI_SHORTCUT_PRIMARY",
+
+        callback = function()
+            ZO_Dialogs_ShowDialog("GROUP_INVITE")
+        end,
+
+        visible = function()
+            --return not self.playerIsGrouped or (self.playerIsLeader and self.groupSize < GROUP_SIZE_MAX)
+            return (GetGroupSize() <= AutoInvite.cfg.maxSize)
+        end
+    },
+
+    -- Start Search
+    {
+        name = GetString(SI_GROUPING_TOOLS_PANEL_START_SEARCH),
+        keybind = "UI_SHORTCUT_SECONDARY",
+
+        callback = function()
+            AutoInvite.startListening()
+        end,
+
+        visible = function()
+            return not AutoInvite.enabled
+        end
+    },
+
+    -- Cancel Search
+    {
+        name = GetString(SI_GROUP_WINDOW_CANCEL_SEARCH),
+        keybind = "UI_SHORTCUT_NEGATIVE",
+
+        callback = function()
+            AutoInvite.disable()
+        end,
+
+        visible = function()
+            return AutoInvite.enabled
+        end
+    },
+}
+
+local function manageKeybinds(_, newState)
+    if(newState == SCENE_SHOWING) then
+        KEYBIND_STRIP:AddKeybindButtonGroup(keybindStripDescriptor)
+    elseif(newState == SCENE_HIDDEN) then
+        KEYBIND_STRIP:RemoveKeybindButtonGroup(keybindStripDescriptor)
+    end
+end
+
+function AutoInviteUI:CreateScene()
+    AUTO_INVITE_SCENE = ZO_Scene:New("autoInvite", SCENE_MANAGER)
+    AUTO_INVITE_SCENE:AddFragmentGroup(FRAGMENT_GROUP.MOUSE_DRIVEN_UI_WINDOW)
+    AUTO_INVITE_SCENE:AddFragmentGroup(FRAGMENT_GROUP.FRAME_TARGET_STANDARD_RIGHT_PANEL)
+    AUTO_INVITE_SCENE:AddFragment(RIGHT_BG_FRAGMENT)
+
+    --AUTO_INVITE_SCENE:AddFragment(GROUP_LIST_FRAGMENT)
+
+    AUTO_INVITE_SCENE:AddFragment(DISPLAY_NAME_FRAGMENT)
+    AUTO_INVITE_SCENE:AddFragment(TITLE_FRAGMENT)
+
+    AUTO_INVITE_SCENE:AddFragment(GROUP_TITLE_FRAGMENT)
+    AUTO_INVITE_SCENE:AddFragment(GROUP_MEMBERS_FRAGMENT)
+
+    AUTO_INVITE_SCENE:AddFragment(AI_SMALL_GROUP_LIST_FRAGMENT)
+
+    AUTO_INVITE_SCENE:AddFragment(AUTO_INVITE_OPTIONS_FRAGMENT)
+    AUTO_INVITE_SCENE:AddFragment(AUTO_INVITE_ENABLED_FRAGMENT)
+    --AUTO_INVITE_SCENE:AddFragment(PREFERRED_ROLES_FRAGMENT)
+    --AUTO_INVITE_SCENE:AddFragment(GROUP_CENTER_INFO_FRAGMENT)
+    --AUTO_INVITE_SCENE:AddFragment(SEARCHING_FOR_GROUP_FRAGMENT) --Could add this in
+    AUTO_INVITE_SCENE:AddFragment(GROUP_WINDOW_SOUNDS)
+
+    --AUTO_INVITE_SCENE:AddFragment(FRAME_EMOTE_FRAGMENT_SOCIAL)
+    AUTO_INVITE_SCENE:AddFragment(PLAYER_PROGRESS_BAR_FRAGMENT)
+    AUTO_INVITE_SCENE:AddFragment(PLAYER_PROGRESS_BAR_CURRENT_FRAGMENT)
+
+    MAIN_MENU.sceneGroupInfo.groupSceneGroup.menuBarIconData[3] = {
+        categoryName = SI_AUTO_INVITE,
+        descriptor = "autoInvite",
+        normal = "EsoUI/Art/Campaign/campaign_tabIcon_summary_up.dds",
+        pressed = "EsoUI/Art/Campaign/campaign_tabIcon_summary_down.dds",
+        highlight = "EsoUI/Art/Campaign/campaign_tabIcon_summary_over.dds",
+    }
+
+    SCENE_MANAGER:GetSceneGroup("groupSceneGroup").scenes[3] = "autoInvite"
+    AUTO_INVITE_SCENE:AddFragment(ZO_FadeSceneFragment:New(MAIN_MENU.sceneGroupBar))
+
+    AUTO_INVITE_SCENE:RegisterCallback("StateChange", manageKeybinds)
+
+    MAIN_MENU:AddRawScene("autoInvite", 6, MAIN_MENU.categoryInfo[6], "groupSceneGroup")
+end
\ No newline at end of file
diff --git a/ui/half_grouplist.lua b/ui/half_grouplist.lua
new file mode 100644
index 0000000..3a6dc0d
--- /dev/null
+++ b/ui/half_grouplist.lua
@@ -0,0 +1,271 @@
+-- This file is part of AutoInvite
+--
+-- (C) 2014 Scott Yeskie (Sasky)
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 2 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+local AI_SmallGroupListing = ZO_SortFilterList:Subclass()
+local AI_GROUP_LIST_ENTRIES = {}
+
+local AI_GROUP_DATA = 1
+
+local ENTRY_SORT_KEYS =
+{
+    ["displayName"] = { },
+}
+
+local STATUS_ORDERING = setmetatable({
+    ONLINE = 1,
+    OFFLINE = 2,
+    SENT = 3,
+    QUEUE = 4,
+    UNKNOWN = 5
+}, { __index = function() return 5 end })
+
+function AI_SmallGroupListing:New(control)
+    local manager = ZO_SortFilterList.New(self, control)
+
+    ZO_ScrollList_AddDataType(manager.list, AI_GROUP_DATA, "AI_SmallGroupListRow", 30, function(control, data) manager:SetupEntry(control, data) end)
+    --ZO_ScrollList_EnableHighlight(manager.list, "ZO_ThinListHighlight")
+
+    manager:SetEmptyText(GetString(SI_GROUP_LIST_PANEL_NO_GROUP_MESSAGE))
+    --manager:SetAlternateRowBackgrounds(true)
+    manager:RefreshData()
+
+    manager.sortHeaderGroup:SelectHeaderByKey("displayName")
+
+    --For updates, tie into the GROUP_MANAGER logic rather than run equivalent events
+    local hookedMasterList = false
+    ZO_PreHook(GROUP_LIST, "BuildMasterList", function(...)
+        d("Hooked BuildMasterList")
+        hookedMasterList = true
+        manager:RefreshData()
+        return true
+    end)
+
+    ZO_PreHook(GROUP_LIST, "FilterScrollList", function(...)
+        d("Hooked FilterScrollList")
+        if not hookedMasterList then
+            manager:FilterScrollList()
+        end
+        hookedMasterList = false
+        return true
+    end)
+
+    AI_SMALL_GROUP_LIST_FRAGMENT = ZO_FadeSceneFragment:New(AI_SmallGroupList)
+
+    return manager
+end
+
+function AI_SmallGroupListing:updateSingle(name)
+    d("Calling AI_SmallGroupListing:updateSingle()")
+    --Used for sent invite, invite declined, add to queue
+    --Updates that one entry then
+    local scrollData = ZO_ScrollList_GetDataList(self.list)
+
+    if AI_GROUP_LIST_ENTRIES[name] then
+        AI_GROUP_LIST_ENTRIES[name]:Update()
+    else
+       AI_GROUP_LIST_ENTRIES[name] = AI_SLG_Entry.New(name)
+    end
+
+    self:RefreshFilters()
+end
+
+function AI_SmallGroupListing:removeSingle(name)
+    d("Calling AI_SmallGroupListing:updateSingle()")
+    AI_GROUP_LIST_ENTRIES[name] = nil
+    self:RefreshFilters()
+end
+
+function AI_SmallGroupListing:getStatus(data)
+    --TODO: Make this a LUT
+    local status = data.status
+    if status == STATUS_ORDERING.ONLINE then
+        return "|c33CC33Online"
+    end
+
+    if status == STATUS_ORDERING.OFFLINE then
+        return "|c666666Offline"
+    end
+
+    if status == STATUS_ORDERING.SENT then
+        return "|c999966Sent"
+    end
+
+    if status == STATUS_ORDERING.QUEUE then
+        return "|c999999Queue"
+    end
+
+    return ""
+end
+
+function AI_SmallGroupListing:SetupEntry(control, data)
+    ZO_SortFilterList.SetupRow(self, control, data)
+
+    control.displayName = data.displayName
+
+    GetControl(control, "DisplayName"):SetText(data.displayName)
+    GetControl(control, "Status"):SetText(self:getStatus(data))
+    --GetControl(control, "BG"):SetWidth(300)
+end
+
+function AI_SmallGroupListing.CompareMembers(listEntry1, listEntry2)
+    local d1 = listEntry1.data
+    local d2 = listEntry2.data
+
+    if d1.status == d2.status then
+        return string.lower(d1.displayName) < string.lower(d2.displayName)
+    else
+        return d1.status < d2.status
+    end
+end
+
+local function addTestCase(name, status, arg)
+    AI_GROUP_LIST_ENTRIES[name] = AI_SLG_Entry.NewDefined(name, status, arg)
+end
+
+function AI_SmallGroupListing:BuildMasterList()
+    d("Calling AI_SmallGroupListing:BuildMasterList()")
+    AI_GROUP_LIST_ENTRIES = {}
+
+    for i=1,GetGroupSize() do
+        local tag = GetGroupUnitTagByIndex(i)
+        local name = GetUnitName(tag)
+        AI_GROUP_LIST_ENTRIES[name] = AI_SLG_Entry.New(name, tag)
+    end
+
+    for name,time in pairs(AutoInvite.sentInvite) do
+        AI_GROUP_LIST_ENTRIES[name] = AI_SLG_Entry.NewDefined(name, STATUS_ORDERING.SENT, time)
+    end
+
+    for _,name in pairs(AutoInvite.__getQueue()) do
+        AI_GROUP_LIST_ENTRIES[name] = AI_SLG_Entry.NewDefined(name, STATUS_ORDERING.QUEUE)
+    end
+
+    addTestCase("Zaniira", 1)
+    addTestCase("Ravlor", 2)
+    addTestCase("Sasky", 1)
+    addTestCase("Jinsa", 3)
+    addTestCase("Sascii", 4)
+end
+
+function AI_SmallGroupListing:FilterScrollList()
+    d("Calling AI_SmallGroupListing:FilterScrollList()")
+    -- No filtering. Copy over from master list
+    local scrollData = ZO_ScrollList_GetDataList(self.list)
+    ZO_ClearNumericallyIndexedTable(scrollData)
+
+    for _,data in pairs(AI_GROUP_LIST_ENTRIES) do
+        table.insert(scrollData, ZO_ScrollList_CreateDataEntry(AI_GROUP_DATA, data))
+    end
+end
+
+function AI_SmallGroupListing:SortScrollList()
+    d("Calling AI_SmallGroupListing:SortScrollList()")
+    if(self.currentSortKey ~= nil and self.currentSortOrder ~= nil) then
+        local scrollData = ZO_ScrollList_GetDataList(self.list)
+        table.sort(scrollData, self.CompareMembers)
+    end
+end
+
+AI_SLG_Entry = {__index = AI_SLG_Entry}
+
+function AI_SLG_Entry.New(name, tag)
+    local self = setmetatable({}, AI_SLG_Entry)
+    self.status = STATUS_ORDERING.UNKNOWN
+    self.displayName = name
+    self.unitName = tag
+    self:update()
+    return self
+end
+
+--For debugging
+function AI_SLG_Entry.NewDefined(name, status, arg)
+    local self = setmetatable({}, AI_SLG_Entry)
+    self.status = status
+    self.displayName = name
+    function self.update() end --No-op
+
+    if status == STATUS_ORDERING.queue then
+        self.position = arg
+    else
+        self.time = arg
+    end
+
+    return self
+end
+
+function AI_SLG_Entry:update()
+    local name = self.displayName
+    local tag = self.unitName
+    if GetUnitName(tag) == name then
+        d(name .. " in group")
+        local offline = AutoInvite.kickTable[name]
+        if IsUnitOnline(tag) then
+            self.status = STATUS_ORDERING.ONLINE
+        else
+            self.status = STATUS_ORDERING.OFFLINE
+            self.time = offline
+        end
+    else
+        d(name .. " not in group")
+        local sent = AutoInvite:IsInviteSent(name)
+        if sent then
+            d(name .. " sent")
+            self.status = STATUS_ORDERING.SENT
+            self.time = sent
+        else
+            local queue = AutoInvite:IsInQueue(name)
+            if queue then
+                d(name .. " in queue")
+                self.status = STATUS_ORDERING.QUEUE
+                --self.position = queue
+            end
+        end
+    end
+end
+
+
+--Global XML Handlers
+-----------------------
+--function ZO_IgnoreListManager:IgnoreListPanelRow_OnMouseUp(control, button, upInside)
+--    if(button == 2 and upInside) then
+--        ClearMenu()
+--
+--        local data = ZO_ScrollList_GetData(control)
+--        if data then
+--            AddMenuItem(GetString(SI_SOCIAL_MENU_EDIT_NOTE), GetNoteEditFunction(self.control, data.displayName))
+--            AddMenuItem(GetString(SI_IGNORE_MENU_REMOVE_IGNORE), function() RemoveIgnore(data.displayName) end)
+--
+--            self:ShowMenu(control)
+--        end
+--    end
+--end
+
+function AI_SmallGroupListing_OnMouseEnter(control)
+    MINI_GROUP_LIST:Row_OnMouseEnter(control)
+end
+
+function AI_SmallGroupListing_OnMouseExit(control)
+    MINI_GROUP_LIST:Row_OnMouseExit(control)
+end
+
+--function AI_SmallGroupListing_OnMouseUp(control, button, upInside)
+--    MINI_GROUP_LIST:IgnoreListPanelRow_OnMouseUp(control, button, upInside)
+--end
+
+function AI_SmallGroupListing_OnInitialized(self)
+    MINI_GROUP_LIST = AI_SmallGroupListing:New(self)
+end
diff --git a/ui/half_grouplist.xml b/ui/half_grouplist.xml
new file mode 100644
index 0000000..adc6242
--- /dev/null
+++ b/ui/half_grouplist.xml
@@ -0,0 +1,96 @@
+<!--
+  ~ This file is part of AutoInvite
+  ~
+  ~ (C) 2014 Scott Yeskie (Sasky)
+  ~
+  ~ This program is free software; you can redistribute it and/or modify
+  ~ it under the terms of the GNU General Public License as published by
+  ~ the Free Software Foundation; either version 2 of the License, or
+  ~ (at your option) any later version.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  ~ GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License
+  ~ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  -->
+
+<GuiXml>
+    <Controls>
+        <Label name="AI_SmallGroupListLabel" font="ZoFontGame" wrapMode="ELLIPSIS" virtual="true"/>
+        <Control name="AI_SmallGroupListRow" mouseEnabled="true" virtual="true">
+            <Dimensions x="300" y="30"/>
+            <OnMouseEnter>
+                AI_SmallGroupListing_OnMouseEnter(self)
+            </OnMouseEnter>
+            <OnMouseExit>
+                AI_SmallGroupListing_OnMouseExit(self)
+            </OnMouseExit>
+            <!--<OnMouseUp>
+                AI_SmallGroupListing_OnMouseUp(self, button, upInside)
+            </OnMouseUp>-->
+            <Controls>
+                <Texture name="$(parent)BG" inherits="ZO_ThinListBgStrip" hidden="true">
+                    <Dimensions x="260"/>
+                </Texture>
+
+                <!--<Button name="$(parent)Cancel" inherits="ZO_IgnoreListRowButton">
+                    <Anchor point="LEFT" offsetX="5"/>
+                    <Textures
+                            normal="EsoUI/Art/Buttons/cancel_up.dds"
+                            pressed="EsoUI/Art/Buttons/cancel_down.dds"
+                            mouseOver="EsoUI/Art/Buttons/cancel_over.dds"
+                            />
+                    <OnMouseEnter>
+                        ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_IGNORE_LIST_REMOVE_IGNORE))
+                        ZO_IgnoreListRow_OnMouseEnter(self:GetParent())
+                    </OnMouseEnter>
+                    <OnMouseExit>
+                        ZO_Tooltips_HideTextTooltip()
+                        ZO_IgnoreListRow_OnMouseExit(self:GetParent())
+                    </OnMouseExit>
+                    <OnClicked>
+                        RemoveIgnore(self:GetParent().displayName)
+                    </OnClicked>
+                </Button>-->
+                <Label name="$(parent)Status" inherits="AI_SmallGroupListLabel">
+                    <Anchor point="LEFT" offsetX="5"/>
+                    <Dimensions x="50"/>
+                </Label>
+                <Label name="$(parent)DisplayName" inherits="AI_SmallGroupListLabel">
+                    <Anchor point="LEFT" relativeTo="$(parent)Status" relativePoint="RIGHT" offsetX="10"/>
+                    <Dimensions x="200"/>
+                </Label>
+            </Controls>
+        </Control>
+
+        <TopLevelControl name="AI_SmallGroupList" inherits="ZO_RightPanelFootPrint" hidden="true">
+            <OnInitialized>
+                AI_SmallGroupListing_OnInitialized(self)
+            </OnInitialized>
+            <Controls>
+                <Control name="$(parent)Headers">
+                    <Anchor point="TOPLEFT" offsetX="30" offsetY="67"/>
+                    <Anchor point="TOPRIGHT" offsetY="67" offsetX="-500"/>
+                    <Dimensions y="32"/>
+                    <Controls>
+                        <Control name="$(parent)DisplayName" inherits="ZO_SortHeader">
+                            <OnInitialized>
+                                ZO_SortHeader_Initialize(self, GetString(SI_GROUP_LIST_PANEL_NAME_HEADER), "displayName", ZO_SORT_ORDER_UP, TEXT_ALIGN_LEFT, "ZoFontGameLargeBold")
+                            </OnInitialized>
+                            <Anchor point="TOPLEFT" offsetX="59"/>
+                            <Dimensions x="200" y="32"/>
+                        </Control>
+                    </Controls>
+                </Control>
+
+                <Control name="$(parent)List" inherits="ZO_ScrollList">
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)Headers" relativePoint="BOTTOMLEFT" offsetY="3"/>
+                    <Anchor point="BOTTOMRIGHT" offsetX="-35" offsetY="-32"/>
+                </Control>
+            </Controls>
+        </TopLevelControl>
+    </Controls>
+</GuiXml>
\ No newline at end of file