Now has a pretty progress bar

Wobin [05-02-14 - 17:37]
Now has a pretty progress bar
Filename
Roomba.lua
Roomba.txt
Roomba.xml
bindings.xml
diff --git a/Roomba.lua b/Roomba.lua
index ce5a067..d8fa115 100644
--- a/Roomba.lua
+++ b/Roomba.lua
@@ -4,44 +4,54 @@
  -
  ]]

-Roomba = {}
+Roomba = ZO_Object:Subclass()
+
+function Roomba:New(...)
+    local roomba = ZO_Object.New(self)
+    roomba:Initialize(...)
+    return roomba
+end
+
+function Roomba:Initialize(control)
+	self.control = control
+	control.ref = self
+	self:InitializeFrame()
+	self:InitializeSettings()
+end

 local LAM = LibStub:GetLibrary("LibAddonMenu-1.0")
 local BACKPACK = ZO_PlayerInventoryBackpack.data
 local GUILDBANK = ZO_GuildBankBackpack.data
-local DELAY = 150
-
-
+local WM = WINDOW_MANAGER
+local DELAY = 100
+local settings = {}
+local format = "                     %3d"
 local containerHooks = { INVENTORY_BACKPACK, INVENTORY_BANK, INVENTORY_GUILD_BANK }
-
-Roomba.currentInventory = {}
-Roomba.guildInfo = {}
+local currentRun = {}

 local function GetItemID(link)
 	return tonumber(string.match(string.match(link, "%d+:"), "%d+"))
 end

-function Roomba.dmsg(msg)
-	if Roomba.Debugging then d(msg) end
+function Roomba:dmsg(msg)
+	if settings.Debugging then d(msg) end
 end

-local dmsg = Roomba.dmsg
-
-function GetInstanceId(target, slotId)
+local function GetInstanceId(target, slotId)
     for i,v in ipairs(target) do
         if v.data.slotIndex == slotId then return v.data.itemInstanceId end
     end
 	return nil
 end

-function FindSlot(target, slotId)
+local function FindSlot(target, slotId)
 	for i,v in ipairs(target) do
 		if v.data.slotIndex == slotId then return i,v.data end
 	end
 	return nil
 end

-local function ClearGuildDetails(guildId)
+local function ClearGuildDetails(guildId)
 	return {	name = GetGuildName(guildId),
 				lookUp = {},
 				duplicates = {},
@@ -49,52 +59,49 @@ local function ClearGuildDetails(guildId)
 			}
 end

+function TableEntryCount(t)
+	local i = next(t)
+	local c = 0
+	while i do
+		c = c + 1
+		i = next(t, i)
+	end
+	return c
+end
+
 -- Who is your Guild and what do they do
-local function GetGuildDetails()
+function Roomba:GetGuildDetails()
+	d("Wiping Guilds")
 	for guildIndex = 1, GetNumGuilds()	do
 		local guildId = GetGuildId(guildIndex)
 		if DoesGuildHavePrivilege(guildId, GUILD_PRIVILEGE_BANK_DEPOSIT) then
-			Roomba.guildInfo[guildId] = true
+			self.guildInfo[guildId] = true
 		end
 	end
 end

 -- Okay, let's see.
 -- First we'll take current bag inventory.
-local function CheckWeHaveEnoughRoom()
-	return CheckInventorySpaceAndWarn(2)
-end
-
--- Now take stock of everything so we don't accidentally move stuff out
--- of our inventory into the bank
-local function AuditCurrentInventory()
-	local _, totalSlots = GetBagInfo(INVENTORY_BACKPACK)
-	Roomba.currentInventory = {}
-	for slot=1, totalSlots do
-		local id = GetItemInstanceId(INVENTORY_BACKPACK, slot)
-		local count = GetItemTotalCount(INVENTORY_BACKPACK, slot)
-		Roomba.currentInventory[slot] = id
-	end
+function Roomba:CheckWeHaveEnoughRoom()
+	return CheckInventorySpaceAndWarn(5)
 end

-
-local function HaveStuffToStack()
-	local bank = Roomba.guildInfo[GetSelectedGuildBankId()]
+function Roomba:HaveStuffToStack()
+	local bank = self.guildInfo[GetSelectedGuildBankId()]
 	if type(bank) == "table" and next(bank.duplicates) then return true end
 	return false
 end

 local checkingBank = false
