Daily checklist, toolbar, Internal data refactor and improvements

Leandro Silva [10-26-18 - 22:08]
Daily checklist, toolbar, Internal data refactor and improvements
Filename
Lang/de.lua
Lang/en.lua
Lang/fr.lua
Lang/jp.lua
Lang/ru.lua
LeoAltholic.lua
LeoAltholic.txt
LeoAltholic.xml
LeoAltholicInit.lua
LeoAltholicUI.lua
LeoAltholic_API.lua
Settings.lua
ui/bio.lua
ui/checklist.lua
ui/inventory.lua
ui/research.lua
ui/skills.lua
ui/toolbar.lua
ui/tracked.lua
ui/writs.lua
diff --git a/Lang/de.lua b/Lang/de.lua
index a9c6ed2..f461bb4 100644
--- a/Lang/de.lua
+++ b/Lang/de.lua
@@ -32,5 +32,16 @@ ZO_CreateStringId("LEOALT_JEWELRY", "SchmuckHandwerk")
 ZO_CreateStringId("LEOALT_PROVISIONER", "Versorger")
 ZO_CreateStringId("LEOALT_WOODWORKER", "Schreiner")

+ZO_CreateStringId("LEOALT_MAIL_BLACKSMITH", "Schmiedematerial")
+ZO_CreateStringId("LEOALT_MAIL_CLOTHIER", "Schneidermaterial")
+ZO_CreateStringId("LEOALT_MAIL_WOODWORKER", "Schreinermaterial")
+ZO_CreateStringId("LEOALT_MAIL_ENCHANTER", "Verzauberermaterial")
+ZO_CreateStringId("LEOALT_MAIL_PROVISIONER", "Versorgerzutaten")
+
 ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TOGGLE_WINDOW', "Zeige/Verstecke Haupt Fenster")
 ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TRACK_QUEST', "Verfolge tägliche Quest")
+
+ZO_CreateStringId("LEOALT_CHECKLIST", "Checkliste")
+ZO_CreateStringId("LEOALT_TOOLBAR", "Toolbar")
+ZO_CreateStringId("LEOALT_BUMP_COMPASS", "Bump Game Compass down")
+ZO_CreateStringId("LEOALT_ACCOUNT_CONFIGURATION", "Accountweite Einstellung")
diff --git a/Lang/en.lua b/Lang/en.lua
index 21bde02..54fe05d 100644
--- a/Lang/en.lua
+++ b/Lang/en.lua
@@ -32,5 +32,16 @@ ZO_CreateStringId("LEOALT_JEWELRY", "Jewelry")
 ZO_CreateStringId("LEOALT_PROVISIONER", "Provisioner")
 ZO_CreateStringId("LEOALT_WOODWORKER", "Woodworker")

+ZO_CreateStringId("LEOALT_MAIL_BLACKSMITH", "Raw Blacksmith Materials")
+ZO_CreateStringId("LEOALT_MAIL_CLOTHIER", "Raw Clothier Materials")
+ZO_CreateStringId("LEOALT_MAIL_WOODWORKER", "Raw Woodworker Materials")
+ZO_CreateStringId("LEOALT_MAIL_ENCHANTER", "Raw Enchanter Materials")
+ZO_CreateStringId("LEOALT_MAIL_PROVISIONER", "Raw Provisioner Materials")
+
 ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TOGGLE_WINDOW', "Show/Hide Main Window")
 ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TRACK_QUEST', "Track Daily Quest")
+
+ZO_CreateStringId("LEOALT_CHECKLIST", "Checklist")
+ZO_CreateStringId("LEOALT_TOOLBAR", "Toolbar")
+ZO_CreateStringId("LEOALT_BUMP_COMPASS", "Bump Game Compass down")
+ZO_CreateStringId("LEOALT_ACCOUNT_CONFIGURATION", "Account Wide Configuration")
diff --git a/Lang/fr.lua b/Lang/fr.lua
index c5691ce..c537845 100644
--- a/Lang/fr.lua
+++ b/Lang/fr.lua
@@ -32,5 +32,15 @@ ZO_CreateStringId("LEOALT_JEWELRY", "joaillerie")
 ZO_CreateStringId("LEOALT_PROVISIONER", "cuisine")
 ZO_CreateStringId("LEOALT_WOODWORKER", "bois")

+ZO_CreateStringId("LEOALT_MAIL_BLACKSMITH", "Matériaux bruts de forge")
+ZO_CreateStringId("LEOALT_MAIL_CLOTHIER", "Matériaux bruts de couture")
+ZO_CreateStringId("LEOALT_MAIL_WOODWORKER", "Matériaux bruts de travail du bois")
+ZO_CreateStringId("LEOALT_MAIL_ENCHANTER", "Matériaux bruts d'enchantement")
+ZO_CreateStringId("LEOALT_MAIL_PROVISIONER", "Matériaux bruts de cuisine")
+
 ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TOGGLE_WINDOW', "Show/Hide Main Window")
 ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TRACK_QUEST', "Track Daily Quest")
+
+ZO_CreateStringId("LEOALT_CHECKLIST", "Liste de contrôle")
+ZO_CreateStringId("LEOALT_TOOLBAR", "Toolbar")
+ZO_CreateStringId("LEOALT_BUMP_COMPASS", "Bump Game Compass down")
diff --git a/Lang/jp.lua b/Lang/jp.lua
index df0be8d..72ca1b9 100644
--- a/Lang/jp.lua
+++ b/Lang/jp.lua
@@ -32,5 +32,15 @@ ZO_CreateStringId("LEOALT_JEWELRY", "Jewelry")
 ZO_CreateStringId("LEOALT_PROVISIONER", "調理")
 ZO_CreateStringId("LEOALT_WOODWORKER", "木工")

+ZO_CreateStringId("LEOALT_MAIL_BLACKSMITH", "鍛冶師用素材")
+ZO_CreateStringId("LEOALT_MAIL_CLOTHIER", "仕立師用素材")
+ZO_CreateStringId("LEOALT_MAIL_WOODWORKER", "木工師用素材")
+ZO_CreateStringId("LEOALT_MAIL_ENCHANTER", "付呪師用素材")
+ZO_CreateStringId("LEOALT_MAIL_PROVISIONER", "調理師用素材")
+
 ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TOGGLE_WINDOW', "表示/非表示 メイン 画面")
 ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TRACK_QUEST', "デイリークエストを追跡")
+
+ZO_CreateStringId("LEOALT_CHECKLIST", "チェックリスト")
+ZO_CreateStringId("LEOALT_TOOLBAR", "Toolbar")
+ZO_CreateStringId("LEOALT_BUMP_COMPASS", "Bump Game Compass down")
diff --git a/Lang/ru.lua b/Lang/ru.lua
deleted file mode 100644
index 21bde02..0000000
--- a/Lang/ru.lua
+++ /dev/null
@@ -1,36 +0,0 @@
-
-ZO_CreateStringId("LEOALT_FINISHED",      "finished")
-ZO_CreateStringId("LEOALT_UNLOCKED",      "unlocked")
-ZO_CreateStringId("LEOALT_REMOVED_FROM",      "Removed <<1>> from <<2>>.")
-ZO_CreateStringId("LEOALT_NOT_DONE_TODAY",      "not done today")
-ZO_CreateStringId("LEOALT_MOUNT_FINISHED",      "<<C:1>> has finished a mount training.")
-ZO_CreateStringId("LEOALT_RESEARCH_FINISHED",      "<<C:1>> has finished a research")
-ZO_CreateStringId("LEOALT_TRACK_ONLY_DAILY",      "Only daily quests can be tracked.")
-ZO_CreateStringId("LEOALT_QUEST_ALREADY_TRACKED", "Quest <<1>> is already being tracked.")
-ZO_CreateStringId("LEOALT_TRACKING", "Tracking")
-ZO_CreateStringId("LEOALT_QUEST_DONE_TODAY", "Quest <<1>> done for today.")
-ZO_CreateStringId("LEOALT_TRACKED_QUESTS", "Tracked Quests")
-ZO_CreateStringId("LEOALT_AUTO_TRACK_WRIT", "Automatically track started daily crafting quests")
-ZO_CreateStringId("LEOALT_AUTO_TRACK_DAILY", "Automatically track started daily quests")
-ZO_CreateStringId("LEOALT_COMPLETED_RESEARCH", "Completed Research")
-ZO_CreateStringId("LEOALT_CHAT_ALL", "Chat message for all characters")
-ZO_CreateStringId("LEOALT_CHAT_ALL_TOOLTIP", "Display a chat message whenever a research is completed for a character")
-ZO_CreateStringId("LEOALT_CENTERSCREEN_CURRENT", "Center Screen message for current character")
-ZO_CreateStringId("LEOALT_CENTERSCREEN_CURRENT_TOOLTIP", "Display a center screen message whenever a research is completed for current character")
-
-ZO_CreateStringId("LEOALT_PLAYED", "Played")
-ZO_CreateStringId("LEOALT_RIDING", "Riding")
-ZO_CreateStringId("LEOALT_MAXIMUM", "Maximum")
-ZO_CreateStringId("LEOALT_RECOVERY", "Recovery")
-
-ZO_CreateStringId("LEOALT_WRIT", "Writ")
-ZO_CreateStringId("LEOALT_ALCHEMIST", "Alchemist")
-ZO_CreateStringId("LEOALT_BLACKSMITH", "Blacksmith")
-ZO_CreateStringId("LEOALT_CLOTHIER", "Clothier")
-ZO_CreateStringId("LEOALT_ENCHANTER", "Enchanter")
-ZO_CreateStringId("LEOALT_JEWELRY", "Jewelry")
-ZO_CreateStringId("LEOALT_PROVISIONER", "Provisioner")
-ZO_CreateStringId("LEOALT_WOODWORKER", "Woodworker")
-
-ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TOGGLE_WINDOW', "Show/Hide Main Window")
-ZO_CreateStringId('SI_BINDING_NAME_LEOALTHOLIC_TRACK_QUEST', "Track Daily Quest")
diff --git a/LeoAltholic.lua b/LeoAltholic.lua
index 5a6224c..6549b95 100644
--- a/LeoAltholic.lua
+++ b/LeoAltholic.lua
@@ -2,15 +2,11 @@
 LeoAltholic.timerQueue = {}
 LeoAltholic.charList = {}
 LeoAltholic.lastUpdatedCharList = nil
-LeoAltholic.myself = nil
-LeoAltholic.myselfIndex = 0
 LeoAltholic.initialized = false
 LeoAltholic.numUpdates = 0

 LeoAltholic.maxTraits = select(3,GetSmithingResearchLineInfo(1,1))
 LeoAltholic.jewelryMaxTraits = select(3,GetSmithingResearchLineInfo(7,1))
-LeoAltholic.panelList = { "Bio", "Stats", "Skills", "Skills2", "Champion", "Tracked", "Writs", "Inventory", "Research" }
-LeoAltholic.craftResearch = {CRAFTING_TYPE_BLACKSMITHING,CRAFTING_TYPE_CLOTHIER,CRAFTING_TYPE_WOODWORKING,CRAFTING_TYPE_JEWELRYCRAFTING}

 local function loadPlayerDataPart(skillType, baseElem)
     if skillType == nil then
@@ -108,14 +104,14 @@ end

 local function initCharsList()

-    if LeoAltholic.savedVariables.CharList == nil then LeoAltholic.savedVariables.CharList = {} end
+    if LeoAltholic.globalData.CharList == nil then LeoAltholic.globalData.CharList = {} end

     LeoAltholic.CharName = GetUnitName("player")

     local function getStat(stat) return GetPlayerStat(stat, STAT_BONUS_OPTION_APPLY_BONUS, STAT_SOFT_CAP_OPTION_APPLY_SOFT_CAP) end

     local numChars = GetNumCharacters()
-    for k, v in pairs(LeoAltholic.savedVariables.CharList) do
+    for k, v in pairs(LeoAltholic.globalData.CharList) do
         local deleted = true
         for i = 1, numChars do
             local charName = GetCharacterInfo(i)
@@ -126,12 +122,12 @@ local function initCharsList()
             end
         end
         if deleted then
-            LeoAltholic.savedVariables.CharList[k] = nil
+            LeoAltholic.globalData.CharList[k] = nil
         end
     end

     LeoAltholic.CharNum = 0
