Mercurial > wow > worldplan
view ClassPlan.lua @ 34:0100d923d8c3
WorldPlan:
- Reward filter toggle changed to clear out other reward filters. The assumption being that one is most often looking only for that particular type of quest when they go to use it.
- Fixed filter bar info falling out of sync after player-triggered world map updates.
- Code stuff:
-- Quest pin shown-state management makes better use of OnShow OnHide handlers, SetShown is toggled and it all goes from there
-- WorldQuests module re-factored outside of the top level frame script.
ClassPlan:
- Available missions are now recorded; the mission list can be toggled between in-progress and available by clicking the heading.
author | Nenue |
---|---|
date | Wed, 02 Nov 2016 19:04:47 -0400 |
parents | e8679ecb48d8 |
children | 26dfa661daa7 |
line wrap: on
line source
local wipe, tinsert, sort = table.wipe, tinsert, table.sort local pairs, ipairs = pairs, ipairs local floor, mod, time = floor, mod, time local max, min = math.max, math.min local GetTime = GetTime local GI_currentTime = time() local print = DEVIAN_WORKSPACE and function(...) print('ClassPlan', ...) end or nop local CG_GetBuildings = C_Garrison.GetBuildings local CG_GetFollowerShipments = C_Garrison.GetFollowerShipments local CG_GetLooseShipments = C_Garrison.GetLooseShipments local CG_GetTalentTrees = C_Garrison.GetTalentTrees local CG_GetCompleteTalent = C_Garrison.GetCompleteTalent local CG_GetLandingPageShipmentInfo = C_Garrison.GetLandingPageShipmentInfo local CG_GetLandingPageShipmentInfoByContainerID = C_Garrison.GetLandingPageShipmentInfoByContainerID local CP_REPLACE_LANDINGPAGE = true local CP_HEADER_SIZE = 24 local CP_BACKGROUND_COLOR = { inProgress = {0, 0, 0, 0.5}, shipmentsReady = {0, 0, 0, 0.25}, complete = {0.5, 0.5, 0.5, 0.5} } local GetTimeLeftString = function(timeLeft) local days = floor(timeLeft/(24*3600)) local hours = floor(mod(timeLeft, (24*3600)) / 3600) local minutes = floor(mod(timeLeft, 3600) / 60) local seconds = mod(timeLeft, 60) if days >= 1 then return (days .. 'd' .. ' ') .. ((hours > 0) and (hours .. 'h') or '') else return ((hours > 0) and (hours .. 'h') or '') .. ((minutes > 0) and (' ' ..minutes .. ' min') or '') end end ClassOrderPlanCore = { events = {}, freeBlocks = {}, blocks = {}, sortedItems = {}, timers = {}, shipments = {}, playerFirst = false, prototypes = {}, Queued = {} } local MissionList = { templateName = 'ClassPlanMissionEntry', listKey = {'missions', 'available'}, listTitle = {'In Progress', 'Available'}, point = 'TOPLEFT', relativePoint ='TOPLEFT', events = { 'GARRISON_MISSION_LIST_UPDATE', 'GARRISON_LANDINGPAGE_SHIPMENTS'}, } local ShipmentList = { templateName = 'ClassPlanShipmentEntry', listKey = {'shipments'}, listTitle = {'Work Orders'}, events = { 'GARRISON_MISSION_LIST_UPDATE', 'GARRISON_LANDINGPAGE_SHIPMENTS', 'GARRISON_TALENT_UPDATE', "GARRISON_TALENT_COMPLETE", "GARRISON_SHIPMENT_RECEIVED", 'GARRISON_FOLLOWER_LIST_UPDATE', 'GARRISON_SHOW_LANDING_PAGE'}, } local SharedHandlers = { numBlocks = 0, isStale = true, } local SharedEntry = {} local ShipmentEntry = {} local MissionEntry = {} local ClassPlan = ClassOrderPlanCore function ClassPlan:OnLoad () self:RegisterEvent('PLAYER_LOGIN') self:RegisterEvent('ADDON_LOADED') self:RegisterEvent('PLAYER_REGEN_ENABLED') self:RegisterEvent('PLAYER_REGEN_DISABLED') self:RegisterForDrag('LeftButton') self:SetMovable(true) self:SetToplevel(true) SLASH_CLASSPLAN1 = "/classplan" SLASH_CLASSPLAN2 = "/cp" SlashCmdList.CLASSPLAN = function(args) self:Toggle() end end function ClassPlan:GetCurrentProfile() WorldPlanData.OrderHall = WorldPlanData.OrderHall or {} local db = WorldPlanData.OrderHall self.data = db local characters = db.characters or {} db.characters = characters local name, realm = UnitName('player') realm = realm or GetRealmName() local profileName = name .. '-' .. realm self.profile = characters[profileName] or {} self.characters = characters characters[profileName] = self.profile local classColor = RAID_CLASS_COLORS[select(2, UnitClass('player'))] local className = UnitClass('player') print('|cFFFFFF00Loaded:|r', classColor.hex, className, profileName) self.Background:SetColorTexture(classColor.r, classColor.g, classColor.b, 0.5) self.profile.classColor = classColor self.profile.className = className return self.profile end function ClassPlan:SetupHandler(handler) print('|cFF00FF00'..handler:GetName()..' loaded') for i, event in ipairs(handler.events) do print('|cFF00FF00 event', event) handler:RegisterEvent(event) end for index, listKey in ipairs(handler.listKey) do self.profile[listKey] = self.profile[listKey] or {} local listTitle = handler.listTitle[index] setmetatable(self.profile[listKey], { __tostring = listTitle }) end handler:SetList(1) handler.sortedItems = {} end function ClassPlan:OnEvent (event, arg) print(event, arg) if event == 'PLAYER_REGEN_DISABLED' then if self:IsVisible() then self.combatHide = true self:SetShown(false) end elseif event == 'PLAYER_REGEN_ENABLED' then if self.combatHide == true then self.combatHide = nil self:SetShown(true) end elseif event == 'ADDON_LOADED' then if arg == 'Blizzard_GarrisonUI' then self:Reanchor() end elseif event == 'PLAYER_LOGIN' then if not self.initialized then self:Setup() end end end function ClassPlan:Setup() if IsLoggedIn() then print('|cFFFFFF00'..self:GetName()..':Setup()|r') self:GetCurrentProfile() for _, handler in ipairs(self.Handlers) do self:SetupHandler(handler) end self.initialized = true self:SetShown(self.data.IsShown) end end --- Update space local max = math.max function ClassPlan:Update() print('|cFF00FFFFRefresh()|r') self.currentHeight = 0 for index, handler in pairs(self.Handlers) do if handler.isStale then print(' |cFF00FF00'..index..' '..handler:GetName()..'|r') local sortedItems = handler.sortedItems local activeKey = handler.activeKey handler.profile = self.profile[handler.activeKey] wipe(sortedItems) handler:GetPlayerData(self.profile) for key, profile in pairs(self.data.characters) do print('profile', key, activeKey) local profileList = profile[activeKey] if profileList and #profileList >= 1 then local classColor = profile.classColor or defaultClassColor local isMine = (profile == self.profile) for index, data in ipairs(profileList) do data.classColor = classColor data.profileKey = key data.isMine = isMine if handler.OnGetItem then handler.OnGetItem(data) end tinsert(sortedItems, data) end end end if handler.SortHandler then sort(sortedItems, handler.SortHandler) end end handler.isStale = nil local itemsHeight = handler:UpdateItems() self.currentHeight = max(itemsHeight, self.currentHeight) end self.isStale = nil self:Reanchor() self:SetHeight(self.currentHeight + CP_HEADER_SIZE) end function ClassPlan:Toggle() if self:IsShown() then self:Hide() else self:Show() end if self.data then self.data.IsShown = self:IsShown() end end function ClassPlan:OnUpdate() if self.isStale then print('|cFFFF4400An illusion! What are you hiding?|r') self:Update() end end function ClassPlan:OnShow() print('|cFF00FFFFShow()') if self.isStale then self:Update() end self:Reanchor() end function ClassPlan:OnHide() print('|cFF00FFFFHide()') end function ClassPlan:Reanchor() self:ClearAllPoints() self:SetPoint('CENTER', self.data.positionX, self.data.positionY) for index, frame in ipairs(self.Handlers) do frame:Reanchor() end end function ClassPlan:OnDragStart() self:StartMoving() end function ClassPlan:OnDragStop() self:StopMovingOrSizing() local x,y = self:GetCenter() if x and y then x = (x - GetScreenWidth()/2) y = (y - GetScreenHeight()/2) * -1 self.data.positionX, self.data.positionY = x,y print('saving positions:', x, y) end end function SharedHandlers:SetList(index) if not index then if self.currentListIndex == #self.listKey then index = 1 else index = self.currentListIndex + 1 end end print('|cFF0088FF'..self:GetName()..'|r:SetList()', index) self.currentListIndex = index self.activeKey = self.listKey[index] self.activeTitle = self.listTitle[index] self.isStale = true end function SharedHandlers:RequestData() print('|cFF0088FF'..self:GetName()..':RequestData()') self.isStale = true end function SharedHandlers:OnEvent(event, arg) if (event == 'GARRISON_MISSION_LIST_UPDATE') and (arg ~= LE_FOLLOWER_TYPE_GARRISON_7_0) then -- ignore non-OrderHall updates return end print('|cFF00FF88'..self:GetName()..':OnEvent()|r', event, arg) if self:IsVisible() then print('|cFF88FF00 frame visible; get busy') self:RequestData() else if not self.NextData then print('|cFF88FF00 setting timer') self.NextData = C_Timer.NewTimer(0.25, function() if self.initialized then self:RequestData() self.NextData:Cancel() self.NextData = nil print('|cFF88FF00'..self:GetName()..' clearing timer') end end) end end end function SharedHandlers:OnUpdate() if self.isStale then self:GetParent():Update() end end -- Stuff set on every list item function SharedHandlers:SetOwnerData (self, data) local name, realm = string.match(data.profileKey, "(.+)%-(.+)") local ownerText = '|c'.. data.classColor.colorStr .. name .. '|r' self.Owner:SetText(ownerText) self.Name:SetText(self.name) self.Name:SetTextColor(data.classColor.r, data.classColor.g, data.classColor.b) end function SharedHandlers:UpdateItems() local sortedItems = self.sortedItems self.blocks = self.blocks or {} local blocks = self.blocks local lastProfile local numItems = #sortedItems local totalHeight = 0 self.lastBlock = nil self.numActive = 0 for i, data in ipairs(sortedItems) do local block = blocks[i] if not block then block = CreateFrame('Button', nil, self, self.templateName) block:SetID(i) block.listType = self.activeKey block.handler = self self.numBlocks = self.numBlocks + 1 blocks[i] = block end print('RefreshItem', block) self.numActive = self.numActive + 1 if self.lastBlock then block:SetPoint('TOPLEFT', self.lastBlock, 'BOTTOMLEFT', 0, 0) print('--', i, data.isComplete, data.missionEndTime, data.name) else block:SetPoint('TOPLEFT', 0, 0) print('--top') end self.lastBlock = block totalHeight = totalHeight + block:GetHeight() block.lastProfile = lastProfile -- blot out arbitrary flags block.offerEndTime = nil block.missionEndTime = nil block.creationTime = nil block.duration = nil block.throttle = 5 for k,v in pairs(data) do if type(block[k]) ~= 'function' then block[k] = v end end block:Update() self:SetOwnerData(block, data) block:Show() lastProfile = data.profileKey end for i = numItems + 1, self.numBlocks do if blocks[i] then blocks[i]:Hide() end end self:Reanchor() return totalHeight end function ShipmentList:Reanchor() print('|cFF00FFFF'..self:GetName()..':Reanchor|r') self:SetPoint('TOPLEFT', 0, -24) self:SetPoint('BOTTOMRIGHT', -ClassOrderPlan:GetWidth()/2, 0) end function MissionList:Reanchor() self:SetPoint('TOPRIGHT', 0, -24) self:SetPoint('BOTTOMLEFT', ClassOrderPlan:GetWidth()/2, 0) self.ListTab:ClearAllPoints() self.ListTab:SetPoint('TOPLEFT', self, 'TOPLEFT', 0, CP_HEADER_SIZE) self.ListTab:SetPoint('BOTTOMRIGHT', self, 'TOPRIGHT', 0, 0) self.ListTab.Label:SetText(self.listTitle[self.currentListIndex]) self.ListTab:Show() print(self.ListTab:GetSize()) end function MissionList:GetPlayerData (profile) wipe(profile.missions) wipe(profile.available) local items = C_Garrison.GetAvailableMissions(GetPrimaryGarrisonFollowerType(LE_GARRISON_TYPE_7_0)); for i = 1, #items do if (not items[i].isBuilding and items[i].isZoneSupport) then else tinsert(profile.available, items[i]) end end local items = C_Garrison.GetLandingPageItems(LE_GARRISON_TYPE_7_0) for index, data in ipairs(items) do print(' -',data.name, '|cFF00FF00'.. data.timeLeft .. '|r', date("%A %I:%m %p", data.missionEndTime)) tinsert(profile.missions, data) end return true end do local ShipmentsInfo = {} local AddShipmentInfo = function(shipmentType, name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID, followerID) -- early login queries may return empty tables, causing the sorter to compare nil if not creationTime then return end --print(shipmentType, name, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString) tinsert(ShipmentsInfo, { shipmentType = shipmentType, name = name, icon = texture, shipmentCapacity = shipmentCapacity, shipmentsReady = shipmentsReady, shipmentsTotal = shipmentsTotal, creationTime = creationTime, duration = duration, timeleftString = timeleftString, itemName = itemName, itemIcon = itemIcon, itemQuality = itemQuality, itemID = itemID, followerID = followerID, }) end function ShipmentList:GetPlayerData (profile) if not profile then return false end local profileList = profile.shipments wipe(ShipmentsInfo) local garrisonType = LE_GARRISON_TYPE_7_0 local buildings = CG_GetBuildings(garrisonType); local shipmentIndex = 0 --print('Buildings:') for i = 1, #buildings do local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID = CG_GetLandingPageShipmentInfo(buildingID); AddShipmentInfo('Building', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, itemName, itemIcon, itemQuality, itemID) end --print('Follower:') local followerShipments = CG_GetFollowerShipments(garrisonType); for i = 1, #followerShipments do local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, _, _, _, _, followerID = CG_GetLandingPageShipmentInfoByContainerID(followerShipments[i]); AddShipmentInfo('Follower', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString, nil, nil, nil, nil, followerID) end --print('Loose:') local looseShipments = CG_GetLooseShipments(garrisonType) for i = 1, #looseShipments do local name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString = CG_GetLandingPageShipmentInfoByContainerID(looseShipments[i]); AddShipmentInfo('Misc', name, texture, shipmentCapacity, shipmentsReady, shipmentsTotal, creationTime, duration, timeleftString) end local talentTrees = CG_GetTalentTrees(garrisonType, select(3, UnitClass("player"))); -- this is a talent that has completed, but has not been seen in the talent UI yet. local completeTalentID = CG_GetCompleteTalent(garrisonType); --print('Talents:') if (talentTrees) then for treeIndex, tree in ipairs(talentTrees) do for talentIndex, talent in ipairs(tree) do local showTalent = false; if (talent.isBeingResearched) or (talent.id == completeTalentID) then AddShipmentInfo('Talent', talent.name, talent.icon, 1, (talent.isBeingResearched and 0 or 1), 1, talent.researchStartTime, talent.researchDuration, talent.timeleftString) end end end end wipe(profileList) for index, data in ipairs(ShipmentsInfo) do --DEFAULT_CHAT_FRAME:AddMessage(data.shipmentType ..' '.. tostring(data.name) ..' '.. tostring(data.creationTime) ..' '.. tostring(data.duration)) tinsert(profileList, data) end self.isStale = true return true end end MissionList.OnGetItem = function(data) if data.missionEndTime and (data.missionEndTime < GI_currentTime) then data.isComplete = true end end MissionList.FreeBlock = function(self, block) end MissionList.SortHandler = function (a,b) local result = false --if not a or not b then -- return true --else --if (a.isMine ~= b.isMine) then -- result = a.isMine --else --if (not b.missionEndTime) or (not a.missionEndTime) then -- print('missing article', b.missionEndTime, a.missionEndTime) --end if b.isComplete ~= a.isComplete then return a.isComplete elseif b.isMine ~= a.isMine then return a.isMine elseif b.missionEndTime then return ( b.missionEndTime > a.missionEndTime) else return ( b.offerEndTime > a.offerEndTime) end --end --end end function MissionList:OnShow() print('|cFF00FF88'..self:GetName()..':OnShow()|r') end function ShipmentList:OnLoad() C_Garrison.RequestLandingPageShipmentInfo(); end function ShipmentList:OnShow() print('|cFF00FF88'..self:GetName()..':OnShow()|r') C_Garrison.RequestLandingPageShipmentInfo() end -- Update shipment flags data local SetActualShipmentTime = function(self) if self.isComplete then print('|cFF00FF88isComplete '..self.name..'|r') return true end local timestamp = time() local timeLeft = self.creationTime + self.duration - timestamp local justFinished = false while (self.shipmentsReady < self.shipmentsTotal) and (timeLeft <= 0) do if not self.originalReady then self.originalReady = self.shipmentsReady self.originalCreationTime = self.creationTime end self.shipmentsReady = self.shipmentsReady + 1 self.creationTime = self.creationTime + self.duration timeLeft = timeLeft + self.duration print('|cFF00FF88udpating '..self.name..'|r', 'timeLeft:', timeLeft, 'shipments:', self.shipmentsReady, self.shipmentsTotal) end if (timeLeft <= 0) and (not self.isBeingResearched) then self.isComplete = true self.isStale = true end return timeLeft end ShipmentList.OnGetItem = function(data) print('OnGetItem()') if data.shipmentsTotal then SetActualShipmentTime(data) end end ShipmentList.SortHandler = function(a, b) if b.isComplete ~= a.isComplete then return a.isComplete and true or false elseif a.shipmentsReady or b.shipmentsReady then return (a.shipmentsReady or 0) > (b.shipmentsReady or 0) else return (a.creationTime) < (b.creationTime) end end function MissionEntry:OnComplete() print('flagging complete', self.name) self:Update() end function MissionEntry:OnUpdate(sinceLast) self.throttle = (self.throttle or .5) + sinceLast if self.throttle < .5 then return else self.throttle = self.throttle - .5 end if self.offerEndTime then local timeLeft = self.offerEndTime self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) self.TimeLeft:SetTextColor(1,1,1) elseif self.missionEndTime then if self.isComplete then return end local timeLeft = self.missionEndTime - time() if timeLeft < 0 then self:OnComplete() else self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) if timeLeft > 3600 then self.TimeLeft:SetTextColor(1,1,1) else self.TimeLeft:SetTextColor(1,1,0) end end if not self.isComplete then local progress = (time() - (self.missionEndTime - self.durationSeconds)) / self.durationSeconds local w = self.ProgressBG:GetWidth() if progress >= 1 then self.ProgressBar:SetWidth(w) else self.ProgressBar:SetWidth(progress * w) local r, g = 1, 0 if progress >= 0.5 then g = 1 r = 1-((progress-0.5)*2) else g = min(progress * 2, 1) r = 1 end self.ProgressBar:SetColorTexture(r,g,0,.4) self.ProgressBG:SetColorTexture(r,g,0,0.125) end self.ProgressBG:Show() self.ProgressBar:Show() else self.ProgressBG:Hide() self.ProgressBar:Hide() end else self.TimeLeft:SetText(self.missionEndTime) end end function MissionEntry:OnLoad() print('|cFFFF4400',self:GetName() or tostring(self), 'onload') self.Count = self.Overlay.Count self.Name = self.Overlay.Name self.TimeLeft = self.Overlay.TimeLeft self.Owner = self.Overlay.Owner self.Icon:SetDesaturated(false) self.Done:Hide() end function MissionEntry:Update() local r,g,b = 1, 1, 1 if self.isRare then r,g,b = 0.1, 0.4, 1 self.IconBorder:SetVertexColor(r, g, b, 1) end --self.missionData = data self.Name:SetText(self.name) if #self.rewards >= 1 then self.Icon:SetTexture(self.rewards[1].icon or GetItemIcon(self.rewards[1].itemID)) self.rewardInfo = self.rewards[1] else self.Icon:SetAtlas(self.typeAtlas, false) end if self.isComplete then self.TimeLeft:SetText('Complete!') self.Background:SetColorTexture(.25,.25,.25,1) else self.Background:SetColorTexture(0,0,0,0.5) end end function MissionEntry:OnEnter() if self.rewardInfo and self.rewardInfo.itemID then GameTooltip:SetOwner(self, 'ANCHOR_LEFT') GameTooltip:SetItemByID(self.rewardInfo.itemID) GameTooltip:Show() end end function MissionEntry:OnLeave() if GameTooltip:IsOwned(self) then GameTooltip:Hide() end end function ShipmentEntry:OnLoad() MissionEntry.OnLoad(self) end function ShipmentEntry:Update() print('|cFF0088FF'.. self.name..'|r:Update()') self.Icon:SetTexture(self.icon) self.Count:SetText(self.shipmentsReady) self.Done:SetShown(self.shipmentsReady and (self.shipmentsReady >= 1)) -- flag as complete local bgColor = CP_BACKGROUND_COLOR.inProgress if ( self.shipmentsReady >= self.shipmentsTotal ) and (not self.isBeingResearched) then self.Swipe:SetCooldownUNIX(0, 0); self.Done:Show(); bgColor = CP_BACKGROUND_COLOR.complete else if (self.shipmentsReady >= 1) and (self.shipmentsReady < self.shipmentsTotal) then bgColor = CP_BACKGROUND_COLOR.shipmentsReady end self.Swipe:SetCooldownUNIX(self.creationTime or 0 , self.duration or 0); end self.Background:SetColorTexture(unpack(bgColor)) SetActualShipmentTime(self) if self.originalReady then print('|cFF00FF88'..self.name..'|r', 'starting ready:', self.originalReady, 'starting time:', self.originalCreationTime) end end function ShipmentEntry:OnUpdate(sinceLast) self.throttle = (self.throttle or 1) + sinceLast if self.throttle >= 1 then self.throttle = self.throttle - 1 else return end if (self.shipmentsReady and self.shipmentsTotal) and (self.shipmentsReady < self.shipmentsTotal) then local timeLeft = SetActualShipmentTime(self) if self.isComplete then self.TimeLeft:SetText('Complete!') self.TimeLeft:SetTextColor(0,0.5,1) elseif self.shipmentsReady >= 1 then self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) self.TimeLeft:SetTextColor(0,1,0) else self.TimeLeft:SetText(GetTimeLeftString(timeLeft)) self.TimeLeft:SetTextColor(1,1,1) end elseif self.isBeingResearched then self.TimeLeft:SetText(GetTimeLeftString(self.researchStartTime + self.researchDuration - time())) self.TimeLeft:SetTextColor(1,1,0) else self.TimeLeft:SetText('Complete!') self.TimeLeft:SetTextColor(0,1,0) end if not self.isComplete then local progress = ((time() - self.creationTime) / self.duration) local w = self.ProgressBG:GetWidth() if progress >= 1 then self.ProgressBar:SetWidth(w) else self.ProgressBar:SetWidth(progress * w) end local r, g = 1, 0 if progress >= 0.5 then g = 1 r = 1-((progress-0.5)*2) else g = min(progress * 2, 1) r = 1 end self.ProgressBar:SetColorTexture(r, g, 0, .4) self.ProgressBG:SetColorTexture(r, g, 0, .125) self.ProgressBG:Show() self.ProgressBar:Show() else self.ProgressBG:Hide() self.ProgressBar:Hide() end end function ShipmentEntry:OnEnter() if ( self.shipmentsReady and self.shipmentsTotal ) then GameTooltip:SetOwner(self, 'ANCHOR_LEFT') GameTooltip:AddLine(self.Owner:GetText(), self.Owner:GetTextColor()) GameTooltip:AddLine(self.shipmentType) GameTooltip:AddLine(self.shipmentsReady .. ' of '.. self.shipmentsTotal) GameTooltip:Show() end end function ShipmentEntry:OnLeave() if GameTooltip:IsOwned(self) then GameTooltip:Hide() end end function ShipmentEntry:OnClick(button) if button == 'RightButton' then self.handler:FreeBlock(self) end end ClassPlanMissionHandler = Mixin(MissionList, SharedHandlers) ClassPlanShipmentHandler = Mixin(ShipmentList, SharedHandlers) ClassPlanMissionEntryMixin = Mixin(MissionEntry, SharedEntry) ClassPlanShipmentEntryMixin = Mixin(ShipmentEntry,SharedEntry) ClassPlanHeaderMixin = { OnClick = function(self) self:GetParent():SetList() self:GetParent().isStale = true ClassOrderPlan:Update() end }