-local currentBank = 1

 -- Bank is ready! Find those duplicates!
-function Roomba.RoombaReady()
+function Roomba:RoombaReady()
 	if not checkingBank then checkingBank = true else return end
-	local bank = Roomba.guildInfo[GetSelectedGuildBankId()]
+	local bank = self.guildInfo[GetSelectedGuildBankId()]
 	if not bank then return end
-	Roomba.guildInfo[GetSelectedGuildBankId()] = ClearGuildDetails(GetSelectedGuildBankId())
-	bank = Roomba.guildInfo[GetSelectedGuildBankId()]
-	dmsg("Bank is ready: " .. #GUILDBANK)
+	self.guildInfo[GetSelectedGuildBankId()] = ClearGuildDetails(GetSelectedGuildBankId())
+	bank = self.guildInfo[GetSelectedGuildBankId()]
+	self:dmsg("Bank is ready")
     -- We only need to store A) slots with items
 	for index, slot in ipairs(GUILDBANK) do
         if slot.data.equipType == 0 then -- Equipped gear cannot be stacked
@@ -110,14 +117,15 @@ function Roomba.RoombaReady()
                     bank.lookUp[id] = {} -- It's a new item!
                 end
                 -- Now group all items by id
-                table.insert(bank.lookUp[id], {slot = slot.data.slotIndex, count = count})
+                table.insert(bank.lookUp[id], {slot = slot.data.slotIndex, count = count, texture = slot.data.iconFile})
             end
         end
     end
     zo_callLater(function() checkingBank = nil end, 3000)