-    local char = LeoAltholic.savedVariables.CharList[LeoAltholic.CharName] or {
+    local char = LeoAltholic.globalData.CharList[LeoAltholic.CharName] or {
         bio = {},
         quests = {
             actives = {},
@@ -283,27 +279,12 @@ local function initCharsList()
     baseElem = char.skills.craft
     loadPlayerDataPart(skillType,baseElem)

-    local function GetBonus(craft)
+    local function GetCraftBonus(craft)
         local skillType0, skillId = GetCraftingSkillLineIndices(craft)
         local _, rank = GetSkillLineInfo(skillType0,skillId)
         return {rank = rank, max = GetMaxSimultaneousSmithingResearch(craft) or 1}
     end

-    if char.research == nil then
-        char.research = {}
-        for _,craft in pairs(LeoAltholic.craftResearch) do
-            char.research[craft] = GetBonus(craft)
-            for line = 1, GetNumSmithingResearchLines(craft) do
-                char.research[craft][line] = {}
-                for trait = 1, LeoAltholic.maxTraits do
-                    if not char.research[craft][line][trait] then
-                        char.research[craft][line][trait] = {}
-                    end
-                end
-            end
-        end
-    end
-
     if GetDiffBetweenTimeStamps(char.attributes.riding.time - GetTimeStamp()) < 0 then
         local data = {
             id = '$M' .. char.bio.name,
@@ -314,14 +295,28 @@ local function initCharsList()
         LeoAltholic.AddToQueue(data)
     end

+    char.research = {}
+    char.research.done = {}
+    char.research.doing = {}
     for _,craft in pairs(LeoAltholic.craftResearch) do
+        char.research.done[craft] = GetCraftBonus(craft)
+        char.research.doing[craft] = {}
         for line = 1, GetNumSmithingResearchLines(craft) do
+            char.research.done[craft][line] = {}
             local lineName, lineIcon = GetSmithingResearchLineInfo(craft, line)
             for trait = 1, LeoAltholic.maxTraits do
                 local traitType, _, known = GetSmithingResearchLineTraitInfo(craft, line, trait)
-                if char.bio.name ~= LeoAltholic.CharName then
-                    local traitData = char.research[craft][line][trait] or false
-                    if type(traitData) == 'number' then
+                if known then
+                    char.research.done[craft][line][trait] = true
+                else
+                    local _,remaining = GetSmithingResearchLineTraitTimes(craft,line,trait)
+                    if remaining and remaining > 0 then
+                        table.insert(char.research.doing[craft], {
+                            craft = craft,
+                            line = line,
+                            trait = trait,
+                            time = remaining
+                        })
                         local data = {
                             id = '$R' .. char.bio.name..craft..line..trait,
                             charName = char.bio.name,
@@ -331,23 +326,16 @@ local function initCharsList()
                                     GetString('SI_ITEMTRAITTYPE',traitType),
                                     lineName
                             ),
-                            time = traitData
+                            time = remaining + GetTimeStamp()
                         }
                         LeoAltholic.AddToQueue(data)
                     end
                 end
-                if known == false then
-                    local _,remaining = GetSmithingResearchLineTraitTimes(craft,line,trait)
-                    if remaining and remaining > 0 then
-                        char.research[craft][line][trait] = remaining + GetTimeStamp()
-                    else
-                        char.research[craft][line][trait] = false
-                    end
-                else
-                    char.research[craft][line][trait] = true
-                end
             end
         end
+        table.sort(char.research.doing[craft], function(a, b)
+            return a.time < b.time
+        end)
     end

     char.champion = {}
@@ -402,18 +390,19 @@ local function initCharsList()

     if char.stats == nil then char.stats = {} end

-    if char.quests == nil or char.quests.tracked == nil then
+    if char.quests == nil then
         char.quests = {
             actives = {},
             tracked = {},
             writs = {}
         }
-    else
-        char.quests.actives = {}
     end
+
     if char.quests.writs == nil then char.quests.writs = {} end
+    if char.quests.tracked == nil then char.quests.tracked = {} end

     local n = 0
+    char.quests.actives = {}
     for i = 1, MAX_JOURNAL_QUESTS do
         if IsValidQuestIndex(i) then
             local quest = createQuestEntry(i)
@@ -423,36 +412,10 @@ local function initCharsList()
     end
     --char.achievements = createCharDataAchievements()

-    LeoAltholic.savedVariables.CharList[LeoAltholic.CharName] = char
-end
-
-local function fixWrits()
-    for charName, char in pairs(LeoAltholic.savedVariables.CharList) do
-        if char.quests == nil then
-            LeoAltholic.savedVariables.CharList[charName].quests = {
-                actives = {},
-                tracked = {},
-                writs = {}
-            }
-        end
-        if char.quests.tracked == nil then LeoAltholic.savedVariables.CharList[charName].quests.tracked = {} end
-        if char.quests.writs == nil then LeoAltholic.savedVariables.CharList[charName].quests.writs = {} end
-        for trackedId, trackedQuest in pairs(char.quests.writs) do
-            if trackedQuest.craft == nil then
-                local craft = LeoAltholic.GetCraftFromQuest(trackedQuest.name)
-                if craft ~= nil then
-                    LeoAltholic.savedVariables.CharList[charName].quests.writs[trackedId].craft = craft
-                end
-            end
-        end
-    end
-end
-
-function LeoAltholic.TodayReset()
-    local diff = zo_floor(GetDiffBetweenTimeStamps(GetTimeStamp(), 1538200800) / 86400)
-    return 1538200800 + (diff * 86400)
+    LeoAltholic.globalData.CharList[LeoAltholic.CharName] = char
 end

+--[[
 local function parseAchievementLinkId(link)

     if (link == nil or link == "") then
@@ -550,6 +513,7 @@ local function createCharDataAchievements()

     return achievements
 end
+]]

 local function copy(obj, seen)
     if type(obj) ~= 'table' then return obj end
@@ -566,7 +530,7 @@ function LeoAltholic.GetCharacters(forceUpdate)

         LeoAltholic.charList =  {}
         local i = 1
-        for k, v in pairs(LeoAltholic.savedVariables.CharList) do
+        for k, v in pairs(LeoAltholic.globalData.CharList) do
             if k == nil then return end
             LeoAltholic.charList[i] = copy(v)
             i = i + 1
@@ -579,20 +543,6 @@ function LeoAltholic.GetCharacters(forceUpdate)
     return LeoAltholic.charList
 end

-function LeoAltholic.ExportCharacters(forceUpdate)
-    LeoAltholic.GetCharacters(forceUpdate)
-    local chars = copy(LeoAltholic.charList)
-    return chars
-end
-
-function LeoAltholic.GetCharByName(name)
-    local chars = LeoAltholic.ExportCharacters()
-    for k, v in pairs(chars) do
-        if v.bio.name == name then return v end
-    end
-    return nil
-end
-
 function LeoAltholic.GetItems(char, bagId)
     local itemLines =  {}
     local i = 1
@@ -616,14 +566,38 @@ function LeoAltholic.log(message)
     d(formatMessage(message))
 end

-function LeoAltholic.GetMyself()
-    return LeoAltholic.savedVariables.CharList[LeoAltholic.CharName]
+local function onResearchStarted(eventCode, craft, line, trait)
+    local _,remaining = GetSmithingResearchLineTraitTimes(craft,line,trait)
+    table.insert(LeoAltholic.globalData.CharList[LeoAltholic.CharName].research.doing[craft], {
+        craft = craft,
+        line = line,
+        trait = trait,
+        time = remaining
+    })
+    if LeoAltholic.IsTabVisible(LeoAltholic.TAB_RESEARCH) then
+        LeoAltholicUI.researchList:RefreshData()
+    end
+end
+
+local function onResearchCanceled(eventCode, craft, line, trait)
+    for i, research in pairs(LeoAltholic.globalData.CharList[LeoAltholic.CharName].research.doing[craft]) do
+        if research.line == line and research.trait == trait then
+            table.remove(LeoAltholic.globalData.CharList[LeoAltholic.CharName].research.doing[craft], i)
+            if LeoAltholic.IsTabVisible(LeoAltholic.TAB_RESEARCH) then
+                LeoAltholicUI.researchList:RefreshData()
+            end
+            return
+        end
+    end
 end

 local function onResearchCompleted(eventCode, craft, line, trait)
-    if LeoAltholic.initialized == false then
-        local myself = LeoAltholic.GetMyself()
-        myself.research[craft][line][trait] = true
+    LeoAltholic.globalData.CharList[LeoAltholic.CharName].research.done[craft][line][trait] = true
+    for i, research in pairs(LeoAltholic.globalData.CharList[LeoAltholic.CharName].research.doing[craft]) do
+        if research.line == line and research.trait == trait then
+            table.remove(LeoAltholic.globalData.CharList[LeoAltholic.CharName].research.doing[craft], i)
+            break
+        end
     end

     local lineName = GetSmithingResearchLineInfo(craft, line)
@@ -636,15 +610,17 @@ local function onResearchCompleted(eventCode, craft, line, trait)
             GetString('SI_ITEMTRAITTYPE',traitType),
             lineName
     )
-    if LeoAltholic.savedVariables.settings.completedResearch.screen == true then
+    if LeoAltholic.globalData.settings.completedResearch.screen == true then
         local messageParams = CENTER_SCREEN_ANNOUNCE:CreateMessageParams(CSA_CATEGORY_SMALL_TEXT, SOUNDS.SMITHING_FINISH_RESEARCH)
         messageParams:SetText(formatMessage(msg))
         CENTER_SCREEN_ANNOUNCE:AddMessageWithParams(messageParams)
     end
-    if LeoAltholic.savedVariables.settings.completedResearch.chat == true then
+    if LeoAltholic.globalData.settings.completedResearch.chat == true then
         LeoAltholic.log(msg)
     end
-    LeoAltholicUI.researchList:RefreshData()
+    if LeoAltholic.IsTabVisible(LeoAltholic.TAB_RESEARCH) then
+        LeoAltholicUI.researchList:RefreshData()
+    end
 end

 function LeoAltholic.AddToQueue(data)
@@ -659,10 +635,10 @@ end
 local function processQueue()
     for x,data in pairs(LeoAltholic.timerQueue) do
         if GetDiffBetweenTimeStamps(data.time, GetTimeStamp()) <= 0 then
-            if data.charName ~= LeoAltholic.CharName and LeoAltholic.savedVariables.settings.completedResearch.chat == true then
+            if data.charName ~= LeoAltholic.CharName and LeoAltholic.globalData.settings.completedResearch.chat == true then
                 LeoAltholic.log(data.info)
             end
-            if data.charName == LeoAltholic.CharName and LeoAltholic.savedVariables.settings.completedResearch.screen == true then
+            if data.charName == LeoAltholic.CharName and LeoAltholic.globalData.settings.completedResearch.screen == true then
                 local messageParams = CENTER_SCREEN_ANNOUNCE:CreateMessageParams(CSA_CATEGORY_SMALL_TEXT, SOUNDS.SMITHING_FINISH_RESEARCH)
                 messageParams:SetText(formatMessage(data.info))
                 CENTER_SCREEN_ANNOUNCE:AddMessageWithParams(messageParams)
@@ -673,7 +649,6 @@ local function processQueue()
 end

 local function createMessageQueue()
-    --LeoAltholic.timerQueue = {}
     for _, char in pairs(LeoAltholic.GetCharacters()) do
         if char.bio.name ~= LeoAltholic.CharName then
             if GetDiffBetweenTimeStamps(char.attributes.riding.time - GetTimeStamp()) < 0 then
@@ -685,26 +660,23 @@ local function createMessageQueue()
                 }
                 LeoAltholic.AddToQueue(data)
             end
-            for _,craft in pairs(LeoAltholic.craftResearch) do
-                for line = 1, GetNumSmithingResearchLines(craft) do
-                    local lineName, lineIcon = GetSmithingResearchLineInfo(craft, line)
-                    for trait = 1, LeoAltholic.maxTraits do
-                        local traitType = GetSmithingResearchLineTraitInfo(craft, line, trait)
-                        local traitData = char.research[craft][line][trait] or false
-                        if type(traitData) == 'number' then
-                            local data = {
-                                id = '$R' .. char.bio.name..craft..line..trait,
-                                charName = char.bio.name,
-                                info = zo_strformat(
-                                        GetString(LEOALT_RESEARCH_FINISHED) .. ': |c00FF00<<C:2>> <<C:3>>|r.',
-                                        char.bio.name,
-                                        GetString('SI_ITEMTRAITTYPE',traitType),
-                                        lineName
-                                ),
-                                time = traitData
-                            }
-                            LeoAltholic.AddToQueue(data)
-                        end
+            for _, craft in pairs(char.research.doing) do
+                if char.research.doing[craft] then
+                    for _, research in pairs(char.research.doing[craft]) do
+                        local lineName, lineIcon = GetSmithingResearchLineInfo(research.craft, research.line)
+                        local traitType = GetSmithingResearchLineTraitInfo(research.craft, research.line, research.trait)
+                        local data = {
+                            id = '$R' .. char.bio.name..research.craft..research.line..research.trait,
+                            charName = char.bio.name,
+                            info = zo_strformat(
+                                    GetString(LEOALT_RESEARCH_FINISHED) .. ': |c00FF00<<C:2>> <<C:3>>|r.',
+                                    char.bio.name,
+                                    GetString('SI_ITEMTRAITTYPE',traitType),
+                                    lineName
+                            ),
+                            time = research..time
+                        }
+                        LeoAltholic.AddToQueue(data)
                     end
                 end
             end
@@ -712,24 +684,55 @@ local function createMessageQueue()
     end
 end

+--[[ Preparing for hirering timers
+local function onMailRedable()
+    for mailId in ZO_GetNextMailIdIter do
+        senderDisplayName, senderCharacterName, subject, icon, unread, fromSystem, fromCustomerService, returned, numAttachments, attachedMoney, codAmount, expiresInDays, secsSinceReceived = GetMailItemInfo(mailId)
+
+        if(subject == GetString(LEOALT_MAIL_BLACKSMITH) and fromSystem) then
+            d(GetTimeStamp() - secsSinceReceived)
+        elseif(subject == GetString(LEOALT_MAIL_CLOTHIER) and fromSystem) then
+            d(GetTimeStamp() - secsSinceReceived)
+        elseif(subject == GetString(LEOALT_MAIL_WOODWORKER) and fromSystem) then
+            d(GetTimeStamp() - secsSinceReceived)
+        elseif(subject == GetString(LEOALT_MAIL_ENCHANTER) and fromSystem) then
+            d(GetTimeStamp() - secsSinceReceived)
+        elseif(subject == GetString(LEOALT_MAIL_PROVISIONER) and fromSystem) then
+            d(GetTimeStamp() - secsSinceReceived)
+        end
+    end
+end
+]]
+
 local function onUpdate()

     processQueue()
+
+    LeoAltholicChecklistUI:checkReset()
+    LeoAltholicToolbarUI:update()
+
     LeoAltholic.numUpdates = LeoAltholic.numUpdates + 1

     if LeoAltholic.numUpdates >= 1800 then -- 3600 seconds = 1h, forces update every hour
         LeoAltholic.numUpdates = 1
-        LeoAltholicUI.researchList:RefreshData()
+        if LeoAltholic.IsTabVisible(LeoAltholic.TAB_RESEARCH) then
+            LeoAltholicUI.researchList:RefreshData()
+        end
     end

     if LeoAltholic.isHidden() then return end

-    LeoAltholicUI:updateBio()
+    if LeoAltholic.IsTabVisible(LeoAltholic.TAB_BIO) then
+        LeoAltholicUI:updateBio()
+    end
+    if LeoAltholic.IsTabVisible(LeoAltholic.TAB_RESEARCH) then
+        LeoAltholicUI:updateResearch()
+    end

+    --[[
     if LeoAltholic.numUpdates >= 30 then -- 60 seconds
         LeoAltholic.numUpdates = 1
-        LeoAltholicUI.researchList:RefreshData()
-        --[[
+        LeoAltholicChecklistUI:update()
         For reference only!!
         LeoAltholicUI.bioList:RefreshData()
         LeoAltholicUI.statsList:RefreshData()
@@ -739,10 +742,12 @@ local function onUpdate()
         LeoAltholicUI.skills2List:RefreshData()
         LeoAltholicUI.researchList:RefreshData()
         LeoAltholicUI.writsList:RefreshData()
-        ]]
     else
-        LeoAltholicUI:updateResearch()
+        if LeoAltholic.IsTabVisible(LeoAltholic.TAB_RESEARCH) then
+            LeoAltholicUI:updateResearch()
+        end
     end
+    ]]
 end

 local function trackQuest(questId, automatically)
@@ -756,9 +761,9 @@ local function trackQuest(questId, automatically)
     local lookInto
     local quest = createQuestEntry(questId)
     if quest.isCrafting then
-        lookInto = LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.writs
+        lookInto = LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.writs
     else
-        lookInto = LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.tracked
+        lookInto = LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.tracked
     end
     for _,trackedQuest in pairs(lookInto) do
         if (trackedQuest.name == quest.name) then
@@ -769,7 +774,11 @@ local function trackQuest(questId, automatically)
         end
     end
     quest.lastDone = nil
-    table.insert(lookInto, quest)
+    if quest.isCrafting then
+        table.insert(LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.writs, quest)
+    else
+        table.insert(LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.tracked, quest)
+    end
     LeoAltholic.log(GetString(LEOALT_TRACKING) .. " " .. quest.name .. "...")
     if quest.isCrafting then
         LeoAltholicUI.writsList:RefreshData()
@@ -783,51 +792,125 @@ end
 local function onQuestAdded(eventCode, journalIndex, questName, objectiveName)
     local quest = createQuestEntry(journalIndex)
     if quest.isDaily == false then return end
-    if LeoAltholic.savedVariables.settings.tracked.allDaily == true or (quest.questType == QUEST_TYPE_CRAFTING and LeoAltholic.savedVariables.settings.tracked.dailyWrits == true) then
+    if LeoAltholic.globalData.settings.tracked.allDaily == true or
+            (quest.questType == QUEST_TYPE_CRAFTING and LeoAltholic.globalData.settings.tracked.dailyWrits == true) then
         trackQuest(journalIndex, true)
     end
 end

+local function onQuestCounterChanged(eventId, questIndex, questName, conditionText, conditionType, currConditionVal, newConditionVal, conditionMax, isFailCondition, stepOverrideText, isPushed, isComplete, isConditionComplete, isStepHidden)
+    for i,trackedQuest in pairs(LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.writs) do
+        if (trackedQuest.name == questName) then
+            LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.writs[i].lastStarted = GetTimeStamp()
+            LeoAltholicChecklistUI:startedWrit(trackedQuest.craft)
+            return
+        end
+    end
+end
+
+local function onQuestRemoved(eventId, isCompleted, journalIndex, questName, zoneIndex, poiIndex)
+    if not isCompleted then
+        for i,trackedQuest in pairs(LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.writs) do
+            if (trackedQuest.name == questName) then
+                LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.writs[i].lastStarted = nil
+                LeoAltholicChecklistUI:stoppedWrit(trackedQuest.craft)
+                return
+            end
+        end
+    end
+end
+
 local function onQuestComplete(eventCode, questName, level, previousExperience, currentExperience, rank, previousPoints, currentPoints)
-    for i,trackedQuest in pairs(LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.writs) do
+    for i,trackedQuest in pairs(LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.writs) do
         if (trackedQuest.name == questName) then
-            LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.writs[i].lastDone = GetTimeStamp()
+            LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.writs[i].lastDone = GetTimeStamp()
             LeoAltholic.log(zo_strformat(GetString(LEOALT_QUEST_DONE_TODAY), questName))
             LeoAltholicUI.writsList:RefreshData()
+            LeoAltholicChecklistUI:doneWrit(trackedQuest.craft)
             return
         end
     end
-    for i,trackedQuest in pairs(LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.tracked) do
+    for i,trackedQuest in pairs(LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.tracked) do
         if (trackedQuest.name == questName) then
-            LeoAltholic.savedVariables.CharList[LeoAltholic.CharName].quests.tracked[i].lastDone = GetTimeStamp()
+            LeoAltholic.globalData.CharList[LeoAltholic.CharName].quests.tracked[i].lastDone = GetTimeStamp()
             LeoAltholic.log(zo_strformat(GetString(LEOALT_QUEST_DONE_TODAY), questName))
             return
         end
     end
 end

+local function migrateDataToV2()
+    for charName, char in pairs(LeoAltholic.globalData.CharList) do
+        local oldResearch = char.research
+        LeoAltholic.globalData.CharList[charName].research = {}
+        LeoAltholic.globalData.CharList[charName].research.done = {}
+        LeoAltholic.globalData.CharList[charName].research.doing = {}
+        for _,craft in pairs(LeoAltholic.craftResearch) do
+            LeoAltholic.globalData.CharList[charName].research.done[craft] = {
+                max = oldResearch[craft].max or 0
+            }
+            LeoAltholic.globalData.CharList[charName].research.doing[craft] = {}
+            for line = 1, GetNumSmithingResearchLines(craft) do
+                LeoAltholic.globalData.CharList[charName].research.done[craft][line] = {}
+                local lineName, _, numTraits = GetSmithingResearchLineInfo(craft, line)
+                for trait = 1, numTraits do
+                    if oldResearch[craft][line][trait] == true then
+                        LeoAltholic.globalData.CharList[charName].research.done[craft][line][trait] = true
+                    end
+                end
+            end
+        end
+    end
+end
+
 local function initializeVars()
-    local oldVariables = ZO_SavedVars:NewAccountWide("LeoAltholicSavedVariables", 2)
-    LeoAltholic.savedVariables = ZO_SavedVars:NewAccountWide("LeoAltholicSavedVariables", 2, nil, nil, GetWorldName())
-    if oldVariables ~= nil and oldVariables.CharList ~= nil then
-        local varCopy = copy(oldVariables)
-        LeoAltholic.savedVariables.activeTab = varCopy.activeTab
-        LeoAltholic.savedVariables.CharList = varCopy.CharList
-        LeoAltholic.savedVariables.position = varCopy.position
-        LeoAltholicSavedVariables["Default"] = nil
-    end
-    if not LeoAltholic.savedVariables.settings or LeoAltholic.savedVariables.settings == nil then
-        LeoAltholic.savedVariables.settings = {
+    local charDefault = {
+        settings = {
+            checklist = {
+                enabled = true,
+                craft = {},
+                riding = true
+            }
+        }
+    }
+    charDefault.settings.checklist.craft[CRAFTING_TYPE_ALCHEMY] = true
+    charDefault.settings.checklist.craft[CRAFTING_TYPE_BLACKSMITHING] = true
+    charDefault.settings.checklist.craft[CRAFTING_TYPE_CLOTHIER] = true
+    charDefault.settings.checklist.craft[CRAFTING_TYPE_ENCHANTING] = true
+    charDefault.settings.checklist.craft[CRAFTING_TYPE_JEWELRYCRAFTING] = true
+    charDefault.settings.checklist.craft[CRAFTING_TYPE_PROVISIONING] = true
+    charDefault.settings.checklist.craft[CRAFTING_TYPE_WOODWORKING] = true
+
+    LeoAltholic.charData = ZO_SavedVars:NewCharacterIdSettings("LeoAltholicCharVariables", 2, nil, charDefault)
+    LeoAltholic.globalData = ZO_SavedVars:NewAccountWide("LeoAltholicSavedVariables", 2, nil, nil, GetWorldName())
+    if not LeoAltholic.globalData.settings or LeoAltholic.globalData.settings == nil then
+        LeoAltholic.globalData.settings = {
             tracked = {
-                dailyWrits = false,
+                dailyWrits = true,
                 allDaily = false
             },
             completedResearch = {
                 chat = true,
                 screen = true
+            },
+            toolbar = {
+                enabled = true
             }
         }
     end
+    if not LeoAltholic.globalData.dataVersion or LeoAltholic.globalData.dataVersion < 2 then
+        migrateDataToV2()
+        LeoAltholic.globalData.dataVersion = 2
+    end
+    initCharsList()
+end
+
+local function onGameMenuEnter()
+    LeoAltholicChecklist:SetHidden(true)
+end
+
+local function onGameMenuExit()
+    LeoAltholicChecklistUI.RestorePosition()
 end

 local function initialize()
@@ -841,9 +924,9 @@ local function initialize()
     LeoAltholic.feedback = feedbackWindow

     LeoAltholic.RestorePosition()
+    LeoAltholicToolbarUI.RestorePosition()
+    LeoAltholicChecklistUI.RestorePosition()

-    initCharsList()
-    fixWrits()
     LeoAltholicUI.InitPanels()
     createMessageQueue()

@@ -890,6 +973,10 @@ local function initialize()

     LeoAltholic.initialized = true
     CALLBACK_MANAGER:FireCallbacks("LeoAltholicInitialized")
+    if LeoAltholic.globalData.settings.toolbar.enabled == true then
+        LeoAltholicToolbarUI:update()
+    end
+    LeoAltholicChecklistUI:update()
 end

 local orig_ZO_QuestJournalNavigationEntry_OnMouseUp = ZO_QuestJournalNavigationEntry_OnMouseUp
@@ -922,6 +1009,23 @@ local function onPlayerDeactivated(event, addonName)
     initCharsList()
 end

+local function onRidingSkillImprovement(ridingSkill, previous, current, source)
+    local riding = {GetRidingStats()}
+    local ridetime = GetTimeUntilCanBeTrained()/1000 or 0
+    if ridetime > 1 then ridetime = ridetime + GetTimeStamp() end
+
+    LeoAltholic.globalData.CharList[LeoAltholic.CharName].attributes.riding = {
+        capacity = riding[1],
+        capacityMax = riding[2],
+        stamina = riding[3],
+        staminaMax = riding[4],
+        speed = riding[5],
+        speedMax = riding[6],
+        time = ridetime
+    }
+    LeoAltholicChecklistUI:doneRiding()
+end
+
 local function onAddOnLoaded(event, addonName)
     if addonName ~= LeoAltholic.name then return end

@@ -931,22 +1035,45 @@ local function onAddOnLoaded(event, addonName)

     if GetDisplayName() == "@LeandroSilva" then
         SLASH_COMMANDS["/rr"] = function(cmd) ReloadUI() end
+        SLASH_COMMANDS["/r1"] = function(cmd)
+            LeoAltholic.globalData = nil
+            ReloadUI()
+        end
     end
     SLASH_COMMANDS["/leoalt"] = function(cmd) LeoAltholic:ShowUI() end

     initializeVars()

     EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_SMITHING_TRAIT_RESEARCH_COMPLETED, onResearchCompleted)
+    EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_SMITHING_TRAIT_RESEARCH_STARTED, onResearchStarted)
+    EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_SMITHING_TRAIT_RESEARCH_CANCELED, onResearchCanceled)

     initialize()

     EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_PLAYER_DEACTIVATED, onPlayerDeactivated)
     EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_QUEST_COMPLETE, onQuestComplete)
     EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_QUEST_ADDED, onQuestAdded)
+    EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_QUEST_REMOVED, onQuestRemoved)
+    EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_QUEST_CONDITION_COUNTER_CHANGED, onQuestCounterChanged)
+
+    --EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_MAIL_READABLE, onMailRedable)
+    --EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_SKILL_POINTS_CHANGED, onUpdateSkills)
     EVENT_MANAGER:RegisterForUpdate(LeoAltholic.name, 2000, onUpdate)
     EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_NEW_MOVEMENT_IN_UI_MODE, onNewMovementInUIMode)
+    EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_RIDING_SKILL_IMPROVEMENT, onRidingSkillImprovement)
     CHAMPION_PERKS_SCENE:RegisterCallback('StateChange', onChampionPerksSceneStateChange)

+    EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_CRAFTING_STATION_INTERACT, onGameMenuEnter)
+    EVENT_MANAGER:RegisterForEvent(LeoAltholic.name, EVENT_END_CRAFTING_STATION_INTERACT, onGameMenuExit)
+    ZO_PreHookHandler(ZO_GameMenu_InGame, "OnShow", onGameMenuEnter)
+    ZO_PreHookHandler(ZO_GameMenu_InGame, "OnHide", onGameMenuExit)
+    ZO_PreHookHandler(ZO_InteractWindow, "OnShow", onGameMenuEnter)
+    ZO_PreHookHandler(ZO_InteractWindow, "OnHide", onGameMenuExit)
+    ZO_PreHookHandler(ZO_KeybindStripControl, "OnShow", onGameMenuEnter)
+    ZO_PreHookHandler(ZO_KeybindStripControl, "OnHide", onGameMenuExit)
+    ZO_PreHookHandler(ZO_MainMenuCategoryBar, "OnShow", onGameMenuEnter)
+    ZO_PreHookHandler(ZO_MainMenuCategoryBar, "OnHide", onGameMenuExit)
+
     LeoAltholic.log("started.")
 end