-    if KEYBIND_STRIP:HasKeybindButtonGroup(Roomba.runDescriptor) then
-    	KEYBIND_STRIP:UpdateKeybindButtonGroup(Roomba.runDescriptor)
-    end
+    if KEYBIND_STRIP:HasKeybindButtonGroup(self.runDescriptor) then
+    	KEYBIND_STRIP:UpdateKeybindButtonGroup(self.runDescriptor)
+    end
+    currentRun = {}
 end

 --[[
@@ -136,6 +144,7 @@ local cSlotIdx = nil
 local cSlot = nil
 local baseSlot = nil

+
 local inBagCollection = {}

 local function ResetAll()
@@ -145,67 +154,67 @@ local function ResetAll()
 	baseSlot = nil
 end

-function Roomba.SelectGuildBank(...)
+function Roomba:SelectGuildBank(...)
 	local eventId, guildBankId = ...
-	currentBank = guildBankId
+	self.currentBank = guildBankId
 	checkingBank = nil
 end

-transitBag = {}
+local transitBag = {}
 local currentReturnIndex

-function Roomba.ReturnItemsToBank(...)
+function Roomba:ReturnItemsToBank(...)
     local error = ...
     local slot
 	-- Now that we've stacked it all lets move it back
-    dmsg("Getting next to move back to bank")
+    self:dmsg("Getting next to move back to bank")
     currentReturnIndex, slot = next(inBagCollection)
     if slot then
         if error then
-            dmsg("trying again")
-            return zo_callLater(Roomba.ReturnItemsToBank, 2000)
+            self:dmsg("trying again")
+            return zo_callLater(function(...) self:ReturnItemsToBank() end, 2000)
         end
         if FindSlot(BACKPACK, slot.bagSlot) then
-            dmsg("Moving stuff back from ".. slot.bagSlot)
+            self:dmsg("Moving stuff back from ".. slot.bagSlot)
             return TransferToGuildBank(INVENTORY_BACKPACK, slot.bagSlot)
         else
             -- we have a space, move to next
             table.remove(inBagCollection, currentReturnIndex)
-            return zo_callLater(Roomba.ReturnItemsToBank, DELAY)
+            return zo_callLater(function(...) self:ReturnItemsToBank(...) end, DELAY)
         end
     else
         -- No more to move, we're complete
-        dmsg("unregistering")
+        self:dmsg("unregistering")
         EVENT_MANAGER:UnregisterForEvent("RoombaGuildBankError", EVENT_GUILD_BANK_TRANSFER_ERROR)
         EVENT_MANAGER:UnregisterForEvent("RoombaGuildBankSuccess", EVENT_GUILD_BANK_ITEM_ADDED)
         -- Kick off the next transaction
-        dmsg("Finished processing item")
+        self:dmsg("Finished processing item")
         ResetAll()
-        return zo_callLater(Roomba.BeginProcess, DELAY)
+        return zo_callLater(function() self:BeginProcess() end, DELAY)
     end
 end

-function Roomba.BankItemsReceived(...)
-	local _, gslot = ...
+function Roomba:BankItemsReceived(...)
+	local eventId, gslot = ...
     local id = GetInstanceId(GUILDBANK, gslot)
     if id ~= cInstanceId then return end
-    dmsg("Moved successfully to slot " ..gslot)
+    self:dmsg("Moved successfully to slot " ..gslot)
     -- We've moved one back! Remove it from contention
     local slot = table.remove(inBagCollection, currentReturnIndex)
     currentReturnIndex = nil
-    dmsg("Clearing slot " .. slot.bagSlot)
-    return zo_callLater(Roomba.ReturnItemsToBank, DELAY)
+    self:dmsg("Clearing slot " .. slot.bagSlot)
+    return zo_callLater(function(...) self:ReturnItemsToBank() end, DELAY)
 end


-function Roomba.StartStacking()
-	dmsg("Found an item to stack")
+function Roomba:StartStacking()
+	self:dmsg("Found an item to stack")
 	baseSlot = nil
     EVENT_MANAGER:UnregisterForEvent("RoombaInventoryAdded", EVENT_INVENTORY_SINGLE_SLOT_UPDATE)
 	for _,slot in pairs(inBagCollection) do
 		if not baseSlot then
 			-- We want to stack everything on this
-			dmsg("Setting ".. slot.bagSlot .." as base slot")
+			self:dmsg("Setting ".. slot.bagSlot .." as base slot")
 			baseSlot = slot
 		else
             baseSlot.count, baseSlot.stack = GetSlotStackSize(INVENTORY_BACKPACK, slot.bagSlot)
@@ -222,30 +231,30 @@ function Roomba.StartStacking()
 				if (result) then result = CallSecureProtected("PlaceInInventory", INVENTORY_BACKPACK, baseSlot.bagSlot) end
 			end
 			ClearCursor()
-            dmsg("Stacked item in backpack")
+            self:dmsg("Stacked item in backpack")
 		end
 	end
 	baseSlot = nil
     -- These events will loop the move back to the guild bank
-	EVENT_MANAGER:RegisterForEvent("RoombaGuildBankError", EVENT_GUILD_BANK_TRANSFER_ERROR, Roomba.ReturnItemsToBank)
-	EVENT_MANAGER:RegisterForEvent("RoombaGuildBankSuccess", EVENT_GUILD_BANK_ITEM_ADDED, Roomba.BankItemsReceived)
-    return zo_callLater(Roomba.ReturnItemsToBank, 1000)
+	EVENT_MANAGER:RegisterForEvent("RoombaGuildBankError", EVENT_GUILD_BANK_TRANSFER_ERROR, function(...) self:ReturnItemsToBank() end)
+	EVENT_MANAGER:RegisterForEvent("RoombaGuildBankSuccess", EVENT_GUILD_BANK_ITEM_ADDED, function(...) self:BankItemsReceived(...) end)
+    return zo_callLater(function(...) self:ReturnItemsToBank() end, 1000)
 end


 -- Event called that item has arrived
-function Roomba.ReceiveItems(...)
+function Roomba:ReceiveItems(...)
 	if baseSlot then return end -- We're still stacking
 	local _, bagId, slotId = ...
     if bagId ~= INVENTORY_BACKPACK then return end
 	if not cInstanceId then return end
 	if IsItemJunk(INVENTORY_BACKPACK, slotId) then
 		SetItemIsJunk(INVENTORY_BACKPACK, slotId, false)
-		return zo_callLater(function(...) Roomba.ReceiveItems(...) end, 1000)
+		return zo_callLater(function(...) self:ReceiveItems(...) end, 1000)
 	end
     if not GetInstanceId(BACKPACK, slotId) then return end -- are we empty
 	if GetInstanceId(BACKPACK, slotId) ~= cInstanceId then return end
-    dmsg("Checking " .. bagId .. " inventory slot " .. slotId .. " to match ".. cInstanceId .. " with " .. (GetInstanceId(BACKPACK, slotId) or "nothing"))
+    self:dmsg("Checking " .. bagId .. " inventory slot " .. slotId .. " to match ".. cInstanceId .. " with " .. (GetInstanceId(BACKPACK, slotId) or "nothing"))
     cSlot.bagSlot = slotId
 	table.insert(inBagCollection, cSlot)
 	-- If we have another slot to move
@@ -253,45 +262,56 @@ function Roomba.ReceiveItems(...)
 		cSlotIdx, cSlot = next(cDuplicateList, cSlotIdx)
 		TransferFromGuildBank(cSlot.slot)
 	else -- No more slots to move, let's stack them
-		return zo_callLater(Roomba.StartStacking, DELAY)
+		return zo_callLater(function() self:StartStacking() end, DELAY)
 	end
 end

-function Roomba.BeginProcess()
-    local bank = Roomba.guildInfo[currentBank]
+function Roomba:BeginProcess()
+    local bank = self.guildInfo[self.currentBank]
     if not bank then return end
+    self:dmsg("Checking for space")
+    if not self:CheckWeHaveEnoughRoom() then return end

     cSlotIdx = nil

     -- Pull the next job off the stack
     cInstanceId, cDuplicateList = next(bank.duplicates, cInstanceId)
+
+    if cInstanceId then currentRun[cInstanceId] = true end
+
+    self.control:SetHidden(false)
+    local index = TableEntryCount(currentRun)
+    local total = TableEntryCount(bank.duplicates)
+    ZO_StatusBar_SmoothTransition(self.speedRow.bar, index , total, FORCE_VALUE)
+    self.speedRow.name:SetText(string.format(format, (index/total)*100) .. "%")
+

     if cDuplicateList then -- First off the rank
         cSlotIdx, cSlot = next(cDuplicateList, cSlotIdx)
+
+        self.icon:SetTexture(cSlot.texture)

         -- Clear this batch
         inBagCollection = {}
         -- And start off the job
-        dmsg("Stacking up ".. zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemLink(3, cSlot.slot, LINK_STYLE_DEFAULT)))
+        self:dmsg("Stacking up ".. zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemLink(3, cSlot.slot, LINK_STYLE_DEFAULT)))

         -- If it suddenly doesn't exist, try the next in the list