diff --git a/LeoAltholic.txt b/LeoAltholic.txt
index a9c984c..5d7e0b4 100644
--- a/LeoAltholic.txt
+++ b/LeoAltholic.txt
@@ -1,8 +1,8 @@
 ## Title: Leo's Altholic
 ## APIVersion: 100024 100025
-## Version: 1.3.8
+## Version: 1.4.0
 ## Author: |c39B027@LeandroSilva|r
-## SavedVariables: LeoAltholicSavedVariables
+## SavedVariables: LeoAltholicSavedVariables LeoAltholicCharVariables
 ## OptionalDependsOn: LibStub LibFeedback LibAddonMenu-2.0

 Libs\LibStub\LibStub.lua
@@ -37,7 +37,10 @@ ui/tracked.lua
 ui/writs.lua
 ui/inventory.lua
 ui/research.lua
+ui/toolbar.lua
+ui/checklist.lua
 LeoAltholic.lua
 LeoAltholicUI.lua
+LeoAltholic_API.lua
 Settings.lua
 Bindings.xml
diff --git a/LeoAltholic.xml b/LeoAltholic.xml
index 30e671c..27b93b6 100644
--- a/LeoAltholic.xml
+++ b/LeoAltholic.xml
@@ -968,57 +968,57 @@
                             <Controls>
                                 <Control name="$(parent)Headers">
                                     <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="20" offsetY="20" />
-                                        <Controls>
-                                            <Control name="$(parent)Name" inherits="ZO_SortHeader">
-                                                <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" />
-                                                <Dimensions x="180" y="20" />
-                                                <OnInitialized>
-                                                    ZO_SortHeader_Initialize(self, GetString(SI_ADDON_MANAGER_NAME), "name", ZO_SORT_ORDER_DOWN, TEXT_ALIGN_LEFT, "LeoAltholicSmallFont")
-                                                </OnInitialized>
-                                            </Control>
-                                            <Texture name="$(parent)1Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_blacksmithing_up.dds">
-                                                <Dimensions x="38" y="38"/>
-                                                <Anchor point="TOPLEFT" relativeTo="$(parent)Name" relativePoint="TOPRIGHT" offsetX="16" offsetY="-8"/>
-                                                <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE13)) </OnMouseEnter>
-                                                <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
-                                            </Texture>
-                                            <Texture name="$(parent)2Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_clothing_up.dds">
-                                                <Dimensions x="38" y="38"/>
-                                                <Anchor point="TOPLEFT" relativeTo="$(parent)1Label" relativePoint="TOPRIGHT" offsetX="44"/>
-                                                <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE14)) </OnMouseEnter>
-                                                <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
-                                            </Texture>
-                                            <Texture name="$(parent)6Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_woodworking_up.dds">
-                                                <Dimensions x="38" y="38"/>
-                                                <Anchor point="TOPLEFT" relativeTo="$(parent)2Label" relativePoint="TOPRIGHT" offsetX="44"/>
-                                                <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE15)) </OnMouseEnter>
-                                                <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
-                                            </Texture>
-                                            <Texture name="$(parent)7Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_jewelrycrafting_up.dds">
-                                                <Dimensions x="38" y="38"/>
-                                                <Anchor point="TOPLEFT" relativeTo="$(parent)6Label" relativePoint="TOPRIGHT" offsetX="44"/>
-                                                <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE24)) </OnMouseEnter>
-                                                <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
-                                            </Texture>
-                                            <Texture name="$(parent)3Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_enchanting_up.dds">
-                                                <Dimensions x="38" y="38"/>
-                                                <Anchor point="TOPLEFT" relativeTo="$(parent)7Label" relativePoint="TOPRIGHT" offsetX="44"/>
-                                                <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE17)) </OnMouseEnter>
-                                                <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
-                                            </Texture>
-                                            <Texture name="$(parent)4Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_alchemy_up.dds">
-                                                <Dimensions x="38" y="38"/>
-                                                <Anchor point="TOPLEFT" relativeTo="$(parent)3Label" relativePoint="TOPRIGHT" offsetX="44"/>
-                                                <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE16)) </OnMouseEnter>
-                                                <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
-                                            </Texture>
-                                            <Texture name="$(parent)5Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_provisioning_up.dds">
-                                                <Dimensions x="38" y="38"/>
-                                                <Anchor point="TOPLEFT" relativeTo="$(parent)4Label" relativePoint="TOPRIGHT" offsetX="44"/>
-                                                <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE18)) </OnMouseEnter>
-                                                <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
-                                            </Texture>
-                                        </Controls>
+                                    <Controls>
+                                        <Control name="$(parent)Name" inherits="ZO_SortHeader">
+                                            <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" />
+                                            <Dimensions x="180" y="20" />
+                                            <OnInitialized>
+                                                ZO_SortHeader_Initialize(self, GetString(SI_ADDON_MANAGER_NAME), "name", ZO_SORT_ORDER_DOWN, TEXT_ALIGN_LEFT, "LeoAltholicSmallFont")
+                                            </OnInitialized>
+                                        </Control>
+                                        <Texture name="$(parent)1Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_blacksmithing_up.dds">
+                                            <Dimensions x="38" y="38"/>
+                                            <Anchor point="TOPLEFT" relativeTo="$(parent)Name" relativePoint="TOPRIGHT" offsetX="16" offsetY="-8"/>
+                                            <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE13)) </OnMouseEnter>
+                                            <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
+                                        </Texture>
+                                        <Texture name="$(parent)2Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_clothing_up.dds">
+                                            <Dimensions x="38" y="38"/>
+                                            <Anchor point="TOPLEFT" relativeTo="$(parent)1Label" relativePoint="TOPRIGHT" offsetX="44"/>
+                                            <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE14)) </OnMouseEnter>
+                                            <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
+                                        </Texture>
+                                        <Texture name="$(parent)6Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_woodworking_up.dds">
+                                            <Dimensions x="38" y="38"/>
+                                            <Anchor point="TOPLEFT" relativeTo="$(parent)2Label" relativePoint="TOPRIGHT" offsetX="44"/>
+                                            <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE15)) </OnMouseEnter>
+                                            <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
+                                        </Texture>
+                                        <Texture name="$(parent)7Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_jewelrycrafting_up.dds">
+                                            <Dimensions x="38" y="38"/>
+                                            <Anchor point="TOPLEFT" relativeTo="$(parent)6Label" relativePoint="TOPRIGHT" offsetX="44"/>
+                                            <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE24)) </OnMouseEnter>
+                                            <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
+                                        </Texture>
+                                        <Texture name="$(parent)3Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_enchanting_up.dds">
+                                            <Dimensions x="38" y="38"/>
+                                            <Anchor point="TOPLEFT" relativeTo="$(parent)7Label" relativePoint="TOPRIGHT" offsetX="44"/>
+                                            <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE17)) </OnMouseEnter>
+                                            <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
+                                        </Texture>
+                                        <Texture name="$(parent)4Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_alchemy_up.dds">
+                                            <Dimensions x="38" y="38"/>
+                                            <Anchor point="TOPLEFT" relativeTo="$(parent)3Label" relativePoint="TOPRIGHT" offsetX="44"/>
+                                            <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE16)) </OnMouseEnter>
+                                            <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
+                                        </Texture>
+                                        <Texture name="$(parent)5Label" mouseEnabled="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_provisioning_up.dds">
+                                            <Dimensions x="38" y="38"/>
+                                            <Anchor point="TOPLEFT" relativeTo="$(parent)4Label" relativePoint="TOPRIGHT" offsetX="44"/>
+                                            <OnMouseEnter> ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SI_ITEMFILTERTYPE18)) </OnMouseEnter>
+                                            <OnMouseExit> ZO_Tooltips_HideTextTooltip() </OnMouseExit>
+                                        </Texture>
+                                    </Controls>
                                 </Control>
                                 <Control name="$(parent)List" inherits="ZO_ScrollList">
                                     <Dimensions x="990" y="600" />
@@ -1844,5 +1844,181 @@
             </Controls>
         </TopLevelControl>

+        <TopLevelControl name="LeoAltholicToolbar" mouseEnabled="true" movable="true" hidden="true" clampedToScreen="true">
+            <Dimensions x="600" y="32" />
+            <Anchor point="TOPLEFT" relativeTo="GuiRoot" relativePoint="TOPLEFT" offsetX="100" offsetY="100" />
+            <OnMoveStop> LeoAltholicToolbarUI:OnWindowMoveStop() </OnMoveStop>
+            <Controls>
+                <Backdrop name="$(parent)BG" centerColor="000000" edgeColor="222222" alpha="0.5">
+                    <Anchor point="TOPLEFT" relativePoint="TOPLEFT" relativeTo="$(parent)"/>
+                    <Dimensions x="600" y="32"/>
+                    <Edge edgeSize="1"/>
+                </Backdrop>
+                <Texture name="$(parent)RidingTexture" hidden="true" textureFile="/esoui/art/tutorial/store_indexicon_mounts_up.dds">
+                    <Dimensions y="32" x="32"/>
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="10" offsetY="0"/>
+                </Texture>
+                <Label name="$(parent)Riding" hidden="true" font="LeoAltholicLargeFont" verticalAlignment="CENTER">
+                    <Dimensions x="80" y="32" />
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)RidingTexture" relativePoint="TOPRIGHT" offsetX="2"/>
+                </Label>
+                <Texture name="$(parent)Craft1Texture" hidden="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_blacksmithing_down.dds">
+                    <Dimensions y="32" x="32"/>
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="10"/>
+                </Texture>
+                <Label name="$(parent)Craft1" hidden="true" font="LeoAltholicLargeFont" verticalAlignment="CENTER">
+                    <Dimensions x="100" y="32" />
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)Craft1Texture" relativePoint="TOPRIGHT" offsetX="2" offsetY="0"/>
+                </Label>
+                <Texture name="$(parent)Craft2Texture" hidden="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_clothing_down.dds">
+                    <Dimensions y="32" x="32"/>
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="10"/>
+                </Texture>
+                <Label name="$(parent)Craft2" hidden="true" font="LeoAltholicLargeFont" verticalAlignment="CENTER">
+                    <Dimensions x="100" y="32" />
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)Craft2Texture" relativePoint="TOPRIGHT" offsetX="2" offsetY="0"/>
+                </Label>
+                <Texture name="$(parent)Craft6Texture" hidden="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_woodworking_down.dds">
+                    <Dimensions y="32" x="32"/>
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="10"/>
+                </Texture>
+                <Label name="$(parent)Craft6" hidden="true" font="LeoAltholicLargeFont" verticalAlignment="CENTER">
+                    <Dimensions x="100" y="32" />
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)Craft6Texture" relativePoint="TOPRIGHT" offsetX="2" offsetY="0"/>
+                </Label>
+                <Texture name="$(parent)Craft7Texture" hidden="true" textureFile="/esoui/art/inventory/inventory_tabicon_craftbag_jewelrycrafting_down.dds">
+                    <Dimensions y="32" x="32"/>
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="10"/>
+                </Texture>
+                <Label name="$(parent)Craft7" hidden="true" font="LeoAltholicLargeFont" verticalAlignment="CENTER">
+                    <Dimensions x="100" y="32" />
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)Craft6Texture" relativePoint="TOPRIGHT" offsetX="2" offsetY="0"/>
+                </Label>
+                <Label name="$(parent)Checklist" hidden="true" font="LeoAltholicLargeFont" verticalAlignment="CENTER">
+                    <Dimensions x="100" y="32" />
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="10"/>
+                </Label>
+                <Texture name="$(parent)HirelingTexture" hidden="true" textureFile="/esoui/art/chatwindow/chat_mail_up.dds">
+                    <Dimensions y="32" x="32"/>
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="10"/>
+                </Texture>
+                <Label name="$(parent)Hireling" hidden="true" font="LeoAltholicLargeFont" verticalAlignment="CENTER">
+                    <Dimensions x="100" y="32" />
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)HirelingTexture" relativePoint="TOPRIGHT" offsetX="2" offsetY="0"/>
+                </Label>
+            </Controls>
+        </TopLevelControl>
+
+        <TopLevelControl name="LeoAltholicChecklist" mouseEnabled="true" movable="true" hidden="false" clampedToScreen="true">
+            <Dimensions x="250" y="50" />
+            <Anchor point="TOPLEFT" relativeTo="GuiRoot" relativePoint="TOPLEFT" offsetX="100" offsetY="100" />
+            <OnMoveStop> LeoAltholicChecklistUI:OnWindowMoveStop() </OnMoveStop>
+            <Controls>
+                <Backdrop name="$(parent)BGHeader" mouseEnabled="true" centerColor="000000" edgeColor="222222" alpha="0.6">
+                    <Anchor point="TOPLEFT" relativePoint="TOPLEFT" relativeTo="$(parent)"/>
+                    <Dimensions x="250" y="40"/>
+                    <Edge edgeSize="1"/>
+                </Backdrop>
+                <Label name="$(parent)Header" color="39B027" font="LeoAltholicLargeFont" verticalAlignment="CENTER" inheritAlpha="false">
+                    <Dimensions x="200" y="32" />
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)BGHeader" relativePoint="TOPLEFT" offsetX="10" offsetY="4"/>
+                    <OnInitialized> self:SetText(GetString(LEOALT_CHECKLIST)) </OnInitialized>
+                </Label>
+                <Button name="$(parent)MinButton" clickSound="Click" inheritAlpha="false">
+                    <Dimensions x="30" y="30"/>
+                    <Anchor point="TOPRIGHT" relativeTo="$(parent)BGHeader" relativePoint="TOPRIGHT" offsetX="-2" offsetY="4"/>
+                    <Textures normal="/esoui/art/chatwindow/maximize_up.dds" mouseOver="/esoui/art/chatwindow/maximize_over.dds" mouseDown="esoui/art/chatwindow/maximize_down.dds" />
+                    <OnClicked>
+                        LeoAltholicChecklistPanel:SetHidden(true)
+                        LeoAltholicChecklistMinButton:SetHidden(true)
+                        LeoAltholicChecklistMaxButton:SetHidden(false)
+                    </OnClicked>
+                </Button>
+                <Button name="$(parent)MaxButton" hidden="true" clickSound="Click" inheritAlpha="false">
+                    <Dimensions x="30" y="30"/>
+                    <Anchor point="TOPRIGHT" relativeTo="$(parent)BGHeader" relativePoint="TOPRIGHT" offsetX="-2" offsetY="4"/>
+                    <Textures normal="/esoui/art/chatwindow/minimize_up.dds" mouseOver="/esoui/art/chatwindow/minimize_over.dds" mouseDown="esoui/art/chatwindow/minimize_down.dds" />
+                    <OnClicked>
+                        LeoAltholicChecklistPanel:SetHidden(false)
+                        LeoAltholicChecklistMinButton:SetHidden(false)
+                        LeoAltholicChecklistMaxButton:SetHidden(true)
+                    </OnClicked>
+                </Button>
+
+                <Backdrop name="$(parent)Panel" centerColor="000000" edgeColor="222222" alpha="0.3" hidden="false">
+                    <Dimensions x="250" y="10"/>
+                    <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="0" offsetY="40"/>
+                    <Edge edgeSize="1"/>
+                    <Controls>
+                        <Texture name="$(parent)Craft1Status" hidden="true" textureFile="/esoui/art/buttons/decline_up.dds" inheritAlpha="false">
+                            <Dimensions x="28" y="28"/>
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="10" offsetY="44"/>
+                        </Texture>
+                        <Label name="$(parent)Craft1" hidden="true" font="LeoAltholicLargeFont" color="FFFFFF" verticalAlignment="CENTER" inheritAlpha="false">
+                            <Dimensions x="200" y="32" />
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)Craft1Status" relativePoint="TOPRIGHT" offsetX="10" offsetY="0"/>
+                        </Label>
+                        <Texture name="$(parent)Craft2Status" hidden="true" textureFile="/esoui/art/buttons/decline_up.dds" inheritAlpha="false">
+                            <Dimensions x="28" y="28"/>
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="10" offsetY="44"/>
+                        </Texture>
+                        <Label name="$(parent)Craft2" hidden="true" font="LeoAltholicLargeFont" color="FFFFFF" verticalAlignment="CENTER" inheritAlpha="false">
+                            <Dimensions x="200" y="32" />
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)Craft2Status" relativePoint="TOPRIGHT" offsetX="10" offsetY="0"/>
+                        </Label>
+                        <Texture name="$(parent)Craft3Status" hidden="true" textureFile="/esoui/art/buttons/decline_up.dds" inheritAlpha="false">
+                            <Dimensions x="28" y="28"/>
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="10" offsetY="44"/>
+                        </Texture>
+                        <Label name="$(parent)Craft3" hidden="true" font="LeoAltholicLargeFont" color="FFFFFF" verticalAlignment="CENTER" inheritAlpha="false">
+                            <Dimensions x="200" y="32" />
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)Craft3Status" relativePoint="TOPRIGHT" offsetX="10" offsetY="0"/>
+                        </Label>
+                        <Texture name="$(parent)Craft4Status" hidden="true" textureFile="/esoui/art/buttons/decline_up.dds" inheritAlpha="false">
+                            <Dimensions x="28" y="28"/>
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="10" offsetY="44"/>
+                        </Texture>
+                        <Label name="$(parent)Craft4" hidden="true" font="LeoAltholicLargeFont" color="FFFFFF" verticalAlignment="CENTER" inheritAlpha="false">
+                            <Dimensions x="200" y="32" />
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)Craft4Status" relativePoint="TOPRIGHT" offsetX="10" offsetY="0"/>
+                        </Label>
+                        <Texture name="$(parent)Craft5Status" hidden="true" textureFile="/esoui/art/buttons/decline_up.dds" inheritAlpha="false">
+                            <Dimensions x="28" y="28"/>
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="10" offsetY="44"/>
+                        </Texture>
+                        <Label name="$(parent)Craft5" hidden="true" font="LeoAltholicLargeFont" color="FFFFFF" verticalAlignment="CENTER" inheritAlpha="false">
+                            <Dimensions x="200" y="32" />
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)Craft5Status" relativePoint="TOPRIGHT" offsetX="10" offsetY="0"/>
+                        </Label>
+                        <Texture name="$(parent)Craft6Status" hidden="true" textureFile="/esoui/art/buttons/decline_up.dds" inheritAlpha="false">
+                            <Dimensions x="28" y="28"/>
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="10" offsetY="44"/>
+                        </Texture>
+                        <Label name="$(parent)Craft6" hidden="true" font="LeoAltholicLargeFont" color="FFFFFF" verticalAlignment="CENTER" inheritAlpha="false">
+                            <Dimensions x="200" y="32" />
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)Craft6Status" relativePoint="TOPRIGHT" offsetX="10" offsetY="0"/>
+                        </Label>
+                        <Texture name="$(parent)Craft7Status" hidden="true" textureFile="/esoui/art/buttons/decline_up.dds" inheritAlpha="false">
+                            <Dimensions x="28" y="28"/>
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="10" offsetY="44"/>
+                        </Texture>
+                        <Label name="$(parent)Craft7" hidden="true" font="LeoAltholicLargeFont" color="FFFFFF" verticalAlignment="CENTER" inheritAlpha="false">
+                            <Dimensions x="200" y="32" />
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)Craft7Status" relativePoint="TOPRIGHT" offsetX="10" offsetY="0"/>
+                        </Label>
+
+                        <Texture name="$(parent)RidingStatus" hidden="true" textureFile="/esoui/art/buttons/decline_up.dds" inheritAlpha="false">
+                            <Dimensions x="28" y="28"/>
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="10" offsetY="44"/>
+                        </Texture>
+                        <Label name="$(parent)Riding" hidden="true" font="LeoAltholicLargeFont" color="FFFFFF" verticalAlignment="CENTER" inheritAlpha="false">
+                            <Dimensions x="200" y="32" />
+                            <Anchor point="TOPLEFT" relativeTo="$(parent)RidingStatus" relativePoint="TOPRIGHT" offsetX="10" offsetY="0"/>
+                            <OnInitialized> self:SetText(GetString(SI_STAT_GAMEPAD_RIDING_HEADER_TRAINING)) </OnInitialized>
+                        </Label>
+                    </Controls>
+                </Backdrop>
+            </Controls>
+        </TopLevelControl>
     </Controls>
 </GuiXml>
diff --git a/LeoAltholicInit.lua b/LeoAltholicInit.lua
index f1a4a4d..232a945 100644
--- a/LeoAltholicInit.lua
+++ b/LeoAltholicInit.lua
@@ -1,8 +1,47 @@

 LeoAltholic = LeoAltholic or {}
 LeoAltholicUI = LeoAltholicUI or {}
+LeoAltholicChecklistUI = LeoAltholicChecklistUI or {}
+LeoAltholicToolbarUI = LeoAltholicToolbarUI or {}

 LeoAltholic.name = "LeoAltholic"
 LeoAltholic.displayName = "Leo's Altholic"
-LeoAltholic.version = "1.3.8"
+LeoAltholic.version = "1.4.0"
 LeoAltholic.chatPrefix = "|c39B027" .. LeoAltholic.name .. "|r: "
+
+LeoAltholic.TAB_BIO = "Bio"
+LeoAltholic.TAB_STATS = "Stats"
+LeoAltholic.TAB_SKILLS = "Skills"
+LeoAltholic.TAB_SKILLS2 = "Skills2"
+LeoAltholic.TAB_CHAMPION = "Champion"
+LeoAltholic.TAB_TRACKED = "Tracked"
+LeoAltholic.TAB_WRITS = "Writs"
+LeoAltholic.TAB_INVENTORY = "Inventory"
+LeoAltholic.TAB_RESEARCH = "Research"
+
+LeoAltholic.panelList = {
+    LeoAltholic.TAB_BIO,
+    LeoAltholic.TAB_STATS,
+    LeoAltholic.TAB_SKILLS,
+    LeoAltholic.TAB_SKILLS2,
+    LeoAltholic.TAB_CHAMPION,
+    LeoAltholic.TAB_TRACKED,
+    LeoAltholic.TAB_WRITS,
+    LeoAltholic.TAB_INVENTORY,
+    LeoAltholic.TAB_RESEARCH
+}
+LeoAltholic.allCrafts = {
+    CRAFTING_TYPE_ALCHEMY,
+    CRAFTING_TYPE_BLACKSMITHING,
+    CRAFTING_TYPE_CLOTHIER,
+    CRAFTING_TYPE_ENCHANTING,
+    CRAFTING_TYPE_JEWELRYCRAFTING,
+    CRAFTING_TYPE_PROVISIONING,
+    CRAFTING_TYPE_WOODWORKING
+}
+LeoAltholic.craftResearch = {
+    CRAFTING_TYPE_BLACKSMITHING,
+    CRAFTING_TYPE_CLOTHIER,
+    CRAFTING_TYPE_WOODWORKING,
+    CRAFTING_TYPE_JEWELRYCRAFTING
+}
diff --git a/LeoAltholicUI.lua b/LeoAltholicUI.lua
index 5876926..de8253f 100644
--- a/LeoAltholicUI.lua
+++ b/LeoAltholicUI.lua
@@ -3,7 +3,7 @@ LeoAltholic.hidden = true
 LeoAltholic.listingInventoryFor = 0

 function LeoAltholic:OnWindowMoveStop()