-        if not FindSlot(GUILDBANK, cSlot.slot) then return zo_callLater(Roomba.BeginProcess, DELAY) end
+        if not FindSlot(GUILDBANK, cSlot.slot) then return zo_callLater(function() self:BeginProcess() end, DELAY) end

-        EVENT_MANAGER:RegisterForEvent("RoombaInventoryAdded", EVENT_INVENTORY_SINGLE_SLOT_UPDATE, Roomba.ReceiveItems)
+        EVENT_MANAGER:RegisterForEvent("RoombaInventoryAdded", EVENT_INVENTORY_SINGLE_SLOT_UPDATE, function(...) self:ReceiveItems(...) end)
         TransferFromGuildBank(cSlot.slot)
     else
-        dmsg("Nothing to restack")
+        self:dmsg("Nothing to restack")
         -- Now rescan and show/hide roomba button
-        Roomba.RoombaReady()
+        self.control:SetHidden(true)
+
+        self:RoombaReady()
         return false
     end
     return true
 end

-local function  IsUsePossible(name)
-	return true
-end
-
 local function RoombaLoaded(eventCode, addOnName)

 	if(addOnName ~= "Roomba") then
@@ -299,48 +319,69 @@ local function RoombaLoaded(eventCode, addOnName)
     end

 	local defaults = {
+		Debugging = true
 	}
+	ROOMBA:GetGuildDetails()
+	ZO_CreateStringId("SI_BINDING_NAME_RUN_ROOMBA", "Run Roomba")
+	ZO_CreateStringId("SI_BINDING_NAME_RESCAN_ROOMBA", "Rescan Bank")
+	settings = ZO_SavedVars:New("Roomba_Settings", 3, nil, defaults)
+    SLASH_COMMANDS["/roombadebug"] = function() settings.Debugging = not settings.Debugging d("Turning debug ".. (settings.Debugging and "on" or "off")) end