-    LeoAltholic.savedVariables.position = {
+    LeoAltholic.globalData.position = {
         left = LeoAltholicWindow:GetLeft(),
         top = LeoAltholicWindow:GetTop()
     }
@@ -22,7 +22,7 @@ function LeoAltholic:isHidden()
 end

 function LeoAltholic.RestorePosition()
-    local position = LeoAltholic.savedVariables.position or { left = 100; top = 100; }
+    local position = LeoAltholic.globalData.position or { left = 200; top = 200; }
     local left = position.left
     local top = position.top

@@ -86,7 +86,7 @@ end

 function LeoAltholic.ShowUI()
     LeoAltholic.hidden = false;
-    LeoAltholic.ShowTab(LeoAltholic.savedVariables.activeTab or "Bio")
+    LeoAltholic.ShowTab(LeoAltholic.globalData.activeTab or "Bio")
 end

 function LeoAltholic.HideUI()
@@ -99,7 +99,7 @@ function LeoAltholic.ToggleUI()
 end

 function LeoAltholic.ShowTab(tab)
-    LeoAltholic.savedVariables.activeTab = tab
+    LeoAltholic.globalData.activeTab = tab
     LeoAltholicWindowTitle:SetText(LeoAltholic.displayName .. " v" .. LeoAltholic.version .. " - " .. tab)
     local control
     for _,panel in ipairs(LeoAltholic.panelList) do
@@ -110,20 +110,16 @@ function LeoAltholic.ShowTab(tab)
     control:SetHidden(false)
 end

-function LeoAltholic.GetTime(seconds, short)
+function LeoAltholic.FormatTime(seconds, short, colorizeCountdown)
     if short == nil then short = false end
     local formats = {
-        day = SI_TIME_FORMAT_DDHHMM_DESC_SHORT,
-        hour = SI_TIME_FORMAT_HHMMSS_DESC_SHORT,
-        minute = SI_TIME_FORMAT_MMSS_DESC_SHORT,
+        dhm = SI_TIME_FORMAT_DDHHMM_DESC_SHORT,
+        day = SI_TIME_FORMAT_DAYS,
+        hm = SI_TIME_FORMAT_HHMM_DESC_SHORT,
+        hms = SI_TIME_FORMAT_HHMMSS_DESC_SHORT,
+        hour = SI_TIME_FORMAT_HOURS,
+        ms = SI_TIME_FORMAT_MMSS_DESC_SHORT,
     }
-    if short then
-        formats = {
-            day = SI_TIME_FORMAT_DDHH_DESC_SHORT,
-            hour = SI_TIME_FORMAT_HHMM_DESC_SHORT,
-            minute = SI_TIME_FORMAT_MMSS_DESC_SHORT,
-        }
-    end
     if seconds and seconds > 0 then
         local ss = seconds % 60
         local mm = math.floor(seconds / 60)
@@ -131,12 +127,28 @@ function LeoAltholic.GetTime(seconds, short)
         mm = mm % 60
         local dn = math.floor(hh / 24)
         local result = ''
-        if dn > 0 then result = zo_strformat(GetString(formats.day), dn, hh - (dn*24), mm)
-        elseif hh > 0 then result = zo_strformat(GetString(formats.hour), hh, mm, ss)
-        elseif mm > 0 then result = zo_strformat(GetString(formats.minute), mm, ss)
+        if dn > 0 then
+            if short then
+                result = zo_strformat(GetString(formats.day), dn) .." "..zo_strformat(GetString(formats.hour), hh - (dn*24))
+            else
+                result = zo_strformat(GetString(formats.dhm), dn, hh - (dn*24), mm)
+            end
+        elseif hh > 0 then
+            if short then
+                result = zo_strformat(GetString(formats.hm), hh, mm)
+            else
+                result = zo_strformat(GetString(formats.hms), hh, mm, ss)
+            end
+        elseif mm >= 0 then result = zo_strformat(GetString(formats.ms), mm, ss)
+        end
+        if colorizeCountdown == true then
+            if seconds < 3600 then result = '|cFF4020'..result..'|r'
+            elseif seconds < 86400 then result = '|cCCCC00'..result..'|r'
+            elseif seconds < 604800 then result = '|cFFFFFF'..result..'|r'
+            else result = '|c00FF00'..result..'|r' end
         end
         return result
-    else return '|cFF4020'..GetString(LEOALT_FINISHED)..'|r' end
+    else return '|cFF4020'..GetString(SI_GAMEPAD_CAMPAIGN_SCORING_DURATION_REMAINING_DONE)..'|r' end
 end

 function LeoAltholicUI.InitPanels()
diff --git a/LeoAltholic_API.lua b/LeoAltholic_API.lua
new file mode 100644
index 0000000..be17035
--- /dev/null
+++ b/LeoAltholic_API.lua
@@ -0,0 +1,123 @@
+
+--[[
+Return the timestamp from today's reset (specifically for craft writs)
+]]
+function LeoAltholic.TodayReset()
+    local diff = zo_floor(GetDiffBetweenTimeStamps(GetTimeStamp(), 1538200800) / 86400)
+    return 1538200800 + (diff * 86400)
+end
+
+--[[
+Return if the timestamp is after the today's reset.
+]]
+function LeoAltholic.IsAfterReset(timestamp)
+    return timestamp >= LeoAltholic.TodayReset()
+end
+
+--[[
+Return if the timestamp is before the today's reset.
+]]
+function LeoAltholic.IsBeforeReset(timestamp)
+    return timestamp <= LeoAltholic.TodayReset()
+end
+
+--[[
+Return if the craft is done for the day for the charName (if not specified, the current character is used)
+]]
+function LeoAltholic.IsWritDoneToday(craft, charName)
+    local char
+    if not charName then char = LeoAltholic.globalData.CharList[LeoAltholic.CharName] end
+    if not char then return end
+    for _, writ in pairs(char.quests.writs) do
+        if craft == writ.craft then
+            return writ.lastDone ~= nil and LeoAltholic.IsAfterReset(writ.lastDone)
+        end
+    end
+    return false
+end
+
+function LeoAltholic.IsWritStartedToday(craft, charName)
+    local char
+    if not charName then char = LeoAltholic.globalData.CharList[LeoAltholic.CharName] end
+    if not char then return end
+    for _, writ in pairs(char.quests.writs) do
+        if craft == writ.craft then
+            return writ.lastStarted ~= nil and LeoAltholic.IsAfterReset(writ.lastStarted)
+        end
+    end
+    return false
+end
+
+function LeoAltholic.HasStillResearchFor(craft, charName)
+    local char
+    if not charName then char = LeoAltholic.globalData.CharList[LeoAltholic.CharName] end
+    for line = 1, GetNumSmithingResearchLines(craft) do
+        local _, _, numTraits = GetSmithingResearchLineInfo(craft, line)
+        for trait = 1, numTraits do
+            if not char.research.done[craft][line][trait] then
+                return true
+            end
+        end
+    end
+end
+
+--[[
+Return the number of researching in progress, the total and the time of the first one to be completed (can be 0 or negative,
+  indicating it's done)
+]]
+function LeoAltholic.GetResearchCounters(craft, charName)
+    local char
+    if not charName then char = LeoAltholic.globalData.CharList[LeoAltholic.CharName] end
+    if not char then return end
+    local lowest = -1
+    if #char.research.doing[craft] > 0 then
+        local research = char.research.doing[craft][1]
+        lowest = research.time
+    end
+    return #char.research.doing[craft], char.research.done[craft].max, lowest
+end
+
+local function copy(obj, seen)
+    if type(obj) ~= 'table' then return obj end
+    if seen and seen[obj] then return seen[obj] end
+    local s = seen or {}
+    local res = setmetatable({}, getmetatable(obj))
+    s[obj] = res
+    for k, v in pairs(obj) do res[copy(k, s)] = copy(v, s) end
+    return res
+end
+
+--[[
+Return a copy of the complete table with all tracked chars. Structure soon.
+]]
+function LeoAltholic.ExportCharacters(forceUpdate)
+    LeoAltholic.GetCharacters(forceUpdate)
+    local chars = copy(LeoAltholic.charList)
+    return chars
+end
+
+--[[
+Return all info on 1 char by name
+]]
+function LeoAltholic.GetCharByName(name, forceUpdate)
+    local chars = LeoAltholic.ExportCharacters(forceUpdate)
+    for k, v in pairs(chars) do
+        if v.bio.name == name then return v end
+    end
+    return nil
+end
+
+--[[
+Return all info on the current char
+]]
+function LeoAltholic.GetMyself()
+    local myself = copy(LeoAltholic.globalData.CharList[LeoAltholic.CharName])
+    return myself
+end
+
+--[[
+Return if a specific tab is visible
+]]
+function LeoAltholic.IsTabVisible(tab)
+    return LeoAltholic.hidden == false and LeoAltholic.globalData.activeTab == tab
+end
diff --git a/Settings.lua b/Settings.lua
index 315d48c..5c8c84b 100644
--- a/Settings.lua
+++ b/Settings.lua
@@ -20,7 +20,7 @@ function LeoAltholic_Settings:CreatePanel()
 		displayName = "|c39B027"..LeoAltholic.displayName.."|r",
 		author = "@LeandroSilva",
 		version = LeoAltholic.version,
-		registerForRefresh = false,
+		registerForRefresh = true,
 		registerForDefaults = true,
 		website = "http://www.esoui.com/downloads/info2140-LeosAltholic.html"
 	}
@@ -29,43 +29,221 @@ function LeoAltholic_Settings:CreatePanel()
 	local optionsData = {
 		{
 			type = "header",
+			name = "|c3f7fff"..GetString(LEOALT_CHECKLIST).."|r"
+		},{
+			type = "checkbox",
+			name = GetString(SI_ADDON_MANAGER_ENABLED),
+			default = true,
+			getFunc = function() return LeoAltholic.charData.settings.checklist.enabled end,
+			setFunc = function(value)
+				LeoAltholic.charData.settings.checklist.enabled = value
+                LeoAltholicChecklistUI.RestorePosition()
+			end,
+		},{
+			type = "submenu",
+			name = GetString(SI_GAMEPAD_OPTIONS_MENU),
+			controls = {
+				{
+					type = "checkbox",
+					name = GetString(SI_ITEMFILTERTYPE16),
+					default = true,
+					disabled = function() return not LeoAltholic.charData.settings.checklist.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_ALCHEMY] end,
+					setFunc = function(value)
+						LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_ALCHEMY] = value
+						LeoAltholicChecklistUI.update()
+					end,
+				},{
+					type = "checkbox",
+					name = GetString(SI_ITEMFILTERTYPE13),
+					default = true,
+					disabled = function() return not LeoAltholic.charData.settings.checklist.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_BLACKSMITHING] end,
+					setFunc = function(value)
+						LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_BLACKSMITHING] = value
+						LeoAltholicChecklistUI.update()
+					end,
+				},{
+					type = "checkbox",
+					name = GetString(SI_ITEMFILTERTYPE14),
+					default = true,
+					disabled = function() return not LeoAltholic.charData.settings.checklist.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_CLOTHIER] end,
+					setFunc = function(value)
+						LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_CLOTHIER] = value
+						LeoAltholicChecklistUI.update()
+					end,
+				},{
+					type = "checkbox",
+					name = GetString(SI_ITEMFILTERTYPE17),
+					default = true,
+					disabled = function() return not LeoAltholic.charData.settings.checklist.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_ENCHANTING] end,
+					setFunc = function(value)
+						LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_ENCHANTING] = value
+						LeoAltholicChecklistUI.update()
+					end,
+				},{
+					type = "checkbox",
+					name = GetString(SI_ITEMFILTERTYPE25),
+					default = true,
+					disabled = function() return not LeoAltholic.charData.settings.checklist.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_JEWELRYCRAFTING] end,
+					setFunc = function(value)
+						LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_JEWELRYCRAFTING] = value
+						LeoAltholicChecklistUI.update()
+					end,
+				},{
+					type = "checkbox",
+					name = GetString(SI_ITEMFILTERTYPE18),
+					default = true,
+					disabled = function() return not LeoAltholic.charData.settings.checklist.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_PROVISIONING] end,
+					setFunc = function(value)
+						LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_PROVISIONING] = value
+						LeoAltholicChecklistUI.update()
+					end,
+				},{
+					type = "checkbox",
+					name = GetString(SI_ITEMFILTERTYPE15),
+					default = true,
+					disabled = function() return not LeoAltholic.charData.settings.checklist.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_WOODWORKING] end,
+					setFunc = function(value)
+						LeoAltholic.charData.settings.checklist.craft[CRAFTING_TYPE_WOODWORKING] = value
+						LeoAltholicChecklistUI.update()
+					end,
+				},{
+					type = "checkbox",
+					name = GetString(SI_STAT_GAMEPAD_RIDING_HEADER_TRAINING),
+					default = true,
+					disabled = function() return not LeoAltholic.charData.settings.checklist.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.charData.settings.checklist.riding end,
+					setFunc = function(value)
+						LeoAltholic.charData.settings.checklist.riding = value
+						LeoAltholicChecklistUI.update()
+					end,
+				}
+			}
+		},{
+			type = "header",
+			name = "|c3f7fff"..GetString(LEOALT_TOOLBAR).."|r"
+		},{
+			type = "description",
+			text = GetString(LEOALT_ACCOUNT_CONFIGURATION)
+		},{
+			type = "checkbox",
+			name = GetString(SI_ADDON_MANAGER_ENABLED),
+			default = true,
+			getFunc = function() return LeoAltholic.globalData.settings.toolbar.enabled end,
+			setFunc = function(value)
+				LeoAltholic.globalData.settings.toolbar.enabled = value
+				LeoAltholicToolbarUI.RestorePosition()
+			end,
+		},{
+			type = "checkbox",
+			name = GetString(LEOALT_BUMP_COMPASS),
+			default = true,
+			getFunc = function() return LeoAltholic.globalData.settings.toolbar.bumpCompass end,
+			setFunc = function(value)
+				LeoAltholic.globalData.settings.toolbar.bumpCompass = value
+				LeoAltholicToolbarUI.bumpCompass()
+			end,
+		},{
+			type = "submenu",
+			name = GetString(SI_GAMEPAD_OPTIONS_MENU),
+			controls = {
+				{
+					type = "checkbox",
+					name = GetString(SI_STAT_GAMEPAD_RIDING_HEADER_TRAINING),
+					default = true,
+					disabled = function() return not LeoAltholic.globalData.settings.toolbar.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.globalData.settings.toolbar.riding end,
+					setFunc = function(value)
+						LeoAltholic.globalData.settings.toolbar.riding = value
+						LeoAltholicToolbarUI.RestorePosition()
+						LeoAltholicToolbarUI.update()
+					end,
+				},{
+					type = "checkbox",
+					name = GetString(SI_GAMEPAD_SMITHING_CURRENT_RESEARCH_HEADER),
+					default = true,
+					disabled = function() return not LeoAltholic.globalData.settings.toolbar.enabled end,
+					width = "half",
+					getFunc = function() return LeoAltholic.globalData.settings.toolbar.researching end,
+					setFunc = function(value)
+						LeoAltholic.globalData.settings.toolbar.researching = value
+						LeoAltholicToolbarUI.RestorePosition()
+						LeoAltholicToolbarUI.update()
+					end,
+				},{
+					type = "checkbox",
+					name = GetString(LEOALT_CHECKLIST) .. " ( soon )",
+					default = true,
+					disabled = true,
+					width = "half",
+					getFunc = function() return LeoAltholic.globalData.settings.toolbar.checklist end,
+					setFunc = function(value)
+						LeoAltholic.globalData.settings.toolbar.checklist = value
+						LeoAltholicToolbarUI.RestorePosition()
+						LeoAltholicToolbarUI.update()
+					end,
+				}
+			}
+		},{
+			type = "header",
 			name = "|c3f7fff"..GetString(LEOALT_TRACKED_QUESTS).."|r"
 		},{
+			type = "description",
+			text = GetString(LEOALT_ACCOUNT_CONFIGURATION)
+		},{
 			type = "checkbox",
 			name = GetString(LEOALT_AUTO_TRACK_WRIT),
-			default = false,
-			getFunc = function() return LeoAltholic.savedVariables.settings.tracked.dailyWrits end,
+			default = true,
+			getFunc = function() return LeoAltholic.globalData.settings.tracked.dailyWrits end,
 			setFunc = function(value)
-				LeoAltholic.savedVariables.settings.tracked.dailyWrits = value
+				LeoAltholic.globalData.settings.tracked.dailyWrits = value
 			end,
 		},{
 			type = "checkbox",
 			name = GetString(LEOALT_AUTO_TRACK_DAILY),
 			default = false,
-			getFunc = function() return LeoAltholic.savedVariables.settings.tracked.allDaily end,
+			getFunc = function() return LeoAltholic.globalData.settings.tracked.allDaily end,
 			setFunc = function(value)
-				LeoAltholic.savedVariables.settings.tracked.allDaily = value
+				LeoAltholic.globalData.settings.tracked.allDaily = value
 			end,
 		},{
 			type = "header",
 			name = "|c3f7fff"..GetString(LEOALT_COMPLETED_RESEARCH).."|r"
 		},{
+			type = "description",
+			text = GetString(LEOALT_ACCOUNT_CONFIGURATION)
+		},{
 			type = "checkbox",
 			name = GetString(LEOALT_CHAT_ALL),
 			tooltip = GetString(LEOALT_CHAT_ALL_TOOLTIP),
 			default = true,
-			getFunc = function() return LeoAltholic.savedVariables.settings.completedResearch.chat end,
+			getFunc = function() return LeoAltholic.globalData.settings.completedResearch.chat end,
 			setFunc = function(value)
-				LeoAltholic.savedVariables.settings.completedResearch.chat = value
+				LeoAltholic.globalData.settings.completedResearch.chat = value
 			end,
 		},{
 			type = "checkbox",
 			name = GetString(LEOALT_CENTERSCREEN_CURRENT),
 			tooltip = GetString(LEOALT_CENTERSCREEN_CURRENT_TOOLTIP),
 			default = true,
-			getFunc = function() return LeoAltholic.savedVariables.settings.completedResearch.screen end,
+			getFunc = function() return LeoAltholic.globalData.settings.completedResearch.screen end,
 			setFunc = function(value)
-				LeoAltholic.savedVariables.settings.completedResearch.screen = value
+				LeoAltholic.globalData.settings.completedResearch.screen = value
 			end,
 		}
 	}
diff --git a/ui/bio.lua b/ui/bio.lua
index a12b372..9782975 100644
--- a/ui/bio.lua
+++ b/ui/bio.lua
@@ -48,29 +48,24 @@ function LeoAltholicBioList:SetupEntry(control, data)
     control.class:SetText(zo_strformat(SI_CLASS_NAME, GetClassName(data.gender, data.classId)))

     control.alliance = GetControl(control, "Alliance")
-    --local icon = ZO_GetAllianceIcon(data.alliance.id)
     local color, icon, allianceName
     if data.alliance.id == ALLIANCE_ALDMERI_DOMINION then
-        --color = 'F1FF77'
         icon = 'esoui/art/guild/guildbanner_icon_aldmeri.dds'
         allianceName = zo_strformat(SI_ALLIANCE_NAME, GetAllianceName(ALLIANCE_ALDMERI_DOMINION))
     elseif data.alliance.id == ALLIANCE_EBONHEART_PACT then
-        --color = 'FF7D77'
         icon = 'esoui/art/guild/guildbanner_icon_ebonheart.dds'
         allianceName = zo_strformat(SI_ALLIANCE_NAME, GetAllianceName(ALLIANCE_EBONHEART_PACT))
     elseif data.alliance.id == ALLIANCE_DAGGERFALL_COVENANT then
-        --color = '779CFF'
         icon = 'esoui/Art/guild/guildbanner_icon_daggerfall.dds'
         allianceName = zo_strformat(SI_ALLIANCE_NAME, GetAllianceName(ALLIANCE_DAGGERFALL_COVENANT))
     end
-    --control.alliance:SetText("|c"..color.."|t20:30:" .. icon .. "|t|r ".. data.alliance.name)
     control.alliance:SetText("|t30:30:" .. icon .. "|t ".. allianceName)

     control.riding = GetControl(control, "Riding")
     local riding = '|t20:20:esoui/art/mounts/ridingskill_speed.dds|t' .. string.format("%02d%%", data.riding.speed) ..
             ' |t20:20:esoui/art/mounts/ridingskill_stamina.dds|t' .. string.format("%02d", data.riding.stamina) ..
             ' |t20:20:esoui/art/mounts/ridingskill_capacity.dds|t' .. string.format("%02d", data.riding.capacity) ..
-            ' |t22:22:esoui/art/miscellaneous/timer_32.dds|t' .. LeoAltholic.GetTime(data.riding.time - GetTimeStamp(), true)
+            ' |t22:22:esoui/art/miscellaneous/timer_32.dds|t' .. LeoAltholic.FormatTime(data.riding.time - GetTimeStamp(), true, true)
     control.riding:SetText(riding)
     control.riding.riding = data.riding

@@ -148,7 +143,7 @@ function LeoAltholicUI:updateBio()
         local riding = '|t20:20:esoui/art/mounts/ridingskill_speed.dds|t' .. string.format("%02d%%", child.riding.speed) ..
                 ' |t20:20:esoui/art/mounts/ridingskill_stamina.dds|t' .. string.format("%02d", child.riding.stamina) ..
                 ' |t20:20:esoui/art/mounts/ridingskill_capacity.dds|t' .. string.format("%02d", child.riding.capacity) ..
-                ' |t22:22:esoui/art/miscellaneous/timer_32.dds|t' .. LeoAltholic.GetTime(child.riding.time - GetTimeStamp(), true)
+                ' |t22:22:esoui/art/miscellaneous/timer_32.dds|t' .. LeoAltholic.FormatTime(child.riding.time - GetTimeStamp(), true, true)
         child:SetText(riding)
     end
 end
diff --git a/ui/checklist.lua b/ui/checklist.lua
new file mode 100644
index 0000000..9363199
--- /dev/null
+++ b/ui/checklist.lua
@@ -0,0 +1,148 @@
+
+function LeoAltholicChecklistUI:OnWindowMoveStop()
+    LeoAltholic.globalData.positionChecklist = {
+        left = LeoAltholicChecklist:GetLeft(),
+        top = LeoAltholicChecklist:GetTop()
+    }
+end
+
+function LeoAltholicChecklistUI.RestorePosition()
+    local position = LeoAltholic.globalData.positionChecklist or { left = 100; top = 200; }
+    local left = position.left
+    local top = position.top
+
+    LeoAltholicChecklist:ClearAnchors()
+    LeoAltholicChecklist:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, left, top)
+    if LeoAltholic.charData.settings.checklist.enabled == false then
+        LeoAltholicChecklist:SetHidden(true)
+    else
+        LeoAltholicChecklist:SetHidden(false)
+    end
+end
+
+local SPACE = 32
+local checklist = WINDOW_MANAGER:GetControlByName("LeoAltholicChecklist")
+local panel = GetControl(checklist, "Panel")
+local height = 0
+local anchorY = SPACE + 4
+local lastChecklist = GetTimeStamp()
+local checklistDone = 0
+
+local function createItem(label, labelText, texture, canShow)
+    if canShow then
+        texture:SetTexture("esoui/art/buttons/decline_up.dds")
+        texture:SetColor(1,0,0,1)
+        texture:SetDimensions(32, 32)
+        texture:SetAnchor(TOPLEFT, checklist, TOPLEFT, 10, height + anchorY)
+
+        height = height + SPACE
+        label:SetText(labelText)
+        label:SetHidden(false)
+        texture:SetHidden(false)
+    else
+        label:SetHidden(true)
+        texture:SetHidden(true)
+    end
+end
+
+function LeoAltholicChecklistUI:checkReset()
+    if LeoAltholic.IsBeforeReset(lastChecklist) then
+        LeoAltholicChecklistUI:update()
+        lastChecklist = GetTimeStamp()
+    end
+end
+
+local function doneItem(label, texture)
+    texture:SetTexture("esoui/art/loot/loot_finesseItem.dds")
+    texture:SetColor(0,1,0,1)
+end
+
+local function startItem(label, texture)
+    texture:SetTexture("esoui/art/loot/loot_finesseItem.dds")
+    texture:SetColor(1,1,0,1)
+end
+
+local function stoppedItem(label, texture)
+    texture:SetTexture("esoui/art/buttons/decline_up.dds")
+    texture:SetColor(1,0,0,1)
+end
+
+local function incrementDone()
+    checklistDone = checklistDone + 1
+    if checklistDone == 8 then
+        LeoAltholicChecklistPanel:SetHidden(true)
+        LeoAltholicChecklistMinButton:SetHidden(true)
+        LeoAltholicChecklistMaxButton:SetHidden(false)
+    end
+end
+
+function LeoAltholicChecklistUI:doneWrit(craft)
+    if not LeoAltholic.charData.settings.checklist.enabled then return end
+
+    local label = GetControl(panel, "Craft"..craft)
+    local texture = GetControl(panel, "Craft"..craft.."Status")
+    doneItem(label, texture)
+    incrementDone()
+end
+
+function LeoAltholicChecklistUI:startedWrit(craft)
+    if not LeoAltholic.charData.settings.checklist.enabled then return end
+
+    local label = GetControl(panel, "Craft"..craft)
+    local texture = GetControl(panel, "Craft"..craft.."Status")
+    startItem(label, texture)
+end
+
+function LeoAltholicChecklistUI:stoppedWrit(craft)
+    if not LeoAltholic.charData.settings.checklist.enabled then return end
+
+    local label = GetControl(panel, "Craft"..craft)
+    local texture = GetControl(panel, "Craft"..craft.."Status")
+    stoppedItem(label, texture)
+end
+
+function LeoAltholicChecklistUI:doneRiding()
+    if not LeoAltholic.charData.settings.checklist.enabled then return end
+
+    local label = GetControl(panel, "Riding")
+    local texture = GetControl(panel, "RidingStatus")
+    doneItem(label, texture)
+    incrementDone()
+end
+
+function LeoAltholicChecklistUI:update()
+
+    if not LeoAltholic.charData.settings.checklist.enabled then return end
+
+    local char = LeoAltholic.GetMyself()
+
+    local texture, label
+    local done = false
+
+    height = 0
+    anchorY = 44
+
+    for _, craft in pairs(LeoAltholic.allCrafts) do
+        label = GetControl(panel, "Craft"..craft)
+        texture = GetControl(panel, "Craft"..craft.."Status")
+        createItem(label, GetCraftingSkillName(craft), texture, LeoAltholic.charData.settings.checklist.craft[craft])
+        if LeoAltholic.IsWritDoneToday(craft) then
+            doneItem(label, texture)
+            done = true
+            incrementDone()
+        elseif LeoAltholic.IsWritStartedToday(craft) then
+            startItem(label, texture)
+        end
+    end
+
+    label = GetControl(panel, "Riding")
+    texture = GetControl(panel, "RidingStatus")
+    createItem(label, GetString(SI_STAT_GAMEPAD_RIDING_HEADER_TRAINING), texture, LeoAltholic.charData.settings.checklist.riding)
+    if char.attributes.riding.time - GetTimeStamp() > 0 then
+        doneItem(label, texture)
+        incrementDone()
+    end
+
+    panel:SetHeight(10 + height)
+    checklist:SetHeight(60 + height)
+end
diff --git a/ui/inventory.lua b/ui/inventory.lua
index 05272ce..6a9b1d3 100644
--- a/ui/inventory.lua
+++ b/ui/inventory.lua
@@ -1,5 +1,4 @@

-
 LeoAltholicInventoryList = ZO_SortFilterList:Subclass()
 function LeoAltholicInventoryList:New(control)

diff --git a/ui/research.lua b/ui/research.lua
index 1ec01f2..399aa88 100644
--- a/ui/research.lua
+++ b/ui/research.lua
@@ -31,69 +31,49 @@ function LeoAltholicResearchList:SetupEntry(control, data)
     local color
     control.craft = {}
     for _,craft in pairs(LeoAltholic.craftResearch) do
-        local i = 1
-        local researching = 0
+        local researching = #data.research.doing[craft]
         control.craft[craft] = GetControl(control, "Craft" .. craft)
-        local lowest = -1
-        local lowestTraitData = 0
+        local first
         local list = {}