-	GetGuildDetails()
-
-	SLASH_COMMANDS["/roombadebug"] = function() Roomba.Debugging = not Roomba.Debugging d("Turning debug ".. (Roomba.Debugging and "on" or "off")) end
+end

-	ZO_CreateStringId("SI_BINDING_NAME_RUN_ROOMBA", "Run Roomba")
-	ZO_CreateStringId("SI_BINDING_NAME_RESCAN_ROOMBA", "Rescan Bank")
+function Roomba:InitializeSettings()
+
+	self.guildInfo = {}
+	self.currentBank = 1

-	Roomba.runDescriptor = {
+	self.runDescriptor = {
 		alignment = KEYBIND_STRIP_ALIGN_LEFT,
 		{
 		    name = "Run Roomba", -- or function that returns a name
 		    keybind = "RUN_ROOMBA",
-		    callback = function(descriptor) Roomba.BeginProcess() end, -- First and only argument is this descriptor table
-		    visible = function(descriptor) return HaveStuffToStack() end, -- An optional predicate, if present returning true indicates that this descriptor is visible, otherwise it is not
-		    icon = [[Roomba\media\Roomba.dds]], -- or a function that returns an icon path, an optional icon to display to the right of the name
+		    control = self,
+		    callback = function(descriptor) self:BeginProcess() end,
+		    visible = function(descriptor) return self:HaveStuffToStack() end,
+		    icon = [[Roomba\media\Roomba.dds]],
 		},
 		{
-		    name = "Scan Bank", -- or function that returns a name
+		    name = "Scan Bank",
 		    keybind = "RESCAN_ROOMBA",
-		    callback = function(descriptor) Roomba.RoombaReady() end, -- First and only argument is this descriptor table
-		    visible = function(descriptor) return ZO_GuildBankBackpackLoading:IsHidden() end, -- An optional predicate, if present returning true indicates that this descriptor is visible, otherwise it is not
-		    icon = [[Roomba\media\RoombaSearch.dds]], -- or a function that returns an icon path, an optional icon to display to the right of the name
+		    control = self,
+		    callback = function(descriptor) self:RoombaReady() end,
+		    visible = function(descriptor) return ZO_GuildBankBackpackLoading:IsHidden() end,
+		    icon = [[Roomba\media\RoombaSearch.dds]],
 		},
-
 	}
+	local bGroup = self.runDescriptor

-	settings = ZO_SavedVars:New("Roomba_Settings", 3, nil, defaults)
-
     -- Guild bank is evented to be ready, but wait a short while before processing.
-	EVENT_MANAGER:RegisterForEvent("RoombaReady", EVENT_GUILD_BANK_ITEMS_READY, function() zo_callLater(Roomba.RoombaReady, 1000) end)
+	EVENT_MANAGER:RegisterForEvent("RoombaReady", EVENT_GUILD_BANK_ITEMS_READY, function() zo_callLater(function() self:RoombaReady() end, 1000) end)
 	-- Clear the flag when swapping banks
-	EVENT_MANAGER:RegisterForEvent("RoombaSelected", EVENT_GUILD_BANK_SELECTED, Roomba.SelectGuildBank)
+	EVENT_MANAGER:RegisterForEvent("RoombaSelected", EVENT_GUILD_BANK_SELECTED, function(...) self:SelectGuildBank(...) end)
 	EVENT_MANAGER:RegisterForEvent("RoombaGuildBankOpen", EVENT_OPEN_GUILD_BANK, function()
-		if not KEYBIND_STRIP:HasKeybindButtonGroup(Roomba.runDescriptor) then
-			KEYBIND_STRIP:AddKeybindButtonGroup(Roomba.runDescriptor)
+		if not KEYBIND_STRIP:HasKeybindButtonGroup(bGroup) then
+			KEYBIND_STRIP:AddKeybindButtonGroup(bGroup)
 		end	end)
-	EVENT_MANAGER:RegisterForEvent("RoombaGuildBankOpen", EVENT_CLOSE_GUILD_BANK, function()
-		if KEYBIND_STRIP:HasKeybindButtonGroup(Roomba.runDescriptor) then
-			KEYBIND_STRIP:RemoveKeybindButtonGroup(Roomba.runDescriptor)
-		end end)
+	EVENT_MANAGER:RegisterForEvent("RoombaGuildBankClose", EVENT_CLOSE_GUILD_BANK, function()
+		if KEYBIND_STRIP:HasKeybindButtonGroup(bGroup) then
+			KEYBIND_STRIP:RemoveKeybindButtonGroup(bGroup)
+		end
+		self.control:SetHidden(true)
+		end)
+end
+
+function Roomba:InitializeFrame()
+	self.speedRow = self.control:GetNamedChild("SpeedRow")
+    self.speedRow.name:SetText("                     0%")
+    self.icon = self.control:GetNamedChild("Icon")
+    ZO_StatusBar_SetGradientColor(self.speedRow.bar, ZO_XP_BAR_GRADIENT_COLORS)
+    ZO_StatusBar_SmoothTransition(self.speedRow.bar, 0, 20, FORCE_VALUE)
+end
+
+function Roomba_Initialize(control)
+    ROOMBA = Roomba:New(control)
 end

+
 EVENT_MANAGER:RegisterForEvent("RoombaLoaded", EVENT_ADD_ON_LOADED, RoombaLoaded)
\ No newline at end of file
diff --git a/Roomba.txt b/Roomba.txt
index 9cda37e..823d32a 100644
--- a/Roomba.txt
+++ b/Roomba.txt
@@ -5,8 +5,8 @@
 ## SavedVariables: Roomba_Settings

 libs/LibStub/LibStub.lua
-libs/AceTimer-3.0/AceTimer-3.0.lua
-libs\LibAddonMenu-1.0\LibAddonMenu-1.0.lua
+libs/LibAddonMenu-1.0/LibAddonMenu-1.0.lua

 Roomba.lua
+Roomba.xml
 bindings.xml
\ No newline at end of file
diff --git a/Roomba.xml b/Roomba.xml
new file mode 100644
index 0000000..bcf29a8
--- /dev/null
+++ b/Roomba.xml
@@ -0,0 +1,26 @@
+<GuiXml>
+    <Controls>
+        <TopLevelControl name="RoombaWindow" hidden="true" mouseEnabled="true">
+          <Dimensions x="565" />
+            <Anchor point="TOPLEFT" relativeTo="ZO_SharedRightPanelBackground" offsetY="90" />
+            <Anchor point="BOTTOMLEFT" relativeTo="ZO_SharedRightPanelBackground" offsetY="-20" />
+            <OnInitialized>
+                Roomba_Initialize(self)
+            </OnInitialized>
+            <Controls>
+                <Texture name="$(parent)BG" textureFile="EsoUI/Art/Miscellaneous/listItem_backdrop.dds">
+                    <AnchorFill />
+                    <TextureCoords left="0" right="1" top="0" bottom=".8125" />
+                </Texture>
+                <Texture name="$(parent)Icon">
+                    <Dimensions x="80" y="80" />
+                    <Anchor point="BOTTOM" relativePoint="CENTER" offsetX="20" offsetY="-40" />
+                </Texture>
+
+                <Control name="$(parent)SpeedRow" inherits="ZO_StableAttributeRow">
+                    <Anchor point="TOP" relativeTo="$(parent)Icon" relativePoint="BOTTOM" offsetY="30" offsetX="30"/>
+                </Control>
+            </Controls>
+        </TopLevelControl>
+    </Controls>
+</GuiXml>
\ No newline at end of file
diff --git a/bindings.xml b/bindings.xml
index ce3d2f6..8610eca 100644
--- a/bindings.xml
+++ b/bindings.xml
@@ -2,10 +2,10 @@
   <Layer name="General">
     <Category name="Roomba">
       <Action name="RUN_ROOMBA">
-        <Down>Roomba.BeginProcess()</Down>
+        <Down>ROOMBA:BeginProcess()</Down>
       </Action>
       <Action name="RESCAN_ROOMBA">
-      	<Down>Roomba.RoombaReady()</Down>
+      	<Down>ROOMBA:RoombaReady()</Down>
       </Action>
     </Category>
   </Layer>