-        for line = 1, GetNumSmithingResearchLines(craft) do
-            local lineName, lineIcon = GetSmithingResearchLineInfo(craft, line)
-            for trait = 1, LeoAltholic.maxTraits do
-                local traitType = GetSmithingResearchLineTraitInfo(craft, line, trait)
-                local traitName = GetString('SI_ITEMTRAITTYPE',traitType)
-                local traitData = data.research[craft][line][trait]
-                if type(traitData) == 'number' then
-                    local diff = traitData - GetTimeStamp()
-                    if lowest == -1 or diff < lowest then
-                        lowest = diff
-                        lowestTraitData = traitData
-                    end
-                    table.insert(list, {
-                        craft = craft,
-                        line = line,
-                        trait = trait,
-                        lineName = lineName,
-                        lineIcon = lineIcon,
-                        traitName = traitName,
-                        timer = LeoAltholic.GetTime(diff),
-                        traitData = traitData
-                    })
-                    i = i + 1
-                    if traitData - GetTimeStamp() > 0 then
-                        researching = researching + 1
-                    end
-                end
-            end
+        for _, research in pairs(data.research.doing[craft]) do
+
+            if first == nil then first = research end
+
+            local lineName, lineIcon = GetSmithingResearchLineInfo(craft, research.line)
+            local traitType = GetSmithingResearchLineTraitInfo(craft, research.line, research.trait)
+            local traitName = GetString('SI_ITEMTRAITTYPE', traitType)
+
+            table.insert(list, {
+                craft = craft,
+                line = research.line,
+                trait = research.trait,
+                lineName = lineName,
+                lineIcon = lineIcon,
+                traitName = traitName,
+                time = research.time,
+                timer = LeoAltholic.FormatTime(research.time, false, true)
+            })
         end
         color = '|c21A121'
-        if researching < data.research[craft].max then
+        if researching < data.research.done[craft].max then
             color = '|cCB110E'
         end
-        if researching > data.research[craft].max then researching = data.research[craft].max end
-        local output = color .. researching .. '/' .. data.research[craft].max .. '|r'
+        if researching > data.research.done[craft].max then researching = data.research.done[craft].max end
+        local output = color .. researching .. '/' .. data.research.done[craft].max .. '|r'
         color = '|cFFFFFF'
-        if lowest <= 3600 then
+        if first and first.time <= 3600 then
             color = '|cFFFF00'
         end
         if #list > 0 then
-            output = output .. " " .. color..LeoAltholic.GetTime(lowest) .. '|r'
+            output = output .. " " .. color..LeoAltholic.FormatTime(first.time) .. '|r'
         end
         control.craft[craft]:SetText(output)
         control.craft[craft].list = list
-        control.craft[craft].timerData = {
-            researching = researching,
-            max = data.research[craft].max,
-            lowest = lowest,
-            showLowest = #list > 0,
-            lowestTraitData = lowestTraitData
-        }
     end

     ZO_SortFilterList.SetupRow(self, control, data)
 end

-
 function LeoAltholicResearchList:ColorRow(control, data, mouseIsOver)

     local color = ZO_SECOND_CONTRAST_TEXT
@@ -157,7 +137,7 @@ function LeoAltholicUI.TooltipResearch(control, visible)
         addLineTitle(InformationTooltip, GetCraftingSkillName(control.list[1].craft))

         for _, trait in pairs(control.list) do
-            addLine(InformationTooltip, "|t30:30:"..trait.lineIcon.."|t "..trait.lineName.." "..trait.traitName.." "..trait.timer)
+            addLine(InformationTooltip, "|t30:30:"..trait.lineIcon.."|t "..trait.lineName.." "..trait.traitName.." |cff0000"..trait.timer)
         end

         InformationTooltip:SetHidden(false)
@@ -168,25 +148,5 @@ function LeoAltholicUI.TooltipResearch(control, visible)
 end

 function LeoAltholicUI:updateResearch()
-    local control = LeoAltholicWindowResearchPanelListScrollListContents
-    for i = 1, control:GetNumChildren() do
-        for j = 2, 5 do
-            local child = control:GetChild(i):GetChild(j)
-            if child and child.timerData then
-                local color = '|c21A121'
-                if child.timerData.researching < child.timerData.max then
-                    color = '|cCB110E'
-                end
-                local output = color .. child.timerData.researching .. '/' .. child.timerData.max .. '|r'
-                color = '|cFFFFFF'
-                if child.timerData.lowest <= 3600 then
-                    color = '|cFFFF00'
-                end
-                if child.timerData.showLowest then
-                    output = output .. " " .. color..LeoAltholic.GetTime(child.timerData.lowestTraitData - GetTimeStamp()) .. '|r'
-                end
-                child:SetText(output)
-            end
-        end
-    end
+    LeoAltholicUI.researchList:RefreshData()
 end
diff --git a/ui/skills.lua b/ui/skills.lua
index f43203b..28aa386 100644
--- a/ui/skills.lua
+++ b/ui/skills.lua
@@ -1,5 +1,4 @@

-
 LeoAltholicSkillsList = ZO_SortFilterList:Subclass()
 function LeoAltholicSkillsList:New(control)

diff --git a/ui/toolbar.lua b/ui/toolbar.lua
new file mode 100644
index 0000000..0f3a9f9
--- /dev/null
+++ b/ui/toolbar.lua
@@ -0,0 +1,124 @@
+
+function LeoAltholicToolbarUI:OnWindowMoveStop()
+    LeoAltholic.globalData.positionToolbar = {
+        left = LeoAltholicToolbar:GetLeft(),
+        top = LeoAltholicToolbar:GetTop()
+    }
+end
+
+function LeoAltholicToolbarUI.RestorePosition()
+    local position = LeoAltholic.globalData.positionToolbar or { left = 100; top = 100; }
+    local left = position.left
+    local top = position.top
+
+    LeoAltholicToolbar:ClearAnchors()
+    LeoAltholicToolbar:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, left, top)
+    if LeoAltholic.globalData.settings.toolbar.enabled == false then
+        LeoAltholicToolbar:SetHidden(true)
+    else
+        LeoAltholicToolbar:SetHidden(false)
+    end
+end
+
+function LeoAltholicToolbarUI.bumpCompass()
+
+    if LeoAltholic.globalData.settings.toolbar.enabled and LeoAltholic.globalData.settings.toolbar.bumpCompass then
+        if LeoAltholicToolbar:GetTop() <= 60 then
+            if math.floor(ZO_CompassFrame:GetTop()) ~= math.floor(LeoAltholicToolbar:GetTop()) + 60 then
+                ZO_CompassFrame:ClearAnchors()
+                ZO_CompassFrame:SetAnchor( TOP, GuiRoot, TOP, 0, LeoAltholicToolbar:GetTop() + 60)
+                ZO_TargetUnitFramereticleover:ClearAnchors()
+                ZO_TargetUnitFramereticleover:SetAnchor( TOP, GuiRoot, TOP, 0, LeoAltholicToolbar:GetTop() + 110)
+            end
+        elseif ZO_CompassFrame:GetTop() ~= 40 then
+            ZO_CompassFrame:ClearAnchors()
+            ZO_CompassFrame:SetAnchor( TOP, GuiRoot, TOP, 0, 40 )
+            ZO_TargetUnitFramereticleover:ClearAnchors()
+            ZO_TargetUnitFramereticleover:SetAnchor( TOP, GuiRoot, TOP, 0, 88 )
+        end
+    elseif ZO_CompassFrame:GetTop() ~= 40 then
+        ZO_CompassFrame:ClearAnchors()
+        ZO_CompassFrame:SetAnchor( TOP, GuiRoot, TOP, 0, 40 )
+        ZO_TargetUnitFramereticleover:ClearAnchors()
+        ZO_TargetUnitFramereticleover:SetAnchor( TOP, GuiRoot, TOP, 0, 88 )
+    end
+end
+
+function LeoAltholicToolbarUI.update()
+
+    LeoAltholicToolbarUI.bumpCompass()
+
+    if not LeoAltholic.globalData.settings.toolbar.enabled then return end
+
+    local char = LeoAltholic.GetMyself()
+    local toolbar = WINDOW_MANAGER:GetControlByName("LeoAltholicToolbar")
+
+    local offsetX = 0
+    local width = 120
+    local numSections = 0
+
+    local label = GetControl(toolbar, "Riding")
+    local texture = GetControl(toolbar, "RidingTexture")
+    label:SetHidden(true)
+    texture:SetHidden(true)
+    if LeoAltholic.globalData.settings.toolbar.riding and
+            (char.attributes.riding.speed < char.attributes.riding.speedMax or
+            char.attributes.riding.stamina < char.attributes.riding.staminaMax or
+            char.attributes.riding.capacity < char.attributes.riding.capacityMax) then
+        label:SetText(LeoAltholic.FormatTime(char.attributes.riding.time - GetTimeStamp(), true, true))
+        label:SetHidden(false)
+        texture:SetHidden(false)
+        offsetX = offsetX + 110
+        numSections = numSections + 1
+    end
+
+    for _,craft in pairs(LeoAltholic.craftResearch) do
+        label = GetControl(toolbar, "Craft"..craft)
+        texture = GetControl(toolbar, "Craft"..craft.."Texture")
+        label:SetHidden(true)
+        texture:SetHidden(true)
+    end
+    if LeoAltholic.globalData.settings.toolbar.researching then
+        for _,craft in pairs(LeoAltholic.craftResearch) do
+            if LeoAltholic.HasStillResearchFor(craft) then
+                label = GetControl(toolbar, "Craft"..craft)
+                texture = GetControl(toolbar, "Craft"..craft.."Texture")
+                local researching, total, lowest = LeoAltholic.GetResearchCounters(craft)
+                local color = '|c21A121'
+                if researching < total then
+                    color = '|cCB110E'
+                end
+                label:SetText(color .. researching .. '/' .. total .. '|r ' .. LeoAltholic.FormatTime(lowest, true, true))
+                label:SetHidden(false)
+                texture:SetHidden(false)
+                texture:SetAnchor(TOPLEFT, toolbar, TOPLEFT, offsetX, 0)
+                label:SetAnchor(TOPLEFT, texture, TOPRIGHT, 2, 0)
+                offsetX = offsetX + width
+                numSections = numSections + 1
+            end
+        end
+    end
+
+    --[[
+    if LeoAltholic.globalData.settings.toolbar.checklist then
+        if char.attributes.riding.time - GetTimeStamp() < 0 then
+            label = GetControl(toolbar, "Checklist")
+            label:SetText("|t28:28:esoui/art/tutorial/store_indexicon_mounts_up.dds|t")
+            label:SetAnchor(TOPLEFT, toolbar, TOPLEFT, offsetX, 0)
+            label:SetHidden(false)
+        else
+            label = GetControl(toolbar, "Checklist")
+            label:SetText("|cFF0000|t28:28:esoui/art/tutorial/store_indexicon_mounts_up.dds|t|r")
+            label:SetAnchor(TOPLEFT, toolbar, TOPLEFT, offsetX, 0)
+            label:SetHidden(false)
+        end
+    end
+    ]]
+
+    if numSections > 0 then
+        toolbar:SetWidth(numSections * 130)
+        GetControl(toolbar, "BG"):SetWidth(numSections * 130)
+    else
+        toolbar:SetHidden(true)
+    end
+end
diff --git a/ui/tracked.lua b/ui/tracked.lua
index 1c54803..f5cd196 100644
--- a/ui/tracked.lua
+++ b/ui/tracked.lua
@@ -52,13 +52,13 @@ function LeoAltholicUI.InitTrackedPanel()
                         label:SetHandler('OnMouseUp', function(control, button, upInside)
                             if upInside == true and button == MOUSE_BUTTON_INDEX_RIGHT then
                                 LeoAltholic.log(zo_strformat(GetString(LEOALT_REMOVED_FROM), label:GetText(), char.bio.name))
-                                table.remove(LeoAltholic.savedVariables.CharList[char.bio.name].quests.tracked, i)
+                                table.remove(LeoAltholic.globalData.CharList[char.bio.name].quests.tracked, i)
                                 control:SetHidden(true)
                                 control:GetParent():GetNamedChild("Quest" .. index .. "Done"):SetHidden(true)
                             end
                         end)
                         if char.quests.tracked[i].lastDone ~= nil then
-                            if char.quests.tracked[i].lastDone <= LeoAltholic.TodayReset() then
+                            if LeoAltholic.IsBeforeReset(char.quests.tracked[i].lastDone) then
                                 done:SetText("|cCB110Enot done today|r")
                             else
                                 local diff = GetTimeStamp() - char.quests.tracked[i].lastDone
diff --git a/ui/writs.lua b/ui/writs.lua
index 9a75d1f..a1ca831 100644
--- a/ui/writs.lua
+++ b/ui/writs.lua
@@ -30,14 +30,14 @@ function LeoAltholicWritsList:SetupEntry(control, data)
     control.name:SetText(data.name)

     local child
-    for _, craft in pairs({CRAFTING_TYPE_ALCHEMY,CRAFTING_TYPE_BLACKSMITHING,CRAFTING_TYPE_CLOTHIER,CRAFTING_TYPE_ENCHANTING,CRAFTING_TYPE_JEWELRYCRAFTING,CRAFTING_TYPE_PROVISIONING,CRAFTING_TYPE_WOODWORKING}) do
+    for _, craft in pairs(LeoAltholic.allCrafts) do
         child = GetControl(control, "Craft"..craft.."Status")
         local icon = "esoui/art/tutorial/menubar_help_up.dds"
         local color = {1,1,1,1}
         local ago = ""
         for _, writ in pairs(data.writs) do
             if craft == writ.craft then
-                if writ.lastDone ~= nil and writ.lastDone > LeoAltholic.TodayReset() then
+                if writ.lastDone ~= nil and LeoAltholic.IsAfterReset(writ.lastDone) then
                     color = {0,1,0,1}
                 else
                     color = {1,0,0,1}