ToC Updates
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
||||
## Interface: 100100
|
||||
## Interface: 100105
|
||||
## Title: Details! Damage Meter
|
||||
## Notes: Essential tool to impress that chick in your raid.
|
||||
## SavedVariables: _detalhes_global, __details_backup
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Interface: 100100
|
||||
## Interface: 100105
|
||||
## Title: Details!: Compare 2.0
|
||||
## Notes: Replace the Compare tab in the player breakdown window.
|
||||
## RequiredDeps: Details
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Interface: 100100
|
||||
## Interface: 100105
|
||||
## Title: Details!: Storage
|
||||
## Notes: Stores information for Details! Damage Meter
|
||||
## DefaultState: Enabled
|
||||
|
||||
@@ -0,0 +1,585 @@
|
||||
|
||||
|
||||
---@alias plugintype
|
||||
---| "SOLO"
|
||||
---| "RAID"
|
||||
---| "TOOLBAR"
|
||||
---| "STATUSBAR"
|
||||
|
||||
---@alias detailsevent
|
||||
---| "DETAILS_INSTANCE_OPEN"
|
||||
---| "DETAILS_INSTANCE_CLOSE"
|
||||
---| "DETAILS_INSTANCE_SIZECHANGED"
|
||||
---| "DETAILS_INSTANCE_STARTRESIZE"
|
||||
---| "DETAILS_INSTANCE_ENDRESIZE"
|
||||
---| "DETAILS_INSTANCE_STARTSTRETCH"
|
||||
---| "DETAILS_INSTANCE_ENDSTRETCH"
|
||||
---| "DETAILS_INSTANCE_CHANGESEGMENT"
|
||||
---| "DETAILS_INSTANCE_CHANGEATTRIBUTE"
|
||||
---| "DETAILS_INSTANCE_CHANGEMODE"
|
||||
---| "DETAILS_INSTANCE_NEWROW"
|
||||
---| "DETAILS_OPTIONS_MODIFIED"
|
||||
---| "DETAILS_DATA_RESET"
|
||||
---| "DETAILS_DATA_SEGMENTREMOVED"
|
||||
---| "COMBAT_ENCOUNTER_START"
|
||||
---| "COMBAT_ENCOUNTER_END"
|
||||
---| "COMBAT_PLAYER_ENTER"
|
||||
---| "COMBAT_PLAYER_LEAVE"
|
||||
---| "COMBAT_PLAYER_TIMESTARTED"
|
||||
---| "COMBAT_BOSS_WIPE"
|
||||
---| "COMBAT_BOSS_DEFEATED"
|
||||
---| "COMBAT_BOSS_FOUND"
|
||||
---| "COMBAT_INVALID"
|
||||
---| "COMBAT_PREPOTION_UPDATED"
|
||||
---| "COMBAT_CHARTTABLES_CREATING"
|
||||
---| "COMBAT_CHARTTABLES_CREATED"
|
||||
---| "COMBAT_ENCOUNTER_PHASE_CHANGED"
|
||||
---| "COMBAT_ARENA_START"
|
||||
---| "COMBAT_ARENA_END"
|
||||
---| "COMBAT_MYTHICDUNGEON_START"
|
||||
---| "COMBAT_MYTHICDUNGEON_END"
|
||||
---| "GROUP_ONENTER"
|
||||
---| "GROUP_ONLEAVE"
|
||||
---| "ZONE_TYPE_CHANGED"
|
||||
---| "REALM_CHANNEL_ENTER"
|
||||
---| "REALM_CHANNEL_LEAVE"
|
||||
---| "COMM_EVENT_RECEIVED"
|
||||
---| "COMM_EVENT_SENT"
|
||||
---| "UNIT_SPEC"
|
||||
---| "UNIT_TALENTS"
|
||||
---| "PLAYER_TARGET"
|
||||
---| "DETAILS_PROFILE_APPLYED"
|
||||
|
||||
---@alias containertype number this container type is the number used to identify the actorcontainer type when using combat:GetContainer(containertype), can be 1, 2, 3, or 4.
|
||||
|
||||
---@alias actorclass string this is the class of the actor, can be "WARRIOR", "PALADIN", "HUNTER", "ROGUE", "PRIEST", "DEATHKNIGHT", "SHAMAN", "MAGE", "WARLOCK", "MONK", "DRUID", "DEMONHUNTER"
|
||||
---@alias actorspec number this is the specID of the actor
|
||||
---@alias uniquecombatid number a unique ID to point to a single combat, each character has its ID counter, use with Details:DoesCombatWithUIDExists(); Details:GetCombatByUID(); retrive with combat:GetCombatUID()
|
||||
|
||||
---@class petinfo : table
|
||||
---@field key1 ownername
|
||||
---@field key2 guid
|
||||
---@field key3 unixtime
|
||||
---@field key4 boolean
|
||||
---@field key5 petname
|
||||
---@field key6 guid
|
||||
|
||||
---@class details
|
||||
---@field SpellTableMixin spelltablemixin
|
||||
---@field GetInstance fun(self: details) : instance
|
||||
---@field GetWindow fun(self: details) : instance this is an alias of GetInstance
|
||||
---@field GetCombat fun(self: details) : combat
|
||||
---@field GetSpellSchoolFormatedName fun(self: details, spellschool: spellschool) : string
|
||||
---@field CommaValue fun(self: details, number: number) : string
|
||||
---@field CreateEventListener fun(self: details) : table
|
||||
|
||||
---@class detailseventlistener : table
|
||||
---@field RegisterEvent fun(self: detailseventlistener, event: detailsevent, callback: function)
|
||||
---@field UnregisterEvent fun(self: detailseventlistener, event: detailsevent)
|
||||
|
||||
---@class deathtable : table
|
||||
---@field key1 any[] what happened to the player before death
|
||||
---@field key2 number unix time
|
||||
---@field key3 string player name
|
||||
---@field key4 string player class
|
||||
---@field key5 number max health
|
||||
---@field key6 string time of death as string
|
||||
---@field dead boolean just a boolean to indicate this is a death table
|
||||
---@field last_cooldown {key1: unixtime, key2: spellid}
|
||||
---@field dead_at combattime
|
||||
---@field spec specializationid
|
||||
|
||||
---@class customspellinfo : {name: string, isPassive: boolean, itemId: number, icon: string|number}
|
||||
---@class customiteminfo: {itemId: number, isPassive: boolean}
|
||||
---@class savedspelldata : {key1: number, key2: string, key3: number}
|
||||
---@class alternatepowertable : {last: number, total: number}
|
||||
|
||||
---@class combat : table
|
||||
---@field bIsClosed boolean if true the combat is closed (passed by the EndCombat() function)
|
||||
---@field __destroyedBy string
|
||||
---@field amountCasts {[string]: table<string, number>}
|
||||
---@field instance_type instancetype "raid" or "party" or "pvp" or "arena" or "none" or "scenario"
|
||||
---@field end_time number
|
||||
---@field start_time number
|
||||
---@field combat_counter number
|
||||
---@field is_trash boolean while in raid this is set to true if the combat isn't raid boss, in dungeon this is set to true if the combat isn't a boss or if the dungeon isn't a mythic+
|
||||
---@field raid_roster table<string, string> [unitName] = unitGUID
|
||||
---@field overall_added boolean is true when the combat got added into the overall combat
|
||||
---@field is_mythic_dungeon_trash boolean
|
||||
---@field is_mythic_dungeon_run_id number
|
||||
---@field is_mythic_dungeon_segment boolean
|
||||
---@field trinketProcs table<actorname, table<spellid, {cooldown: number, total: number}>>
|
||||
---@field alternate_power table<actorname, alternatepowertable>
|
||||
---@field totals {key1: table, key2: table, key3: table, key3: table}
|
||||
---@field totals_grupo {key1: table, key2: table, key3: table, key3: table}
|
||||
---@field __destroyed boolean
|
||||
---@field PhaseData table
|
||||
---@field is_boss table
|
||||
---@field is_world_trash_combat boolean when true this combat is a regular combat done in the world, not in a dungeon, raid, battleground, arena, ...
|
||||
---@field player_last_events table<string, table[]> record the latest events of each player, latter used to build the death log
|
||||
---@field GetCombatUID fun(combat: combat) : uniquecombatid
|
||||
---@field GetTimeData fun(combat: combat, dataName: string) : table
|
||||
---@field GetPhases fun(combat: combat) : table
|
||||
---@field GetCombatTime fun(combat) : number
|
||||
---@field GetDeaths fun(combat) : table --get the table which contains the deaths of the combat
|
||||
---@field GetStartTime fun(combat: combat) : number
|
||||
---@field SetStartTime fun(combat: combat, time: number)
|
||||
---@field GetEndTime fun(combat: combat) : number
|
||||
---@field GetDifficulty fun(combat: combat) : number return the dungeon or raid difficulty for boss fights
|
||||
---@field GetEncounterCleuID fun(combat: combat) : number return the encounterId for boss fights, this number is gotten from the ENCOUNTER_START event
|
||||
---@field GetBossInfo fun(combat: combat) : table a table containing many informations about the boss fight
|
||||
---@field SetEndTime fun(combat: combat, time: number)
|
||||
---@field CopyDeathsFrom fun(combat1: combat, combat2: combat, bMythicPlus: boolean) copy the deaths from combat2 to combat1, use true on bMythicPlus if the combat is from a mythic plus run
|
||||
---@field GetContainer fun(combat: combat, containerType: containertype) : actorcontainer get an actorcontainer, containerType can be 1 for damage, 2 heal, 3 resources, 4 utility
|
||||
---@field GetSpellCastAmount fun(combat: combat, actorName: string, spellName: string) : number get the amount of times a spell was casted
|
||||
---@field RemoveActorFromSpellCastTable fun(combat: combat, actorName: string)
|
||||
---@field GetSpellCastTable fun(combat: combat, actorName: string|nil) : table
|
||||
---@field GetSpellUptime fun(combat: combat, actorName: string, spellId: number, auraType: string|nil) : number get the uptime of a buff or debuff
|
||||
---@field GetActor fun(combat: combat, containerType: number, playerName: string) : actor
|
||||
---@field CreateAlternatePowerTable fun(combat: combat, actorName: string) : alternatepowertable
|
||||
---@field GetCombatNumber fun(combat: combat) : number get a unique number representing the combatId, each combat has a unique number
|
||||
---@field SetDate fun(combat: combat, startDate: string, endDate: string) set the start and end date of the combat, format: "H:M:S"
|
||||
---@field GetDate fun(combat: combat) : string, string get the start and end date of the combat, format: "H:M:S"
|
||||
---@field GetRoster fun(combat: combat) : table<string, string> get the roster of the combat, the table contains the names of the players in the combat
|
||||
---@field InstanceType fun(combat: combat) : string get the instance type of the combat, can be "raid" or "party" or "pvp" or "arena" or "none"
|
||||
---@field IsTrash fun(combat: combat) : boolean is true if the combat is a trash combat
|
||||
|
||||
---@class actorcontainer : table contains two tables _ActorTable and _NameIndexTable, the _ActorTable contains the actors, the _NameIndexTable contains the index of the actors in the _ActorTable, making quick to reorder them without causing overhead
|
||||
---@field need_refresh boolean when true the container is dirty and needs to be refreshed
|
||||
---@field _ActorTable table array of actors
|
||||
---@field _NameIndexTable table<string, number> [actorName] = actorIndex in the _ActorTable, actorcontainer:Remap() refreshes the _NameIndexTable
|
||||
---@field GetActor fun(container: actorcontainer, actorName: string) get an actor by its name
|
||||
---@field GetSpellSource fun(container: actorcontainer, spellId: number) get the first actor found which casted the spell
|
||||
---@field GetAmount fun(container: actorcontainer, actorName: string, key: string) get the amount of actor[key]
|
||||
---@field GetTotal fun(container: actorcontainer, key: string) get the total amount of actor[key] for all actors
|
||||
---@field GetTotalOnRaid fun(container: actorcontainer, key: string, combat: combat) get the total amount of actor[key] only for the actors which are in the raid
|
||||
---@field GetActorTable fun(container: actorcontainer) get the table<actorIndex, actorObject> which contains the actors
|
||||
---@field ListActors fun(container: actorcontainer) usage: for index, actorObject in container:ListActors() do
|
||||
---@field RemoveActor fun(container: actorcontainer, actor: actor) remove an actor from the container
|
||||
---@field GetType fun(container: actorcontainer) : number get the container type, 1 for damage, 2 for heal, 3 for energy, 4 for utility
|
||||
---@field Remap fun(container: actorcontainer) refreshes the _NameIndexTable part of the container
|
||||
---@field Cleanup fun(container: actorcontainer) remove all destroyed actors from the container
|
||||
|
||||
---@class spellcontainer : table
|
||||
---@field _ActorTable table store [spellId] = spelltable
|
||||
---@field GetSpell fun(container: spellcontainer, spellId: number) get a spell by its id, does not create if not found
|
||||
---@field ListActors fun(container: spellcontainer) : any, any usage: for spellId, spelltable in container:ListActors() do
|
||||
---@field ListSpells fun(container: spellcontainer) : any, any usage: for spellId, spelltable in container:ListActors() do
|
||||
---@field HasTwoOrMoreSpells fun(container: spellcontainer) : boolean return true if the container has two or more spells
|
||||
---@field GetOrCreateSpell fun(self: spellcontainer, spellId: number, bCanCreateSpellIfMissing: boolean|nil, cleuToken: string|nil) : spelltable
|
||||
|
||||
---@class friendlyfiretable : table
|
||||
---@field total number total amount of friendly fire caused by the actor
|
||||
---@field spells table<spellid, number> spellId = total
|
||||
|
||||
---@class spelltable : table
|
||||
---@field uptime number
|
||||
---@field total number
|
||||
---@field spellschool number
|
||||
---@field counter number amount of hits
|
||||
---@field c_amt number critical hits by a damage or heal spell
|
||||
---@field c_min number min damage or healing done by critical hits of the spell
|
||||
---@field c_max number min damage or healing done by critical hits of the spell
|
||||
---@field c_total number total damage or heal made by critical hits of the spell
|
||||
---@field n_amt number normal hits by a damage or heal spell
|
||||
---@field n_min number min damage or healing done by normal hits of the spell
|
||||
---@field n_max number min damage or healing done by normal hits of the spell
|
||||
---@field n_total number total damage or heal made by normal hits of the spell
|
||||
---@field targets table<string, number> store the [target name] = total value
|
||||
---@field targets_overheal table<string, number>
|
||||
---@field targets_absorbs table<string, number>
|
||||
---@field extra table store extra data
|
||||
---@field id number --spellid
|
||||
---@field is_shield boolean --true if the spell is a shield
|
||||
---@field successful_casted number successful casted times (only for enemies)
|
||||
---@field g_amt number glacing hits
|
||||
---@field g_dmg number
|
||||
---@field r_amt number --resisted
|
||||
---@field r_dmg number
|
||||
---@field b_amt number --blocked
|
||||
---@field b_dmg number
|
||||
---@field a_amt number --absorved
|
||||
---@field a_dmg number
|
||||
---@field e_total number
|
||||
---@field e_amt number
|
||||
---@field e_lvl table<number, number>
|
||||
---@field e_dmg table<number, number>
|
||||
---@field e_heal table<number, number>
|
||||
---@field isReflection boolean
|
||||
---@field totalabsorb number healing absorbed
|
||||
---@field absorbed number damage absorbed by shield | healing absorbed by buff or debuff
|
||||
---@field overheal number
|
||||
---@field totaldenied number
|
||||
|
||||
---@class targettable : {[string]: number}
|
||||
|
||||
---@class actor : table
|
||||
---@field owner actor
|
||||
---@field tipo number the container type
|
||||
---@field ownerName string name of the owner of the pet, a pet without an owner is considered an orphan and be suitable for garbage collection
|
||||
---@field pets table<number, string>
|
||||
---@field arena_enemy boolean if true the actor is an enemy in an arena match
|
||||
---@field dps_started boolean if true the actor started to do damage or healing
|
||||
---@field start_time unixtime when this actor started to be tracked
|
||||
---@field end_time number when this actor stopped to be tracked, end_time - start_time is the activity time of the actor
|
||||
---@field displayName string actor name shown in the regular window
|
||||
---@field pvp boolean indicates if the actor is a part of a pvp match
|
||||
---@field flag_original number original actor flag from what was received in the combat log
|
||||
---@field debuff_uptime_spells table
|
||||
---@field buff_uptime_spells table
|
||||
---@field spells spellcontainer
|
||||
---@field aID number|string actorID is a realm-playername or npcID
|
||||
---@field spellicon number|string
|
||||
---@field cooldowns_defensive_spells table
|
||||
---@field nome string name of the actor
|
||||
---@field isTank boolean if true the player had the spec TANK during the combat
|
||||
---@field serial string
|
||||
---@field spec number
|
||||
---@field grupo boolean
|
||||
---@field fight_component boolean
|
||||
---@field boss_fight_component boolean
|
||||
---@field pvp_component boolean
|
||||
---@field boss boolean
|
||||
---@field last_event unixtime
|
||||
---@field total_without_pet number
|
||||
---@field total number
|
||||
---@field targets targettable
|
||||
---@field GetSpell fun(actor: actor, spellId: number) : spelltable
|
||||
---@field BuildSpellTargetFromBreakdownSpellData fun(actor: actor, bkSpellData: spelltableadv) : table
|
||||
---@field BuildSpellTargetFromSpellTable fun(actor: actor, spellTable: spelltable) : table
|
||||
---@field raid_targets table<number, number>
|
||||
---@field IsPlayer fun(actor: actor) : boolean return true if the actor is controlled by a player
|
||||
---@field IsPetOrGuardian fun(actor: actor) : boolean return true if the actor is a pet or guardian
|
||||
---@field IsGroupPlayer fun(actor: actor) : boolean return true if the actor is a player in the group (or was in the group during the combat)
|
||||
---@field GetSpellContainer fun(actor: actor, containerType: "debuff"|"buff"|"spell"|"cooldowns"|"dispel") : spellcontainer
|
||||
---@field Class fun(actor: actor) : string get the ingame class of the actor
|
||||
---@field Spec fun(actor: actor) : string get the ingame spec of the actor
|
||||
---@field Name fun(actor: actor) : string get the name of the actor
|
||||
---@field Tempo fun(actor: actor) : number get the activity or effective time of the actor
|
||||
---@field GetPets fun(actor: actor) : table<number, string> get a table with all pet names that belong to the player
|
||||
---@field GetSpellList fun(actor: actor) : table<number, spelltable>
|
||||
---@field GetSpellContainerNames fun(container: actorcontainer) : string[] get the table which contains the names of the spell containers
|
||||
|
||||
---@class actordamage : actor
|
||||
---@field friendlyfire_total number
|
||||
---@field friendlyfire table<actorname, friendlyfiretable>
|
||||
---@field damage_taken number amount of damage the actor took during the segment
|
||||
---@field damage_from table<string, boolean> store the name of the actors which damaged the actor, format: [actorName] = true
|
||||
---@field totalabsorbed number amount of damage dealt by the actor by got absorbed by the target, this is a "ABSORB" type of miss but still counts as damage done
|
||||
|
||||
---@class actorheal : actor
|
||||
---@field healing_taken number amount of healing the actor took during the segment
|
||||
---@field totalover number amount of healing that was overhealed
|
||||
---@field totalabsorb number amount of healing that was absorbed
|
||||
---@field heal_enemy_amt number amount of healing done to enemies this included enemy to enemy heals
|
||||
---@field totaldenied number amount of healing that was denied by the target - from cleu event SPELL_HEAL_ABSORBED
|
||||
---@field totalover_without_pet number amount of healing that was overhealed without the pet healing
|
||||
---@field healing_from table<string, boolean> store the name of the actors which healed the actor, format: [actorName] = true
|
||||
---@field heal_enemy table<number, number> store the amount of healing done by each spell that landed into an enemy, format: [spellId] = healing done
|
||||
---@field targets_overheal table<string, number> [targetName] = overheal
|
||||
---@field targets_absorbs table<string, number> [targetName] = absorbs
|
||||
|
||||
---@class actorresource : actor
|
||||
---@field powertype number power type of the actor
|
||||
---@field alternatepower number alternate power of the actor
|
||||
|
||||
---@class actorutility : actor
|
||||
---@field cc_break number amount of times the actor broke a cc
|
||||
---@field interrupt number amount of times the actor interrupted a spell
|
||||
---@field ress number amount of times the actor ressed a player
|
||||
---@field dead number amount of times the actor died
|
||||
---@field cooldowns_defensive number amount of times the actor used a defensive cooldown
|
||||
---@field buff_uptime number amount of time the actor had a buff
|
||||
---@field debuff_uptime number amount of time the actor had a debuff
|
||||
---@field cc_done number amount of times the actor applyed a crowdcontrol on a target
|
||||
---@field cc_done_targets table<string, number> [targetName] = amount of times the actor cc'd the target
|
||||
---@field cc_done_spells spellcontainer
|
||||
---@field dispell number amount of times the actor dispelled a buff or debuff
|
||||
---@field dispell_spells spellcontainer
|
||||
---@field dispell_targets table<string, number> [targetName] = amount
|
||||
---@field dispell_oque table<number, number> [spellId] = amount, amount of times the actor dispelled the spellId
|
||||
|
||||
--interrupt_targets interrupt_spells interrompeu_oque
|
||||
--cc_break_targets cc_break_spells cc_break_oque
|
||||
|
||||
|
||||
---@class segmentid : number
|
||||
---@class instanceid : number
|
||||
---@class attributeid : number
|
||||
---@class modeid : number
|
||||
|
||||
---@class instance : table
|
||||
---@field segmento segmentid
|
||||
---@field showing combat
|
||||
---@field meu_id instanceid
|
||||
---@field is_interacting boolean
|
||||
---@field modo modeid
|
||||
---@field atributo attributeid
|
||||
---@field sub_atributo attributeid
|
||||
---@field ativa boolean
|
||||
---@field freezed boolean
|
||||
---@field sub_atributo_last table
|
||||
---@field row_info table
|
||||
---@field GetSize fun(instance: instance) : width, height
|
||||
---@field GetInstanceGroup fun() : table
|
||||
---@field GetCombat fun(instance: instance)
|
||||
---@field ChangeIcon fun(instance: instance)
|
||||
---@field CheckIntegrity fun(instance: instance)
|
||||
---@field SetMode fun(instance: instance, mode: modeid)
|
||||
---@field GetMode fun(instance: instance) : modeid
|
||||
---@field IsInteracting fun(instance: instance) : boolean
|
||||
---@field IsLowerInstance fun(instance: instance) : boolean
|
||||
---@field IsEnabled fun(instance: instance) : boolean
|
||||
---@field GetId fun(instance: instance) : instanceid
|
||||
---@field GetSegmentId fun(instance: instance) : segmentid
|
||||
---@field RefreshCombat fun(instance: instance)
|
||||
---@field Freeze fun(instance: instance)
|
||||
---@field UnFreeze fun(instance: instance)
|
||||
---@field SetSegment fun(instance: instance, segment: segmentid, force: boolean|nil)
|
||||
---@field GetDisplay fun(instance: instance) : attributeid, attributeid
|
||||
---@field ResetWindow fun(instance: instance, resetType: number|nil, segmentId: segmentid|nil)
|
||||
---@field RefreshData fun(instance: instance, force: boolean|nil)
|
||||
---@field RefreshWindow fun(instance: instance, force: boolean|nil)
|
||||
|
||||
---@class trinketdata : table
|
||||
---@field itemName string
|
||||
---@field spellName string
|
||||
---@field lastActivation number
|
||||
---@field lastPlayerName string
|
||||
---@field totalCooldownTime number
|
||||
---@field activations number
|
||||
---@field lastCombatId number
|
||||
---@field minTime number
|
||||
---@field maxTime number
|
||||
---@field averageTime number
|
||||
|
||||
---@class tabframe : frame this is the tab frame object for the breakdown window
|
||||
|
||||
---@class breakdownwindow : frame
|
||||
---@field shownPluginObject table
|
||||
---@field BreakdownSideMenuFrame frame frame attached to the left or right side of the breakdown window
|
||||
---@field BreakdownPluginSelectionFrame frame frame which has buttons to select a plugin to show in the breakdown window
|
||||
---@field BreakdownTabsFrame frame where the tab buttons are located (parent frame)
|
||||
---@field RegisteredPluginButtons button[] table which contains plugins buttons that are registered to the breakdown window
|
||||
---@field RegisterPluginButton fun(button: button) register a plugin button to the breakdown window
|
||||
---@field GetShownPluginObject fun() : table get the plugin object that is currently shown in the breakdown window
|
||||
|
||||
|
||||
---@class breakdownscrolldata : table
|
||||
---@field totalValue number total done by the actor
|
||||
---@field combatTime number
|
||||
---@field [spelltableadv] spelltableadv indexed part of the table
|
||||
|
||||
---@class headercolumndatasaved : {enabled: boolean, width: number, align: string}
|
||||
|
||||
---@class breakdownexpandbutton : button
|
||||
---@field texture texture
|
||||
|
||||
---@class breakdownspellscrollframe : df_scrollboxmixin, scrollframe
|
||||
---@field Header df_headerframe
|
||||
---@field RefreshMe fun(scrollFrame: breakdownspellscrollframe, data: table|nil)
|
||||
---@field SortKey string
|
||||
---@field SortOrder string
|
||||
|
||||
---@class breakdowntargetscrollframe : df_scrollboxmixin, scrollframe
|
||||
---@field Header df_headerframe
|
||||
---@field RefreshMe fun(scrollFrame: breakdowntargetscrollframe, data: table|nil)
|
||||
|
||||
---@class breakdowngenericscrollframe : df_scrollboxmixin, scrollframe
|
||||
---@field Header df_headerframe
|
||||
---@field RefreshMe fun(scrollFrame: breakdowngenericscrollframe, data: table|nil)
|
||||
|
||||
---@class breakdownphasescrollframe : df_scrollboxmixin, scrollframe
|
||||
---@field Header df_headerframe
|
||||
---@field RefreshMe fun(scrollFrame: breakdownphasescrollframe, data: table|nil)
|
||||
|
||||
---@class breakdownphasebar : button, df_headerfunctions
|
||||
---@field index number
|
||||
---@field Icon texture
|
||||
---@field InLineTexts fontstring[]
|
||||
---@field statusBar breakdownspellbarstatusbar
|
||||
|
||||
---@class breakdowngenericbar : button, df_headerfunctions
|
||||
---@field index number
|
||||
---@field rank number
|
||||
---@field name string
|
||||
---@field percent number
|
||||
---@field amount number
|
||||
---@field total number
|
||||
---@field actorName string
|
||||
---@field Icon texture
|
||||
---@field InLineTexts fontstring[]
|
||||
---@field statusBar breakdownspellbarstatusbar
|
||||
---@field bIsFromLeftScroll boolean
|
||||
---@field bIsFromRightScroll boolean
|
||||
|
||||
---@class breakdowntargetbar : button, df_headerfunctions
|
||||
---@field index number
|
||||
---@field rank number
|
||||
---@field name string
|
||||
---@field percent number
|
||||
---@field amount number
|
||||
---@field total number
|
||||
---@field actorName string
|
||||
---@field bkTargetData breakdowntargettable
|
||||
---@field Icon texture
|
||||
---@field InLineTexts fontstring[]
|
||||
---@field statusBar breakdownspellbarstatusbar
|
||||
|
||||
---@class breakdownspellbar : button, df_headerfunctions
|
||||
---@field index number
|
||||
---@field rank number
|
||||
---@field spellId number
|
||||
---@field name string
|
||||
---@field combatTime number
|
||||
---@field perSecond number
|
||||
---@field percent number
|
||||
---@field amountCasts number
|
||||
---@field average number
|
||||
---@field castAverage number
|
||||
---@field onMouseUpTime number GetTime() of when the spellbar got OnMouseUp event
|
||||
---@field cursorPosX number mouse position when the spellbar got OnMouseDown event
|
||||
---@field cursorPosY number mouse position when the spellbar got OnMouseDown event
|
||||
---@field spellTable spelltable
|
||||
---@field bkSpellData spelltableadv
|
||||
---@field statusBar breakdownspellbarstatusbar
|
||||
---@field expandButton breakdownexpandbutton
|
||||
---@field spellIconFrame frame
|
||||
---@field spellIcon texture
|
||||
---@field targetsSquareFrame breakdowntargetframe
|
||||
---@field targetsSquareTexture texture
|
||||
---@field overlayTexture texture
|
||||
---@field bIsExpandedSpell boolean
|
||||
---@field ExpandedChildren breakdownspellbar[] store the spellbars which are expanded from this spellbar (spellbars shown when the expand button is pressed)
|
||||
---@field InLineTexts fontstring[]
|
||||
|
||||
---@class breakdownspellbarstatusbar : statusbar
|
||||
---@field backgroundTexture texture
|
||||
---@field overlayTexture texture
|
||||
---@field highlightTexture texture
|
||||
|
||||
---spelltableadv is similar to spelltable but allow custom members, methods and any modification isn't save to saved variables
|
||||
---@class spelltableadv : spelltable, spelltablemixin
|
||||
---@field expanded boolean if is true the show the nested spells
|
||||
---@field spellTables spelltable[]
|
||||
---@field nestedData bknesteddata[]
|
||||
---@field bCanExpand boolean
|
||||
---@field expandedIndex number
|
||||
---@field bIsExpanded boolean
|
||||
---@field statusBarValue number
|
||||
---@field npcId npcid
|
||||
---@field actorName string --when showing an actor header, this is the actor name
|
||||
---@field bIsActorHeader boolean if this is true, the spellbar is an actor header, which is a bar with the actor name with the actor spells nested
|
||||
---@field actorIcon textureid|texturepath
|
||||
|
||||
---@class bknesteddata : {spellId: number, spellTable: spelltable, actorName: string, value: number, bIsActorHeader: boolean} fills .nestedData table in spelltableadv, used to store the nested spells data, 'value' is set when the breakdown sort the values by the selected header
|
||||
|
||||
---@class breakdowntargetframe : frame
|
||||
---@field spellId number
|
||||
---@field bkSpellData spelltableadv
|
||||
---@field spellTable spelltable
|
||||
---@field texture texture
|
||||
---@field bIsMainLine boolean
|
||||
|
||||
---@class breakdowntargettablelist : breakdowntargettable[]
|
||||
---@field totalValue number
|
||||
---@field totalValueOverheal number
|
||||
---@field combatTime number
|
||||
|
||||
---@class breakdowntargettable : table
|
||||
---@field name string
|
||||
---@field total number
|
||||
---@field overheal number|nil
|
||||
---@field absorbed number|nil
|
||||
---@field statusBarValue number
|
||||
|
||||
---@class breakdownspelldatalist : spelltableadv[]
|
||||
---@field totalValue number
|
||||
---@field combatTime number
|
||||
|
||||
---@class breakdownspellstab : tabframe
|
||||
---@field SpellScrollFrame breakdownspellscrollframe
|
||||
---@field SpellBlockFrame breakdownspellblockframe
|
||||
|
||||
---@class breakdownspellblockframe : frame container for the spellblocks in the breakdown window
|
||||
---@field SpellBlocks breakdownspellblock[] array of spellblocks
|
||||
---@field blocksInUse number number of blocks currently in use
|
||||
---@field UpdateBlocks fun(self: breakdownspellblockframe) update the blocks
|
||||
---@field ClearBlocks fun(self: breakdownspellblockframe) clear all blocks
|
||||
---@field GetBlock fun(self: breakdownspellblockframe, index: number) : breakdownspellblock return the block at the index
|
||||
---@field GetBlocksInUse fun(self: breakdownspellblockframe) : number return the number of blocks currently in use
|
||||
---@field GetBlocksAmount fun(self: breakdownspellblockframe) : number return the total blocks created
|
||||
---@field ShowEmptyBlock fun(self: breakdownspellblockframe, index: number) show the empty block
|
||||
|
||||
---@class breakdownspellblock : statusbar breakdownspellblock object which is created inside the breakdownspellblockframe
|
||||
---@field Lines breakdownspellblockline[]
|
||||
---@field reportButton button
|
||||
---@field overlay texture
|
||||
---@field statusBarTexture texture
|
||||
---@field sparkTexture texture
|
||||
---@field gradientTexture texture
|
||||
---@field backgroundTexture texture
|
||||
---@field GetLine fun(self: breakdownspellblock, index: number) : breakdownspellblockline
|
||||
---@field GetLines fun(self: breakdownspellblock) : breakdownspellblockline, breakdownspellblockline, breakdownspellblockline
|
||||
---@field SetColor fun(self: breakdownspellblock, r: any, g: number|nil, b: number|nil, a: number|nil)
|
||||
|
||||
---@class breakdownspellblockline : frame a line inside a breakdownspellblock, there's 3 of them in each breakdownspellblock
|
||||
---@field leftText fontstring
|
||||
---@field centerText fontstring
|
||||
---@field rightText fontstring
|
||||
|
||||
---@class breakdownspelltab
|
||||
---@field selectedSpellBar breakdownspellbar
|
||||
---@field TabFrame breakdownspellstab
|
||||
---@field mainAttribute number
|
||||
---@field subAttribute number
|
||||
---@field TargetScrollFrame breakdowntargetscrollframe
|
||||
---@field PhaseScrollFrame breakdownphasescrollframe
|
||||
---@field GenericScrollFrameLeft breakdowngenericscrollframe
|
||||
---@field GenericScrollFrameRight breakdowngenericscrollframe
|
||||
---@field SpellContainerFrame df_framecontainer
|
||||
---@field BlocksContainerFrame df_framecontainer
|
||||
---@field TargetsContainerFrame df_framecontainer
|
||||
---@field PhaseContainerFrame df_framecontainer
|
||||
---@field GenericContainerFrameLeft df_framecontainer
|
||||
---@field GenericContainerFrameRight df_framecontainer
|
||||
---@field GetActor fun() : actor
|
||||
---@field GetCombat fun() : combat
|
||||
---@field GetInstance fun() : instance
|
||||
---@field GetSpellScrollFrame fun() : breakdownspellscrollframe
|
||||
---@field GetSpellBlockFrame fun() : breakdownspellblockframe
|
||||
---@field GetTargetScrollFrame fun() : breakdowntargetscrollframe
|
||||
---@field GetSpellScrollContainer fun() : df_framecontainer
|
||||
---@field GetSpellBlockContainer fun() : df_framecontainer
|
||||
---@field GetTargetScrollContainer fun() : df_framecontainer
|
||||
---@field OnProfileChange fun()
|
||||
---@field UpdateHeadersSettings fun(containerType: string)
|
||||
---@field BuildHeaderTable fun(containerType: string) : {name: string, width: number, text: string, align: string}[]
|
||||
---@field SelectSpellBar fun(spellBar: breakdownspellbar)
|
||||
---@field UnSelectSpellBar fun()
|
||||
---@field GetSelectedSpellBar fun() : breakdownspellbar
|
||||
---@field HasSelectedSpellBar fun() : boolean
|
||||
---@field OnShownTab fun()
|
||||
---@field OnCreateTabCallback fun(tabButton: button, tabFrame: frame)
|
||||
---@field CreateSpellBlock fun(spellBlockContainer: breakdownspellblockframe, index: number) : breakdownspellblock
|
||||
---@field CreateSpellBlockContainer fun(tabFrame: tabframe) : breakdownspellblockframe
|
||||
---@field UpdateShownSpellBlock fun()
|
||||
---@field CreateTargetContainer fun(tabFrame: tabframe) : breakdowntargetscrollframe
|
||||
---@field CreateGenericContainers fun(tabFrame: tabframe) : breakdowngenericscrollframe, breakdowngenericscrollframe
|
||||
---@field CreateSpellScrollContainer fun(tabFrame: tabframe) : breakdownspellscrollframe
|
||||
---@field CreateTargetBar fun(self: breakdowntargetscrollframe, index: number) : breakdowntargetbar
|
||||
---@field CreateSpellBar fun(self: breakdownspellscrollframe, index: number) : breakdownspellbar
|
||||
|
||||
---@class timemachine : table
|
||||
---@field Ticker fun() runs each second and check if actors are performing damage and healing actions, if the actor isn't, stop the activity time of that actor
|
||||
---@field Start fun() start the time machine, called once from the start.lua
|
||||
---@field Cleanup fun() check for actors with __destroyed flag and remove them from the time machine
|
||||
---@field Restart fun() reset all data inside the time machine
|
||||
---@field AddActor fun(actor: actor) add the actor to the time machine
|
||||
---@field RemoveActor fun(actor: actor) remove the actor from the time machine
|
||||
---@field StopTime fun(actor: actor) stop the time of the actor
|
||||
---@field SetOrGetPauseState fun(actor: actor, bPause: boolean|nil) : boolean|nil set or get the pause state of the actor, if bPause is nil, then it will return the current pause state
|
||||
|
||||
---@class details222 : table
|
||||
---@field TimeMachine timemachine
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
enUS.lua
|
||||
ptBR.lua
|
||||
frames.lua
|
||||
|
||||
Details_EncounterDetails.lua
|
||||
Details_EncounterDetails.lua
|
||||
frames_chart.lua
|
||||
frames_emote.lua
|
||||
frames_phases.lua
|
||||
frames_summary.lua
|
||||
frames.lua
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
## Interface: 100100
|
||||
## Interface: 100105
|
||||
## Title: Details!: Encounter Breakdown (plugin)
|
||||
## Notes: Show detailed information about a boss encounter. Also provide damage per phase, graphic charts, easy weakauras creation.
|
||||
## RequiredDeps: Details
|
||||
@@ -10,6 +10,12 @@
|
||||
|
||||
enUS.lua
|
||||
ptBR.lua
|
||||
frames.lua
|
||||
|
||||
Details_EncounterDetails.lua
|
||||
frames_chart.lua
|
||||
frames_emote.lua
|
||||
frames_phases.lua
|
||||
frames_summary.lua
|
||||
frames.lua
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
enUS.lua
|
||||
ptBR.lua
|
||||
frames.lua
|
||||
|
||||
Details_EncounterDetails.lua
|
||||
Details_EncounterDetails.lua
|
||||
frames_chart.lua
|
||||
frames_emote.lua
|
||||
frames_phases.lua
|
||||
frames_summary.lua
|
||||
frames.lua
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
---@class ed_barline : button
|
||||
---@field statusBar statusbar
|
||||
---@field lineText1 fontstring
|
||||
---@field lineText4 fontstring
|
||||
---@field statusBarTexture texture
|
||||
---@field Icon texture
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
background.blp
|
||||
border_1.blp
|
||||
border_2.blp
|
||||
border_3.blp
|
||||
cooltip_background.blp
|
||||
feedback_sites.blp
|
||||
icons.blp
|
||||
mail.blp
|
||||
*.json
|
||||
CHANGES.txt
|
||||
@@ -0,0 +1,66 @@
|
||||
DFPixelUtil = {};
|
||||
|
||||
function DFPixelUtil.GetPixelToUIUnitFactor()
|
||||
local physicalWidth, physicalHeight = GetPhysicalScreenSize();
|
||||
return 768.0 / physicalHeight;
|
||||
end
|
||||
|
||||
function DFPixelUtil.GetNearestPixelSize(uiUnitSize, layoutScale, minPixels)
|
||||
if uiUnitSize == 0 and (not minPixels or minPixels == 0) then
|
||||
return 0;
|
||||
end
|
||||
|
||||
local uiUnitFactor = DFPixelUtil.GetPixelToUIUnitFactor();
|
||||
local numPixels = Round((uiUnitSize * layoutScale) / uiUnitFactor);
|
||||
local rawNumPixels = numPixels;
|
||||
if minPixels then
|
||||
if uiUnitSize < 0.0 then
|
||||
if numPixels > -minPixels then
|
||||
numPixels = -minPixels;
|
||||
end
|
||||
else
|
||||
if numPixels < minPixels then
|
||||
numPixels = minPixels;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return numPixels * uiUnitFactor / layoutScale;
|
||||
end
|
||||
|
||||
function DFPixelUtil.SetWidth(region, width, minPixels)
|
||||
region:SetWidth(DFPixelUtil.GetNearestPixelSize(width, region:GetEffectiveScale(), minPixels));
|
||||
end
|
||||
|
||||
function DFPixelUtil.SetHeight(region, height, minPixels)
|
||||
region:SetHeight(DFPixelUtil.GetNearestPixelSize(height, region:GetEffectiveScale(), minPixels));
|
||||
end
|
||||
|
||||
function DFPixelUtil.SetSize(region, width, height, minWidthPixels, minHeightPixels)
|
||||
DFPixelUtil.SetWidth(region, width, minWidthPixels);
|
||||
DFPixelUtil.SetHeight(region, height, minHeightPixels);
|
||||
end
|
||||
|
||||
function DFPixelUtil.SetPoint(region, point, relativeTo, relativePoint, offsetX, offsetY, minOffsetXPixels, minOffsetYPixels)
|
||||
region:SetPoint(point, relativeTo, relativePoint,
|
||||
DFPixelUtil.GetNearestPixelSize(offsetX, region:GetEffectiveScale(), minOffsetXPixels),
|
||||
DFPixelUtil.GetNearestPixelSize(offsetY, region:GetEffectiveScale(), minOffsetYPixels)
|
||||
);
|
||||
end
|
||||
|
||||
function DFPixelUtil.SetStatusBarValue(statusBar, value)
|
||||
local width = statusBar:GetWidth();
|
||||
if width and width > 0.0 then
|
||||
local min, max = statusBar:GetMinMaxValues();
|
||||
local percent = ClampedPercentageBetween(value, min, max);
|
||||
if percent == 0.0 or percent == 1.0 then
|
||||
statusBar:SetValue(value);
|
||||
else
|
||||
local numPixels = DFPixelUtil.GetNearestPixelSize(statusBar:GetWidth() * percent, statusBar:GetEffectiveScale());
|
||||
local roundedValue = Lerp(min, max, numPixels / width);
|
||||
statusBar:SetValue(roundedValue);
|
||||
end
|
||||
else
|
||||
statusBar:SetValue(value);
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
## Interface: 100100
|
||||
## Title: Lib: LibDFramework-1.0
|
||||
## Notes: Base Framework for many Addons
|
||||
|
||||
load.xml
|
||||
@@ -0,0 +1,132 @@
|
||||
|
||||
local DF = _G ["DetailsFramework"]
|
||||
local _
|
||||
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
--runs when the addon received addon_loaded
|
||||
local addonPreLoad = function(addonFrame, event, ...)
|
||||
--check if the saved variables table is created, if not create one
|
||||
_G[addonFrame.__savedVarsName] = _G[addonFrame.__savedVarsName] or {}
|
||||
|
||||
if (addonFrame.__savedVarsDefaultTemplate) then
|
||||
--load saved vars for this character
|
||||
DF.SavedVars.LoadSavedVarsForPlayer(addonFrame)
|
||||
end
|
||||
|
||||
if (addonFrame.OnLoad) then
|
||||
DF:Dispatch(addonFrame.OnLoad, addonFrame, ...)
|
||||
end
|
||||
end
|
||||
|
||||
--runs when the addon received player_login
|
||||
local addonInit = function(addonFrame, event, ...)
|
||||
if (addonFrame.OnInit) then
|
||||
DF:Dispatch(addonFrame.OnInit, addonFrame, ...)
|
||||
end
|
||||
end
|
||||
|
||||
--when the player logout or reloadUI
|
||||
local addonUnload = function(addonFrame, event, ...)
|
||||
--close saved tables
|
||||
DF.SavedVars.CloseSavedTable(addonFrame.db)
|
||||
end
|
||||
|
||||
local addonEvents = {
|
||||
["ADDON_LOADED"] = addonPreLoad,
|
||||
["PLAYER_LOGIN"] = addonInit,
|
||||
["PLAYER_LOGOUT"] = addonUnload,
|
||||
}
|
||||
|
||||
local addonOnEvent = function(addonFrame, event, ...)
|
||||
local func = addonEvents[event]
|
||||
if (func) then
|
||||
func(addonFrame, event, ...)
|
||||
else
|
||||
--might be a registered event from the user
|
||||
if (addonFrame[event]) then
|
||||
DF:CoreDispatch(addonFrame.__name, addonFrame[event], addonFrame, event, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local getAddonName = function(addonFrame)
|
||||
return addonFrame:GetName()
|
||||
end
|
||||
|
||||
function DF:CreateNewAddOn(addonName, globalSavedVariablesName, savedVarsTemplate)
|
||||
local newAddon = CreateFrame("frame", addonName, UIParent)
|
||||
newAddon.__name = addonName
|
||||
newAddon.__savedVarsName = globalSavedVariablesName
|
||||
newAddon.__savedVarsDefaultTemplate = savedVarsTemplate
|
||||
|
||||
newAddon.GetAddonName = getAddonName
|
||||
|
||||
newAddon:RegisterEvent("ADDON_LOADED")
|
||||
newAddon:RegisterEvent("PLAYER_LOGIN")
|
||||
newAddon:RegisterEvent("PLAYER_LOGOUT")
|
||||
newAddon:SetScript("OnEvent", addonOnEvent)
|
||||
|
||||
return newAddon
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--old create addon
|
||||
function DF:CreateAddOn (name, global_saved, global_table, options_table, broker)
|
||||
|
||||
local addon = LibStub("AceAddon-3.0"):NewAddon (name, "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "DetailsFramework-1.0", "AceComm-3.0")
|
||||
_G [name] = addon
|
||||
addon.__name = name
|
||||
|
||||
function addon:OnInitialize()
|
||||
|
||||
if (global_saved) then
|
||||
if (broker and broker.Minimap and not global_table.Minimap) then
|
||||
DF:Msg(name, "broker.Minimap is true but no global.Minimap declared.")
|
||||
end
|
||||
self.db = LibStub("AceDB-3.0"):New (global_saved, global_table or {}, true)
|
||||
end
|
||||
|
||||
if (options_table) then
|
||||
LibStub("AceConfig-3.0"):RegisterOptionsTable (name, options_table)
|
||||
addon.OptionsFrame1 = LibStub("AceConfigDialog-3.0"):AddToBlizOptions (name, name)
|
||||
|
||||
LibStub("AceConfig-3.0"):RegisterOptionsTable (name .. "-Profiles", LibStub("AceDBOptions-3.0"):GetOptionsTable (self.db))
|
||||
addon.OptionsFrame2 = LibStub("AceConfigDialog-3.0"):AddToBlizOptions (name .. "-Profiles", "Profiles", name)
|
||||
end
|
||||
|
||||
if (broker) then
|
||||
local broker_click_function = broker.OnClick
|
||||
if (not broker_click_function and options_table) then
|
||||
broker_click_function = function()
|
||||
InterfaceOptionsFrame_OpenToCategory (name)
|
||||
InterfaceOptionsFrame_OpenToCategory (name)
|
||||
end
|
||||
end
|
||||
|
||||
local databroker = LibStub("LibDataBroker-1.1"):NewDataObject (name, {
|
||||
type = broker.type or "launcher",
|
||||
icon = broker.icon or [[Interface\PvPRankBadges\PvPRank15]],
|
||||
text = broker.text or "",
|
||||
OnTooltipShow = broker.OnTooltipShow,
|
||||
OnClick = broker_click_function
|
||||
})
|
||||
|
||||
if (databroker and broker.Minimap and global_table.Minimap) then
|
||||
LibStub("LibDBIcon-1.0"):Register (name, databroker, addon.db.profile.Minimap)
|
||||
end
|
||||
end
|
||||
|
||||
if (addon.OnInit) then
|
||||
xpcall(addon.OnInit, geterrorhandler(), addon)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return addon
|
||||
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ .. \FrameXML\UI.xsd">
|
||||
<Script file="button.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
--documentation: see the header of the file charts.lua
|
||||
|
||||
|
||||
--1º example: making a simple chart, just copy and paste this code into a lua file and run it
|
||||
do
|
||||
local ChartFrameTest = ChartFrameExample1 or DetailsFramework:CreateGraphicLineFrame(UIParent, "ChartFrameExample1")
|
||||
ChartFrameTest:SetPoint("left", UIParent, "left", 10, 0) --set the position of the chart
|
||||
ChartFrameTest:SetSize(800, 600) --set the size of the chart
|
||||
DetailsFramework:ApplyStandardBackdrop(ChartFrameTest) --apply a backdrop to this example hence see the frame size
|
||||
|
||||
--set the data (required)
|
||||
local data = {1, 2, 30, 25, 6, 5, 4, 8, 7, 4, 1, 12, 15, 24, 18, 17, 14, 15, 8, 4, 14, 42, 22, 25, 30, 35, 39, 8, 7, 4, 1, 2, 5, 4, 8, 7, 4, 12, 12, 4}
|
||||
local smoothnessLevel = 1 --(optional, default: 1)
|
||||
ChartFrameTest:SetData(data, smoothnessLevel)
|
||||
--draw the chart
|
||||
ChartFrameTest:Plot()
|
||||
end
|
||||
|
||||
--2º example: setting the color, thickness and scale of the line:
|
||||
do
|
||||
local ChartFrameTest = ChartFrameExample2 or DetailsFramework:CreateGraphicLineFrame(UIParent, "ChartFrameExample2")
|
||||
ChartFrameTest:SetPoint("left", UIParent, "left", 10, 0) --set the position of the chart
|
||||
ChartFrameTest:SetSize(800, 600) --set the size of the chart
|
||||
DetailsFramework:ApplyStandardBackdrop(ChartFrameTest) --apply a backdrop to this example hence see the frame size
|
||||
|
||||
--set the line thickness (optional, default: 2)
|
||||
local lineThickness = 3
|
||||
ChartFrameTest:SetLineThickness(lineThickness)
|
||||
|
||||
--set the chart color (optional, default: "white")
|
||||
local lineColor = {r = 1, g = 1, b = 0} --set it to "yellow"
|
||||
ChartFrameTest:SetColor(lineColor) --using {r = 1, g = 1, b = 0}
|
||||
ChartFrameTest:SetColor("yellow") --using the color name
|
||||
ChartFrameTest:SetColor(1, 1, 0) --passing the rgb directly
|
||||
ChartFrameTest:SetColor({1, 1, 0}) --using an index table
|
||||
|
||||
--set the data (required)
|
||||
local data = {1, 2, 30, 25, 6, 5, 4, 8, 7, 4, 1, 12, 15, 24 ,18, 17 ,14, 15, 8 , 4, 14, 42, 22, 25, 30, 35, 39, 8, 7, 4, 1, 2, 5, 4 ,8, 7 ,4, 12, 12 , 4}
|
||||
local smoothnessLevel = 1 --(optional, default: 1)
|
||||
ChartFrameTest:SetData(data, smoothnessLevel)
|
||||
|
||||
--height modifier, if for some reason need to scale the chart height
|
||||
local heightScale = 1 --(optional, default: 1)
|
||||
--draw the chart
|
||||
ChartFrameTest:Plot(heightScale)
|
||||
end
|
||||
|
||||
--3º example: setting the axes lines and labels
|
||||
do
|
||||
local ChartFrameTest = ChartFrameExample3 or DetailsFramework:CreateGraphicLineFrame(UIParent, "ChartFrameExample3")
|
||||
ChartFrameTest:SetPoint("left", UIParent, "left", 10, 0)
|
||||
ChartFrameTest:SetSize(800, 600)
|
||||
DetailsFramework:ApplyStandardBackdrop(ChartFrameTest)
|
||||
|
||||
--create guide lines in the left and bottom of the chart
|
||||
local xOffset = 48 --pixels from the left border of the chart
|
||||
local yOffset = 28 --pixels from the bottom border of the chart
|
||||
local whichSide = "left" --which side of vertical line should be placed
|
||||
local thickness = 1
|
||||
local amountYLabels = 10 --amounf of texts indicating the scale of the chart
|
||||
local amountXLabels = 10
|
||||
local r, g, b, a = 1, 1, 1, 1
|
||||
ChartFrameTest:CreateAxesLines(xOffset, yOffset, whichSide, thickness, amountYLabels, amountXLabels, r, g, b, a)
|
||||
|
||||
--the labels in the bottom line can be 'time', 'number' or 'value'
|
||||
ChartFrameTest:SetXAxisDataType("time")
|
||||
--set the data to be used in the bottom line labels, how the data is formatted depends on the type set above
|
||||
ChartFrameTest:SetXAxisData(10) --with type 'time' the chart interprets this as seconds and shows 1:00 to 10:00
|
||||
|
||||
ChartFrameTest:SetXAxisDataType("number")
|
||||
ChartFrameTest:SetXAxisData(600) --the chart interprets this as a 'number' type and displays it as 60, 120, 180.
|
||||
|
||||
ChartFrameTest:SetXAxisDataType("value")
|
||||
ChartFrameTest:SetXAxisData("hello", "world", 1, 2, 3, 4, "chart", 0, 1, 0) --and 'value' show the values passed
|
||||
|
||||
--setting the data, doesn't matter if it is set at the top or right before Plot()
|
||||
local data = {1, 2, 30, 25, 6, 5, 4, 8, 7, 4, 1, 12, 15, 24 ,18, 17 ,14, 15, 8 , 4, 14, 42, 22, 25, 30, 35, 39, 8, 7, 4, 1, 2, 5, 4 ,8, 7 ,4, 12, 12 , 4}
|
||||
ChartFrameTest:SetData(data) --smoothnessLevel is absent here, it'll use 1 as default
|
||||
ChartFrameTest:Plot()
|
||||
end
|
||||
|
||||
--4º example: a multi line chart is a chart which supports multiple lines, each line can have a different color, name, smoothnessLevel and thickness
|
||||
do
|
||||
local ChartFrameTest = ChartFrameExample4 or DetailsFramework:CreateGraphicMultiLineFrame(UIParent, "ChartFrameExample4")
|
||||
ChartFrameTest:SetPoint("left", UIParent, "left", 10, 0)
|
||||
ChartFrameTest:SetSize(800, 600)
|
||||
DetailsFramework:ApplyStandardBackdrop(ChartFrameTest)
|
||||
|
||||
--when using multi-line, the Reset() function instructs the chart to discard the previous data as new data is about to be added
|
||||
ChartFrameTest:Reset()
|
||||
|
||||
--smoothnessLevel, name, red, green, blue, alpha
|
||||
local smoothnessLevel = 2 --(optional, default: 0)
|
||||
local line1Name, line2Name, line3Name = "Line 1", "Line 2", "Line 3" --show the line name at the top right corner (optional, default none)
|
||||
local line1Color, line2Color, line3Color = "lime", "purple", "orange" --(optional, default "white")
|
||||
|
||||
--add data into the chart (it plots a line for each data added when :Plot() is called)
|
||||
local data1 = {1, 2, 30, 25, 6, 5, 4, 8, 7, 4, 1, 12, 15, 24 ,18, 17 ,14, 15, 8 , 4, 14, 42, 22, 25, 30, 35, 39, 8, 7, 4, 1, 2, 5, 4}
|
||||
ChartFrameTest:AddData(data1, smoothnessLevel, line1Name, line1Color)
|
||||
|
||||
local data2 = {3, 5, 20, 25, 6, 5, 15, 18, 12, 14, 11, 8, 7, 8 ,7, 4 ,1, 25, 26 , 30, 28, 20, 22, 25, 20, 15, 10, 8, 7, 4, 1, 2, 5, 4}
|
||||
ChartFrameTest:AddData(data2, smoothnessLevel, line2Name, line2Color)
|
||||
|
||||
local data3 = {5, 7, 15, 30, 6, 2, 10, 13, 10, 5, 11, 8, 7, 5, 3, 1, 1, 8, 10 , 12, 15, 20, 25, 25, 20, 17, 12, 7, 7, 6, 4, 5, 6, 5}
|
||||
ChartFrameTest:AddData(data3, smoothnessLevel, line3Name, line3Color)
|
||||
|
||||
ChartFrameTest:Plot()
|
||||
end
|
||||
@@ -0,0 +1,884 @@
|
||||
|
||||
local detailsFramework = _G["DetailsFramework"]
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local CreateFrame = CreateFrame
|
||||
local unpack = unpack
|
||||
local wipe = table.wipe
|
||||
local _
|
||||
|
||||
---@class chart_guideline : fontstring
|
||||
---@field circleTexture texture
|
||||
---@field guideLine line
|
||||
|
||||
---@class chart_nameindicator : frame
|
||||
---@field Texture texture
|
||||
---@field Label fontstring
|
||||
|
||||
---@alias x_axisdatatype
|
||||
---| "time" when setting the text into the labels, it will be converted into a time format
|
||||
---| "number" same as timer, but the number is not comverted to time
|
||||
---| "value" a fixed table with values is passed by the SetXAxisData() function
|
||||
|
||||
---@class df_chartshared: table
|
||||
---@field yAxisLine line the vertical line which can be anchored in the left or right side of the frame, if the chart is a multi chart, this line is shared by all charts
|
||||
---@field xAxisLine line the horizontal line which can be anchored in the top or bottom side of the frame, if the chart is a multi chart, this line is shared by all charts
|
||||
---@field xAxisDataNumber any if the data type of the x axis is "number" or "time"
|
||||
---@field xAxisDataValues table if the data type of the x axis is "value"
|
||||
---@field xAxisDataType x_axisdatatype the data type of the x axis, if time, the x axis will be a time axis, if value, the x axis will be a value axis
|
||||
---@field yAxisLabels chart_guideline[] the vertical axis labels to indicate the values of the chart data
|
||||
---@field xAxisLabels fontstring[] the horizontal axis labels to indicate the values of the chart data
|
||||
---@field plotFrame frame the plot frame which is the frame that will hold the chart lines
|
||||
---@field lineThickness number the thickness of the chart lines
|
||||
---@field chartLeftOffset number the offset of the left side of the chart frame to the plot frame
|
||||
---@field chartBottomOffset number the offset of the bottom side of the chart frame to the plot frame
|
||||
---@field xAxisLabelsYOffset number default: -6, the offset of the horizontal axis labels to the horizontal axis line (y coordinate)
|
||||
---@field smoothnessLevel number default: 0, the smoothness level of the chart lines, 0 is no smoothness
|
||||
---@field SetAxesColor fun(self: df_chartmulti, red: number|string|table|nil, green: number|nil, blue: number|nil, alpha: number|nil) : boolean set the color of both axis lines
|
||||
---@field SetAxesThickness fun(self: df_chartmulti, thickness: number) : boolean set the thickness of both axis lines
|
||||
---@field CreateAxesLines fun(self: df_chartmulti|df_chart, xOffset: number, yOffset: number, whichSide: "left"|"right", thickness: number, amountYLabels: number, amountXLabels: number, red: any, green: number|nil, blue: number|nil, alpha: number|nil)
|
||||
---@field SetXAxisDataType fun(self: df_chartmulti|df_chart, dataType: x_axisdatatype) : boolean set the data type of the x axis, if time, the x axis will be a time axis, if value, the x axis will be a value axis
|
||||
---@field SetXAxisData fun(self: df_chartmulti|df_chart, data: any) set the data of the x axis, if time, the x axis will be a time axis, if value, the x axis will be a value axis
|
||||
---@field SharedContrustor fun(self: df_chartmulti|df_chart) set default values for fields used on both chart types
|
||||
---@field IsMultiChart fun(self: df_chartmulti|df_chart) : boolean return true if the chart is a multi chart
|
||||
|
||||
---@param self df_chart|df_chartmulti
|
||||
local chartFrameSharedConstructor = function(self)
|
||||
self.xAxisDataType = "number"
|
||||
self.lineThickness = 2
|
||||
self.xAxisDataNumber = 0
|
||||
self.xAxisDataValues = {}
|
||||
self.xAxisLabels = {}
|
||||
self.yAxisLabels = {}
|
||||
self.chartLeftOffset = 0
|
||||
self.chartBottomOffset = 0
|
||||
self.xAxisLabelsYOffset = -6
|
||||
self.smoothnessLevel = 0
|
||||
end
|
||||
|
||||
---@class df_chart: frame, df_data, df_value, df_chartshared
|
||||
---@field _dataInfo df_data
|
||||
---@field color number[] red green blue alpha
|
||||
---@field height number
|
||||
---@field nextLine number
|
||||
---@field minValue number
|
||||
---@field maxValue number
|
||||
---@field data number[]
|
||||
---@field lines line[]
|
||||
---@field fixedLineWidth number
|
||||
---@field chartName string
|
||||
---@field ChartFrameConstructor fun(self: df_chart) set the default values for the chart frame
|
||||
---@field GetLine fun(self: df_chart) : line return a line and also internally handle next line
|
||||
---@field GetLines fun(self: df_chart) : line[] return a table with all lines already created
|
||||
---@field GetLineWidth fun(self: df_chart) : number calculate the width of each drawn line
|
||||
---@field SetLineWidth fun(self: df_chart, width: number) set the line width to a fixed value
|
||||
---@field GetAmountLines fun(self: df_chart) : number return the amount of lines in use
|
||||
---@field OnSizeChanged fun(self: df_chart)
|
||||
---@field HideLines fun(self: df_chart) hide all lines already created
|
||||
---@field Reset fun(self: df_chart) hide all lines and reset the next line to 1
|
||||
---@field SetColor fun(self: df_chart, r: number|string|table|nil, g: number|nil, b: number|nil, a: number|nil) set the color for the lines
|
||||
---@field GetColor fun(self: df_chart) : red, green, blue, alpha
|
||||
---@field SetLineThickness fun(self: df_chart, thickness: number) set the line thickness
|
||||
---@field CalcYAxisPointForValue fun(self: df_chart, value: number, plotFrameHeightScaled: number) : number
|
||||
---@field UpdateFrameSizeCache fun(self: df_chart)
|
||||
---@field Plot fun(self: df_chart, yPointScale: number|nil, bUpdateLabels: boolean|nil) draw the graphic using lines and following the data set by SetData() or AddData() in multi chart
|
||||
|
||||
---@class df_chartmulti : df_chart, df_chartshared
|
||||
---@field chartFrames df_chart[]
|
||||
---@field nextChartselframe number
|
||||
---@field biggestDataValue number
|
||||
---@field nextChartFrame number
|
||||
---@field lineNameIndicators chart_nameindicator[]
|
||||
---@field MultiChartFrameConstructor fun(self: df_chartmulti)
|
||||
---@field GetCharts fun(self: df_chartmulti) : df_chart[]
|
||||
---@field GetChart fun(self: df_chartmulti) : df_chart
|
||||
---@field AddData fun(self: df_chartmulti, data: table, name: string, red: any, green: number|nil, blue: number|nil, alpha: number|nil)
|
||||
---@field GetAmountCharts fun(self: df_chartmulti): number
|
||||
---@field HideCharts fun(self: df_chartmulti)
|
||||
---@field Reset fun(self: df_chartmulti)
|
||||
---@field SetChartsMinMaxValues fun(self: df_chartmulti, minValue: number, maxValue: number)
|
||||
---@field SetMaxDataSize fun(self: df_chartmulti, dataSize: number)
|
||||
---@field GetMaxDataSize fun(self: df_chartmulti)
|
||||
---@field SetLineThickness fun(self: df_chart, thickness: number) set the line thickness for all chart frames
|
||||
---@field UpdateChartNamesIndicator fun(self: df_chartmulti) if the chart names has been passed while adding data, this function will update the chart names indicator
|
||||
---@field Plot fun(self: df_chartmulti) draw the graphic using lines and following the data set by SetData() or AddData() in multi chart
|
||||
|
||||
---create the plot frame which is the frame that will hold the chart lines
|
||||
---@param self df_chartmulti|df_chart
|
||||
---@return frame
|
||||
local createPlotFrame = function(self)
|
||||
local plotFrame = CreateFrame("frame", "$parentPlotFrame", self, "BackdropTemplate")
|
||||
plotFrame:SetAllPoints()
|
||||
self.plotFrame = plotFrame
|
||||
return plotFrame
|
||||
end
|
||||
|
||||
---generate the vertical axis labels to indicate the values of the chart data
|
||||
---@param parent frame
|
||||
---@param amountLabels number
|
||||
---@param labelsTable chart_guideline[]
|
||||
---@param red number
|
||||
---@param green number
|
||||
---@param blue number
|
||||
---@param alpha number
|
||||
local createVerticalAxisLabels = function(parent, amountLabels, labelsTable, red, green, blue, alpha)
|
||||
for i = 1, amountLabels do
|
||||
---@type fontstring
|
||||
local label = parent:CreateFontString("$parentYAxisLabel" .. i, "overlay", "GameFontNormal")
|
||||
---@cast label chart_guideline
|
||||
|
||||
label:SetJustifyH("right")
|
||||
label:SetTextColor(red, green, blue, alpha)
|
||||
detailsFramework:SetFontSize(label, 11)
|
||||
table.insert(labelsTable, label)
|
||||
|
||||
local circleTexture = parent:CreateTexture("$parentYAxisLabel" .. i .. "CircleTexture", "border")
|
||||
circleTexture:SetSize(4, 4)
|
||||
circleTexture:SetTexture([[Interface\CHARACTERFRAME\TempPortraitAlphaMaskSmall]])
|
||||
circleTexture:SetVertexColor(red, green, blue, alpha)
|
||||
circleTexture:SetPoint("right", label, "right", 5, 0)
|
||||
|
||||
local guideLine = parent:CreateLine("$parentYAxisLabel" .. i .. "GuideLine", "border")
|
||||
guideLine:SetThickness(1)
|
||||
guideLine:SetColorTexture(red, green, blue, 0.05)
|
||||
|
||||
label.circleTexture = circleTexture
|
||||
label.guideLine = guideLine
|
||||
end
|
||||
end
|
||||
|
||||
---generate the horizontal axis labels to indicate the values of the chart data
|
||||
---@param parent frame
|
||||
---@param amountLabels number
|
||||
---@param labelsTable fontstring[]
|
||||
---@param red number
|
||||
---@param green number
|
||||
---@param blue number
|
||||
---@param alpha number
|
||||
local createHorizontalAxisLabels = function(parent, amountLabels, labelsTable, red, green, blue, alpha)
|
||||
for i = 1, amountLabels do
|
||||
local label = parent:CreateFontString("$parentXAxisLabel" .. i, "overlay", "GameFontNormal")
|
||||
label:SetJustifyH("left")
|
||||
label:SetTextColor(red, green, blue, alpha)
|
||||
detailsFramework:SetFontSize(label, 11)
|
||||
table.insert(labelsTable, label)
|
||||
end
|
||||
end
|
||||
|
||||
---create the x and y axis lines with their labels
|
||||
---@param self df_chart|df_chartmulti
|
||||
---@param xOffset number
|
||||
---@param yOffset number
|
||||
---@param whichSide "left"|"right"
|
||||
---@param thickness number
|
||||
---@param amountYLabels number
|
||||
---@param amountXLabels number
|
||||
---@param red any
|
||||
---@param green number|nil
|
||||
---@param blue number|nil
|
||||
---@param alpha number|nil
|
||||
---@return boolean
|
||||
local createAxesLines = function(self, xOffset, yOffset, whichSide, thickness, amountYLabels, amountXLabels, red, green, blue, alpha)
|
||||
if (self.axisCreated) then
|
||||
return false
|
||||
end
|
||||
|
||||
local plotFrame = self.plotFrame
|
||||
|
||||
self.chartLeftOffset = xOffset or 48
|
||||
self.chartBottomOffset = yOffset or 28
|
||||
whichSide = whichSide or "left"
|
||||
thickness = thickness or 1
|
||||
amountYLabels = amountYLabels or 10
|
||||
amountXLabels = amountXLabels or 10
|
||||
red = red or 1
|
||||
green = green or 1
|
||||
blue = blue or 1
|
||||
alpha = alpha or 1
|
||||
|
||||
--adjust the plotFrame size and point taking in consideration of the left and bottom offsets, this is done to free space for the axis labels
|
||||
plotFrame:SetSize(self:GetWidth() - self.chartLeftOffset - 10, self:GetHeight() - self.chartBottomOffset - 20)
|
||||
plotFrame:ClearAllPoints()
|
||||
plotFrame:SetPoint("topleft", self, "topleft", self.chartLeftOffset, -1)
|
||||
plotFrame:SetPoint("bottomright", self, "bottomright", -1, self.chartBottomOffset)
|
||||
|
||||
--this is the vertical line which can be anchored in the left or right side of the frame, it separates the chart lines from the labels
|
||||
---@type line
|
||||
local yAxisLine = plotFrame:CreateLine("$parentYAxisLine", "overlay")
|
||||
self.yAxisLine = yAxisLine
|
||||
--and the horizontal line which is always anchored in the bottom of the frame
|
||||
---@type line
|
||||
local xAxisLine = plotFrame:CreateLine("$parentXAxisLine", "overlay")
|
||||
self.xAxisLine = xAxisLine
|
||||
|
||||
--vertical axis point
|
||||
if (whichSide == "left") then
|
||||
yAxisLine:SetStartPoint("topleft", plotFrame, 0, -1)
|
||||
yAxisLine:SetEndPoint("bottomleft", plotFrame, 0, self.chartBottomOffset * -1)
|
||||
else
|
||||
yAxisLine:SetStartPoint("topright", plotFrame, 0, -1)
|
||||
yAxisLine:SetEndPoint("bottomleft", plotFrame, 0, self.chartBottomOffset)
|
||||
end
|
||||
|
||||
--horizontal axis point
|
||||
xAxisLine:SetStartPoint("bottomleft", plotFrame, self.chartLeftOffset * -1, 0)
|
||||
xAxisLine:SetEndPoint("bottomright", plotFrame, -1, 0)
|
||||
|
||||
red, green, blue, alpha = detailsFramework:ParseColors(red, green, blue, alpha)
|
||||
self:SetAxesColor(red, green, blue, alpha)
|
||||
|
||||
--set the thickness of the both axis lines
|
||||
self:SetAxesThickness(thickness)
|
||||
|
||||
createVerticalAxisLabels(plotFrame, amountYLabels, self.yAxisLabels, red, green, blue, alpha)
|
||||
createHorizontalAxisLabels(plotFrame, amountXLabels, self.xAxisLabels, red, green, blue, alpha)
|
||||
|
||||
self.axisCreated = true
|
||||
return true
|
||||
end
|
||||
|
||||
---@param self df_chartmulti|df_chart
|
||||
---@param ... any
|
||||
local setXAxisData = function(self, ...)
|
||||
--when the data type is set to time, the x axis data is a number which represents the biggest time in seconds of all charts added
|
||||
if (self.xAxisDataType == "time" or self.xAxisDataType == "number") then
|
||||
self.xAxisDataNumber = math.max(self.xAxisDataNumber, select(1, ...))
|
||||
else
|
||||
wipe(self.xAxisDataValues)
|
||||
self.xAxisDataValues = {...}
|
||||
end
|
||||
end
|
||||
|
||||
---@param self df_chartmulti|df_chart
|
||||
---@param dataType x_axisdatatype
|
||||
local setXAxisDataType = function(self, dataType)
|
||||
assert(type(dataType) == "string", "string expected on :SetXAxisDataType(string)")
|
||||
self.xAxisDataType = dataType
|
||||
|
||||
if (dataType == "time" or dataType == "number") then
|
||||
self.xAxisDataNumber = 0
|
||||
|
||||
elseif (dataType == "value") then
|
||||
wipe(self.xAxisDataValues)
|
||||
end
|
||||
end
|
||||
|
||||
---updates the values of the labels on the axes to reflect the data shown
|
||||
---@param self df_chart|df_chartmulti
|
||||
local updateLabelValues = function(self)
|
||||
local maxValue = self:GetMaxValue()
|
||||
local height = self.plotFrame:GetHeight()
|
||||
local verticalLabelCount = #self.yAxisLabels
|
||||
local heightStep = height / verticalLabelCount
|
||||
|
||||
--update the labels in the vertical axis line
|
||||
for i = 1, verticalLabelCount do
|
||||
local label = self.yAxisLabels[i]
|
||||
local value = maxValue * (i / verticalLabelCount)
|
||||
label:ClearAllPoints()
|
||||
label:SetPoint("topright", self.yAxisLine, "bottomleft", -6, heightStep * i + self.chartBottomOffset)
|
||||
label:SetText(detailsFramework.FormatNumber(value))
|
||||
|
||||
label.circleTexture:ClearAllPoints()
|
||||
label.circleTexture:SetPoint("center", self.yAxisLine, "bottomleft", -2, heightStep * i - 5 + self.chartBottomOffset)
|
||||
|
||||
label.guideLine:SetStartPoint("center", label.circleTexture, 0, 0)
|
||||
label.guideLine:SetEndPoint("bottomright", self.plotFrame, 0, heightStep * i - 5)
|
||||
end
|
||||
|
||||
--update the labels in the horizontal axis line
|
||||
local xAxisDataType = self.xAxisDataType
|
||||
local horizontalLabelCount = #self.xAxisLabels
|
||||
local width = self.plotFrame:GetWidth()
|
||||
local widthStep = width / horizontalLabelCount
|
||||
|
||||
for i = horizontalLabelCount, 1, -1 do
|
||||
local label = self.xAxisLabels[i]
|
||||
label:ClearAllPoints()
|
||||
label:SetJustifyH("right")
|
||||
|
||||
--set the point of each x axis label
|
||||
label:SetPoint("topright", self.plotFrame, "bottomleft", widthStep * i, self.xAxisLabelsYOffset or -6)
|
||||
|
||||
--get the type set for the x axis labels and format the value accordingly
|
||||
if (xAxisDataType == "time" or xAxisDataType == "number") then
|
||||
local maxNumberValue = self.xAxisDataNumber
|
||||
local thisValue = maxNumberValue * (i / horizontalLabelCount)
|
||||
if (xAxisDataType == "time") then
|
||||
label:SetText(detailsFramework:IntegerToTimer(thisValue))
|
||||
else
|
||||
label:SetText(detailsFramework.FormatNumber(thisValue))
|
||||
end
|
||||
|
||||
elseif (xAxisDataType == "value") then
|
||||
label:SetText(self.xAxisDataValues[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
detailsFramework.ChartFrameSharedMixin = {
|
||||
---set the color of both axis lines
|
||||
---@param self df_chart|df_chartmulti
|
||||
---@param red any
|
||||
---@param green number|nil
|
||||
---@param blue number|nil
|
||||
---@param alpha number|nil
|
||||
---@return boolean bColorChanged return true if the color was set, false if the axis lines are not created yet
|
||||
SetAxesColor = function(self, red, green, blue, alpha)
|
||||
if (not self.yAxisLine) then
|
||||
return false
|
||||
end
|
||||
|
||||
--set the color of both axis lines
|
||||
red, green, blue, alpha = detailsFramework:ParseColors(red, green, blue, alpha)
|
||||
self.yAxisLine:SetColorTexture(red, green, blue, alpha)
|
||||
self.xAxisLine:SetColorTexture(red, green, blue, alpha)
|
||||
|
||||
--iterage over all labels and set their color
|
||||
for i = 1, #self.yAxisLabels do
|
||||
self.yAxisLabels[i]:SetTextColor(red, green, blue, alpha)
|
||||
end
|
||||
|
||||
for i = 1, #self.xAxisLabels do
|
||||
self.xAxisLabels[i]:SetTextColor(red, green, blue, alpha)
|
||||
end
|
||||
|
||||
return true
|
||||
end,
|
||||
|
||||
---set the thickness of both axis lines
|
||||
---@param self df_chart|df_chartmulti
|
||||
---@param thickness number
|
||||
---@return boolean bThicknessChanged return true if the thickness was set, false if the axis lines are not created yet
|
||||
SetAxesThickness = function(self, thickness)
|
||||
if (not self.yAxisLine) then
|
||||
return false
|
||||
end
|
||||
self.yAxisLine:SetThickness(thickness)
|
||||
self.xAxisLine:SetThickness(thickness)
|
||||
return true
|
||||
end,
|
||||
|
||||
---create the x and y axis lines with their labels
|
||||
---@param self df_chart|df_chartmulti
|
||||
---@param xOffset number
|
||||
---@param yOffset number
|
||||
---@param whichSide "left"|"right"
|
||||
---@param thickness number
|
||||
---@param amountYLabels number
|
||||
---@param amountXLabels number
|
||||
---@param red any
|
||||
---@param green number|nil
|
||||
---@param blue number|nil
|
||||
---@param alpha number|nil
|
||||
---@return boolean
|
||||
CreateAxesLines = function(self, xOffset, yOffset, whichSide, thickness, amountYLabels, amountXLabels, red, green, blue, alpha)
|
||||
return createAxesLines(self, xOffset, yOffset, whichSide, thickness, amountYLabels, amountXLabels, red, green, blue, alpha)
|
||||
end,
|
||||
|
||||
---@param self df_chartmulti|df_chart
|
||||
---@param ... any
|
||||
SetXAxisData = function(self, ...)
|
||||
setXAxisData(self, ...)
|
||||
end,
|
||||
|
||||
---@param self df_chartmulti|df_chart
|
||||
---@param dataType x_axisdatatype
|
||||
SetXAxisDataType = function(self, dataType)
|
||||
setXAxisDataType(self, dataType)
|
||||
end,
|
||||
}
|
||||
|
||||
detailsFramework.ChartFrameMixin = {
|
||||
---set the default values for the chart frame
|
||||
---@param self df_chart
|
||||
ChartFrameConstructor = function(self)
|
||||
self.nextLine = 1
|
||||
self.minValue = 0
|
||||
self.maxValue = 1
|
||||
self.lineThickness = 2
|
||||
self.data = {}
|
||||
self.lines = {}
|
||||
self.color = {1, 1, 1, 1}
|
||||
--OnSizeChanged
|
||||
self:SetScript("OnSizeChanged", self.OnSizeChanged)
|
||||
|
||||
chartFrameSharedConstructor(self)
|
||||
end,
|
||||
|
||||
IsMultiChart = function(self)
|
||||
return false
|
||||
end,
|
||||
|
||||
---get the chart color
|
||||
---@param self df_chart
|
||||
---@return number red
|
||||
---@return number green
|
||||
---@return number blue
|
||||
---@return number alpha
|
||||
GetColor = function(self)
|
||||
return unpack(self.color)
|
||||
end,
|
||||
|
||||
---set the color for the lines
|
||||
---@param self df_chart
|
||||
---@param r number
|
||||
---@param g number
|
||||
---@param b number
|
||||
---@param a number|nil
|
||||
SetColor = function(self, r, g, b, a)
|
||||
r, g, b, a = detailsFramework:ParseColors(r, g, b, a)
|
||||
self.color[1] = r
|
||||
self.color[2] = g
|
||||
self.color[3] = b
|
||||
self.color[4] = a or 1
|
||||
end,
|
||||
|
||||
---internally handle next line
|
||||
---@param self df_chart
|
||||
GetLine = function(self)
|
||||
---@type line
|
||||
local line = self.lines[self.nextLine]
|
||||
|
||||
if (not line) then
|
||||
---@type line
|
||||
line = self.plotFrame:CreateLine(nil, "overlay", nil, 5)
|
||||
self.lines[self.nextLine] = line
|
||||
end
|
||||
|
||||
self.nextLine = self.nextLine + 1
|
||||
line:Show()
|
||||
return line
|
||||
end,
|
||||
|
||||
---return all lines created for this chart
|
||||
---@param self df_chart
|
||||
---@return line[]
|
||||
GetLines = function(self)
|
||||
return self.lines
|
||||
end,
|
||||
|
||||
---return the amount of lines in use
|
||||
---@param self df_chart
|
||||
---@return number
|
||||
GetAmountLines = function(self)
|
||||
return self.nextLine - 1
|
||||
end,
|
||||
|
||||
---hide all lines already created
|
||||
---@param self df_chart
|
||||
HideLines = function(self)
|
||||
local allLines = self:GetLines()
|
||||
for i = 1, #allLines do
|
||||
local line = allLines[i]
|
||||
line:Hide()
|
||||
end
|
||||
end,
|
||||
|
||||
---hide all lines and reset the next line to 1
|
||||
---@param self df_chart
|
||||
Reset = function(self)
|
||||
self:HideLines()
|
||||
self.nextLine = 1
|
||||
end,
|
||||
|
||||
---@param self df_chart
|
||||
---@param value number
|
||||
SetLineThickness = function(self, value)
|
||||
assert(type(value) == "number", "number expected on :SetLineThickness(number)")
|
||||
self.lineThickness = value
|
||||
end,
|
||||
|
||||
---calculate the width of each drawn line
|
||||
---@param self df_chart
|
||||
GetLineWidth = function(self)
|
||||
--self:SetLineWidth(nil) to erase the fixed value
|
||||
if (self.fixedLineWidth) then
|
||||
return self.fixedLineWidth
|
||||
else
|
||||
local amountData = self:GetDataSize()
|
||||
local frameWidth = self.plotFrame:GetWidth()
|
||||
return frameWidth / amountData
|
||||
end
|
||||
end,
|
||||
|
||||
---set the line width to a fixed value
|
||||
---@param self df_chart
|
||||
---@param width number
|
||||
SetLineWidth = function(self, width)
|
||||
assert(type(width) == "number", "number expected on :SetLineWidth(number)")
|
||||
self.fixedLineWidth = width
|
||||
end,
|
||||
|
||||
---@param self df_chart
|
||||
---@param value number
|
||||
---@param plotFrameHeightScaled number
|
||||
---@return number
|
||||
CalcYAxisPointForValue = function(self, value, plotFrameHeightScaled)
|
||||
return value / self.maxValue * (plotFrameHeightScaled)
|
||||
end,
|
||||
|
||||
---@param self df_chart
|
||||
UpdateFrameSizeCache = function(self)
|
||||
self.width = self:GetWidth()
|
||||
self.height = self:GetHeight()
|
||||
end,
|
||||
|
||||
---@param self df_chart
|
||||
OnSizeChanged = function(self)
|
||||
self:UpdateFrameSizeCache()
|
||||
end,
|
||||
|
||||
---@param self df_chart
|
||||
---@param yPointScale number|nil
|
||||
---@param bUpdateLabels boolean|nil
|
||||
Plot = function(self, yPointScale, bUpdateLabels)
|
||||
--debug
|
||||
--self:SetData({38, 26, 12, 63, 100, 96, 42, 94, 25, 75, 61, 54, 71, 40, 34, 100, 66, 90, 39, 13, 99, 18, 72, 18, 83, 45, 56, 24, 33, 85, 95, 71, 15, 66, 19, 58, 52, 9, 83, 99, 100, 4, 3, 56, 6, 80, 94, 7, 40, 55, 98, 92, 20, 9, 35, 89, 72, 7, 13, 81, 29, 78, 55, 70, 12, 33, 39, 3, 84, 31, 10, 53, 51, 69, 66, 58, 71, 60, 31, 71, 27, 76, 21, 75, 15, 89, 2, 81, 72, 78, 74, 80, 97, 10, 59, 0, 31, 5, 1, 82, 71, 89, 78, 94, 74, 20, 65, 72, 56, 40, 92, 91, 40, 79, 4, 56, 18, 88, 88, 20, 20, 10, 47, 26, 80, 26, 75, 21, 57, 10, 67, 66, 84, 83, 14, 47, 83, 9, 7, 73, 63, 32, 64, 20, 40, 3, 46, 54, 17, 37, 82, 66, 65, 22, 12, 1, 100, 41, 1, 72, 38, 41, 71, 69, 88, 34, 10, 50, 9, 25, 19, 27, 3, 13, 40, 75, 3, 11, 93, 58, 81, 80, 93, 25, 74, 68, 91, 87, 79, 48, 66, 53, 64, 18, 51, 19, 32, 4, 21, 43})
|
||||
|
||||
self:UpdateFrameSizeCache()
|
||||
|
||||
--max amount of data is the max amount of point the chart will have
|
||||
local maxLines = self:GetDataSize()
|
||||
|
||||
--calculate where the first point height will be
|
||||
local firstValue = self:GetDataFirstValue()
|
||||
assert(firstValue, "Can't Plot(), chart has no data, use Chart:SetData(table)")
|
||||
|
||||
local plotFrameHeightScaled = self.plotFrame:GetHeight() * (yPointScale or 1)
|
||||
local currentXPoint = 0
|
||||
local currentYPoint = self:CalcYAxisPointForValue(firstValue, plotFrameHeightScaled)
|
||||
|
||||
--calculate the width space which line should have
|
||||
local eachLineWidth = self:GetLineWidth()
|
||||
|
||||
self:ResetDataIndex()
|
||||
|
||||
for i = 1, maxLines do
|
||||
local line = self:GetLine()
|
||||
|
||||
line:SetColorTexture(unpack(self.color))
|
||||
|
||||
if (line.thickness ~= self.lineThickness) then
|
||||
line:SetThickness(self.lineThickness)
|
||||
line.thickness = self.lineThickness
|
||||
end
|
||||
|
||||
--the start point starts where the latest point finished
|
||||
line:SetStartPoint("bottomleft", currentXPoint, currentYPoint)
|
||||
|
||||
--move x
|
||||
currentXPoint = currentXPoint + eachLineWidth
|
||||
|
||||
--end point
|
||||
local value = self:GetDataNextValue()
|
||||
currentYPoint = self:CalcYAxisPointForValue(value, plotFrameHeightScaled)
|
||||
line:SetEndPoint("bottomleft", currentXPoint, currentYPoint)
|
||||
end
|
||||
|
||||
if (bUpdateLabels or bUpdateLabels == nil) then
|
||||
updateLabelValues(self)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
---create a chart frame object
|
||||
---@param parent frame
|
||||
---@param name string|nil
|
||||
---@return df_chart
|
||||
local createChartFrame = function(parent, name)
|
||||
---@type df_chart
|
||||
local chartFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
||||
|
||||
detailsFramework:Mixin(chartFrame, detailsFramework.DataMixin)
|
||||
detailsFramework:Mixin(chartFrame, detailsFramework.ValueMixin)
|
||||
detailsFramework:Mixin(chartFrame, detailsFramework.ChartFrameMixin)
|
||||
detailsFramework:Mixin(chartFrame, detailsFramework.ChartFrameSharedMixin)
|
||||
|
||||
chartFrame:DataConstructor()
|
||||
chartFrame:ValueConstructor()
|
||||
chartFrame:ChartFrameConstructor()
|
||||
|
||||
--when a new data is set, update the min and max values
|
||||
local onSetDataCallback = function(data, smoothnessLevel)
|
||||
local newData = {}
|
||||
|
||||
smoothnessLevel = smoothnessLevel or 0
|
||||
|
||||
if (smoothnessLevel > 0) then
|
||||
smoothnessLevel = smoothnessLevel + 2
|
||||
|
||||
for i = 1, #data do
|
||||
local thisValue = 0
|
||||
local amountDataAdded = 0
|
||||
|
||||
--calculate the sum within the window
|
||||
for o = i - math.floor(smoothnessLevel / 2), i + math.floor(smoothnessLevel / 2) do
|
||||
if o >= 1 and o <= #data then
|
||||
thisValue = thisValue + data[o]
|
||||
amountDataAdded = amountDataAdded + 1
|
||||
end
|
||||
end
|
||||
|
||||
--calculate the average and store in the smoothedData value
|
||||
local average = thisValue / amountDataAdded
|
||||
table.insert(newData, average)
|
||||
end
|
||||
else
|
||||
newData = data
|
||||
end
|
||||
|
||||
chartFrame:SetDataRaw(newData)
|
||||
|
||||
local minValue, maxValue = chartFrame:GetDataMinMaxValues()
|
||||
chartFrame:SetMinMaxValues(minValue, maxValue)
|
||||
--clear the lines
|
||||
chartFrame:HideLines()
|
||||
end
|
||||
chartFrame:AddDataChangeCallback(onSetDataCallback)
|
||||
|
||||
createPlotFrame(chartFrame) --creates chartFrame.plotFrame
|
||||
return chartFrame
|
||||
end
|
||||
|
||||
function detailsFramework:CreateGraphicLineFrame(parent, name)
|
||||
---@type df_chart
|
||||
local newGraphicFrame = createChartFrame(parent, name)
|
||||
return newGraphicFrame
|
||||
end
|
||||
|
||||
detailsFramework.MultiChartFrameMixin = {
|
||||
MultiChartFrameConstructor = function(self)
|
||||
self.nextChartselframe = 1
|
||||
self.biggestDataValue = 0
|
||||
self.lineThickness = 2
|
||||
self.nextChartFrame = 1
|
||||
self.chartFrames = {}
|
||||
self.lineNameIndicators = {}
|
||||
|
||||
chartFrameSharedConstructor(self)
|
||||
end,
|
||||
|
||||
IsMultiChart = function(self)
|
||||
return true
|
||||
end,
|
||||
|
||||
---add a new chart data and create a new chart frame if necessary to the multi chart
|
||||
---@param self df_chartmulti
|
||||
---@param data table
|
||||
---@param smoothnessLevel number|nil
|
||||
---@param name string|nil
|
||||
---@param red any
|
||||
---@param green number|nil
|
||||
---@param blue number|nil
|
||||
---@param alpha number|nil
|
||||
AddData = function(self, data, smoothnessLevel, name, red, green, blue, alpha)
|
||||
assert(type(data) == "table", "MultiChartFrame:AddData() usage: AddData(table)")
|
||||
local chartFrame = self:GetChart()
|
||||
|
||||
red, green, blue, alpha = detailsFramework:ParseColors(red, green, blue, alpha)
|
||||
chartFrame:SetColor(red, green, blue, alpha)
|
||||
chartFrame:SetData(data, smoothnessLevel)
|
||||
|
||||
chartFrame.chartName = name or ""
|
||||
|
||||
self:SetMaxValueIfBigger(chartFrame:GetMaxValue())
|
||||
self:SetMinValueIfLower(chartFrame:GetMinValue())
|
||||
|
||||
local dataAmount = chartFrame:GetDataSize()
|
||||
self:SetMaxDataSize(dataAmount)
|
||||
end,
|
||||
|
||||
---internally handle next line
|
||||
---@param self df_chartmulti
|
||||
---@return df_chart
|
||||
GetChart = function(self)
|
||||
local chartFrame = self.chartFrames[self.nextChartFrame]
|
||||
if (not chartFrame) then
|
||||
chartFrame = createChartFrame(self, "$parentChartFrame" .. self.nextChartFrame)
|
||||
chartFrame:SetAllPoints()
|
||||
chartFrame:UpdateFrameSizeCache()
|
||||
self.chartFrames[self.nextChartFrame] = chartFrame
|
||||
end
|
||||
self.nextChartFrame = self.nextChartFrame + 1
|
||||
chartFrame:Show()
|
||||
return chartFrame
|
||||
end,
|
||||
|
||||
---get all charts added to the multi chart frame
|
||||
---@param self df_chartmulti
|
||||
---@return df_chart[]
|
||||
GetCharts = function(self)
|
||||
return self.chartFrames
|
||||
end,
|
||||
|
||||
---get the amount of charts added to the multi chart frame
|
||||
---@param self df_chartmulti
|
||||
---@return number
|
||||
GetAmountCharts = function(self)
|
||||
return self.nextChartFrame - 1
|
||||
end,
|
||||
|
||||
---hide all charts
|
||||
---@param self df_chartmulti
|
||||
HideCharts = function(self)
|
||||
local charts = self:GetCharts()
|
||||
for i = 1, #charts do
|
||||
local chartFrame = charts[i]
|
||||
chartFrame:Hide()
|
||||
end
|
||||
end,
|
||||
|
||||
---reset the multi chart frame
|
||||
---@param self df_chartmulti
|
||||
Reset = function(self)
|
||||
self:HideCharts()
|
||||
self.nextChartFrame = 1
|
||||
end,
|
||||
|
||||
---set the min and max values of all charts
|
||||
---@param self df_chartmulti
|
||||
---@param minValue number
|
||||
---@param maxValue number
|
||||
SetChartsMinMaxValues = function(self, minValue, maxValue)
|
||||
local allCharts = self:GetCharts()
|
||||
for i = 1, self:GetAmountCharts() do
|
||||
local chartFrame = allCharts[i]
|
||||
chartFrame:SetMinMaxValues(minValue, maxValue)
|
||||
end
|
||||
end,
|
||||
|
||||
---set the max data size of all charts
|
||||
---@param self df_chartmulti
|
||||
---@param dataSize number
|
||||
SetMaxDataSize = function(self, dataSize)
|
||||
self.biggestDataValue = math.max(self.biggestDataValue, dataSize)
|
||||
end,
|
||||
|
||||
---get the max data size of all charts
|
||||
---@param self df_chartmulti
|
||||
---@return number
|
||||
GetMaxDataSize = function(self)
|
||||
return self.biggestDataValue
|
||||
end,
|
||||
|
||||
---@param self df_chartmulti
|
||||
---@param value number
|
||||
SetLineThickness = function(self, value)
|
||||
assert(type(value) == "number", "number expected on :SetLineThickness(number)")
|
||||
self.lineThickness = value
|
||||
end,
|
||||
|
||||
---@param self df_chartmulti
|
||||
UpdateChartNamesIndicator = function(self)
|
||||
local allCharts = self:GetCharts()
|
||||
local allChartsAmount = self:GetAmountCharts()
|
||||
|
||||
--hide all indicators already created
|
||||
for i = 1, #self.lineNameIndicators do
|
||||
local thisIndicator = self.lineNameIndicators[i]
|
||||
thisIndicator:Hide()
|
||||
end
|
||||
|
||||
local nameIndicatorIndex = 1
|
||||
|
||||
for i = allChartsAmount, 1, -1 do
|
||||
local chartFrame = allCharts[i]
|
||||
local chartName = chartFrame.chartName
|
||||
local red, green, blue, alpha = chartFrame:GetColor()
|
||||
|
||||
---@type chart_nameindicator
|
||||
local thisIndicator = self.lineNameIndicators[nameIndicatorIndex]
|
||||
if (not thisIndicator) then
|
||||
---@type chart_nameindicator
|
||||
thisIndicator = CreateFrame("frame", "$parentLineNameIndicator" .. i, self)
|
||||
thisIndicator:SetSize(60, 12)
|
||||
thisIndicator:Hide()
|
||||
if (nameIndicatorIndex == 1) then
|
||||
thisIndicator:SetPoint("topright", self, "topright", nameIndicatorIndex * -10, -10)
|
||||
end
|
||||
|
||||
thisIndicator.Texture = thisIndicator:CreateTexture("$parentTexture", "overlay")
|
||||
thisIndicator.Texture:SetSize(12, 12)
|
||||
|
||||
thisIndicator.Label = thisIndicator:CreateFontString("$parentLabel", "overlay", "GameFontNormal")
|
||||
detailsFramework:SetFontSize(thisIndicator.Label, 11)
|
||||
detailsFramework:SetFontColor(thisIndicator.Label, "white")
|
||||
|
||||
thisIndicator.Texture:SetPoint("left", thisIndicator, "left", 0, 0)
|
||||
thisIndicator.Label:SetPoint("left", thisIndicator.Texture, "right", 2, 0)
|
||||
self.lineNameIndicators[nameIndicatorIndex] = thisIndicator
|
||||
end
|
||||
|
||||
thisIndicator.Texture:SetColorTexture(red, green, blue, alpha)
|
||||
thisIndicator.Label:SetText(chartName)
|
||||
local textWidth = thisIndicator.Label:GetStringWidth()
|
||||
thisIndicator:SetWidth(math.max(textWidth + thisIndicator.Texture:GetWidth() + 4, 85))
|
||||
|
||||
if (nameIndicatorIndex > 1) then
|
||||
local previousIndicator = self.lineNameIndicators[nameIndicatorIndex-1]
|
||||
thisIndicator:SetPoint("topright", previousIndicator, "topleft", -2, 0)
|
||||
end
|
||||
|
||||
nameIndicatorIndex = nameIndicatorIndex + 1
|
||||
|
||||
if (chartName ~= "") then
|
||||
thisIndicator:Show()
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
---draw all the charts added to the multi chart frame
|
||||
---@param multiChartFrame df_chartmulti
|
||||
Plot = function(multiChartFrame)
|
||||
local minValue, multiChartMaxValue = multiChartFrame:GetMinMaxValues()
|
||||
local plotAreaWidth = multiChartFrame.plotFrame:GetWidth() --if there's no axis, the plotFrame has no width
|
||||
local maxDataSize = multiChartFrame:GetMaxDataSize()
|
||||
local eachLineWidth = plotAreaWidth / maxDataSize
|
||||
local allCharts = multiChartFrame:GetCharts()
|
||||
|
||||
for i = 1, multiChartFrame:GetAmountCharts() do
|
||||
local chartFrame = allCharts[i]
|
||||
chartFrame.chartLeftOffset = multiChartFrame.chartLeftOffset
|
||||
chartFrame.chartBottomOffset = multiChartFrame.chartLeftOffset
|
||||
|
||||
chartFrame.plotFrame:ClearAllPoints()
|
||||
chartFrame.plotFrame:SetAllPoints(multiChartFrame.plotFrame)
|
||||
|
||||
chartFrame:SetLineThickness(multiChartFrame.lineThickness)
|
||||
chartFrame:SetLineWidth(eachLineWidth)
|
||||
|
||||
--get the percentage of how small this data is compared to the biggest data
|
||||
--this percentage is then used to scale down the to fit correctly the fontStrings showing the value metrics
|
||||
local yPointScale = chartFrame.maxValue / multiChartMaxValue
|
||||
local bUpdateLabels = false
|
||||
chartFrame:Plot(yPointScale, bUpdateLabels)
|
||||
end
|
||||
|
||||
updateLabelValues(multiChartFrame)
|
||||
multiChartFrame:UpdateChartNamesIndicator()
|
||||
end,
|
||||
}
|
||||
|
||||
---create a chart frame object with support to multi lines
|
||||
---@param parent frame
|
||||
---@param name string|nil
|
||||
---@return df_chartmulti
|
||||
function detailsFramework:CreateGraphicMultiLineFrame(parent, name)
|
||||
name = name or ("DetailsMultiChartFrameID" .. math.random(1, 10000000))
|
||||
|
||||
---@type df_chartmulti
|
||||
local chartFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
||||
|
||||
detailsFramework:Mixin(chartFrame, detailsFramework.ValueMixin)
|
||||
detailsFramework:Mixin(chartFrame, detailsFramework.MultiChartFrameMixin)
|
||||
detailsFramework:Mixin(chartFrame, detailsFramework.ChartFrameSharedMixin)
|
||||
|
||||
chartFrame:ValueConstructor()
|
||||
chartFrame:MultiChartFrameConstructor()
|
||||
|
||||
createPlotFrame(chartFrame) --creates chartFrame.plotFrame
|
||||
return chartFrame
|
||||
end
|
||||
@@ -0,0 +1,184 @@
|
||||
do
|
||||
|
||||
local DF = _G ["DetailsFramework"]
|
||||
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
DF.alias_text_colors = DF.alias_text_colors or {}
|
||||
|
||||
local defaultColors = {
|
||||
["HUNTER"] = {0.67, 0.83, 0.45},
|
||||
["WARLOCK"] = {0.58, 0.51, 0.79},
|
||||
["PRIEST"] = {1.0, 1.0, 1.0},
|
||||
["PALADIN"] = {0.96, 0.55, 0.73},
|
||||
["MAGE"] = {0.41, 0.8, 0.94},
|
||||
["ROGUE"] = {1.0, 0.96, 0.41},
|
||||
["DRUID"] = {1.0, 0.49, 0.04},
|
||||
["SHAMAN"] = {0.0, 0.44, 0.87},
|
||||
["WARRIOR"] = {0.78, 0.61, 0.43},
|
||||
["DEATHKNIGHT"] = {0.77, 0.12, 0.23},
|
||||
["MONK"] = {0.0, 1.00, 0.59},
|
||||
["DEMONHUNTER"] = {0.64, 0.19, 0.79},
|
||||
["EVOKER"] = {0.20, 0.58, 0.50},
|
||||
|
||||
["dark1"] = {0.1215, 0.1176, 0.1294},
|
||||
["dark2"] = {0.2215, 0.2176, 0.2294},
|
||||
["dark3"] = {0.3215, 0.3176, 0.3294},
|
||||
|
||||
["aliceblue"] = {0.941176, 0.972549, 1, 1},
|
||||
["antiquewhite"] = {0.980392, 0.921569, 0.843137, 1},
|
||||
["aqua"] = {0, 1, 1, 1},
|
||||
["aquamarine"] = {0.498039, 1, 0.831373, 1},
|
||||
["azure"] = {0.941176, 1, 1, 1},
|
||||
["beige"] = {0.960784, 0.960784, 0.862745, 1},
|
||||
["bisque"] = {1, 0.894118, 0.768627, 1},
|
||||
["black"] = {0, 0, 0, 1},
|
||||
["blanchedalmond"] = {1, 0.921569, 0.803922, 1},
|
||||
["blue"] = {0, 0, 1, 1},
|
||||
["blueviolet"] = {0.541176, 0.168627, 0.886275, 1},
|
||||
["brown"] = {0.647059, 0.164706, 0.164706, 1},
|
||||
["burlywood"] = {0.870588, 0.721569, 0.529412, 1},
|
||||
["cadetblue"] = {0.372549, 0.619608, 0.627451, 1},
|
||||
["chartreuse"] = {0.498039, 1, 0, 1},
|
||||
["chocolate"] = {0.823529, 0.411765, 0.117647, 1},
|
||||
["coral"] = {1, 0.498039, 0.313725, 1},
|
||||
["cornflowerblue"] = {0.392157, 0.584314, 0.929412, 1},
|
||||
["cornsilk"] = {1, 0.972549, 0.862745, 1},
|
||||
["crimson"] = {0.862745, 0.0784314, 0.235294, 1},
|
||||
["cyan"] = {0, 1, 1, 1},
|
||||
["darkblue"] = {0, 0, 0.545098, 1},
|
||||
["darkcyan"] = {0, 0.545098, 0.545098, 1},
|
||||
["darkgoldenrod"] = {0.721569, 0.52549, 0.0431373, 1},
|
||||
["darkgray"] = {0.662745, 0.662745, 0.662745, 1},
|
||||
["darkgreen"] = {0, 0.392157, 0, 1},
|
||||
["darkkhaki"] = {0.741176, 0.717647, 0.419608, 1},
|
||||
["darkmagenta"] = {0.545098, 0, 0.545098, 1},
|
||||
["darkolivegreen"] = {0.333333, 0.419608, 0.184314, 1},
|
||||
["darkorange"] = {1, 0.54902, 0, 1},
|
||||
["darkorchid"] = {0.6, 0.196078, 0.8, 1},
|
||||
["darkred"] = {0.545098, 0, 0, 1},
|
||||
["darksalmon"] = {0.913725, 0.588235, 0.478431, 1},
|
||||
["darkseagreen"] = {0.560784, 0.737255, 0.560784, 1},
|
||||
["darkslateblue"] = {0.282353, 0.239216, 0.545098, 1},
|
||||
["darkslategray"] = {0.184314, 0.309804, 0.309804, 1},
|
||||
["darkturquoise"] = {0, 0.807843, 0.819608, 1},
|
||||
["darkviolet"] = {0.580392, 0, 0.827451, 1},
|
||||
["deeppink"] = {1, 0.0784314, 0.576471, 1},
|
||||
["deepskyblue"] = {0, 0.74902, 1, 1},
|
||||
["dimgray"] = {0.411765, 0.411765, 0.411765, 1},
|
||||
["dimgrey"] = {0.411765, 0.411765, 0.411765, 1},
|
||||
["dodgerblue"] = {0.117647, 0.564706, 1, 1},
|
||||
["firebrick"] = {0.698039, 0.133333, 0.133333, 1},
|
||||
["firebrickdark"] = {0.258039, 0.033333, 0.033333, 1},
|
||||
["floralwhite"] = {1, 0.980392, 0.941176, 1},
|
||||
["forestgreen"] = {0.133333, 0.545098, 0.133333, 1},
|
||||
["fuchsia"] = {1, 0, 1, 1},
|
||||
["gainsboro"] = {0.862745, 0.862745, 0.862745, 1},
|
||||
["ghostwhite"] = {0.972549, 0.972549, 1, 1},
|
||||
["gold"] = {1, 0.843137, 0, 1},
|
||||
["goldenrod"] = {0.854902, 0.647059, 0.12549, 1},
|
||||
["gray"] = {0.501961, 0.501961, 0.501961, 1},
|
||||
["green"] = {0, 0.501961, 0, 1},
|
||||
["greenyellow"] = {0.678431, 1, 0.184314, 1},
|
||||
["honeydew"] = {0.941176, 1, 0.941176, 1},
|
||||
["hotpink"] = {1, 0.411765, 0.705882, 1},
|
||||
["indianred"] = {0.803922, 0.360784, 0.360784, 1},
|
||||
["indigo"] = {0.294118, 0, 0.509804, 1},
|
||||
["ivory"] = {1, 1, 0.941176, 1},
|
||||
["khaki"] = {0.941176, 0.901961, 0.54902, 1},
|
||||
["lavender"] = {0.901961, 0.901961, 0.980392, 1},
|
||||
["lavenderblush"] = {1, 0.941176, 0.960784, 1},
|
||||
["lawngreen"] = {0.486275, 0.988235, 0, 1},
|
||||
["lemonchiffon"] = {1, 0.980392, 0.803922, 1},
|
||||
["lightblue"] = {0.678431, 0.847059, 0.901961, 1},
|
||||
["lightcoral"] = {0.941176, 0.501961, 0.501961, 1},
|
||||
["lightcyan"] = {0.878431, 1, 1, 1},
|
||||
["lightgoldenrodyellow"] = {0.980392, 0.980392, 0.823529, 1},
|
||||
["lightgray"] = {0.827451, 0.827451, 0.827451, 1},
|
||||
["lightgreen"] = {0.564706, 0.933333, 0.564706, 1},
|
||||
["lightpink"] = {1, 0.713725, 0.756863, 1},
|
||||
["lightsalmon"] = {1, 0.627451, 0.478431, 1},
|
||||
["lightseagreen"] = {0.12549, 0.698039, 0.666667, 1},
|
||||
["lightskyblue"] = {0.529412, 0.807843, 0.980392, 1},
|
||||
["lightslategray"] = {0.466667, 0.533333, 0.6, 1},
|
||||
["lightsteelblue"] = {0.690196, 0.768627, 0.870588, 1},
|
||||
["lightyellow"] = {1, 1, 0.878431, 1},
|
||||
["lime"] = {0, 1, 0, 1},
|
||||
["limegreen"] = {0.196078, 0.803922, 0.196078, 1},
|
||||
["linen"] = {0.980392, 0.941176, 0.901961, 1},
|
||||
["magenta"] = {1, 0, 1, 1},
|
||||
["maroon"] = {0.501961, 0, 0, 1},
|
||||
["mediumaquamarine"] = {0.4, 0.803922, 0.666667, 1},
|
||||
["mediumblue"] = {0, 0, 0.803922, 1},
|
||||
["mediumorchid"] = {0.729412, 0.333333, 0.827451, 1},
|
||||
["mediumpurple"] = {0.576471, 0.439216, 0.858824, 1},
|
||||
["mediumseagreen"] = {0.235294, 0.701961, 0.443137, 1},
|
||||
["mediumslateblue"] = {0.482353, 0.407843, 0.933333, 1},
|
||||
["mediumspringgreen"] = {0, 0.980392, 0.603922, 1},
|
||||
["mediumturquoise"] = {0.282353, 0.819608, 0.8, 1},
|
||||
["mediumvioletred"] = {0.780392, 0.0823529, 0.521569, 1},
|
||||
["midnightblue"] = {0.0980392, 0.0980392, 0.439216, 1},
|
||||
["mintcream"] = {0.960784, 1, 0.980392, 1},
|
||||
["mistyrose"] = {1, 0.894118, 0.882353, 1},
|
||||
["moccasin"] = {1, 0.894118, 0.709804, 1},
|
||||
["navajowhite"] = {1, 0.870588, 0.678431, 1},
|
||||
["navy"] = {0, 0, 0.501961, 1},
|
||||
["none"] ={0, 0, 0, 0},
|
||||
["oldlace"] = {0.992157, 0.960784, 0.901961, 1},
|
||||
["olive"] = {0.501961, 0.501961, 0, 1},
|
||||
["olivedrab"] = {0.419608, 0.556863, 0.137255, 1},
|
||||
["orange"] = {1, 0.647059, 0, 1},
|
||||
["orangered"] = {1, 0.270588, 0, 1},
|
||||
["orchid"] = {0.854902, 0.439216, 0.839216, 1},
|
||||
["palegoldenrod"] = {0.933333, 0.909804, 0.666667, 1},
|
||||
["palegreen"] = {0.596078, 0.984314, 0.596078, 1},
|
||||
["paleturquoise"] = {0.686275, 0.933333, 0.933333, 1},
|
||||
["palevioletred"] = {0.858824, 0.439216, 0.576471, 1},
|
||||
["papayawhip"] = {1, 0.937255, 0.835294, 1},
|
||||
["peachpuff"] = {1, 0.854902, 0.72549, 1},
|
||||
["peru"] = {0.803922, 0.521569, 0.247059, 1},
|
||||
["pink"] = {1, 0.752941, 0.796078, 1},
|
||||
["plum"] = {0.866667, 0.627451, 0.866667, 1},
|
||||
["powderblue"] = {0.690196, 0.878431, 0.901961, 1},
|
||||
["purple"] = {0.501961, 0, 0.501961, 1},
|
||||
["red"] = {1, 0, 0, 1},
|
||||
["rosybrown"] = {0.737255, 0.560784, 0.560784, 1},
|
||||
["royalblue"] = {0.254902, 0.411765, 0.882353, 1},
|
||||
["saddlebrown"] = {0.545098, 0.270588, 0.0745098, 1},
|
||||
["salmon"] = {0.980392, 0.501961, 0.447059, 1},
|
||||
["sandybrown"] = {0.956863, 0.643137, 0.376471, 1},
|
||||
["seagreen"] = {0.180392, 0.545098, 0.341176, 1},
|
||||
["seashell"] = {1, 0.960784, 0.933333, 1},
|
||||
["sienna"] = {0.627451, 0.321569, 0.176471, 1},
|
||||
["silver"] = {0.752941, 0.752941, 0.752941, 1},
|
||||
["skyblue"] = {0.529412, 0.807843, 0.921569, 1},
|
||||
["slateblue"] = {0.415686, 0.352941, 0.803922, 1},
|
||||
["slategray"] = {0.439216, 0.501961, 0.564706, 1},
|
||||
["snow"] = {1, 0.980392, 0.980392, 1},
|
||||
["springgreen"] = {0, 1, 0.498039, 1},
|
||||
["steelblue"] = {0.27451, 0.509804, 0.705882, 1},
|
||||
["tan"] = {0.823529, 0.705882, 0.54902, 1},
|
||||
["teal"] = {0, 0.501961, 0.501961, 1},
|
||||
["thistle"] = {0.847059, 0.74902, 0.847059, 1},
|
||||
["tomato"] = {1, 0.388235, 0.278431, 1},
|
||||
["transparent"] ={0, 0, 0, 0},
|
||||
["turquoise"] = {0.25098, 0.878431, 0.815686, 1},
|
||||
["violet"] = {0.933333, 0.509804, 0.933333, 1},
|
||||
["wheat"] = {0.960784, 0.870588, 0.701961, 1},
|
||||
["white"] = {1, 1, 1, 1},
|
||||
["whitesmoke"] = {0.960784, 0.960784, 0.960784, 1},
|
||||
["yellow"] = {1, 1, 0, 1},
|
||||
["yellowgreen"] = {0.603922, 0.803922, 0.196078, 1}
|
||||
}
|
||||
|
||||
function DF:GetDefaultColorList()
|
||||
return defaultColors
|
||||
end
|
||||
|
||||
for colorName, colorTable in pairs(defaultColors) do
|
||||
DF.alias_text_colors [colorName] = colorTable
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,565 @@
|
||||
|
||||
local detailsFramework = _G ["DetailsFramework"]
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local _
|
||||
local DF = detailsFramework
|
||||
|
||||
local CreateFrame = CreateFrame
|
||||
local wipe = wipe
|
||||
local unpack = unpack
|
||||
|
||||
---@class df_framecontainer : frame, dfframecontainermixin, df_optionsmixin
|
||||
---@field bIsSizing boolean
|
||||
---@field options table
|
||||
---@field currentWidth number
|
||||
---@field currentHeight number
|
||||
---@field bottomLeftResizer framecontainerresizer
|
||||
---@field bottomRightResizer framecontainerresizer
|
||||
---@field topLeftResizer framecontainerresizer
|
||||
---@field topRightResizer framecontainerresizer
|
||||
---@field topResizer framecontainerresizer
|
||||
---@field bottomResizer framecontainerresizer
|
||||
---@field leftResizer framecontainerresizer
|
||||
---@field rightResizer framecontainerresizer
|
||||
---@field cornerResizers framecontainerresizer[]
|
||||
---@field sideResizers framecontainerresizer[]
|
||||
---@field components table<frame, boolean>
|
||||
---@field moverFrame frame
|
||||
---@field movableChildren table<frame, boolean>
|
||||
---@field settingChangedCallback fun(frameContainer: df_framecontainer, settingName: string, settingValue: any)
|
||||
---@field OnSizeChanged fun(frameContainer: df_framecontainer)
|
||||
---@field OnResizerMouseDown fun(resizerButton: button, mouseButton: string)
|
||||
---@field OnResizerMouseUp fun(resizerButton: button, mouseButton: string)
|
||||
---@field HideResizer fun(frameContainer: df_framecontainer)
|
||||
---@field ShowResizer fun(frameContainer: df_framecontainer)
|
||||
---@field OnInitialize fun(frameContainer: df_framecontainer)
|
||||
---@field SetResizeLocked fun(frameContainer: df_framecontainer, isLocked: boolean)
|
||||
---@field SetMovableLocked fun(frameContainer: df_framecontainer, isLocked: boolean)
|
||||
---@field CheckResizeLockedState fun(frameContainer: df_framecontainer)
|
||||
---@field CheckMovableLockedState fun(frameContainer: df_framecontainer)
|
||||
---@field CreateMover fun(frameContainer: df_framecontainer)
|
||||
---@field CreateResizers fun(frameContainer: df_framecontainer)
|
||||
---@field RegisterChildForDrag fun(frameContainer: df_framecontainer, child: frame)
|
||||
---@field UnregisterChildForDrag fun(frameContainer: df_framecontainer, child: frame)
|
||||
---@field RefreshChildrenState fun(frameContainer: df_framecontainer)
|
||||
---@field OnChildDragStart fun(frameContainer: df_framecontainer, child: frame)
|
||||
---@field OnChildDragStop fun(frameContainer: df_framecontainer, child: frame)
|
||||
---@field SetSettingChangedCallback fun(frameContainer: df_framecontainer, callback: fun(frameContainer: df_framecontainer, settingName: string, settingValue: any))
|
||||
---@field SendSettingChangedCallback fun(frameContainer: df_framecontainer, settingName: string, settingValue: any)
|
||||
|
||||
|
||||
|
||||
---@class framecontainerresizer : button
|
||||
---@field sizingFrom string
|
||||
|
||||
---@class dfframecontainermixin
|
||||
detailsFramework.FrameContainerMixin = {
|
||||
--methods
|
||||
|
||||
---run when the user click on the resizer
|
||||
---@param resizerButton framecontainerresizer
|
||||
---@param mouseButton string
|
||||
OnResizerMouseDown = function(resizerButton, mouseButton)
|
||||
if (mouseButton ~= "LeftButton") then
|
||||
return
|
||||
end
|
||||
|
||||
---@type df_framecontainer
|
||||
local frameContainer = resizerButton:GetParent() --Cannot assign `frame` to `df_framecontainer`. .. but df_framecontainer is inherited from frame
|
||||
|
||||
if (frameContainer.bIsSizing) then
|
||||
return
|
||||
end
|
||||
|
||||
frameContainer.bIsSizing = true
|
||||
frameContainer:StartSizing(resizerButton.sizingFrom)
|
||||
end,
|
||||
|
||||
---run when the user click on the resizer
|
||||
---@param resizerButton framecontainerresizer
|
||||
---@param mouseButton string
|
||||
OnResizerMouseUp = function(resizerButton, mouseButton)
|
||||
---@type df_framecontainer
|
||||
local frameContainer = resizerButton:GetParent() --Cannot assign `frame` to `df_framecontainer`. .. but df_framecontainer is inherited from frame
|
||||
|
||||
if (not frameContainer.bIsSizing) then
|
||||
return
|
||||
end
|
||||
|
||||
frameContainer:StopMovingOrSizing()
|
||||
frameContainer.bIsSizing = false
|
||||
end,
|
||||
|
||||
---hide resizer
|
||||
---@param frameContainer df_framecontainer
|
||||
HideResizer = function(frameContainer)
|
||||
for i = 1, #frameContainer.cornerResizers do
|
||||
frameContainer.cornerResizers[i]:Hide()
|
||||
end
|
||||
|
||||
for i = 1, #frameContainer.sideResizers do
|
||||
frameContainer.sideResizers[i]:Hide()
|
||||
end
|
||||
end,
|
||||
|
||||
---show resizer
|
||||
---@param frameContainer df_framecontainer
|
||||
ShowResizer = function(frameContainer)
|
||||
--corner resizers
|
||||
if (frameContainer.options.use_bottomleft_resizer) then
|
||||
frameContainer.bottomLeftResizer:Show()
|
||||
end
|
||||
if (frameContainer.options.use_bottomright_resizer) then
|
||||
frameContainer.bottomRightResizer:Show()
|
||||
end
|
||||
if (frameContainer.options.use_topleft_resizer) then
|
||||
frameContainer.topRightResizer:Show()
|
||||
end
|
||||
if (frameContainer.options.use_topright_resizer) then
|
||||
frameContainer.topRightResizer:Show()
|
||||
end
|
||||
|
||||
--side resizers
|
||||
if (frameContainer.options.use_top_resizer) then
|
||||
frameContainer.topResizer:Show()
|
||||
end
|
||||
if (frameContainer.options.use_bottom_resizer) then
|
||||
frameContainer.bottomResizer:Show()
|
||||
end
|
||||
if (frameContainer.options.use_left_resizer) then
|
||||
frameContainer.leftResizer:Show()
|
||||
end
|
||||
if (frameContainer.options.use_right_resizer) then
|
||||
frameContainer.rightResizer:Show()
|
||||
end
|
||||
end,
|
||||
|
||||
---check the lock state and show or hide the resizer, set the frame as movable or not, resizeable or not
|
||||
---@param frameContainer df_framecontainer
|
||||
CheckResizeLockedState = function(frameContainer)
|
||||
if (frameContainer.options.is_locked) then
|
||||
frameContainer:HideResizer()
|
||||
frameContainer:SetResizable(false)
|
||||
else
|
||||
frameContainer:ShowResizer()
|
||||
frameContainer:SetResizable(true)
|
||||
end
|
||||
end,
|
||||
|
||||
---check if the framecontainer can be moved and show or hide the mover
|
||||
---@param frameContainer df_framecontainer
|
||||
CheckMovableLockedState = function(frameContainer)
|
||||
if (frameContainer.options.is_movement_locked) then
|
||||
frameContainer:SetMovable(false)
|
||||
frameContainer:EnableMouse(false)
|
||||
frameContainer.moverFrame:Hide()
|
||||
else
|
||||
frameContainer:SetMovable(true)
|
||||
frameContainer:EnableMouse(true)
|
||||
frameContainer.moverFrame:Show()
|
||||
end
|
||||
end,
|
||||
|
||||
---set the lock state
|
||||
---@param frameContainer df_framecontainer
|
||||
---@param isLocked boolean
|
||||
SetResizeLocked = function(frameContainer, isLocked)
|
||||
frameContainer.options.is_locked = isLocked
|
||||
frameContainer:SendSettingChangedCallback("is_locked", isLocked)
|
||||
frameContainer:CheckResizeLockedState()
|
||||
end,
|
||||
|
||||
---set the state of the mover frame
|
||||
---@param frameContainer df_framecontainer
|
||||
---@param isLocked boolean
|
||||
SetMovableLocked = function(frameContainer, isLocked)
|
||||
frameContainer.options.is_movement_locked = isLocked
|
||||
frameContainer:SendSettingChangedCallback("is_movement_locked", isLocked)
|
||||
frameContainer:CheckMovableLockedState()
|
||||
end,
|
||||
|
||||
---create a mover to move the frame
|
||||
---@param frameContainer df_framecontainer
|
||||
CreateMover = function(frameContainer)
|
||||
local mover = CreateFrame("button", nil, frameContainer)
|
||||
frameContainer.moverFrame = mover
|
||||
mover:SetAllPoints(frameContainer)
|
||||
mover:EnableMouse(false)
|
||||
mover:SetMovable(true)
|
||||
mover:SetScript("OnMouseDown", function(self, mouseButton)
|
||||
if (mouseButton ~= "LeftButton" or frameContainer.options.is_movement_locked) then
|
||||
return
|
||||
end
|
||||
frameContainer:StartMoving()
|
||||
end)
|
||||
mover:SetScript("OnMouseUp", function(self, mouseButton)
|
||||
if (mouseButton ~= "LeftButton" or frameContainer.options.is_movement_locked) then
|
||||
return
|
||||
end
|
||||
frameContainer:StopMovingOrSizing()
|
||||
end)
|
||||
end,
|
||||
|
||||
---create four corner resizer and four side resizer
|
||||
---@param frameContainer df_framecontainer
|
||||
CreateResizers = function(frameContainer)
|
||||
local parent = frameContainer:GetParent()
|
||||
--create resizers for the container corners
|
||||
local bottomLeftResizer, bottomRightResizer = detailsFramework:CreateResizeGrips(frameContainer, nil, parent:GetName() .. "BottomLeftResizer", parent:GetName() .. "BottomRightResizer")
|
||||
frameContainer.bottomLeftResizer = bottomLeftResizer
|
||||
frameContainer.bottomRightResizer = bottomRightResizer
|
||||
|
||||
local topLeftResizer, topRightResizer = detailsFramework:CreateResizeGrips(frameContainer, nil, parent:GetName() .. "TopLeftResizer", parent:GetName() .. "TopRightResizer")
|
||||
frameContainer.topLeftResizer = topLeftResizer
|
||||
frameContainer.topRightResizer = topRightResizer
|
||||
|
||||
local topResizer, bottomResizer = detailsFramework:CreateResizeGrips(frameContainer, nil, parent:GetName() .. "TopResizer", parent:GetName() .. "BottomResizer")
|
||||
frameContainer.topResizer = topResizer
|
||||
frameContainer.bottomResizer = bottomResizer
|
||||
|
||||
local leftResizer, rightResizer = detailsFramework:CreateResizeGrips(frameContainer, nil, parent:GetName() .. "LeftResizer", parent:GetName() .. "RightResizer")
|
||||
frameContainer.leftResizer = leftResizer
|
||||
frameContainer.rightResizer = rightResizer
|
||||
|
||||
frameContainer.cornerResizers = {
|
||||
bottomLeftResizer,
|
||||
bottomRightResizer,
|
||||
topLeftResizer,
|
||||
topRightResizer,
|
||||
}
|
||||
|
||||
frameContainer.sideResizers = {
|
||||
topResizer,
|
||||
bottomResizer,
|
||||
leftResizer,
|
||||
rightResizer,
|
||||
}
|
||||
|
||||
--add all resizers to the frameContainer.components table
|
||||
for i = 1, #frameContainer.cornerResizers do
|
||||
frameContainer.components[frameContainer.cornerResizers[i]] = true
|
||||
end
|
||||
for i = 1, #frameContainer.sideResizers do
|
||||
frameContainer.components[frameContainer.sideResizers[i]] = true
|
||||
end
|
||||
|
||||
--hide all resizers
|
||||
frameContainer:HideResizer()
|
||||
end,
|
||||
|
||||
---run when the container is created
|
||||
---@param frameContainer df_framecontainer
|
||||
OnInitialize = function(frameContainer) --õninit ~init ~oninit
|
||||
--set the default members
|
||||
frameContainer.bIsSizing = false
|
||||
frameContainer:SetSize(frameContainer.options.width, frameContainer.options.height)
|
||||
|
||||
--iterate among the corner resizers and set the mouse down and up scripts
|
||||
for i = 1, #frameContainer.cornerResizers do
|
||||
frameContainer.cornerResizers[i]:SetScript("OnMouseDown", frameContainer.OnResizerMouseDown)
|
||||
frameContainer.cornerResizers[i]:SetScript("OnMouseUp", frameContainer.OnResizerMouseUp)
|
||||
end
|
||||
|
||||
local sideResizeThickness = 2
|
||||
|
||||
--iterate among the side resizers and set the mouse down and up scripts; set the texture color; clear all points; set the thickness
|
||||
for i = 1, #frameContainer.sideResizers do
|
||||
frameContainer.sideResizers[i]:SetScript("OnMouseDown", frameContainer.OnResizerMouseDown)
|
||||
frameContainer.sideResizers[i]:SetScript("OnMouseUp", frameContainer.OnResizerMouseUp)
|
||||
|
||||
frameContainer.sideResizers[i]:GetNormalTexture():SetColorTexture(1, 1, 1, 0.6)
|
||||
frameContainer.sideResizers[i]:GetHighlightTexture():SetColorTexture(detailsFramework:ParseColors("aqua"))
|
||||
frameContainer.sideResizers[i]:GetPushedTexture():SetColorTexture(1, 1, 1, 1)
|
||||
|
||||
frameContainer.sideResizers[i]:ClearAllPoints()
|
||||
|
||||
--can use SetSize here because the width or height are set by the point, e.g. 'topleft' to 'topright' overwrite the width set here
|
||||
frameContainer.sideResizers[i]:SetSize(sideResizeThickness, sideResizeThickness)
|
||||
end
|
||||
|
||||
--flip the corner resizers texturess
|
||||
frameContainer.topLeftResizer:GetNormalTexture():SetTexCoord(1, 0, 1, 0)
|
||||
frameContainer.topLeftResizer:GetHighlightTexture():SetTexCoord(1, 0, 1, 0)
|
||||
frameContainer.topLeftResizer:GetPushedTexture():SetTexCoord(1, 0, 1, 0)
|
||||
frameContainer.topRightResizer:GetNormalTexture():SetTexCoord(0, 1, 1, 0)
|
||||
frameContainer.topRightResizer:GetHighlightTexture():SetTexCoord(0, 1, 1, 0)
|
||||
frameContainer.topRightResizer:GetPushedTexture():SetTexCoord(0, 1, 1, 0)
|
||||
frameContainer.topLeftResizer:ClearAllPoints()
|
||||
frameContainer.topLeftResizer:SetPoint("topleft", frameContainer, "topleft", 0, 0)
|
||||
frameContainer.topRightResizer:ClearAllPoints()
|
||||
frameContainer.topRightResizer:SetPoint("topright", frameContainer, "topright", 0, 0)
|
||||
|
||||
--resize from for the corner resizers
|
||||
frameContainer.bottomLeftResizer.sizingFrom = "bottomleft"
|
||||
frameContainer.bottomRightResizer.sizingFrom = "bottomright"
|
||||
frameContainer.topLeftResizer.sizingFrom = "topleft"
|
||||
frameContainer.topRightResizer.sizingFrom = "topright"
|
||||
|
||||
--resize from for the side resizers
|
||||
frameContainer.topResizer.sizingFrom = "top"
|
||||
frameContainer.bottomResizer.sizingFrom = "bottom"
|
||||
frameContainer.leftResizer.sizingFrom = "left"
|
||||
frameContainer.rightResizer.sizingFrom = "right"
|
||||
|
||||
--set the side resizer points
|
||||
frameContainer.topResizer:SetPoint("topleft", frameContainer, "topleft", 0, 2)
|
||||
frameContainer.topResizer:SetPoint("topright", frameContainer, "topright", 0, 2)
|
||||
frameContainer.bottomResizer:SetPoint("bottomleft", frameContainer, "bottomleft", 0, -2)
|
||||
frameContainer.bottomResizer:SetPoint("bottomright", frameContainer, "bottomright", 0, -2)
|
||||
frameContainer.leftResizer:SetPoint("topleft", frameContainer, "topleft", -2, 0)
|
||||
frameContainer.leftResizer:SetPoint("bottomleft", frameContainer, "bottomleft", -2, 0)
|
||||
frameContainer.rightResizer:SetPoint("topright", frameContainer, "topright", 2, 0)
|
||||
frameContainer.rightResizer:SetPoint("bottomright", frameContainer, "bottomright", 2, 0)
|
||||
|
||||
if (frameContainer.options.is_locked) then
|
||||
frameContainer:HideResizer()
|
||||
else
|
||||
frameContainer:ShowResizer()
|
||||
end
|
||||
|
||||
frameContainer:CheckResizeLockedState()
|
||||
frameContainer:CheckMovableLockedState()
|
||||
|
||||
if (frameContainer.SetMinResize) then --old versions of the game uses this method
|
||||
frameContainer:SetMinResize(50, 50)
|
||||
frameContainer:SetMaxResize(1000,1000)
|
||||
else
|
||||
frameContainer:SetResizeBounds(50, 50, 1000, 1000) --new versions has this method
|
||||
end
|
||||
end,
|
||||
|
||||
---run when the container has its size changed
|
||||
---@param frameContainer df_framecontainer
|
||||
OnSizeChanged = function(frameContainer)
|
||||
---@type frame[]
|
||||
local children = {frameContainer:GetChildren()}
|
||||
---@type number
|
||||
local childrenAmount = #children
|
||||
|
||||
--get the container size before its size was changed and calculate the percent of the difference between the old size and the new size
|
||||
--adding +1 to the width and height difference to prevent the child from shrinking to 0, so it is scaled by 1
|
||||
---@type number
|
||||
local widthDifference = 1 + (frameContainer:GetWidth() - frameContainer.currentWidth) / frameContainer.currentWidth
|
||||
---@type number
|
||||
local heightDifference = 1 + (frameContainer:GetHeight() - frameContainer.currentHeight) / frameContainer.currentHeight
|
||||
|
||||
for i = 1, childrenAmount do
|
||||
---@type frame
|
||||
local child = children[i]
|
||||
--if the child is a component, skip it
|
||||
if (not frameContainer.components[child]) then
|
||||
child:SetWidth(child:GetWidth() * widthDifference)
|
||||
child:SetHeight(child:GetHeight() * heightDifference)
|
||||
end
|
||||
end
|
||||
|
||||
--update the current size of the container
|
||||
frameContainer.currentWidth = frameContainer:GetWidth()
|
||||
frameContainer.currentHeight = frameContainer:GetHeight()
|
||||
|
||||
frameContainer:SendSettingChangedCallback("width", frameContainer.currentWidth)
|
||||
frameContainer:SendSettingChangedCallback("height", frameContainer.currentHeight)
|
||||
end,
|
||||
|
||||
OnChildDragStop = function(child)
|
||||
child:StopMovingOrSizing()
|
||||
child:SetScript("OnUpdate", nil)
|
||||
end,
|
||||
|
||||
---@param child frame
|
||||
OnChildDragStart = function(child)
|
||||
---@type df_framecontainer
|
||||
local frameContainer = child:GetParent()
|
||||
|
||||
---get the coordinates for the frame container, which is called 'boundingBox' for convenience
|
||||
---@type objectcoordinates
|
||||
local boundingBox = detailsFramework:GetObjectCoordinates(frameContainer)
|
||||
|
||||
child:StartMoving()
|
||||
|
||||
--save the current point of the child, so it can be restored if the child is dragged outside the container
|
||||
local childPoints = {}
|
||||
for pointIndex = 1, child:GetNumPoints() do
|
||||
childPoints[pointIndex] = {child:GetPoint(pointIndex)}
|
||||
end
|
||||
|
||||
child:SetScript("OnUpdate", function(self)
|
||||
---@type objectcoordinates
|
||||
local childPos = detailsFramework:GetObjectCoordinates(self)
|
||||
--check if the borders of the rectangle 'rec' collided with the borders of the rectangle 'bbox'
|
||||
if ((childPos.left < boundingBox.left or childPos.right > boundingBox.right) or (childPos.top > boundingBox.top or childPos.bottom < boundingBox.bottom)) then
|
||||
child:ClearAllPoints()
|
||||
for pointIndex = 1, #childPoints do
|
||||
child:SetPoint(unpack(childPoints[pointIndex]))
|
||||
end
|
||||
else
|
||||
wipe(childPoints)
|
||||
for pointIndex = 1, child:GetNumPoints() do
|
||||
childPoints[pointIndex] = {child:GetPoint(pointIndex)}
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
|
||||
---check if the children can be moved and set the properties on thisFrame
|
||||
---@param frameContainer df_framecontainer
|
||||
RefreshChildrenState = function(frameContainer)
|
||||
frameContainer:EnableMouse(true)
|
||||
if (frameContainer.options.can_move_children) then
|
||||
for child, _ in pairs(frameContainer.movableChildren) do
|
||||
child:EnableMouse(true)
|
||||
child:SetMovable(true)
|
||||
child:RegisterForDrag("LeftButton")
|
||||
child:SetScript("OnDragStart", detailsFramework.FrameContainerMixin.OnChildDragStart)
|
||||
child:SetScript("OnDragStop", detailsFramework.FrameContainerMixin.OnChildDragStop)
|
||||
end
|
||||
else
|
||||
for child, _ in pairs(frameContainer.movableChildren) do
|
||||
child:EnableMouse(false)
|
||||
child:SetMovable(false)
|
||||
child:RegisterForDrag("")
|
||||
child:SetScript("OnDragStart", nil)
|
||||
child:SetScript("OnDragStop", nil)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
---@param frameContainer df_framecontainer
|
||||
---@param child frame
|
||||
RegisterChildForDrag = function(frameContainer, child)
|
||||
frameContainer.movableChildren[child] = true
|
||||
frameContainer:RefreshChildrenState()
|
||||
child:SetFrameStrata(frameContainer:GetFrameStrata())
|
||||
child:SetFrameLevel(frameContainer:GetFrameLevel() + 1)
|
||||
end,
|
||||
|
||||
---@param frameContainer df_framecontainer
|
||||
---@param child frame
|
||||
UnregisterChildForDrag = function(frameContainer, child)
|
||||
frameContainer.movableChildren[child] = nil
|
||||
frameContainer:RefreshChildrenState()
|
||||
end,
|
||||
|
||||
---@param frameContainer df_framecontainer
|
||||
---@param callback function
|
||||
SetSettingChangedCallback = function(frameContainer, callback)
|
||||
frameContainer.settingChangedCallback = callback
|
||||
end,
|
||||
|
||||
---send a callback to the setting changed callback
|
||||
---@param frameContainer df_framecontainer
|
||||
---@param key string
|
||||
---@param value any
|
||||
SendSettingChangedCallback = function(frameContainer, key, value)
|
||||
if (type(frameContainer.settingChangedCallback) == "function") then
|
||||
detailsFramework:Dispatch(frameContainer.settingChangedCallback, frameContainer, key, value)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
---these are the default settings for the frame container; these keys can be accessed by df_framecontainer.options[key]
|
||||
---@type table<string, any>
|
||||
local frameContainerOptions = {
|
||||
--default settings
|
||||
width = 300,
|
||||
height = 150,
|
||||
is_locked = true, --can or not be resized
|
||||
is_movement_locked = true, --can or not be moved
|
||||
can_move_children = true,
|
||||
use_topleft_resizer = false,
|
||||
use_topright_resizer = false,
|
||||
use_bottomleft_resizer = false,
|
||||
use_bottomright_resizer = false,
|
||||
use_top_resizer = false,
|
||||
use_bottom_resizer = false,
|
||||
use_left_resizer = false,
|
||||
use_right_resizer = false,
|
||||
}
|
||||
|
||||
---create a frame container, which is a frame that envelops another frame, and can be moved, resized, etc.
|
||||
---@param parent frame
|
||||
---@param options table|nil
|
||||
---@param frameName string|nil
|
||||
---@return df_framecontainer
|
||||
function DF:CreateFrameContainer(parent, options, frameName)
|
||||
---@type df_framecontainer
|
||||
local frameContainer = CreateFrame("frame", frameName or ("$parentFrameContainer" .. math.random(10000, 99999)), parent, "BackdropTemplate")
|
||||
frameContainer.components = {}
|
||||
frameContainer.movableChildren = {}
|
||||
frameContainer:EnableMouse(false)
|
||||
|
||||
detailsFramework:Mixin(frameContainer, detailsFramework.FrameContainerMixin)
|
||||
detailsFramework:Mixin(frameContainer, detailsFramework.OptionsFunctions)
|
||||
|
||||
frameContainer:CreateResizers()
|
||||
frameContainer:CreateMover()
|
||||
frameContainer:BuildOptionsTable(frameContainerOptions, options)
|
||||
|
||||
frameContainer:OnInitialize()
|
||||
|
||||
frameContainer.currentWidth = frameContainer:GetWidth()
|
||||
frameContainer.currentHeight = frameContainer:GetHeight()
|
||||
frameContainer:SetScript("OnSizeChanged", frameContainer.OnSizeChanged)
|
||||
|
||||
return frameContainer
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function DF:CreateFrameContainerTest(parent, options, frameName)
|
||||
local container = DF:CreateFrameContainer(parent, options, frameName)
|
||||
container:SetSize(400, 400)
|
||||
container:SetPoint("center", _G.UIParent, "center", 0, 0)
|
||||
|
||||
detailsFramework:ApplyStandardBackdrop(container)
|
||||
|
||||
local verticalLastBox = nil
|
||||
for i = 1, 4 do
|
||||
local lastBox = nil
|
||||
for o = 1, 4 do
|
||||
local frame = CreateFrame("frame", "$parentFrame" .. i .. o, container, "BackdropTemplate")
|
||||
container:RegisterChildForDrag(frame)
|
||||
|
||||
frame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||
frame:SetBackdropColor(0, 0, 0, 0.5)
|
||||
frame:SetBackdropBorderColor(1, 1, 1, 0.5)
|
||||
frame:SetSize(98, 98)
|
||||
if (lastBox) then
|
||||
frame:SetPoint("TOPLEFT", lastBox, "topright", 1, 0)
|
||||
else
|
||||
if (verticalLastBox) then
|
||||
frame:SetPoint("TOPLEFT", verticalLastBox, "bottomleft", 0, -1)
|
||||
verticalLastBox = frame
|
||||
else
|
||||
local x = 1 + (o - 1) * 99
|
||||
local y = -10 - (i - 1) * 99
|
||||
frame:SetPoint("TOPLEFT", container, "TOPLEFT", x, y)
|
||||
verticalLastBox = frame
|
||||
end
|
||||
end
|
||||
lastBox = frame
|
||||
end
|
||||
end
|
||||
|
||||
C_Timer.After(2, function()
|
||||
--container:SetResizeLocked(true)
|
||||
end)
|
||||
end
|
||||
|
||||
--C_Timer.After(2, function()
|
||||
-- DetailsFramework:CreateFrameContainerTest(UIParent)
|
||||
--end)
|
||||
|
||||
--[=[
|
||||
/run DetailsFramework:CreateFrameContainerTest(UIParent)
|
||||
|
||||
C_Timer.After(2, function()
|
||||
DetailsFramework:CreateFrameContainerTest(UIParent)
|
||||
end)
|
||||
|
||||
|
||||
--]=]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ .. \FrameXML\UI.xsd">
|
||||
|
||||
<Script file="cooltip.lua"/>
|
||||
|
||||
</Ui>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ .. \FrameXML\UI.xsd">
|
||||
<Script file="dropdown.lua"/>
|
||||
</Ui>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
|
||||
<Script file="Libs\LibStub\LibStub.lua"/>
|
||||
<Include file="Libs\CallbackHandler-1.0\CallbackHandler-1.0.lua"/>
|
||||
<Include file="Libs\LibSharedMedia-3.0\lib.xml"/>
|
||||
<Include file="Libs\AceGUI-3.0\AceGUI-3.0.xml"/>
|
||||
<Include file="Libs\AceDBOptions-3.0\AceDBOptions-3.0.xml"/>
|
||||
<Include file="Libs\AceLocale-3.0\AceLocale-3.0.xml" />
|
||||
<Include file="Libs\AceAddon-3.0\AceAddon-3.0.xml" />
|
||||
<Include file="Libs\AceDB-3.0\AceDB-3.0.xml" />
|
||||
<Include file="Libs\AceTimer-3.0\AceTimer-3.0.xml" />
|
||||
<Include file="Libs\AceConfig-3.0\AceConfig-3.0.xml"/>
|
||||
<Include file="Libs\AceEvent-3.0\AceEvent-3.0.xml"/>
|
||||
<Include file="Libs\AceComm-3.0\AceComm-3.0.xml" />
|
||||
<Include file="Libs\AceConsole-3.0\AceConsole-3.0.xml"/>
|
||||
<Include file="Libs\AceSerializer-3.0\AceSerializer-3.0.xml"/>
|
||||
<Script file="Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua"/>
|
||||
<Script file="Libs\LibDBIcon-1.0\LibDBIcon-1.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,116 @@
|
||||
local detailsFramework = _G ["DetailsFramework"]
|
||||
if (not detailsFramework) then
|
||||
return
|
||||
end
|
||||
|
||||
local IS_WOW_PROJECT_MAINLINE = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE
|
||||
local IS_WOW_PROJECT_NOT_MAINLINE = WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE
|
||||
local IS_WOW_PROJECT_CLASSIC_ERA = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC
|
||||
|
||||
detailsFramework.CastInfo = detailsFramework.CastInfo or {}
|
||||
|
||||
--NOTE: This NEEDs a chance to run, as Plater is depending on this working and LibCC is not bundled neccessarily in other addons.
|
||||
-- for classic era use LibClassicCasterino:
|
||||
|
||||
--in vanilla wow, other addons might load the framework before an addon with libCasterino loads
|
||||
--check here if libCasterino is loaded, if is, check if the framework is already using libCasterino, if not, make it use
|
||||
function detailsFramework:LoadLCC(LibCC)
|
||||
local fCast = CreateFrame("frame")
|
||||
|
||||
local getCastBar = function(unitId)
|
||||
local plateFrame = C_NamePlate.GetNamePlateForUnit (unitId)
|
||||
if (not plateFrame) then
|
||||
return
|
||||
end
|
||||
|
||||
local castBar = plateFrame.unitFrame and plateFrame.unitFrame.castBar
|
||||
if (not castBar) then
|
||||
return
|
||||
end
|
||||
|
||||
return castBar
|
||||
end
|
||||
|
||||
local triggerCastEvent = function(castBar, event, unitId, ...)
|
||||
if (castBar and castBar.OnEvent) then
|
||||
return castBar.OnEvent (castBar, event, unitId)
|
||||
end
|
||||
end
|
||||
|
||||
local funcCast = function(event, unitId, ...)
|
||||
local castBar = getCastBar (unitId)
|
||||
if (castBar) then
|
||||
return triggerCastEvent (castBar, event, unitId)
|
||||
end
|
||||
end
|
||||
|
||||
fCast.UNIT_SPELLCAST_START = function(self, event, unitId, ...)
|
||||
return triggerCastEvent (getCastBar (unitId), event, unitId)
|
||||
end
|
||||
|
||||
fCast.UNIT_SPELLCAST_STOP = function(self, event, unitId, ...)
|
||||
return triggerCastEvent (getCastBar (unitId), event, unitId)
|
||||
end
|
||||
|
||||
fCast.UNIT_SPELLCAST_DELAYED = function(self, event, unitId, ...)
|
||||
return triggerCastEvent (getCastBar (unitId), event, unitId)
|
||||
end
|
||||
|
||||
fCast.UNIT_SPELLCAST_FAILED = function(self, event, unitId, ...)
|
||||
return triggerCastEvent (getCastBar (unitId), event, unitId)
|
||||
end
|
||||
|
||||
fCast.UNIT_SPELLCAST_INTERRUPTED = function(self, event, unitId, ...)
|
||||
return triggerCastEvent (getCastBar (unitId), event, unitId)
|
||||
end
|
||||
|
||||
fCast.UNIT_SPELLCAST_CHANNEL_START = function(self, event, unitId, ...)
|
||||
return triggerCastEvent (getCastBar (unitId), event, unitId)
|
||||
end
|
||||
|
||||
fCast.UNIT_SPELLCAST_CHANNEL_UPDATE = function(self, event, unitId, ...)
|
||||
return triggerCastEvent (getCastBar (unitId), event, unitId)
|
||||
end
|
||||
|
||||
fCast.UNIT_SPELLCAST_CHANNEL_STOP = function(self, event, unitId, ...)
|
||||
return triggerCastEvent (getCastBar (unitId), event, unitId)
|
||||
end
|
||||
|
||||
LibCC.RegisterCallback(fCast,"UNIT_SPELLCAST_START", funcCast)
|
||||
LibCC.RegisterCallback(fCast,"UNIT_SPELLCAST_DELAYED", funcCast) -- only for player
|
||||
LibCC.RegisterCallback(fCast,"UNIT_SPELLCAST_STOP", funcCast)
|
||||
LibCC.RegisterCallback(fCast,"UNIT_SPELLCAST_FAILED", funcCast)
|
||||
LibCC.RegisterCallback(fCast,"UNIT_SPELLCAST_INTERRUPTED", funcCast)
|
||||
LibCC.RegisterCallback(fCast,"UNIT_SPELLCAST_CHANNEL_START", funcCast)
|
||||
LibCC.RegisterCallback(fCast,"UNIT_SPELLCAST_CHANNEL_UPDATE", funcCast) -- only for player
|
||||
LibCC.RegisterCallback(fCast,"UNIT_SPELLCAST_CHANNEL_STOP", funcCast)
|
||||
|
||||
detailsFramework.CastInfo.UnitCastingInfo = function(unit)
|
||||
return LibCC:UnitCastingInfo (unit)
|
||||
end
|
||||
|
||||
detailsFramework.CastInfo.UnitChannelInfo = function(unit)
|
||||
return LibCC:UnitChannelInfo (unit)
|
||||
end
|
||||
end
|
||||
|
||||
if IS_WOW_PROJECT_CLASSIC_ERA then
|
||||
local LibCC = LibStub("LibClassicCasterino", true)
|
||||
if (LibCC and not _G.DetailsFrameworkLCCLoaded) then
|
||||
detailsFramework:LoadLCC(LibCC)
|
||||
_G.DetailsFrameworkLCCLoaded = true
|
||||
|
||||
elseif not LibCC then
|
||||
detailsFramework.CastInfo.UnitCastingInfo = CastingInfo
|
||||
detailsFramework.CastInfo.UnitChannelInfo = ChannelInfo
|
||||
end
|
||||
else -- end classic era
|
||||
|
||||
detailsFramework.CastInfo.UnitCastingInfo = UnitCastingInfo
|
||||
detailsFramework.CastInfo.UnitChannelInfo = UnitChannelInfo
|
||||
end
|
||||
|
||||
|
||||
if (not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,686 @@
|
||||
|
||||
local detailsFramework = DetailsFramework
|
||||
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local unpack = unpack
|
||||
local CreateFrame = CreateFrame
|
||||
local geterrorhandler = geterrorhandler
|
||||
local wipe = wipe
|
||||
|
||||
--definitions
|
||||
|
||||
---@class df_headercolumndata : {key: string, name: string, icon: string, texcoord: table, text: string, canSort: boolean, selected: boolean, width: number, height: number, align: string, offset: number}
|
||||
|
||||
---@class df_headerchild : uiobject
|
||||
---@field FramesToAlign table
|
||||
|
||||
---@class df_headerframe : frame, df_headermixin, df_optionsmixin
|
||||
---@field columnHeadersCreated df_headercolumnframe[]
|
||||
---@field options table
|
||||
---@field HeaderTable df_headercolumndata[]
|
||||
---@field columnSelected number
|
||||
|
||||
---@class df_headermixin : table
|
||||
---@field NextHeader number
|
||||
---@field HeaderWidth number
|
||||
---@field HeaderHeight number
|
||||
---@field OnColumnSettingChangeCallback function
|
||||
---@field GetColumnWidth fun(self: df_headerframe, columnId: number) : number
|
||||
---@field SetHeaderTable fun(self: df_headerframe, table)
|
||||
---@field GetSelectedColumn fun(self: df_headerframe) : number, string, string, string
|
||||
---@field Refresh fun(self: df_headerframe)
|
||||
---@field UpdateSortArrow fun(self: df_headerframe, columnHeader: df_headercolumnframe, defaultShown: boolean|nil, defaultOrder: string|nil)
|
||||
---@field UpdateColumnHeader fun(self: df_headerframe, columnHeader: df_headercolumnframe, headerIndex)
|
||||
---@field ResetColumnHeaderBackdrop fun(self: df_headerframe, columnHeader: df_headercolumnframe)
|
||||
---@field SetBackdropColorForSelectedColumnHeader fun(self: df_headerframe, columnHeader: df_headercolumnframe)
|
||||
---@field ClearColumnHeader fun(self: df_headerframe, columnHeader: df_headercolumnframe)
|
||||
---@field GetNextHeader fun(self: df_headerframe) : df_headercolumnframe
|
||||
---@field SetColumnSettingChangedCallback fun(self: df_headerframe, func: function) : boolean
|
||||
|
||||
---@class df_headercolumnframe : button
|
||||
---@field Icon texture
|
||||
---@field Text fontstring
|
||||
---@field Arrow texture
|
||||
---@field Separator texture
|
||||
---@field resizerButton df_headerresizer
|
||||
---@field bIsRezising boolean
|
||||
---@field bInUse boolean
|
||||
---@field columnData table
|
||||
---@field order string
|
||||
---@field columnIndex number
|
||||
---@field columnAlign string
|
||||
---@field XPosition number
|
||||
---@field columnOffset number
|
||||
---@field key string used to sort the values
|
||||
|
||||
---@class df_headerresizer : button
|
||||
---@field texture texture
|
||||
|
||||
--mixed functions
|
||||
---@class df_headerfunctions : table
|
||||
detailsFramework.HeaderFunctions = {
|
||||
---comment
|
||||
---@param self df_headerchild
|
||||
---@param frame uiobject
|
||||
AddFrameToHeaderAlignment = function(self, frame)
|
||||
self.FramesToAlign = self.FramesToAlign or {}
|
||||
table.insert(self.FramesToAlign, frame)
|
||||
end,
|
||||
|
||||
---comment
|
||||
---@param self df_headerchild
|
||||
ResetFramesToHeaderAlignment = function(self)
|
||||
wipe(self.FramesToAlign)
|
||||
end,
|
||||
|
||||
SetFramesToHeaderAlignment = function(self, ...)
|
||||
---@cast self df_headerchild
|
||||
wipe(self.FramesToAlign)
|
||||
self.FramesToAlign = {...}
|
||||
end,
|
||||
|
||||
GetFramesFromHeaderAlignment = function(self, frame)
|
||||
return self.FramesToAlign or {}
|
||||
end,
|
||||
|
||||
---@param self uiobject
|
||||
---@param headerFrame df_headerframe
|
||||
---@param anchor string
|
||||
AlignWithHeader = function(self, headerFrame, anchor)
|
||||
local columnHeaderFrames = headerFrame.columnHeadersCreated
|
||||
anchor = anchor or "topleft"
|
||||
|
||||
---@cast self df_headerchild
|
||||
|
||||
for i = 1, #self.FramesToAlign do
|
||||
---@type uiobject
|
||||
local uiObject = self.FramesToAlign[i]
|
||||
uiObject:ClearAllPoints()
|
||||
|
||||
---@type df_headercolumnframe
|
||||
local columnHeader = columnHeaderFrames[i]
|
||||
if (columnHeader) then
|
||||
local offset = 0
|
||||
|
||||
if (columnHeader.columnAlign == "right") then
|
||||
offset = columnHeader:GetWidth()
|
||||
end
|
||||
|
||||
if (uiObject:GetObjectType() == "FontString") then
|
||||
---@cast uiObject fontstring
|
||||
if (columnHeader.columnAlign == "right") then
|
||||
uiObject:SetJustifyH("right")
|
||||
elseif (columnHeader.columnAlign == "left") then
|
||||
uiObject:SetJustifyH("left")
|
||||
elseif (columnHeader.columnAlign == "center") then
|
||||
uiObject:SetJustifyH("center")
|
||||
end
|
||||
end
|
||||
|
||||
uiObject:SetPoint(columnHeader.columnAlign, self, anchor, columnHeader.XPosition + columnHeader.columnOffset + offset, 0)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
---comment
|
||||
---@param columnHeader df_headercolumnframe
|
||||
---@param buttonClicked string
|
||||
OnClick = function(columnHeader, buttonClicked)
|
||||
--get the header main frame
|
||||
local headerFrame = columnHeader:GetParent()
|
||||
---@cast headerFrame df_headerframe
|
||||
|
||||
--if this header does not have a clickable header, just ignore
|
||||
if (not headerFrame.columnSelected) then
|
||||
return
|
||||
end
|
||||
|
||||
--check if this column has 'canSort' key, otherwise ignore the click
|
||||
if (not columnHeader.columnData.canSort) then
|
||||
return
|
||||
end
|
||||
|
||||
--get the latest column header selected
|
||||
---@type df_headercolumnframe
|
||||
local previousColumnHeader = headerFrame.columnHeadersCreated[headerFrame.columnSelected]
|
||||
previousColumnHeader.Arrow:Hide()
|
||||
headerFrame:ResetColumnHeaderBackdrop(previousColumnHeader)
|
||||
headerFrame:SetBackdropColorForSelectedColumnHeader(columnHeader)
|
||||
|
||||
if (headerFrame.columnSelected == columnHeader.columnIndex) then
|
||||
columnHeader.order = columnHeader.order ~= "ASC" and "ASC" or "DESC"
|
||||
end
|
||||
headerFrame.columnOrder = columnHeader.order
|
||||
|
||||
--set the new column header selected
|
||||
headerFrame.columnSelected = columnHeader.columnIndex
|
||||
|
||||
headerFrame:UpdateSortArrow(columnHeader)
|
||||
|
||||
if (headerFrame.options.header_click_callback) then
|
||||
--callback with the main header frame, column header, column index and column order as payload
|
||||
local okay, errortext = pcall(headerFrame.options.header_click_callback, headerFrame, columnHeader, columnHeader.columnIndex, columnHeader.order)
|
||||
if (not okay) then
|
||||
print("DF: Header onClick callback error:", errortext)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
---comment
|
||||
---@param self button
|
||||
---@param buttonClicked string
|
||||
OnMouseDown = function(self, buttonClicked)
|
||||
if (buttonClicked == "LeftButton") then
|
||||
|
||||
end
|
||||
end,
|
||||
|
||||
---comment
|
||||
---@param self button
|
||||
---@param buttonClicked string
|
||||
OnMouseUp = function(self, buttonClicked)
|
||||
if (buttonClicked == "LeftButton") then
|
||||
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
---@class df_headermixin : table
|
||||
detailsFramework.HeaderMixin = {
|
||||
---@param self df_headerframe
|
||||
---@param columnId number
|
||||
---@return number
|
||||
GetColumnWidth = function(self, columnId)
|
||||
return self.HeaderTable[columnId].width
|
||||
end,
|
||||
|
||||
---@param self df_headerframe
|
||||
---@param newTable table
|
||||
SetHeaderTable = function(self, newTable)
|
||||
self.columnHeadersCreated = self.columnHeadersCreated or {}
|
||||
self.HeaderTable = newTable
|
||||
self.NextHeader = 1
|
||||
self.HeaderWidth = 0
|
||||
self.HeaderHeight = 0
|
||||
self:Refresh()
|
||||
end,
|
||||
|
||||
---@param self df_headerframe
|
||||
---@param func function
|
||||
---@return boolean
|
||||
SetColumnSettingChangedCallback = function(self, func)
|
||||
if (type(func) ~= "function") then
|
||||
self.OnColumnSettingChangeCallback = nil
|
||||
return false
|
||||
end
|
||||
self.OnColumnSettingChangeCallback = func
|
||||
return true
|
||||
end,
|
||||
|
||||
--return which header is current selected and the the order ASC DESC
|
||||
---@param self df_headerframe
|
||||
---@return number, string, string, string
|
||||
GetSelectedColumn = function(self)
|
||||
---@type number
|
||||
local columnSelected = self.columnSelected
|
||||
---@type df_headercolumnframe
|
||||
local columnHeader = self.columnHeadersCreated[columnSelected or 1]
|
||||
return columnSelected, columnHeader.order, columnHeader.key, columnHeader.columnData.name
|
||||
end,
|
||||
|
||||
--clean up and rebuild the header following the header options
|
||||
--@self: main header frame
|
||||
---@param self df_headerframe
|
||||
Refresh = function(self)
|
||||
--refresh background frame
|
||||
self:SetBackdrop(self.options.backdrop)
|
||||
self:SetBackdropColor(unpack(self.options.backdrop_color))
|
||||
self:SetBackdropBorderColor(unpack(self.options.backdrop_border_color))
|
||||
|
||||
--reset all header frames
|
||||
for i = 1, #self.columnHeadersCreated do
|
||||
local columnHeader = self.columnHeadersCreated[i]
|
||||
columnHeader.bInUse = false
|
||||
columnHeader:Hide()
|
||||
end
|
||||
|
||||
local previousColumnHeader
|
||||
local growDirection = string.lower(self.options.grow_direction)
|
||||
|
||||
--amount of headers to be updated
|
||||
local headerSize = #self.HeaderTable
|
||||
|
||||
--update header frames
|
||||
for i = 1, headerSize do
|
||||
--get the header button, a new one is created if it doesn't exists yet
|
||||
local columnHeader = self:GetNextHeader()
|
||||
self:UpdateColumnHeader(columnHeader, i)
|
||||
|
||||
--grow direction
|
||||
if (not previousColumnHeader) then
|
||||
columnHeader:SetPoint("topleft", self, "topleft", 0, 0)
|
||||
|
||||
if (growDirection == "right") then
|
||||
if (self.options.use_line_separators) then
|
||||
columnHeader.Separator:Show()
|
||||
columnHeader.Separator:SetWidth(self.options.line_separator_width)
|
||||
columnHeader.Separator:SetColorTexture(unpack(self.options.line_separator_color))
|
||||
|
||||
columnHeader.Separator:ClearAllPoints()
|
||||
if (self.options.line_separator_gap_align) then
|
||||
columnHeader.Separator:SetPoint("topleft", columnHeader, "topright", 0, 0)
|
||||
else
|
||||
columnHeader.Separator:SetPoint("topright", columnHeader, "topright", 0, 0)
|
||||
end
|
||||
columnHeader.Separator:SetHeight(self.options.line_separator_height)
|
||||
end
|
||||
end
|
||||
else
|
||||
if (growDirection == "right") then
|
||||
columnHeader:SetPoint("topleft", previousColumnHeader, "topright", self.options.padding, 0)
|
||||
|
||||
if (self.options.use_line_separators) then
|
||||
columnHeader.Separator:Show()
|
||||
columnHeader.Separator:SetWidth(self.options.line_separator_width)
|
||||
columnHeader.Separator:SetColorTexture(unpack(self.options.line_separator_color))
|
||||
|
||||
columnHeader.Separator:ClearAllPoints()
|
||||
if (self.options.line_separator_gap_align) then
|
||||
columnHeader.Separator:SetPoint("topleft", columnHeader, "topright", 0, 0)
|
||||
else
|
||||
columnHeader.Separator:SetPoint("topleft", columnHeader, "topright", 0, 0)
|
||||
end
|
||||
columnHeader.Separator:SetHeight(self.options.line_separator_height)
|
||||
|
||||
if (headerSize == i) then
|
||||
columnHeader.Separator:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
elseif (growDirection == "left") then
|
||||
columnHeader:SetPoint("topright", previousColumnHeader, "topleft", -self.options.padding, 0)
|
||||
|
||||
elseif (growDirection == "bottom") then
|
||||
columnHeader:SetPoint("topleft", previousColumnHeader, "bottomleft", 0, -self.options.padding)
|
||||
|
||||
elseif (growDirection == "top") then
|
||||
columnHeader:SetPoint("bottomleft", previousColumnHeader, "topleft", 0, self.options.padding)
|
||||
end
|
||||
end
|
||||
|
||||
previousColumnHeader = columnHeader
|
||||
end
|
||||
|
||||
self:SetSize(self.HeaderWidth, self.HeaderHeight)
|
||||
end,
|
||||
|
||||
---@param self df_headerframe
|
||||
---@param columnHeader df_headercolumnframe
|
||||
---@param defaultShown boolean
|
||||
---@param defaultOrder string
|
||||
UpdateSortArrow = function(self, columnHeader, defaultShown, defaultOrder)
|
||||
local options = self.options
|
||||
local order = defaultOrder or columnHeader.order
|
||||
local arrowIcon = columnHeader.Arrow
|
||||
|
||||
if (type(defaultShown) ~= "boolean") then
|
||||
arrowIcon:Show()
|
||||
else
|
||||
arrowIcon:SetShown(defaultShown)
|
||||
if (defaultShown) then
|
||||
self:SetBackdropColorForSelectedColumnHeader(columnHeader)
|
||||
end
|
||||
end
|
||||
|
||||
arrowIcon:SetAlpha(options.arrow_alpha)
|
||||
|
||||
if (order == "ASC") then
|
||||
arrowIcon:SetTexture(options.arrow_up_texture)
|
||||
arrowIcon:SetTexCoord(unpack(options.arrow_up_texture_coords))
|
||||
arrowIcon:SetSize(unpack(options.arrow_up_size))
|
||||
|
||||
elseif (order == "DESC") then
|
||||
arrowIcon:SetTexture(options.arrow_down_texture)
|
||||
arrowIcon:SetTexCoord(unpack(options.arrow_down_texture_coords))
|
||||
arrowIcon:SetSize(unpack(options.arrow_down_size))
|
||||
end
|
||||
end,
|
||||
|
||||
---@param self df_headerframe
|
||||
---@param columnHeader df_headercolumnframe
|
||||
---@param headerIndex number
|
||||
UpdateColumnHeader = function(self, columnHeader, headerIndex)
|
||||
--this is the data to update the columnHeader
|
||||
local columnData = self.HeaderTable[headerIndex]
|
||||
columnHeader.key = columnData.key or "total"
|
||||
|
||||
if (columnData.icon) then
|
||||
columnHeader.Icon:SetTexture(columnData.icon)
|
||||
|
||||
if (columnData.texcoord) then
|
||||
columnHeader.Icon:SetTexCoord(unpack(columnData.texcoord))
|
||||
else
|
||||
columnHeader.Icon:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
|
||||
columnHeader.Icon:SetPoint("left", columnHeader, "left", self.options.padding, 0)
|
||||
columnHeader.Icon:Show()
|
||||
end
|
||||
|
||||
if (columnData.text) then
|
||||
columnHeader.Text:SetText(columnData.text)
|
||||
|
||||
--text options
|
||||
detailsFramework:SetFontColor(columnHeader.Text, self.options.text_color)
|
||||
detailsFramework:SetFontSize(columnHeader.Text, self.options.text_size)
|
||||
detailsFramework:SetFontOutline(columnHeader.Text, self.options.text_shadow)
|
||||
|
||||
--point
|
||||
if (not columnData.icon) then
|
||||
columnHeader.Text:SetPoint("left", columnHeader, "left", self.options.padding, 0)
|
||||
else
|
||||
columnHeader.Text:SetPoint("left", columnHeader.Icon, "right", self.options.padding, 0)
|
||||
end
|
||||
|
||||
columnHeader.Text:Show()
|
||||
end
|
||||
|
||||
--column header index
|
||||
columnHeader.columnIndex = headerIndex
|
||||
|
||||
if (columnData.canSort) then
|
||||
columnHeader.order = "DESC"
|
||||
columnHeader.Arrow:SetTexture(self.options.arrow_up_texture)
|
||||
else
|
||||
columnHeader.Arrow:Hide()
|
||||
end
|
||||
|
||||
if (columnData.selected) then
|
||||
columnHeader.Arrow:Show()
|
||||
columnHeader.Arrow:SetAlpha(.843)
|
||||
self:UpdateSortArrow(columnHeader, true, columnHeader.order)
|
||||
self.columnSelected = headerIndex
|
||||
else
|
||||
if (columnData.canSort) then
|
||||
self:UpdateSortArrow(columnHeader, false, columnHeader.order)
|
||||
end
|
||||
end
|
||||
|
||||
--size
|
||||
if (columnData.width) then
|
||||
columnHeader:SetWidth(columnData.width)
|
||||
end
|
||||
if (columnData.height) then
|
||||
columnHeader:SetHeight(columnData.height)
|
||||
end
|
||||
|
||||
columnHeader.XPosition = self.HeaderWidth -- + self.options.padding
|
||||
columnHeader.YPosition = self.HeaderHeight -- + self.options.padding
|
||||
|
||||
columnHeader.columnAlign = columnData.align or "left"
|
||||
columnHeader.columnOffset = columnData.offset or 0
|
||||
|
||||
--add the header piece size to the total header size
|
||||
local growDirection = string.lower(self.options.grow_direction)
|
||||
|
||||
if (growDirection == "right" or growDirection == "left") then
|
||||
self.HeaderWidth = self.HeaderWidth + columnHeader:GetWidth() + self.options.padding
|
||||
self.HeaderHeight = math.max(self.HeaderHeight, columnHeader:GetHeight())
|
||||
|
||||
elseif (growDirection == "top" or growDirection == "bottom") then
|
||||
self.HeaderWidth = math.max(self.HeaderWidth, columnHeader:GetWidth())
|
||||
self.HeaderHeight = self.HeaderHeight + columnHeader:GetHeight() + self.options.padding
|
||||
end
|
||||
|
||||
local bShowColumnHeaderReziser = self.options.reziser_shown
|
||||
if (bShowColumnHeaderReziser) then
|
||||
local resizerButton = columnHeader.resizerButton
|
||||
resizerButton:Show()
|
||||
resizerButton.texture:SetVertexColor(unpack(self.options.reziser_color))
|
||||
resizerButton:SetWidth(self.options.reziser_width)
|
||||
resizerButton:SetHeight(columnHeader:GetHeight())
|
||||
else
|
||||
columnHeader.resizerButton:Hide()
|
||||
end
|
||||
|
||||
columnHeader:Show()
|
||||
columnHeader.bInUse = true
|
||||
columnHeader.columnData = columnData
|
||||
end,
|
||||
|
||||
---reset column header backdrop
|
||||
---@param self df_headerframe
|
||||
---@param columnHeader df_headercolumnframe
|
||||
ResetColumnHeaderBackdrop = function(self, columnHeader)
|
||||
columnHeader:SetBackdrop(self.options.header_backdrop)
|
||||
columnHeader:SetBackdropColor(unpack(self.options.header_backdrop_color))
|
||||
columnHeader:SetBackdropBorderColor(unpack(self.options.header_backdrop_border_color))
|
||||
end,
|
||||
|
||||
---@param self df_headerframe
|
||||
---@param columnHeader df_headercolumnframe
|
||||
SetBackdropColorForSelectedColumnHeader = function(self, columnHeader)
|
||||
columnHeader:SetBackdropColor(unpack(self.options.header_backdrop_color_selected))
|
||||
end,
|
||||
|
||||
---clear the column header
|
||||
---@param self df_headerframe
|
||||
---@param columnHeader df_headercolumnframe
|
||||
ClearColumnHeader = function(self, columnHeader)
|
||||
columnHeader:SetSize(self.options.header_width, self.options.header_height)
|
||||
self:ResetColumnHeaderBackdrop(columnHeader)
|
||||
|
||||
columnHeader:ClearAllPoints()
|
||||
|
||||
columnHeader.Icon:SetTexture("")
|
||||
columnHeader.Icon:Hide()
|
||||
columnHeader.Text:SetText("")
|
||||
columnHeader.Text:Hide()
|
||||
end,
|
||||
|
||||
---get the next column header, create one if doesn't exists
|
||||
---@param self df_headerframe
|
||||
GetNextHeader = function(self)
|
||||
local nextHeader = self.NextHeader
|
||||
local columnHeader = self.columnHeadersCreated[nextHeader]
|
||||
|
||||
if (not columnHeader) then
|
||||
--create a new column header
|
||||
---@type df_headercolumnframe
|
||||
columnHeader = CreateFrame("button", "$parentHeaderIndex" .. nextHeader, self, "BackdropTemplate")
|
||||
columnHeader:SetScript("OnClick", detailsFramework.HeaderFunctions.OnClick)
|
||||
columnHeader:SetMovable(true)
|
||||
columnHeader:SetResizable(true)
|
||||
|
||||
--header icon
|
||||
detailsFramework:CreateImage(columnHeader, "", self.options.header_height, self.options.header_height, "ARTWORK", nil, "Icon", "$parentIcon")
|
||||
--header separator
|
||||
detailsFramework:CreateImage(columnHeader, "", 1, 1, "ARTWORK", nil, "Separator", "$parentSeparator")
|
||||
--header name text
|
||||
detailsFramework:CreateLabel(columnHeader, "", self.options.text_size, self.options.text_color, "GameFontNormal", "Text", "$parentText", "ARTWORK")
|
||||
--header selected and order icon
|
||||
detailsFramework:CreateImage(columnHeader, self.options.arrow_up_texture, 12, 12, "ARTWORK", nil, "Arrow", "$parentArrow")
|
||||
|
||||
---rezise button
|
||||
---@type df_headerresizer
|
||||
local resizerButton = CreateFrame("button", "$parentResizer", columnHeader)
|
||||
resizerButton:SetWidth(4)
|
||||
resizerButton:SetFrameLevel(columnHeader:GetFrameLevel()+2)
|
||||
resizerButton:SetPoint("topright", columnHeader, "topright", -1, -1)
|
||||
resizerButton:SetPoint("bottomright", columnHeader, "bottomright", -1, 1)
|
||||
resizerButton:EnableMouse(true)
|
||||
resizerButton:RegisterForClicks("LeftButtonDown", "LeftButtonUp")
|
||||
columnHeader.resizerButton = resizerButton
|
||||
|
||||
resizerButton:SetScript("OnEnter", function()
|
||||
resizerButton.texture:SetVertexColor(1, 1, 1, 0.9)
|
||||
end)
|
||||
|
||||
resizerButton:SetScript("OnLeave", function()
|
||||
resizerButton.texture:SetVertexColor(unpack(self.options.reziser_color))
|
||||
end)
|
||||
|
||||
resizerButton:SetScript("OnMouseDown", function() --move this to a single function
|
||||
if (not columnHeader.bIsRezising) then
|
||||
--get the string length to know the min size
|
||||
local textLength = columnHeader.Text:GetStringWidth() + 6
|
||||
columnHeader:SetResizeBounds(math.max(textLength, self.options.reziser_min_width), columnHeader:GetHeight(), self.options.reziser_max_width, columnHeader:GetHeight())
|
||||
columnHeader.bIsRezising = true
|
||||
columnHeader:StartSizing("right")
|
||||
end
|
||||
end)
|
||||
|
||||
resizerButton:SetScript("OnMouseUp", function()
|
||||
if (columnHeader.bIsRezising) then
|
||||
columnHeader.bIsRezising = false
|
||||
columnHeader:StopMovingOrSizing()
|
||||
|
||||
--callback or modify into a passed by table?
|
||||
if (self.OnColumnSettingChangeCallback) then --need to get the header name
|
||||
local columnName = columnHeader.columnData.name
|
||||
xpcall(self.OnColumnSettingChangeCallback, geterrorhandler(), self, "width", columnName, columnHeader:GetWidth())
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
resizerButton:SetScript("OnHide", function()
|
||||
if (columnHeader.bIsRezising) then
|
||||
columnHeader:StopMovingOrSizing()
|
||||
columnHeader.bIsRezising = false
|
||||
end
|
||||
end)
|
||||
|
||||
resizerButton.texture = resizerButton:CreateTexture(nil, "overlay")
|
||||
resizerButton.texture:SetAllPoints()
|
||||
resizerButton.texture:SetColorTexture(1, 1, 1, 1)
|
||||
|
||||
local xOffset = self.options.reziser_shown and -5 or -1
|
||||
columnHeader.Arrow:SetPoint("right", columnHeader, "right", xOffset, 0)
|
||||
|
||||
columnHeader.Separator:Hide()
|
||||
columnHeader.Arrow:Hide()
|
||||
|
||||
self:UpdateSortArrow(columnHeader, false, "DESC")
|
||||
|
||||
table.insert(self.columnHeadersCreated, columnHeader)
|
||||
columnHeader = columnHeader
|
||||
end
|
||||
|
||||
self:ClearColumnHeader(columnHeader)
|
||||
self.NextHeader = self.NextHeader + 1
|
||||
return columnHeader
|
||||
end,
|
||||
|
||||
---return a header button by passing its name (.name on the column table)
|
||||
---@param self df_headerframe
|
||||
---@param columnName string
|
||||
---@return df_headercolumnframe|nil
|
||||
GetHeaderColumnByName = function(self, columnName)
|
||||
for _, headerColumnFrame in ipairs(self.columnHeadersCreated) do
|
||||
if (headerColumnFrame.columnData.name == columnName) then
|
||||
return headerColumnFrame
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
NextHeader = 1,
|
||||
HeaderWidth = 0,
|
||||
HeaderHeight = 0,
|
||||
}
|
||||
|
||||
--default options
|
||||
local default_header_options = {
|
||||
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
||||
backdrop_color = {0, 0, 0, 0.2},
|
||||
backdrop_border_color = {0.1, 0.1, 0.1, .2},
|
||||
|
||||
text_color = {1, 1, 1, 1},
|
||||
text_size = 10,
|
||||
text_shadow = false,
|
||||
grow_direction = "RIGHT",
|
||||
padding = 2,
|
||||
|
||||
reziser_shown = false, --make sure to set the callback function with: header:SetOnColumnResizeScript(callbackFunction)
|
||||
reziser_width = 2,
|
||||
reziser_color = {1, 0.6, 0, 0.6},
|
||||
reziser_min_width = 16,
|
||||
reziser_max_width = 200,
|
||||
|
||||
--each piece of the header
|
||||
header_backdrop = {bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
||||
header_backdrop_color = {0, 0, 0, 0.5},
|
||||
header_backdrop_color_selected = {0.3, 0.3, 0.3, 0.5},
|
||||
header_backdrop_border_color = {0, 0, 0, 0},
|
||||
header_width = 120,
|
||||
header_height = 20,
|
||||
|
||||
arrow_up_texture = [[Interface\Buttons\Arrow-Up-Down]],
|
||||
arrow_up_texture_coords = {0, 1, 6/16, 1},
|
||||
arrow_up_size = {12, 11},
|
||||
arrow_down_texture = [[Interface\Buttons\Arrow-Down-Down]],
|
||||
arrow_down_texture_coords = {0, 1, 0, 11/16},
|
||||
arrow_down_size = {12, 11},
|
||||
arrow_alpha = 0.659,
|
||||
|
||||
use_line_separators = false,
|
||||
line_separator_color = {.1, .1, .1, .6},
|
||||
line_separator_width = 1,
|
||||
line_separator_height = 200,
|
||||
line_separator_gap_align = false,
|
||||
}
|
||||
|
||||
---create a df_headerframe, alias 'header'.
|
||||
---a header is a frame that can hold multiple columns which are also frames, each column is a df_headercolumnframe, these columns are arranged in horizontal form.
|
||||
---a header is used to organize columns giving them a name/title, a way to sort and align them.
|
||||
---each column is placed on the right side of the previous column.
|
||||
---@param parent frame
|
||||
---@param headerTable table
|
||||
---@param options table|nil
|
||||
---@param frameName string|nil
|
||||
---@return df_headerframe
|
||||
function detailsFramework:CreateHeader(parent, headerTable, options, frameName)
|
||||
---create the header frame which is returned by this function
|
||||
---@type df_headerframe
|
||||
local newHeader = CreateFrame("frame", frameName or "$parentHeaderLine", parent, "BackdropTemplate")
|
||||
|
||||
detailsFramework:Mixin(newHeader, detailsFramework.OptionsFunctions)
|
||||
detailsFramework:Mixin(newHeader, detailsFramework.HeaderMixin)
|
||||
|
||||
newHeader:BuildOptionsTable(default_header_options, options)
|
||||
|
||||
--set the backdrop and backdrop color following the values in the options table
|
||||
newHeader:SetBackdrop(newHeader.options.backdrop)
|
||||
newHeader:SetBackdropColor(unpack(newHeader.options.backdrop_color))
|
||||
newHeader:SetBackdropBorderColor(unpack(newHeader.options.backdrop_border_color))
|
||||
|
||||
newHeader:SetHeaderTable(headerTable)
|
||||
|
||||
return newHeader
|
||||
end
|
||||
|
||||
|
||||
--[=[example:
|
||||
C_Timer.After(1, function()
|
||||
|
||||
|
||||
local parent = UIParent
|
||||
|
||||
--declare the columns the headerFrame will have
|
||||
---@type df_headercolumndata[]
|
||||
local headerTable = {
|
||||
{name = "playername", text = "Player Name", width = 120, align = "left", canSort = true},
|
||||
{name = "damage", text = "Damage Done", width = 80, align = "right", canSort = true},
|
||||
{name = "points", text = "Total Points", width = 80, align = "right", canSort = false},
|
||||
}
|
||||
local frameName = "MyAddOnOptionsFrame"
|
||||
local options = {}
|
||||
|
||||
local headerFrame = DetailsFramework:CreateHeader(parent, headerTable, options, frameName)
|
||||
headerFrame:SetPoint("center", parent, "center", 10, -10)
|
||||
|
||||
|
||||
end)
|
||||
--]=]
|
||||
@@ -0,0 +1,123 @@
|
||||
|
||||
|
||||
local DF = _G ["DetailsFramework"]
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local _
|
||||
local rawset = rawset --lua local
|
||||
local rawget = rawget --lua local
|
||||
|
||||
local APIHelpFunctions = false
|
||||
local HelpMetaFunctions = {}
|
||||
|
||||
local get_members_function_index = {}
|
||||
|
||||
HelpMetaFunctions.__index = function(_table, _member_requested)
|
||||
|
||||
local func = get_members_function_index [_member_requested]
|
||||
if (func) then
|
||||
return func (_table, _member_requested)
|
||||
end
|
||||
|
||||
local fromMe = rawget (_table, _member_requested)
|
||||
if (fromMe) then
|
||||
return fromMe
|
||||
end
|
||||
|
||||
return HelpMetaFunctions [_member_requested]
|
||||
end
|
||||
|
||||
local set_members_function_index = {}
|
||||
|
||||
HelpMetaFunctions.__newindex = function(_table, _key, _value)
|
||||
local func = set_members_function_index [_key]
|
||||
if (func) then
|
||||
return func (_table, _value)
|
||||
else
|
||||
return rawset (_table, _key, _value)
|
||||
end
|
||||
end
|
||||
|
||||
function HelpMetaFunctions:AddHelp (width, height, x, y, buttonX, buttonY, text, anchor)
|
||||
self.helpTable [#self.helpTable + 1] = {
|
||||
HighLightBox = {x = x, y = y, width = width, height = height},
|
||||
ButtonPos = { x = buttonX, y = buttonY},
|
||||
ToolTipDir = anchor or "RIGHT",
|
||||
ToolTipText = text
|
||||
}
|
||||
end
|
||||
|
||||
function HelpMetaFunctions:SetPoint(v1, v2, v3, v4, v5)
|
||||
v1, v2, v3, v4, v5 = DF:CheckPoints (v1, v2, v3, v4, v5, self)
|
||||
if (not v1) then
|
||||
print("Invalid parameter for SetPoint")
|
||||
return
|
||||
end
|
||||
return self.widget:SetPoint(v1, v2, v3, v4, v5)
|
||||
end
|
||||
|
||||
function HelpMetaFunctions:ShowHelp()
|
||||
if (not HelpPlate_IsShowing (self.helpTable)) then
|
||||
HelpPlate_Show (self.helpTable, self.frame, self.button, true)
|
||||
else
|
||||
HelpPlate_Hide (true)
|
||||
end
|
||||
end
|
||||
|
||||
local nameCounter = 1
|
||||
function DF:NewHelp (parent, width, height, x, y, buttonWidth, buttonHeight, name)
|
||||
|
||||
local help = {}
|
||||
|
||||
if (parent.dframework) then
|
||||
parent = parent.widget
|
||||
end
|
||||
|
||||
local helpButton = CreateFrame("button", name or "DetailsFrameworkHelpButton"..nameCounter, parent, "MainHelpPlateButton")
|
||||
nameCounter = nameCounter + 1
|
||||
|
||||
if (not APIHelpFunctions) then
|
||||
APIHelpFunctions = true
|
||||
local idx = getmetatable(helpButton).__index
|
||||
for funcName, funcAddress in pairs(idx) do
|
||||
if (not HelpMetaFunctions [funcName]) then
|
||||
HelpMetaFunctions [funcName] = function(object, ...)
|
||||
local x = loadstring ( "return _G."..object.button:GetName()..":"..funcName.."(...)")
|
||||
return x (...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (buttonWidth and buttonHeight) then
|
||||
helpButton:SetWidth(buttonWidth)
|
||||
helpButton:SetHeight(buttonHeight)
|
||||
helpButton.I:SetWidth(buttonWidth*0.8)
|
||||
helpButton.I:SetHeight(buttonHeight*0.8)
|
||||
helpButton.Ring:SetWidth(buttonWidth)
|
||||
helpButton.Ring:SetHeight(buttonHeight)
|
||||
helpButton.Ring:SetPoint("center", buttonWidth*.2, -buttonWidth*.2)
|
||||
end
|
||||
|
||||
help.helpTable = {
|
||||
FramePos = {x = x, y = y},
|
||||
FrameSize = {width = width, height = height}
|
||||
}
|
||||
|
||||
help.frame = parent
|
||||
help.button = helpButton
|
||||
help.widget = helpButton
|
||||
help.I = helpButton.I
|
||||
help.Ring = helpButton.Ring
|
||||
|
||||
helpButton:SetScript("OnClick", function()
|
||||
help:ShowHelp()
|
||||
end)
|
||||
|
||||
setmetatable(help, HelpMetaFunctions)
|
||||
|
||||
return help
|
||||
|
||||
end
|
||||
@@ -0,0 +1,487 @@
|
||||
|
||||
local detailsFramework = DetailsFramework
|
||||
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local unpack = unpack
|
||||
local CreateFrame = CreateFrame
|
||||
local PixelUtil = PixelUtil
|
||||
|
||||
detailsFramework.IconMixin = {
|
||||
---create a new icon frame
|
||||
---@param self frame the parent frame
|
||||
---@param iconName string the name of the icon frame
|
||||
---@return frame
|
||||
CreateIcon = function(self, iconName)
|
||||
local iconFrame = CreateFrame("frame", iconName, self, "BackdropTemplate")
|
||||
|
||||
iconFrame.Texture = iconFrame:CreateTexture(nil, "artwork")
|
||||
PixelUtil.SetPoint(iconFrame.Texture, "topleft", iconFrame, "topleft", 1, -1)
|
||||
PixelUtil.SetPoint(iconFrame.Texture, "bottomright", iconFrame, "bottomright", -1, 1)
|
||||
|
||||
iconFrame.Border = iconFrame:CreateTexture(nil, "background")
|
||||
iconFrame.Border:SetAllPoints()
|
||||
iconFrame.Border:SetColorTexture(0, 0, 0)
|
||||
|
||||
iconFrame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1})
|
||||
iconFrame:SetBackdropBorderColor(0, 0, 0, 0)
|
||||
iconFrame:EnableMouse(false)
|
||||
|
||||
local cooldownFrame = CreateFrame("cooldown", "$parentCooldown", iconFrame, "CooldownFrameTemplate, BackdropTemplate")
|
||||
cooldownFrame:SetAllPoints()
|
||||
cooldownFrame:EnableMouse(false)
|
||||
cooldownFrame:SetFrameLevel(iconFrame:GetFrameLevel()+1)
|
||||
iconFrame.Cooldown = cooldownFrame
|
||||
|
||||
iconFrame.CountdownText = cooldownFrame:CreateFontString(nil, "overlay", "GameFontNormal")
|
||||
iconFrame.CountdownText:SetPoint("center", iconFrame, "center", 0, 0)
|
||||
iconFrame.CountdownText:Hide()
|
||||
|
||||
iconFrame.StackText = iconFrame:CreateFontString(nil, "overlay", "GameFontNormal")
|
||||
iconFrame.StackText:SetPoint("center", iconFrame, "bottomright", 0, 0)
|
||||
iconFrame.StackText:Hide()
|
||||
|
||||
iconFrame.Desc = iconFrame:CreateFontString(nil, "overlay", "GameFontNormal")
|
||||
iconFrame.Desc:SetPoint("bottom", iconFrame, "top", 0, 2)
|
||||
iconFrame.Desc:Hide()
|
||||
|
||||
return iconFrame
|
||||
end,
|
||||
|
||||
GetIcon = function(self)
|
||||
local iconFrame = self.IconPool[self.NextIcon]
|
||||
|
||||
if (not iconFrame) then
|
||||
local newIconFrame = self:CreateIcon("$parentIcon" .. self.NextIcon)
|
||||
newIconFrame.parentIconRow = self
|
||||
newIconFrame.Cooldown:SetHideCountdownNumbers(self.options.surpress_blizzard_cd_timer)
|
||||
newIconFrame.Cooldown.noCooldownCount = self.options.surpress_tulla_omni_cc
|
||||
|
||||
newIconFrame.CountdownText:ClearAllPoints()
|
||||
newIconFrame.CountdownText:SetPoint(self.options.text_anchor or "center", iconFrame, self.options.text_rel_anchor or "center", self.options.text_x_offset or 0, self.options.text_y_offset or 0)
|
||||
newIconFrame.StackText:ClearAllPoints()
|
||||
newIconFrame.StackText:SetPoint(self.options.stack_text_anchor or "center", iconFrame, self.options.stack_text_rel_anchor or "bottomright", self.options.stack_text_x_offset or 0, self.options.stack_text_y_offset or 0)
|
||||
newIconFrame.Desc:ClearAllPoints()
|
||||
newIconFrame.Desc:SetPoint(self.options.desc_text_anchor or "bottom", iconFrame, self.options.desc_text_rel_anchor or "top", self.options.desc_text_x_offset or 0, self.options.desc_text_y_offset or 2)
|
||||
|
||||
self.IconPool[self.NextIcon] = newIconFrame
|
||||
iconFrame = newIconFrame
|
||||
end
|
||||
|
||||
iconFrame:ClearAllPoints()
|
||||
|
||||
local anchor = self.options.anchor
|
||||
local anchorTo = self.NextIcon == 1 and self or self.IconPool[self.NextIcon - 1]
|
||||
local xPadding = self.NextIcon == 1 and self.options.left_padding or self.options.icon_padding or 1
|
||||
local growDirection = self.options.grow_direction
|
||||
|
||||
if (growDirection == 1) then --grow to right
|
||||
if (self.NextIcon == 1) then
|
||||
PixelUtil.SetPoint(iconFrame, "left", anchorTo, "left", xPadding, 0)
|
||||
else
|
||||
PixelUtil.SetPoint(iconFrame, "left", anchorTo, "right", xPadding, 0)
|
||||
end
|
||||
|
||||
elseif (growDirection == 2) then --grow to left
|
||||
if (self.NextIcon == 1) then
|
||||
PixelUtil.SetPoint(iconFrame, "right", anchorTo, "right", xPadding, 0)
|
||||
else
|
||||
PixelUtil.SetPoint(iconFrame, "right", anchorTo, "left", xPadding, 0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
detailsFramework:SetFontColor(iconFrame.CountdownText, self.options.text_color)
|
||||
|
||||
self.NextIcon = self.NextIcon + 1
|
||||
return iconFrame
|
||||
end,
|
||||
|
||||
--adds only if not existing already in the cache
|
||||
AddSpecificIcon = function(self, identifierKey, spellId, borderColor, startTime, duration, forceTexture, descText, count, debuffType, caster, canStealOrPurge, spellName, isBuff)
|
||||
if (not identifierKey or identifierKey == "") then
|
||||
return
|
||||
end
|
||||
|
||||
if (not self.AuraCache[identifierKey]) then
|
||||
local icon = self:SetIcon(spellId, borderColor, startTime, duration, forceTexture, descText, count, debuffType, caster, canStealOrPurge, spellName, isBuff or false)
|
||||
icon.identifierKey = identifierKey
|
||||
self.AuraCache[identifierKey] = true
|
||||
end
|
||||
end,
|
||||
|
||||
SetIcon = function(self, spellId, borderColor, startTime, duration, forceTexture, descText, count, debuffType, caster, canStealOrPurge, spellName, isBuff, modRate)
|
||||
local actualSpellName, _, spellIcon = GetSpellInfo(spellId)
|
||||
|
||||
if forceTexture then
|
||||
spellIcon = forceTexture
|
||||
end
|
||||
|
||||
spellName = spellName or actualSpellName or "unknown_aura"
|
||||
modRate = modRate or 1
|
||||
|
||||
if (spellIcon) then
|
||||
local iconFrame = self:GetIcon()
|
||||
iconFrame.Texture:SetTexture(spellIcon)
|
||||
iconFrame.Texture:SetTexCoord(unpack(self.options.texcoord))
|
||||
|
||||
if (borderColor) then
|
||||
iconFrame:SetBackdropBorderColor(detailsFramework:ParseColors(borderColor))
|
||||
else
|
||||
iconFrame:SetBackdropBorderColor(0, 0, 0 ,0)
|
||||
end
|
||||
|
||||
if (startTime) then
|
||||
CooldownFrame_Set(iconFrame.Cooldown, startTime, duration, true, true, modRate)
|
||||
|
||||
if (self.options.show_text) then
|
||||
iconFrame.CountdownText:Show()
|
||||
|
||||
local now = GetTime()
|
||||
|
||||
iconFrame.timeRemaining = (startTime + duration - now) / modRate
|
||||
iconFrame.expirationTime = startTime + duration
|
||||
|
||||
local formattedTime = (iconFrame.timeRemaining > 0) and self.options.decimal_timer and iconFrame.parentIconRow.FormatCooldownTimeDecimal(iconFrame.timeRemaining) or iconFrame.parentIconRow.FormatCooldownTime(iconFrame.timeRemaining) or ""
|
||||
iconFrame.CountdownText:SetText(formattedTime)
|
||||
|
||||
iconFrame.CountdownText:SetPoint(self.options.text_anchor or "center", iconFrame, self.options.text_rel_anchor or "center", self.options.text_x_offset or 0, self.options.text_y_offset or 0)
|
||||
detailsFramework:SetFontSize(iconFrame.CountdownText, self.options.text_size)
|
||||
detailsFramework:SetFontFace (iconFrame.CountdownText, self.options.text_font)
|
||||
detailsFramework:SetFontOutline (iconFrame.CountdownText, self.options.text_outline)
|
||||
|
||||
if self.options.on_tick_cooldown_update then
|
||||
iconFrame.lastUpdateCooldown = now
|
||||
iconFrame:SetScript("OnUpdate", self.OnIconTick)
|
||||
else
|
||||
iconFrame:SetScript("OnUpdate", nil)
|
||||
end
|
||||
|
||||
else
|
||||
iconFrame:SetScript("OnUpdate", nil)
|
||||
iconFrame.CountdownText:Hide()
|
||||
end
|
||||
|
||||
iconFrame.Cooldown:SetReverse(self.options.cooldown_reverse)
|
||||
iconFrame.Cooldown:SetDrawSwipe(self.options.cooldown_swipe_enabled)
|
||||
iconFrame.Cooldown:SetEdgeTexture(self.options.cooldown_edge_texture)
|
||||
iconFrame.Cooldown:SetHideCountdownNumbers(self.options.surpress_blizzard_cd_timer)
|
||||
else
|
||||
iconFrame.timeRemaining = nil
|
||||
iconFrame.expirationTime = nil
|
||||
iconFrame:SetScript("OnUpdate", nil)
|
||||
iconFrame.CountdownText:Hide()
|
||||
end
|
||||
|
||||
if (descText and self.options.desc_text) then
|
||||
iconFrame.Desc:Show()
|
||||
iconFrame.Desc:SetText(descText.text)
|
||||
iconFrame.Desc:SetTextColor(detailsFramework:ParseColors(descText.text_color or self.options.desc_text_color))
|
||||
iconFrame.Desc:SetPoint(self.options.desc_text_anchor or "bottom", iconFrame, self.options.desc_text_rel_anchor or "top", self.options.desc_text_x_offset or 0, self.options.desc_text_y_offset or 2)
|
||||
detailsFramework:SetFontSize(iconFrame.Desc, descText.text_size or self.options.desc_text_size)
|
||||
detailsFramework:SetFontFace(iconFrame.Desc, self.options.desc_text_font)
|
||||
detailsFramework:SetFontOutline(iconFrame.Desc, self.options.desc_text_outline)
|
||||
else
|
||||
iconFrame.Desc:Hide()
|
||||
end
|
||||
|
||||
if (count and count > 1 and self.options.stack_text) then
|
||||
iconFrame.StackText:Show()
|
||||
iconFrame.StackText:SetText(count)
|
||||
iconFrame.StackText:SetTextColor(detailsFramework:ParseColors(self.options.stack_text_color))
|
||||
iconFrame.StackText:SetPoint(self.options.stack_text_anchor or "center", iconFrame, self.options.stack_text_rel_anchor or "bottomright", self.options.stack_text_x_offset or 0, self.options.stack_text_y_offset or 0)
|
||||
detailsFramework:SetFontSize(iconFrame.StackText, self.options.stack_text_size)
|
||||
detailsFramework:SetFontFace(iconFrame.StackText, self.options.stack_text_font)
|
||||
detailsFramework:SetFontOutline(iconFrame.StackText, self.options.stack_text_outline)
|
||||
else
|
||||
iconFrame.StackText:Hide()
|
||||
end
|
||||
|
||||
PixelUtil.SetSize(iconFrame, self.options.icon_width, self.options.icon_height)
|
||||
iconFrame:Show()
|
||||
|
||||
--update the size of the frame
|
||||
self:SetWidth((self.options.left_padding * 2) + (self.options.icon_padding * (self.NextIcon-2)) + (self.options.icon_width * (self.NextIcon - 1)))
|
||||
self:SetHeight(self.options.icon_height + (self.options.top_padding * 2))
|
||||
|
||||
--make information available
|
||||
iconFrame.spellId = spellId
|
||||
iconFrame.startTime = startTime
|
||||
iconFrame.duration = duration
|
||||
iconFrame.count = count
|
||||
iconFrame.debuffType = debuffType
|
||||
iconFrame.caster = caster
|
||||
iconFrame.canStealOrPurge = canStealOrPurge
|
||||
iconFrame.isBuff = isBuff
|
||||
iconFrame.spellName = spellName
|
||||
|
||||
iconFrame.identifierKey = nil -- only used for "specific" add/remove
|
||||
|
||||
--add the spell into the cache
|
||||
self.AuraCache[spellId or -1] = true
|
||||
self.AuraCache[spellName] = true
|
||||
self.AuraCache.canStealOrPurge = self.AuraCache.canStealOrPurge or canStealOrPurge
|
||||
self.AuraCache.hasEnrage = self.AuraCache.hasEnrage or debuffType == "" --yes, enrages are empty-string...
|
||||
|
||||
--show the frame
|
||||
self:Show()
|
||||
|
||||
return iconFrame
|
||||
end
|
||||
end,
|
||||
|
||||
OnIconTick = function(self, deltaTime)
|
||||
local now = GetTime()
|
||||
if (self.lastUpdateCooldown + 0.05) <= now then
|
||||
self.timeRemaining = self.expirationTime - now
|
||||
if self.timeRemaining > 0 then
|
||||
if self.parentIconRow.options.decimal_timer then
|
||||
self.CountdownText:SetText(self.parentIconRow.FormatCooldownTimeDecimal(self.timeRemaining))
|
||||
else
|
||||
self.CountdownText:SetText(self.parentIconRow.FormatCooldownTime(self.timeRemaining))
|
||||
end
|
||||
else
|
||||
self.CountdownText:SetText("")
|
||||
end
|
||||
self.lastUpdateCooldown = now
|
||||
end
|
||||
end,
|
||||
|
||||
FormatCooldownTime = function(formattedTime)
|
||||
if (formattedTime >= 3600) then
|
||||
formattedTime = math.floor(formattedTime / 3600) .. "h"
|
||||
|
||||
elseif (formattedTime >= 60) then
|
||||
formattedTime = math.floor(formattedTime / 60) .. "m"
|
||||
|
||||
else
|
||||
formattedTime = math.floor(formattedTime)
|
||||
end
|
||||
return formattedTime
|
||||
end,
|
||||
|
||||
FormatCooldownTimeDecimal = function(formattedTime)
|
||||
if formattedTime < 10 then
|
||||
return ("%.1f"):format(formattedTime)
|
||||
|
||||
elseif formattedTime < 60 then
|
||||
return ("%d"):format(formattedTime)
|
||||
|
||||
elseif formattedTime < 3600 then
|
||||
return ("%d:%02d"):format(formattedTime/60%60, formattedTime%60)
|
||||
|
||||
elseif formattedTime < 86400 then
|
||||
return ("%dh %02dm"):format(formattedTime/(3600), formattedTime/60%60)
|
||||
|
||||
else
|
||||
return ("%dd %02dh"):format(formattedTime/86400, (formattedTime/3600) - (math.floor(formattedTime/86400) * 24))
|
||||
end
|
||||
end,
|
||||
|
||||
RemoveSpecificIcon = function(self, identifierKey)
|
||||
if (not identifierKey or identifierKey == "") then
|
||||
return
|
||||
end
|
||||
|
||||
table.wipe(self.AuraCache)
|
||||
|
||||
local iconPool = self.IconPool
|
||||
local countStillShown = 0
|
||||
|
||||
for i = 1, self.NextIcon -1 do
|
||||
local iconFrame = iconPool[i]
|
||||
if (iconFrame.identifierKey and iconFrame.identifierKey == identifierKey) then
|
||||
iconFrame:Hide()
|
||||
iconFrame:ClearAllPoints()
|
||||
iconFrame.identifierKey = nil
|
||||
else
|
||||
self.AuraCache[iconFrame.spellId] = true
|
||||
self.AuraCache[iconFrame.spellName] = true
|
||||
self.AuraCache.canStealOrPurge = self.AuraCache.canStealOrPurge or iconFrame.canStealOrPurge
|
||||
self.AuraCache.hasEnrage = self.AuraCache.hasEnrage or iconFrame.debuffType == "" --yes, enrages are empty-string...
|
||||
countStillShown = countStillShown + 1
|
||||
end
|
||||
end
|
||||
|
||||
self:AlignAuraIcons()
|
||||
end,
|
||||
|
||||
ClearIcons = function(self, resetBuffs, resetDebuffs)
|
||||
resetBuffs = resetBuffs ~= false
|
||||
resetDebuffs = resetDebuffs ~= false
|
||||
table.wipe(self.AuraCache)
|
||||
|
||||
local iconPool = self.IconPool
|
||||
|
||||
for i = 1, self.NextIcon -1 do
|
||||
local iconFrame = iconPool[i]
|
||||
if (iconFrame.isBuff == nil) then
|
||||
iconFrame:Hide()
|
||||
iconFrame:ClearAllPoints()
|
||||
|
||||
elseif (resetBuffs and iconFrame.isBuff) then
|
||||
iconFrame:Hide()
|
||||
iconFrame:ClearAllPoints()
|
||||
|
||||
elseif (resetDebuffs and not iconFrame.isBuff) then
|
||||
iconFrame:Hide()
|
||||
iconFrame:ClearAllPoints()
|
||||
|
||||
else
|
||||
self.AuraCache[iconFrame.spellId] = true
|
||||
self.AuraCache[iconFrame.spellName] = true
|
||||
self.AuraCache.canStealOrPurge = self.AuraCache.canStealOrPurge or iconFrame.canStealOrPurge
|
||||
self.AuraCache.hasEnrage = self.AuraCache.hasEnrage or iconFrame.debuffType == "" --yes, enrages are empty-string...
|
||||
end
|
||||
end
|
||||
|
||||
self:AlignAuraIcons()
|
||||
end,
|
||||
|
||||
AlignAuraIcons = function(self)
|
||||
local iconPool = self.IconPool
|
||||
local iconAmount = #iconPool
|
||||
local countStillShown = 0
|
||||
|
||||
table.sort(iconPool, function(i1, i2) return i1:IsShown() and not i2:IsShown() end)
|
||||
|
||||
if iconAmount == 0 then
|
||||
self:Hide()
|
||||
else
|
||||
--re-anchor not hidden
|
||||
for i = 1, iconAmount do
|
||||
local iconFrame = iconPool[i]
|
||||
local anchor = self.options.anchor
|
||||
local anchorTo = i == 1 and self or self.IconPool[i - 1]
|
||||
local xPadding = i == 1 and self.options.left_padding or self.options.icon_padding or 1
|
||||
local growDirection = self.options.grow_direction
|
||||
|
||||
countStillShown = countStillShown + (iconFrame:IsShown() and 1 or 0)
|
||||
|
||||
iconFrame:ClearAllPoints()
|
||||
if (growDirection == 1) then --grow to right
|
||||
if (i == 1) then
|
||||
PixelUtil.SetPoint(iconFrame, "left", anchorTo, "left", xPadding, 0)
|
||||
else
|
||||
PixelUtil.SetPoint(iconFrame, "left", anchorTo, "right", xPadding, 0)
|
||||
end
|
||||
elseif (growDirection == 2) then --grow to left
|
||||
if (i == 1) then
|
||||
PixelUtil.SetPoint(iconFrame, "right", anchorTo, "right", xPadding, 0)
|
||||
else
|
||||
PixelUtil.SetPoint(iconFrame, "right", anchorTo, "left", xPadding, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.NextIcon = countStillShown + 1
|
||||
end,
|
||||
|
||||
GetIconGrowDirection = function(self)
|
||||
local side = self.options.anchor.side
|
||||
|
||||
if (side == 1) then
|
||||
return 1
|
||||
elseif (side == 2) then
|
||||
return 2
|
||||
elseif (side == 3) then
|
||||
return 1
|
||||
elseif (side == 4) then
|
||||
return 1
|
||||
elseif (side == 5) then
|
||||
return 2
|
||||
elseif (side == 6) then
|
||||
return 1
|
||||
elseif (side == 7) then
|
||||
return 2
|
||||
elseif (side == 8) then
|
||||
return 1
|
||||
elseif (side == 9) then
|
||||
return 1
|
||||
elseif (side == 10) then
|
||||
return 1
|
||||
elseif (side == 11) then
|
||||
return 2
|
||||
elseif (side == 12) then
|
||||
return 1
|
||||
elseif (side == 13) then
|
||||
return 1
|
||||
end
|
||||
end,
|
||||
|
||||
OnOptionChanged = function(self, optionName)
|
||||
self:SetBackdropColor(unpack(self.options.backdrop_color))
|
||||
self:SetBackdropBorderColor(unpack(self.options.backdrop_border_color))
|
||||
end,
|
||||
}
|
||||
|
||||
local default_icon_row_options = {
|
||||
icon_width = 20,
|
||||
icon_height = 20,
|
||||
texcoord = {.1, .9, .1, .9},
|
||||
show_text = true,
|
||||
text_color = {1, 1, 1, 1},
|
||||
text_size = 12,
|
||||
text_font = "Arial Narrow",
|
||||
text_outline = "NONE",
|
||||
text_anchor = "center",
|
||||
text_rel_anchor = "center",
|
||||
text_x_offset = 0,
|
||||
text_y_offset = 0,
|
||||
desc_text = true,
|
||||
desc_text_color = {1, 1, 1, 1},
|
||||
desc_text_size = 7,
|
||||
desc_text_font = "Arial Narrow",
|
||||
desc_text_outline = "NONE",
|
||||
desc_text_anchor = "bottom",
|
||||
desc_text_rel_anchor = "top",
|
||||
desc_text_x_offset = 0,
|
||||
desc_text_y_offset = 2,
|
||||
stack_text = true,
|
||||
stack_text_color = {1, 1, 1, 1},
|
||||
stack_text_size = 10,
|
||||
stack_text_font = "Arial Narrow",
|
||||
stack_text_outline = "NONE",
|
||||
stack_text_anchor = "center",
|
||||
stack_text_rel_anchor = "bottomright",
|
||||
stack_text_x_offset = 0,
|
||||
stack_text_y_offset = 0,
|
||||
left_padding = 1, --distance between right and left
|
||||
top_padding = 1, --distance between top and bottom
|
||||
icon_padding = 1, --distance between each icon
|
||||
backdrop = {},
|
||||
backdrop_color = {0, 0, 0, 0.5},
|
||||
backdrop_border_color = {0, 0, 0, 1},
|
||||
anchor = {side = 6, x = 2, y = 0},
|
||||
grow_direction = 1, --1 = to right 2 = to left
|
||||
surpress_blizzard_cd_timer = false,
|
||||
surpress_tulla_omni_cc = false,
|
||||
on_tick_cooldown_update = true,
|
||||
decimal_timer = false,
|
||||
cooldown_reverse = false,
|
||||
cooldown_swipe_enabled = true,
|
||||
cooldown_edge_texture = "Interface\\Cooldown\\edge",
|
||||
}
|
||||
|
||||
function detailsFramework:CreateIconRow(parent, name, options)
|
||||
local newIconRowFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
||||
newIconRowFrame.IconPool = {}
|
||||
newIconRowFrame.NextIcon = 1
|
||||
newIconRowFrame.AuraCache = {}
|
||||
|
||||
detailsFramework:Mixin(newIconRowFrame, detailsFramework.IconMixin)
|
||||
detailsFramework:Mixin(newIconRowFrame, detailsFramework.OptionsFunctions)
|
||||
|
||||
newIconRowFrame:BuildOptionsTable(default_icon_row_options, options)
|
||||
|
||||
newIconRowFrame:SetSize(newIconRowFrame.options.icon_width, newIconRowFrame.options.icon_height + (newIconRowFrame.options.top_padding * 2))
|
||||
|
||||
newIconRowFrame:SetBackdrop(newIconRowFrame.options.backdrop)
|
||||
newIconRowFrame:SetBackdropColor(unpack(newIconRowFrame.options.backdrop_color))
|
||||
newIconRowFrame:SetBackdropBorderColor(unpack(newIconRowFrame.options.backdrop_border_color))
|
||||
|
||||
return newIconRowFrame
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
local detailsFramework = _G["DetailsFramework"]
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
--namespace
|
||||
detailsFramework.Items = {}
|
||||
|
||||
local containerAPIVersion = 1
|
||||
if (detailsFramework.IsDragonflightAndBeyond()) then
|
||||
containerAPIVersion = 2
|
||||
end
|
||||
|
||||
function detailsFramework.Items.GetContainerItemInfo(containerIndex, slotIndex)
|
||||
if (containerAPIVersion == 2 and C_Container and C_Container.GetContainerItemInfo) then
|
||||
local itemInfo = C_Container.GetContainerItemInfo(containerIndex, slotIndex)
|
||||
return itemInfo.iconFileID, itemInfo.stackCount, itemInfo.isLocked, itemInfo.quality, itemInfo.isReadable, itemInfo.hasLoot, itemInfo.hyperlink, itemInfo.isFiltered, itemInfo.hasNoValue, itemInfo.itemID, itemInfo.isBound
|
||||
else
|
||||
return GetContainerItemInfo(containerIndex, slotIndex)
|
||||
end
|
||||
end
|
||||
|
||||
function detailsFramework.Items.IsItemSoulbound(containerIndex, slotIndex)
|
||||
local bIsBound = select(11, detailsFramework.Items.GetContainerItemInfo(containerIndex, slotIndex))
|
||||
return bIsBound
|
||||
end
|
||||
@@ -0,0 +1,341 @@
|
||||
|
||||
local detailsFramework = _G["DetailsFramework"]
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local _
|
||||
local loadedAPILabelFunctions = false
|
||||
|
||||
do
|
||||
local metaPrototype = {
|
||||
WidgetType = "label",
|
||||
dversion = detailsFramework.dversion,
|
||||
}
|
||||
|
||||
--check if there's a metaPrototype already existing
|
||||
if (_G[detailsFramework.GlobalWidgetControlNames["label"]]) then
|
||||
--get the already existing metaPrototype
|
||||
local oldMetaPrototype = _G[detailsFramework.GlobalWidgetControlNames ["label"]]
|
||||
--check if is older
|
||||
if ( (not oldMetaPrototype.dversion) or (oldMetaPrototype.dversion < detailsFramework.dversion) ) then
|
||||
--the version is older them the currently loading one
|
||||
--copy the new values into the old metatable
|
||||
for funcName, _ in pairs(metaPrototype) do
|
||||
oldMetaPrototype[funcName] = metaPrototype[funcName]
|
||||
end
|
||||
end
|
||||
else
|
||||
--first time loading the framework
|
||||
_G[detailsFramework.GlobalWidgetControlNames ["label"]] = metaPrototype
|
||||
end
|
||||
end
|
||||
|
||||
local LabelMetaFunctions = _G[detailsFramework.GlobalWidgetControlNames ["label"]]
|
||||
|
||||
detailsFramework:Mixin(LabelMetaFunctions, detailsFramework.SetPointMixin)
|
||||
detailsFramework:Mixin(LabelMetaFunctions, detailsFramework.ScriptHookMixin)
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--metatables
|
||||
|
||||
LabelMetaFunctions.__call = function(object, value)
|
||||
return object.label:SetText(value)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--members
|
||||
|
||||
--get text
|
||||
local gmember_text = function(object)
|
||||
return object.label:GetText()
|
||||
end
|
||||
|
||||
--text width
|
||||
local gmember_width = function(object)
|
||||
return object.label:GetStringWidth()
|
||||
end
|
||||
|
||||
--text height
|
||||
local gmember_height = function(object)
|
||||
return object.label:GetStringHeight()
|
||||
end
|
||||
|
||||
--text color
|
||||
local gmember_textcolor = function(object)
|
||||
return object.label:GetTextColor()
|
||||
end
|
||||
|
||||
--text font
|
||||
local gmember_textfont = function(object)
|
||||
local fontface = object.label:GetFont()
|
||||
return fontface
|
||||
end
|
||||
|
||||
--text size
|
||||
local gmember_textsize = function(object)
|
||||
local _, fontsize = object.label:GetFont()
|
||||
return fontsize
|
||||
end
|
||||
|
||||
LabelMetaFunctions.GetMembers = LabelMetaFunctions.GetMembers or {}
|
||||
detailsFramework:Mixin(LabelMetaFunctions.GetMembers, detailsFramework.LayeredRegionMetaFunctionsGet)
|
||||
detailsFramework:Mixin(LabelMetaFunctions.GetMembers, detailsFramework.DefaultMetaFunctionsGet)
|
||||
|
||||
LabelMetaFunctions.GetMembers["width"] = gmember_width
|
||||
LabelMetaFunctions.GetMembers["height"] = gmember_height
|
||||
LabelMetaFunctions.GetMembers["text"] = gmember_text
|
||||
LabelMetaFunctions.GetMembers["fontcolor"] = gmember_textcolor
|
||||
LabelMetaFunctions.GetMembers["fontface"] = gmember_textfont
|
||||
LabelMetaFunctions.GetMembers["fontsize"] = gmember_textsize
|
||||
LabelMetaFunctions.GetMembers["textcolor"] = gmember_textcolor --alias
|
||||
LabelMetaFunctions.GetMembers["textfont"] = gmember_textfont --alias
|
||||
LabelMetaFunctions.GetMembers["textsize"] = gmember_textsize --alias
|
||||
|
||||
LabelMetaFunctions.__index = function(object, key)
|
||||
local func = LabelMetaFunctions.GetMembers[key]
|
||||
if (func) then
|
||||
return func(object, key)
|
||||
end
|
||||
|
||||
local alreadyHaveKey = rawget(object, key)
|
||||
if (alreadyHaveKey) then
|
||||
return alreadyHaveKey
|
||||
end
|
||||
|
||||
return LabelMetaFunctions[key]
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--text
|
||||
local smember_text = function(object, value)
|
||||
return object.label:SetText(value)
|
||||
end
|
||||
|
||||
--text color
|
||||
local smember_textcolor = function(object, value)
|
||||
local value1, value2, value3, value4 = detailsFramework:ParseColors(value)
|
||||
return object.label:SetTextColor(value1, value2, value3, value4)
|
||||
end
|
||||
|
||||
--text font
|
||||
local smember_textfont = function(object, value)
|
||||
return detailsFramework:SetFontFace(object.label, value)
|
||||
end
|
||||
|
||||
--text size
|
||||
local smember_textsize = function(object, value)
|
||||
return detailsFramework:SetFontSize(object.label, value)
|
||||
end
|
||||
|
||||
--text align
|
||||
local smember_textalign = function(object, value)
|
||||
if (value == "<") then
|
||||
value = "left"
|
||||
elseif (value == ">") then
|
||||
value = "right"
|
||||
elseif (value == "|") then
|
||||
value = "center"
|
||||
end
|
||||
return object.label:SetJustifyH(value)
|
||||
end
|
||||
|
||||
--text valign
|
||||
local smember_textvalign = function(object, value)
|
||||
if (value == "^") then
|
||||
value = "top"
|
||||
elseif (value == "_") then
|
||||
value = "bottom"
|
||||
elseif (value == "|") then
|
||||
value = "middle"
|
||||
end
|
||||
return object.label:SetJustifyV(value)
|
||||
end
|
||||
|
||||
--field size width
|
||||
local smember_width = function(object, value)
|
||||
return object.label:SetWidth(value)
|
||||
end
|
||||
|
||||
--field size height
|
||||
local smember_height = function(object, value)
|
||||
return object.label:SetHeight(value)
|
||||
end
|
||||
|
||||
--outline (shadow)
|
||||
local smember_outline = function(object, value)
|
||||
detailsFramework:SetFontOutline(object.label, value)
|
||||
end
|
||||
|
||||
--text rotation
|
||||
local smember_rotation = function(object, rotation)
|
||||
if (type(rotation) == "number") then
|
||||
if (not object.__rotationAnimation) then
|
||||
object.__rotationAnimation = detailsFramework:CreateAnimationHub(object.label)
|
||||
object.__rotationAnimation.rotator = detailsFramework:CreateAnimation(object.__rotationAnimation, "rotation", 1, 0, 0)
|
||||
object.__rotationAnimation.rotator:SetEndDelay(10^8)
|
||||
object.__rotationAnimation.rotator:SetSmoothProgress(1)
|
||||
end
|
||||
object.__rotationAnimation.rotator:SetDegrees(rotation)
|
||||
object.__rotationAnimation:Play()
|
||||
object.__rotationAnimation:Pause()
|
||||
end
|
||||
end
|
||||
|
||||
LabelMetaFunctions.SetMembers = LabelMetaFunctions.SetMembers or {}
|
||||
detailsFramework:Mixin(LabelMetaFunctions.SetMembers, detailsFramework.LayeredRegionMetaFunctionsSet)
|
||||
detailsFramework:Mixin(LabelMetaFunctions.SetMembers, detailsFramework.DefaultMetaFunctionsSet)
|
||||
|
||||
LabelMetaFunctions.SetMembers["align"] = smember_textalign
|
||||
LabelMetaFunctions.SetMembers["valign"] = smember_textvalign
|
||||
LabelMetaFunctions.SetMembers["text"] = smember_text
|
||||
LabelMetaFunctions.SetMembers["width"] = smember_width
|
||||
LabelMetaFunctions.SetMembers["height"] = smember_height
|
||||
LabelMetaFunctions.SetMembers["fontcolor"] = smember_textcolor
|
||||
LabelMetaFunctions.SetMembers["color"] = smember_textcolor--alias
|
||||
LabelMetaFunctions.SetMembers["fontface"] = smember_textfont
|
||||
LabelMetaFunctions.SetMembers["fontsize"] = smember_textsize
|
||||
LabelMetaFunctions.SetMembers["textcolor"] = smember_textcolor--alias
|
||||
LabelMetaFunctions.SetMembers["textfont"] = smember_textfont--alias
|
||||
LabelMetaFunctions.SetMembers["textsize"] = smember_textsize--alias
|
||||
LabelMetaFunctions.SetMembers["shadow"] = smember_outline
|
||||
LabelMetaFunctions.SetMembers["outline"] = smember_outline--alias
|
||||
LabelMetaFunctions.SetMembers["rotation"] = smember_rotation
|
||||
|
||||
LabelMetaFunctions.__newindex = function(object, key, value)
|
||||
local func = LabelMetaFunctions.SetMembers[key]
|
||||
if (func) then
|
||||
return func(object, value)
|
||||
else
|
||||
return rawset(object, key, value)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--methods
|
||||
|
||||
--text text
|
||||
function LabelMetaFunctions:SetTextTruncated(text, maxWidth)
|
||||
self.widget:SetText(text)
|
||||
detailsFramework:TruncateText(self.widget, maxWidth)
|
||||
end
|
||||
|
||||
--textcolor
|
||||
function LabelMetaFunctions:SetTextColor(r, g, b, a)
|
||||
r, g, b, a = detailsFramework:ParseColors(r, g, b, a)
|
||||
return self.label:SetTextColor(r, g, b, a)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--template
|
||||
|
||||
function LabelMetaFunctions:SetTemplate(template)
|
||||
if (template.size) then
|
||||
detailsFramework:SetFontSize(self.label, template.size)
|
||||
end
|
||||
if (template.color) then
|
||||
local r, g, b, a = detailsFramework:ParseColors(template.color)
|
||||
self:SetTextColor(r, g, b, a)
|
||||
end
|
||||
if (template.font) then
|
||||
local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0")
|
||||
local font = SharedMedia:Fetch("font", template.font)
|
||||
detailsFramework:SetFontFace(self.label, font)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--object constructor
|
||||
|
||||
function detailsFramework:CreateLabel(parent, text, size, color, font, member, name, layer)
|
||||
return detailsFramework:NewLabel(parent, nil, name, member, text, font, size, color, layer)
|
||||
end
|
||||
|
||||
function detailsFramework:NewLabel(parent, container, name, member, text, font, size, color, layer)
|
||||
if (not parent) then
|
||||
return error("Details! Framework: parent not found.", 2)
|
||||
end
|
||||
if (not container) then
|
||||
container = parent
|
||||
end
|
||||
|
||||
if (not name) then
|
||||
name = "DetailsFrameworkLabelNumber" .. detailsFramework.LabelNameCounter
|
||||
detailsFramework.LabelNameCounter = detailsFramework.LabelNameCounter + 1
|
||||
end
|
||||
|
||||
if (name:find("$parent")) then
|
||||
local parentName = detailsFramework.GetParentName(parent)
|
||||
name = name:gsub("$parent", parentName)
|
||||
end
|
||||
|
||||
local labelObject = {type = "label", dframework = true}
|
||||
|
||||
if (member) then
|
||||
parent[member] = labelObject
|
||||
end
|
||||
|
||||
if (parent.dframework) then
|
||||
parent = parent.widget
|
||||
end
|
||||
|
||||
if (container.dframework) then
|
||||
container = container.widget
|
||||
end
|
||||
|
||||
if (not font or font == "") then
|
||||
font = "GameFontNormal"
|
||||
end
|
||||
|
||||
labelObject.label = parent:CreateFontString(name, layer or "OVERLAY", font)
|
||||
labelObject.widget = labelObject.label
|
||||
labelObject.label.MyObject = labelObject
|
||||
|
||||
if (not loadedAPILabelFunctions) then
|
||||
loadedAPILabelFunctions = true
|
||||
local idx = getmetatable(labelObject.label).__index
|
||||
for funcName, funcAddress in pairs(idx) do
|
||||
if (not LabelMetaFunctions[funcName]) then
|
||||
LabelMetaFunctions[funcName] = function(object, ...)
|
||||
local x = loadstring( "return _G['"..object.label:GetName().."']:"..funcName.."(...)")
|
||||
return x(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--if the text is a table, it means a language table has been passed
|
||||
if (type(text) == "table") then
|
||||
local locTable = text
|
||||
if (detailsFramework.Language.IsLocTable(locTable)) then
|
||||
detailsFramework.Language.SetTextWithLocTable(labelObject.widget, locTable)
|
||||
else
|
||||
labelObject.label:SetText(text)
|
||||
end
|
||||
else
|
||||
labelObject.label:SetText(text)
|
||||
end
|
||||
|
||||
labelObject.label:SetJustifyH("left")
|
||||
|
||||
if (color) then
|
||||
local r, g, b, a = detailsFramework:ParseColors(color)
|
||||
labelObject.label:SetTextColor(r, g, b, a)
|
||||
end
|
||||
|
||||
if (size and type(size) == "number") then
|
||||
detailsFramework:SetFontSize(labelObject.label, size)
|
||||
end
|
||||
|
||||
labelObject.HookList = {}
|
||||
|
||||
setmetatable(labelObject, LabelMetaFunctions)
|
||||
|
||||
--if template has been passed as the third parameter
|
||||
if (size and type(size) == "table") then
|
||||
labelObject:SetTemplate(size)
|
||||
end
|
||||
|
||||
return labelObject
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
|
||||
|
||||
<Script file ="DFPixelUtil.lua"/>
|
||||
<Script file="fw.lua"/>
|
||||
<Script file="mixins.lua"/>
|
||||
<Script file="util.lua"/>
|
||||
<Script file="header.lua"/>
|
||||
<Script file="containers.lua"/>
|
||||
<Script file="iteminfo.lua"/>
|
||||
<Script file="addon.lua"/>
|
||||
<Script file="colors.lua"/>
|
||||
<Script file="help.lua"/>
|
||||
<Script file="schedules.lua"/>
|
||||
<Script file="label.lua"/>
|
||||
<Script file="picture.lua"/>
|
||||
<Script file="slider.lua"/>
|
||||
<Script file="scrollbar.lua"/>
|
||||
<Script file="spells.lua"/>
|
||||
<Script file="math.lua"/>
|
||||
<Script file="savedvars.lua"/>
|
||||
<Script file="languages.lua"/>
|
||||
<Script file="timebar.lua"/>
|
||||
<Script file="charts.lua"/>
|
||||
<Script file="scripting.lua"/>
|
||||
<Script file="externals.lua"/>
|
||||
|
||||
<Include file="tutorial_alert.xml"/>
|
||||
<Include file="split_bar.xml"/>
|
||||
<Include file="textentry.xml"/>
|
||||
<Include file="button.xml"/>
|
||||
<Include file="cooltip.xml"/>
|
||||
<Include file="dropdown.xml"/>
|
||||
<Include file="normal_bar.xml"/>
|
||||
<Include file="panel.xml"/>
|
||||
|
||||
<Script file="icon.lua"/>
|
||||
<Script file="pictureedit.lua"/>
|
||||
<Script file="auras.lua"/>
|
||||
<Script file="tabcontainer.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,176 @@
|
||||
|
||||
local DF = _G["DetailsFramework"]
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local UnitExists = UnitExists
|
||||
local atan2 = math.atan2
|
||||
local pi = math.pi
|
||||
local abs = math.abs
|
||||
|
||||
SMALL_FLOAT = 0.000001
|
||||
|
||||
--find distance between two players
|
||||
function DF:GetDistance_Unit(unit1, unit2)
|
||||
if (UnitExists(unit1) and UnitExists(unit2)) then
|
||||
local u1X, u1Y = UnitPosition(unit1)
|
||||
local u2X, u2Y = UnitPosition(unit2)
|
||||
|
||||
local dX = u2X - u1X
|
||||
local dY = u2Y - u1Y
|
||||
|
||||
return ((dX*dX) + (dY*dY)) ^ .5
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
--find distance between two points
|
||||
function DF:GetDistance_Point(x1, y1, x2, y2)
|
||||
local dx = x2 - x1
|
||||
local dy = y2 - y1
|
||||
return ((dx * dx) + (dy * dy)) ^ .5
|
||||
end
|
||||
|
||||
--find a rotation for an object from a point to another point
|
||||
function DF:FindLookAtRotation(x1, y1, x2, y2)
|
||||
return atan2 (y2 - y1, x2 - x1) + pi
|
||||
end
|
||||
|
||||
--find the value scale between two given values. e.g: value of 500 in a range 0-100 result in 10 in a scale for 0-10
|
||||
function DF:MapRangeClamped(inputX, inputY, outputX, outputY, value)
|
||||
return DF:GetRangeValue(outputX, outputY, Clamp(DF:GetRangePercent(inputX, inputY, value), 0, 1))
|
||||
end
|
||||
|
||||
--find the value scale between two given values. e.g: value of 75 in a range 0-100 result in 7.5 in a scale for 0-10
|
||||
function DF:MapRangeUnclamped(inputX, inputY, outputX, outputY, value)
|
||||
return DF:GetRangeValue(outputX, outputY, DF:GetRangePercent(inputX, inputY, value))
|
||||
end
|
||||
|
||||
--find the normalized percent of the value in the range. e.g range of 200-400 and a value of 250 result in 0.25
|
||||
function DF:GetRangePercent(minValue, maxValue, value)
|
||||
return (value - minValue) / max((maxValue - minValue), SMALL_FLOAT)
|
||||
end
|
||||
|
||||
--find the value in the range given from a normalized percent. e.g range of 200-400 and a percent of 0.8 result in 360
|
||||
function DF:GetRangeValue(minValue, maxValue, percent)
|
||||
return Lerp(minValue, maxValue, percent)
|
||||
end
|
||||
|
||||
function DF:GetColorRangeValue(r1, g1, b1, r2, g2, b2, value)
|
||||
local newR = DF:LerpNorm(r1, r2, value)
|
||||
local newG = DF:LerpNorm(g1, g2, value)
|
||||
local newB = DF:LerpNorm(b1, b2, value)
|
||||
return newR, newG, newB
|
||||
end
|
||||
|
||||
--dot product of two 2D Vectors
|
||||
function DF:GetDotProduct(value1, value2)
|
||||
return (value1.x * value2.x) + (value1.y * value2.y)
|
||||
end
|
||||
|
||||
function DF:GetBezierPoint(value, point1, point2, point3)
|
||||
local bP1 = Lerp(point1, point2, value)
|
||||
local bP2 = Lerp(point2, point3, value)
|
||||
return Lerp(bP1, bP2, value)
|
||||
end
|
||||
|
||||
--normalized value 0-1 result in the value on the range given, e.g 200-400 range with a value of .5 result in 300
|
||||
function DF:LerpNorm(minValue, maxValue, value)
|
||||
return (minValue + value * (maxValue - minValue))
|
||||
end
|
||||
|
||||
--change the color by the deltaTime
|
||||
function DF:LerpLinearColor(deltaTime, interpSpeed, r1, g1, b1, r2, g2, b2)
|
||||
deltaTime = deltaTime * interpSpeed
|
||||
local r = r1 + (r2 - r1) * deltaTime
|
||||
local g = g1 + (g2 - g1) * deltaTime
|
||||
local b = b1 + (b2 - b1) * deltaTime
|
||||
return r, g, b
|
||||
end
|
||||
|
||||
--check if a number is near another number by a tolerance
|
||||
function DF:IsNearlyEqual(value1, value2, tolerance)
|
||||
tolerance = tolerance or SMALL_FLOAT
|
||||
return abs(value1 - value2) <= tolerance
|
||||
end
|
||||
|
||||
--check if a number is near zero
|
||||
function DF:IsNearlyZero(value, tolerance)
|
||||
tolerance = tolerance or SMALL_FLOAT
|
||||
return abs(value) <= tolerance
|
||||
end
|
||||
|
||||
--check if a number is within a two other numbers, if isInclusive is true, it'll include the max value
|
||||
function DF:IsWithin(minValue, maxValue, value, isInclusive)
|
||||
if (isInclusive) then
|
||||
return ((value >= minValue) and (value <= maxValue))
|
||||
else
|
||||
return ((value >= minValue) and (value < maxValue))
|
||||
end
|
||||
end
|
||||
|
||||
--dont allow a number ot be lower or bigger than a certain range
|
||||
function DF:Clamp(minValue, maxValue, value)
|
||||
return value < minValue and minValue or value < maxValue and value or maxValue
|
||||
end
|
||||
|
||||
--from http://lua-users.org/wiki/SimpleRound cut fractions on a float
|
||||
function DF:Round(num, numDecimalPlaces)
|
||||
local mult = 10^(numDecimalPlaces or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end
|
||||
|
||||
local BoundingBox = {}
|
||||
BoundingBox.CoordinatesData = {
|
||||
["topleft"] = {["x"] = 'number', ["y"] = 'number'},
|
||||
["topright"] = {["x"] = 'number', ["y"] = 'number'},
|
||||
["bottomleft"] = {["x"] = 'number', ["y"] = 'number'},
|
||||
["bottomright"] = {["x"] = 'number', ["y"] = 'number'},
|
||||
["center"] = {["x"] = 'number', ["y"] = 'number'},
|
||||
["width"] = 'number',
|
||||
["height"] = 'number',
|
||||
}
|
||||
|
||||
---@class objectcoordinates
|
||||
---@field topleft {["x"]: number, ["y"]: number}
|
||||
---@field topright {["x"]: number, ["y"]: number}
|
||||
---@field bottomleft {["x"]: number, ["y"]: number}
|
||||
---@field bottomright {["x"]: number, ["y"]: number}
|
||||
---@field center {["x"]: number, ["y"]: number}
|
||||
---@field width number
|
||||
---@field height number
|
||||
---@field left number
|
||||
---@field right number
|
||||
---@field top number
|
||||
---@field bottom number
|
||||
|
||||
---return the coordinates of the four corners of an object
|
||||
---@param object uiobject
|
||||
---@return objectcoordinates
|
||||
function DF:GetObjectCoordinates(object)
|
||||
local centerX, centerY = object:GetCenter()
|
||||
local width = object:GetWidth()
|
||||
local height = object:GetHeight()
|
||||
|
||||
local halfWidth = width / 2
|
||||
local halfHeight = height / 2
|
||||
|
||||
return {
|
||||
["width"] = width,
|
||||
["height"] = height,
|
||||
["left"] = centerX - halfWidth,
|
||||
["right"] = centerX + halfWidth,
|
||||
["top"] = centerY + halfHeight,
|
||||
["bottom"] = centerY - halfHeight,
|
||||
["center"] = {x = centerX, y = centerY},
|
||||
["topleft"] = {x = centerX - halfWidth, y = centerY + halfHeight},
|
||||
["topright"] = {x = centerX + halfWidth, y = centerY + halfHeight},
|
||||
["bottomleft"] = {x = centerX - halfWidth, y = centerY - halfHeight},
|
||||
["bottomright"] = {x = centerX + halfWidth, y = centerY - halfHeight},
|
||||
}
|
||||
end
|
||||
|
||||
function DF:ScaleBack()
|
||||
|
||||
end
|
||||
@@ -0,0 +1,965 @@
|
||||
|
||||
local detailsFramework = _G["DetailsFramework"]
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local _
|
||||
|
||||
local getFrame = function(frame)
|
||||
return rawget(frame, "widget") or frame
|
||||
end
|
||||
|
||||
detailsFramework.WidgetFunctions = {
|
||||
GetCapsule = function(self)
|
||||
return self.MyObject
|
||||
end,
|
||||
|
||||
GetObject = function(self)
|
||||
return self.MyObject
|
||||
end,
|
||||
}
|
||||
|
||||
detailsFramework.DefaultMetaFunctionsGet = {
|
||||
parent = function(object)
|
||||
return object:GetParent()
|
||||
end,
|
||||
|
||||
shown = function(object)
|
||||
return object:IsShown()
|
||||
end,
|
||||
}
|
||||
|
||||
detailsFramework.TooltipHandlerMixin = {
|
||||
SetTooltip = function(self, tooltip)
|
||||
if (tooltip) then
|
||||
if (detailsFramework.Language.IsLocTable(tooltip)) then
|
||||
--register the locTable as a tableKey
|
||||
local locTable = tooltip
|
||||
detailsFramework.Language.RegisterTableKeyWithLocTable(self, "have_tooltip", locTable)
|
||||
else
|
||||
self.have_tooltip = tooltip
|
||||
end
|
||||
else
|
||||
self.have_tooltip = nil
|
||||
end
|
||||
end,
|
||||
|
||||
GetTooltip = function(self)
|
||||
return self.have_tooltip
|
||||
end,
|
||||
|
||||
ShowTooltip = function(self)
|
||||
local tooltipText = self:GetTooltip()
|
||||
|
||||
if (type(tooltipText) == "function") then
|
||||
local tooltipFunction = tooltipText
|
||||
local gotTooltip, tooltipString = xpcall(tooltipFunction, geterrorhandler())
|
||||
if (gotTooltip) then
|
||||
tooltipText = tooltipString
|
||||
end
|
||||
end
|
||||
|
||||
if (tooltipText) then
|
||||
GameCooltip:Preset(2)
|
||||
GameCooltip:AddLine(tooltipText)
|
||||
GameCooltip:ShowCooltip(getFrame(self), "tooltip")
|
||||
end
|
||||
end,
|
||||
|
||||
HideTooltip = function(self)
|
||||
local tooltipText = self:GetTooltip()
|
||||
if (tooltipText) then
|
||||
if (GameCooltip:IsOwner(getFrame(self))) then
|
||||
GameCooltip:Hide()
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
detailsFramework.DefaultMetaFunctionsSet = {
|
||||
parent = function(object, value)
|
||||
return object:SetParent(value)
|
||||
end,
|
||||
|
||||
show = function(object, value)
|
||||
if (value) then
|
||||
return object:Show()
|
||||
else
|
||||
return object:Hide()
|
||||
end
|
||||
end,
|
||||
|
||||
hide = function(object, value)
|
||||
if (value) then
|
||||
return object:Hide()
|
||||
else
|
||||
return object:Show()
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
detailsFramework.DefaultMetaFunctionsSet.shown = detailsFramework.DefaultMetaFunctionsSet.show
|
||||
|
||||
detailsFramework.LayeredRegionMetaFunctionsSet = {
|
||||
drawlayer = function(object, value)
|
||||
object.image:SetDrawLayer(value)
|
||||
end,
|
||||
|
||||
sublevel = function(object, value)
|
||||
local drawLayer = object:GetDrawLayer()
|
||||
object:SetDrawLayer(drawLayer, value)
|
||||
end,
|
||||
}
|
||||
|
||||
detailsFramework.LayeredRegionMetaFunctionsGet = {
|
||||
drawlayer = function(object)
|
||||
return object.image:GetDrawLayer()
|
||||
end,
|
||||
|
||||
sublevel = function(object)
|
||||
local _, subLevel = object.image:GetDrawLayer()
|
||||
return subLevel
|
||||
end,
|
||||
}
|
||||
|
||||
detailsFramework.FrameMixin = {
|
||||
SetFrameStrata = function(self, strata)
|
||||
self = getFrame(self)
|
||||
if (type(strata) == "table" and strata.GetObjectType) then
|
||||
local UIObject = strata
|
||||
self:SetFrameStrata(UIObject:GetFrameStrata())
|
||||
else
|
||||
self:SetFrameStrata(strata)
|
||||
end
|
||||
end,
|
||||
|
||||
SetFrameLevel = function(self, level, UIObject)
|
||||
self = getFrame(self)
|
||||
if (not UIObject) then
|
||||
self:SetFrameLevel(level)
|
||||
else
|
||||
local framelevel = UIObject:GetFrameLevel(UIObject) + level
|
||||
self:SetFrameLevel(framelevel)
|
||||
end
|
||||
end,
|
||||
|
||||
SetSize = function(self, width, height)
|
||||
self = getFrame(self)
|
||||
if (width) then
|
||||
self:SetWidth(width)
|
||||
end
|
||||
if (height) then
|
||||
self:SetHeight(height)
|
||||
end
|
||||
end,
|
||||
|
||||
SetBackdrop = function(self, ...)
|
||||
self = getFrame(self)
|
||||
self:SetBackdrop(...)
|
||||
end,
|
||||
|
||||
SetBackdropColor = function(self, ...)
|
||||
self = getFrame(self)
|
||||
self:SetBackdropColor(...)
|
||||
end,
|
||||
|
||||
SetBackdropBorderColor = function(self, ...)
|
||||
self = getFrame(self)
|
||||
getFrame(self):SetBackdropBorderColor(...)
|
||||
end,
|
||||
}
|
||||
|
||||
local doublePoint = {
|
||||
["lefts"] = true,
|
||||
["rights"] = true,
|
||||
["tops"] = true,
|
||||
["bottoms"] = true,
|
||||
|
||||
["left-left"] = true,
|
||||
["right-right"] = true,
|
||||
["top-top"] = true,
|
||||
["bottom-bottom"] = true,
|
||||
|
||||
["bottom-top"] = true,
|
||||
["top-bottom"] = true,
|
||||
["right-left"] = true,
|
||||
["left-right"] = true,
|
||||
}
|
||||
|
||||
detailsFramework.SetPointMixin = {
|
||||
SetPoint = function(object, anchorName1, anchorObject, anchorName2, xOffset, yOffset)
|
||||
if (doublePoint[anchorName1]) then
|
||||
object:ClearAllPoints()
|
||||
local anchorTo
|
||||
if (anchorObject and type(anchorObject) == "table") then
|
||||
xOffset, yOffset = anchorName2 or 0, xOffset or 0
|
||||
anchorTo = getFrame(anchorObject)
|
||||
else
|
||||
xOffset, yOffset = anchorObject or 0, anchorName2 or 0
|
||||
anchorTo = object:GetParent()
|
||||
end
|
||||
|
||||
--offset always inset to inner
|
||||
if (anchorName1 == "lefts") then
|
||||
object:SetPoint("topleft", anchorTo, "topleft", xOffset, -yOffset)
|
||||
object:SetPoint("bottomleft", anchorTo, "bottomleft", xOffset, yOffset)
|
||||
|
||||
elseif (anchorName1 == "rights") then
|
||||
object:SetPoint("topright", anchorTo, "topright", xOffset, -yOffset)
|
||||
object:SetPoint("bottomright", anchorTo, "bottomright", xOffset, yOffset)
|
||||
|
||||
elseif (anchorName1 == "tops") then
|
||||
object:SetPoint("topleft", anchorTo, "topleft", xOffset, -yOffset)
|
||||
object:SetPoint("topright", anchorTo, "topright", -xOffset, -yOffset)
|
||||
|
||||
elseif (anchorName1 == "bottoms") then
|
||||
object:SetPoint("bottomleft", anchorTo, "bottomleft", xOffset, yOffset)
|
||||
object:SetPoint("bottomright", anchorTo, "bottomright", -xOffset, yOffset)
|
||||
|
||||
elseif (anchorName1 == "left-left") then
|
||||
object:SetPoint("left", anchorTo, "left", xOffset, yOffset)
|
||||
|
||||
elseif (anchorName1 == "right-right") then
|
||||
object:SetPoint("right", anchorTo, "right", xOffset, yOffset)
|
||||
|
||||
elseif (anchorName1 == "top-top") then
|
||||
object:SetPoint("top", anchorTo, "top", xOffset, yOffset)
|
||||
|
||||
elseif (anchorName1 == "bottom-bottom") then
|
||||
object:SetPoint("bottom", anchorTo, "bottom", xOffset, yOffset)
|
||||
|
||||
elseif (anchorName1 == "bottom-top") then
|
||||
object:SetPoint("bottomleft", anchorTo, "topleft", xOffset, yOffset)
|
||||
object:SetPoint("bottomright", anchorTo, "topright", -xOffset, yOffset)
|
||||
|
||||
elseif (anchorName1 == "top-bottom") then
|
||||
object:SetPoint("topleft", anchorTo, "bottomleft", xOffset, -yOffset)
|
||||
object:SetPoint("topright", anchorTo, "bottomright", -xOffset, -yOffset)
|
||||
|
||||
elseif (anchorName1 == "right-left") then
|
||||
object:SetPoint("topright", anchorTo, "topleft", xOffset, -yOffset)
|
||||
object:SetPoint("bottomright", anchorTo, "bottomleft", xOffset, yOffset)
|
||||
|
||||
elseif (anchorName1 == "left-right") then
|
||||
object:SetPoint("topleft", anchorTo, "topright", xOffset, -yOffset)
|
||||
object:SetPoint("bottomleft", anchorTo, "bottomright", xOffset, yOffset)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
xOffset = xOffset or 0
|
||||
yOffset = yOffset or 0
|
||||
|
||||
anchorName1, anchorObject, anchorName2, xOffset, yOffset = detailsFramework:CheckPoints(anchorName1, anchorObject, anchorName2, xOffset, yOffset, object)
|
||||
if (not anchorName1) then
|
||||
error("SetPoint: Invalid parameter.")
|
||||
return
|
||||
end
|
||||
|
||||
if (not object.widget) then
|
||||
local SetPoint = getmetatable(object).__index.SetPoint
|
||||
return SetPoint(object, anchorName1, anchorObject, anchorName2, xOffset, yOffset)
|
||||
else
|
||||
return object.widget:SetPoint(anchorName1, anchorObject, anchorName2, xOffset, yOffset)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
---mixin for options
|
||||
---@class df_optionsmixin
|
||||
detailsFramework.OptionsFunctions = {
|
||||
SetOption = function(self, optionName, optionValue)
|
||||
if (self.options) then
|
||||
self.options [optionName] = optionValue
|
||||
else
|
||||
self.options = {}
|
||||
self.options [optionName] = optionValue
|
||||
end
|
||||
|
||||
if (self.OnOptionChanged) then
|
||||
detailsFramework:Dispatch (self.OnOptionChanged, self, optionName, optionValue)
|
||||
end
|
||||
end,
|
||||
|
||||
GetOption = function(self, optionName)
|
||||
return self.options and self.options [optionName]
|
||||
end,
|
||||
|
||||
GetAllOptions = function(self)
|
||||
if (self.options) then
|
||||
local optionsTable = {}
|
||||
for key, _ in pairs(self.options) do
|
||||
optionsTable [#optionsTable + 1] = key
|
||||
end
|
||||
return optionsTable
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end,
|
||||
|
||||
BuildOptionsTable = function(self, defaultOptions, userOptions)
|
||||
self.options = self.options or {}
|
||||
detailsFramework.table.deploy(self.options, userOptions or {})
|
||||
detailsFramework.table.deploy(self.options, defaultOptions or {})
|
||||
end
|
||||
}
|
||||
|
||||
--payload mixin
|
||||
detailsFramework.PayloadMixin = {
|
||||
ClearPayload = function(self)
|
||||
self.payload = {}
|
||||
end,
|
||||
|
||||
SetPayload = function(self, ...)
|
||||
self.payload = {...}
|
||||
return self.payload
|
||||
end,
|
||||
|
||||
AddPayload = function(self, ...)
|
||||
local currentPayload = self.payload or {}
|
||||
self.payload = currentPayload
|
||||
|
||||
for i = 1, select("#", ...) do
|
||||
local value = select(i, ...)
|
||||
currentPayload[#currentPayload+1] = value
|
||||
end
|
||||
|
||||
return self.payload
|
||||
end,
|
||||
|
||||
GetPayload = function(self)
|
||||
return self.payload
|
||||
end,
|
||||
|
||||
DumpPayload = function(self)
|
||||
return unpack(self.payload)
|
||||
end,
|
||||
|
||||
--does not copy wow objects, just pass them to the new table, tables strings and numbers are copied entirely
|
||||
DuplicatePayload = function(self)
|
||||
local duplicatedPayload = detailsFramework.table.duplicate({}, self.payload)
|
||||
return duplicatedPayload
|
||||
end,
|
||||
}
|
||||
|
||||
---mixin to use with DetailsFramework:Mixin(table, detailsFramework.ScriptHookMixin)
|
||||
---
|
||||
---@class DetailsFramework.ScriptHookMixin
|
||||
detailsFramework.ScriptHookMixin = {
|
||||
RunHooksForWidget = function(self, event, ...)
|
||||
local hooks = self.HookList[event]
|
||||
|
||||
if (not hooks) then
|
||||
print(self.widget:GetName(), "no hooks for", event)
|
||||
return
|
||||
end
|
||||
|
||||
for i, func in ipairs(hooks) do
|
||||
local success, canInterrupt = xpcall(func, geterrorhandler(), ...)
|
||||
|
||||
if (not success) then
|
||||
--error("Details! Framework: " .. event .. " hook for " .. self:GetName() .. ": " .. canInterrupt)
|
||||
return false
|
||||
|
||||
elseif (canInterrupt) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
SetHook = function(self, hookType, func)
|
||||
if (self.HookList[hookType]) then
|
||||
if (type(func) == "function") then
|
||||
local isRemoval = false
|
||||
for i = #self.HookList[hookType], 1, -1 do
|
||||
if (self.HookList[hookType][i] == func) then
|
||||
table.remove(self.HookList[hookType], i)
|
||||
isRemoval = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if (not isRemoval) then
|
||||
table.insert(self.HookList[hookType], func)
|
||||
end
|
||||
else
|
||||
if (detailsFramework.debug) then
|
||||
print(debugstack())
|
||||
error("Details! Framework: invalid function for widget " .. self.WidgetType .. ".")
|
||||
end
|
||||
end
|
||||
else
|
||||
if (detailsFramework.debug) then
|
||||
error("Details! Framework: unknown hook type for widget " .. self.WidgetType .. ": '" .. hookType .. "'.")
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
HasHook = function(self, hookType, func)
|
||||
if (self.HookList[hookType]) then
|
||||
if (type(func) == "function") then
|
||||
for i = #self.HookList[hookType], 1, -1 do
|
||||
if (self.HookList[hookType][i] == func) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
ClearHooks = function(self)
|
||||
for hookType, hookTable in pairs(self.HookList) do
|
||||
table.wipe(hookTable)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
---mixin to use with DetailsFramework:Mixin(table, detailsFramework.SortFunctions)
|
||||
---add methods to be used on scrollframes
|
||||
---@class df_scrollboxmixin
|
||||
detailsFramework.ScrollBoxFunctions = {
|
||||
---refresh the scrollbox by resetting all lines created with :CreateLine(), then calling the refresh_func which was set at :CreateScrollBox()
|
||||
---@param self table
|
||||
---@return table
|
||||
Refresh = function(self)
|
||||
--hide all frames and tag as not in use
|
||||
self._LinesInUse = 0
|
||||
for index, frame in ipairs(self.Frames) do
|
||||
if (not self.DontHideChildrenOnPreRefresh) then
|
||||
frame:Hide()
|
||||
end
|
||||
frame._InUse = nil
|
||||
end
|
||||
|
||||
local offset = 0
|
||||
if (self.IsFauxScroll) then
|
||||
self:UpdateFaux(#self.data, self.LineAmount, self.LineHeight)
|
||||
offset = self:GetOffsetFaux()
|
||||
end
|
||||
|
||||
--call the refresh function
|
||||
detailsFramework:CoreDispatch((self:GetName() or "ScrollBox") .. ":Refresh()", self.refresh_func, self, self.data, offset, self.LineAmount)
|
||||
|
||||
--hide all frames that are not in use
|
||||
for index, frame in ipairs(self.Frames) do
|
||||
if (not frame._InUse) then
|
||||
frame:Hide()
|
||||
else
|
||||
frame:Show()
|
||||
end
|
||||
end
|
||||
|
||||
self:Show()
|
||||
|
||||
local frameName = self:GetName()
|
||||
if (frameName) then
|
||||
if (self.HideScrollBar) then
|
||||
local scrollBar = _G[frameName .. "ScrollBar"]
|
||||
if (scrollBar) then
|
||||
scrollBar:Hide()
|
||||
end
|
||||
else
|
||||
--[=[ --maybe in the future I visit this again
|
||||
local scrollBar = _G[frameName .. "ScrollBar"]
|
||||
local height = self:GetHeight()
|
||||
local totalLinesRequired = #self.data
|
||||
local linesShown = self._LinesInUse
|
||||
|
||||
local percent = linesShown / totalLinesRequired
|
||||
local thumbHeight = height * percent
|
||||
scrollBar.ThumbTexture:SetSize(12, thumbHeight)
|
||||
print("thumbHeight:", thumbHeight)
|
||||
--]=]
|
||||
end
|
||||
end
|
||||
return self.Frames
|
||||
end,
|
||||
|
||||
OnVerticalScroll = function(self, offset)
|
||||
self:OnVerticalScrollFaux(offset, self.LineHeight, self.Refresh)
|
||||
return true
|
||||
end,
|
||||
|
||||
---create a line within the scrollbox
|
||||
---@param self table is the scrollbox
|
||||
---@param func function|nil function to create the line object, this function will receive the line index as argument and return a table with the line object
|
||||
---@return table line object (table)
|
||||
CreateLine = function(self, func)
|
||||
if (not func) then
|
||||
func = self.CreateLineFunc
|
||||
end
|
||||
|
||||
local okay, newLine = pcall(func, self, #self.Frames+1)
|
||||
if (okay) then
|
||||
if (not newLine) then
|
||||
error("ScrollFrame:CreateLine() function did not returned a line, use: 'return line'")
|
||||
end
|
||||
tinsert(self.Frames, newLine)
|
||||
newLine.Index = #self.Frames
|
||||
return newLine
|
||||
else
|
||||
error("ScrollFrame:CreateLine() error on creating a line: " .. newLine)
|
||||
end
|
||||
end,
|
||||
|
||||
CreateLines = function(self, callback, lineAmount)
|
||||
for i = 1, lineAmount do
|
||||
self:CreateLine(callback)
|
||||
end
|
||||
end,
|
||||
|
||||
GetLine = function(self, lineIndex)
|
||||
local line = self.Frames[lineIndex]
|
||||
if (line) then
|
||||
line._InUse = true
|
||||
end
|
||||
|
||||
self._LinesInUse = self._LinesInUse + 1
|
||||
return line
|
||||
end,
|
||||
|
||||
SetData = function(self, data)
|
||||
self.data = data
|
||||
end,
|
||||
GetData = function(self)
|
||||
return self.data
|
||||
end,
|
||||
|
||||
GetFrames = function(self)
|
||||
return self.Frames
|
||||
end,
|
||||
GetLines = function(self) --alias of GetFrames
|
||||
return self.Frames
|
||||
end,
|
||||
|
||||
GetNumFramesCreated = function(self)
|
||||
return #self.Frames
|
||||
end,
|
||||
|
||||
GetNumFramesShown = function(self)
|
||||
return self.LineAmount
|
||||
end,
|
||||
|
||||
SetNumFramesShown = function(self, newAmount)
|
||||
--hide frames which won't be used
|
||||
if (newAmount < #self.Frames) then
|
||||
for i = newAmount+1, #self.Frames do
|
||||
self.Frames[i]:Hide()
|
||||
end
|
||||
end
|
||||
--set the new amount
|
||||
self.LineAmount = newAmount
|
||||
end,
|
||||
|
||||
SetFramesHeight = function(self, height)
|
||||
self.LineHeight = height
|
||||
self:OnSizeChanged()
|
||||
self:Refresh()
|
||||
end,
|
||||
|
||||
OnSizeChanged = function(self)
|
||||
if (self.ReajustNumFrames) then
|
||||
--how many lines the scroll can show
|
||||
local amountOfFramesToShow = floor(self:GetHeight() / self.LineHeight)
|
||||
|
||||
--how many lines the scroll already have
|
||||
local totalFramesCreated = self:GetNumFramesCreated()
|
||||
|
||||
--how many lines are current shown
|
||||
local totalFramesShown = self:GetNumFramesShown()
|
||||
|
||||
--the amount of frames increased
|
||||
if (amountOfFramesToShow > totalFramesShown) then
|
||||
for i = totalFramesShown+1, amountOfFramesToShow do
|
||||
--check if need to create a new line
|
||||
if (i > totalFramesCreated) then
|
||||
self:CreateLine(self.CreateLineFunc)
|
||||
end
|
||||
end
|
||||
|
||||
--the amount of frames decreased
|
||||
elseif (amountOfFramesToShow < totalFramesShown) then
|
||||
--hide all frames above the new amount to show
|
||||
for i = totalFramesCreated, amountOfFramesToShow, -1 do
|
||||
if (self.Frames[i]) then
|
||||
self.Frames[i]:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--set the new amount of frames
|
||||
self:SetNumFramesShown(amountOfFramesToShow)
|
||||
--refresh lines
|
||||
self:Refresh()
|
||||
end
|
||||
end,
|
||||
|
||||
--moved functions from blizzard faux scroll that are called from insecure code environment
|
||||
--this reduces the amount of taints while using the faux scroll frame
|
||||
GetOffsetFaux = function(self)
|
||||
return self.offset or 0
|
||||
end,
|
||||
OnVerticalScrollFaux = function(self, value, itemHeight, updateFunction)
|
||||
local scrollbar = self:GetChildFramesFaux();
|
||||
scrollbar:SetValue(value);
|
||||
self.offset = math.floor((value / itemHeight) + 0.5);
|
||||
if (updateFunction) then
|
||||
updateFunction(self)
|
||||
end
|
||||
end,
|
||||
GetChildFramesFaux = function(frame)
|
||||
local frameName = frame:GetName();
|
||||
if frameName then
|
||||
return _G[ frameName.."ScrollBar" ], _G[ frameName.."ScrollChildFrame" ], _G[ frameName.."ScrollBarScrollUpButton" ], _G[ frameName.."ScrollBarScrollDownButton" ];
|
||||
else
|
||||
return frame.ScrollBar, frame.ScrollChildFrame, frame.ScrollBar.ScrollUpButton, frame.ScrollBar.ScrollDownButton;
|
||||
end
|
||||
end,
|
||||
UpdateFaux = function(frame, numItems, numToDisplay, buttonHeight, button, smallWidth, bigWidth, highlightFrame, smallHighlightWidth, bigHighlightWidth, alwaysShowScrollBar)
|
||||
local scrollBar, scrollChildFrame, scrollUpButton, scrollDownButton = frame:GetChildFramesFaux();
|
||||
-- If more than one screen full of items then show the scrollbar
|
||||
local showScrollBar;
|
||||
if ( numItems > numToDisplay or alwaysShowScrollBar ) then
|
||||
frame:Show();
|
||||
showScrollBar = 1;
|
||||
else
|
||||
scrollBar:SetValue(0);
|
||||
frame:Hide();
|
||||
end
|
||||
if ( frame:IsShown() ) then
|
||||
local scrollFrameHeight = 0;
|
||||
local scrollChildHeight = 0;
|
||||
|
||||
if ( numItems > 0 ) then
|
||||
scrollFrameHeight = (numItems - numToDisplay) * buttonHeight;
|
||||
scrollChildHeight = numItems * buttonHeight;
|
||||
if ( scrollFrameHeight < 0 ) then
|
||||
scrollFrameHeight = 0;
|
||||
end
|
||||
scrollChildFrame:Show();
|
||||
else
|
||||
scrollChildFrame:Hide();
|
||||
end
|
||||
local maxRange = (numItems - numToDisplay) * buttonHeight;
|
||||
if (maxRange < 0) then
|
||||
maxRange = 0;
|
||||
end
|
||||
scrollBar:SetMinMaxValues(0, maxRange);
|
||||
scrollBar:SetValueStep(buttonHeight);
|
||||
scrollBar:SetStepsPerPage(numToDisplay-1);
|
||||
scrollChildFrame:SetHeight(scrollChildHeight);
|
||||
|
||||
-- Arrow button handling
|
||||
if ( scrollBar:GetValue() == 0 ) then
|
||||
scrollUpButton:Disable();
|
||||
else
|
||||
scrollUpButton:Enable();
|
||||
end
|
||||
if ((scrollBar:GetValue() - scrollFrameHeight) == 0) then
|
||||
scrollDownButton:Disable();
|
||||
else
|
||||
scrollDownButton:Enable();
|
||||
end
|
||||
|
||||
-- Shrink because scrollbar is shown
|
||||
if ( highlightFrame ) then
|
||||
highlightFrame:SetWidth(smallHighlightWidth);
|
||||
end
|
||||
if ( button ) then
|
||||
for i=1, numToDisplay do
|
||||
_G[button..i]:SetWidth(smallWidth);
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Widen because scrollbar is hidden
|
||||
if ( highlightFrame ) then
|
||||
highlightFrame:SetWidth(bigHighlightWidth);
|
||||
end
|
||||
if ( button ) then
|
||||
for i=1, numToDisplay do
|
||||
_G[button..i]:SetWidth(bigWidth);
|
||||
end
|
||||
end
|
||||
end
|
||||
return showScrollBar;
|
||||
end,
|
||||
}
|
||||
|
||||
--back compatibility, can be removed in the future (28/04/2023)
|
||||
---@class DetailsFramework.ScrollBoxFunctions : df_scrollboxmixin
|
||||
|
||||
local SortMember = ""
|
||||
local SortByMember = function(t1, t2)
|
||||
return t1[SortMember] > t2[SortMember]
|
||||
end
|
||||
local SortByMemberReverse = function(t1, t2)
|
||||
return t1[SortMember] < t2[SortMember]
|
||||
end
|
||||
|
||||
---mixin to use with DetailsFramework:Mixin(table, detailsFramework.SortFunctions)
|
||||
---adds the method Sort() to a table, this method can be used to sort another table by a member, can't sort itself
|
||||
---@class DetailsFramework.SortFunctions
|
||||
detailsFramework.SortFunctions = {
|
||||
---sort a table by a member
|
||||
---@param self table
|
||||
---@param tThisTable table
|
||||
---@param sMemberName string
|
||||
---@param bIsReverse boolean
|
||||
Sort = function(self, tThisTable, sMemberName, bIsReverse)
|
||||
SortMember = sMemberName
|
||||
if (not bIsReverse) then
|
||||
table.sort(tThisTable, SortByMember)
|
||||
else
|
||||
table.sort(tThisTable, SortByMemberReverse)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
---@class df_data : table
|
||||
---@field _dataInfo {data: table, dataCurrentIndex: number, callbacks: function[]}
|
||||
---@field callbacks table<function, any[]>
|
||||
---@field dataCurrentIndex number
|
||||
---@field DataConstructor fun(self: df_data)
|
||||
---@field AddDataChangeCallback fun(self: df_data, callback: function, ...: any)
|
||||
---@field RemoveDataChangeCallback fun(self: df_data, callback: function)
|
||||
---@field GetData fun(self: df_data)
|
||||
---@field GetDataSize fun(self: df_data) : number
|
||||
---@field GetDataFirstValue fun(self: df_data) : any
|
||||
---@field GetDataLastValue fun(self: df_data) : any
|
||||
---@field GetDataMinMaxValues fun(self: df_data) : number, number
|
||||
---@field GetDataMinMaxValueFromSubTable fun(self: df_data, key: string) : number, number when data uses sub tables, get the min max values from a specific index or key, if the value stored is number, return the min and max values
|
||||
---@field SetData fun(self: df_data, data: table, anyValue: any)
|
||||
---@field SetDataRaw fun(self: df_data, data: table) set the data without triggering callback
|
||||
---@field GetDataNextValue fun(self: df_data) : any
|
||||
---@field ResetDataIndex fun(self: df_data)
|
||||
|
||||
---mixin to use with DetailsFramework:Mixin(table, detailsFramework.DataMixin)
|
||||
---add 'data' to a table, this table can be used to store data for the object
|
||||
---@class DetailsFramework.DataMixin
|
||||
detailsFramework.DataMixin = {
|
||||
---initialize the data table
|
||||
---@param self table
|
||||
DataConstructor = function(self)
|
||||
self._dataInfo = {
|
||||
data = {},
|
||||
dataCurrentIndex = 1,
|
||||
callbacks = {},
|
||||
}
|
||||
end,
|
||||
|
||||
---when data is changed, functions registered with this function will be called
|
||||
---@param self table
|
||||
---@param func function
|
||||
---@param ... unknown
|
||||
AddDataChangeCallback = function(self, func, ...)
|
||||
assert(type(func) == "function", "invalid function for AddDataChangeCallback.")
|
||||
local allCallbacks = self._dataInfo.callbacks
|
||||
allCallbacks[func] = {...}
|
||||
end,
|
||||
|
||||
---remove a previous registered callback function
|
||||
---@param self table
|
||||
---@param func function
|
||||
RemoveDataChangeCallback = function(self, func)
|
||||
assert(type(func) == "function", "invalid function for RemoveDataChangeCallback.")
|
||||
local allCallbacks = self._dataInfo.callbacks
|
||||
allCallbacks[func] = nil
|
||||
end,
|
||||
|
||||
---set the data without callback
|
||||
---@param self table
|
||||
---@param data table
|
||||
SetDataRaw = function(self, data)
|
||||
assert(type(data) == "table", "invalid table for SetData.")
|
||||
self._dataInfo.data = data
|
||||
self:ResetDataIndex()
|
||||
end,
|
||||
|
||||
---set the data table
|
||||
---@param self table
|
||||
---@param data table
|
||||
---@param anyValue any @any value to pass to the callback functions before the payload is added
|
||||
SetData = function(self, data, anyValue)
|
||||
assert(type(data) == "table", "invalid table for SetData.")
|
||||
self._dataInfo.data = data
|
||||
self:ResetDataIndex()
|
||||
|
||||
local allCallbacks = self._dataInfo.callbacks
|
||||
for func, payload in pairs(allCallbacks) do
|
||||
xpcall(func, geterrorhandler(), data, anyValue, unpack(payload))
|
||||
end
|
||||
end,
|
||||
|
||||
---get the data table
|
||||
---@param self table
|
||||
GetData = function(self)
|
||||
return self._dataInfo.data
|
||||
end,
|
||||
|
||||
---get the next value from the data table
|
||||
---@param self table
|
||||
---@return any
|
||||
GetDataNextValue = function(self)
|
||||
local currentValue = self._dataInfo.dataCurrentIndex
|
||||
local value = self:GetData()[currentValue]
|
||||
self._dataInfo.dataCurrentIndex = self._dataInfo.dataCurrentIndex + 1
|
||||
return value
|
||||
end,
|
||||
|
||||
---reset the data index, making GetDataNextValue() return the first value again
|
||||
---@param self table
|
||||
ResetDataIndex = function(self)
|
||||
self._dataInfo.dataCurrentIndex = 1
|
||||
end,
|
||||
|
||||
---get the size of the data table
|
||||
---@param self table
|
||||
---@return number
|
||||
GetDataSize = function(self)
|
||||
return #self:GetData()
|
||||
end,
|
||||
|
||||
---get the first value from the data table
|
||||
---@param self table
|
||||
---@return any
|
||||
GetDataFirstValue = function(self)
|
||||
return self:GetData()[1]
|
||||
end,
|
||||
|
||||
---get the last value from the data table
|
||||
---@param self table
|
||||
---@return any
|
||||
GetDataLastValue = function(self)
|
||||
local data = self:GetData()
|
||||
return data[#data]
|
||||
end,
|
||||
|
||||
---get the min and max values from the data table, if the value stored is number, return the min and max values
|
||||
---could be used together with SetMinMaxValues from the df_value mixin
|
||||
---@param self table
|
||||
---@return number, number
|
||||
GetDataMinMaxValues = function(self)
|
||||
local minDataValue = 0
|
||||
local maxDataValue = 0
|
||||
|
||||
local data = self:GetData()
|
||||
for i = 1, #data do
|
||||
local thisData = data[i]
|
||||
if (thisData > maxDataValue) then
|
||||
maxDataValue = thisData
|
||||
|
||||
elseif (thisData < minDataValue) then
|
||||
minDataValue = thisData
|
||||
end
|
||||
end
|
||||
|
||||
return minDataValue, maxDataValue
|
||||
end,
|
||||
|
||||
---when data uses sub tables, get the min max values from a specific index or key, if the value stored is number, return the min and max values
|
||||
---@param self table
|
||||
---@param key string
|
||||
---@return number, number
|
||||
GetDataMinMaxValueFromSubTable = function(self, key)
|
||||
local minDataValue = 0
|
||||
local maxDataValue = 0
|
||||
|
||||
local data = self:GetData()
|
||||
for i = 1, #data do
|
||||
local thisData = data[i]
|
||||
if (thisData[key] > maxDataValue) then
|
||||
maxDataValue = thisData[key]
|
||||
|
||||
elseif (thisData[key] < minDataValue) then
|
||||
minDataValue = thisData[key]
|
||||
end
|
||||
end
|
||||
|
||||
return minDataValue, maxDataValue
|
||||
end,
|
||||
}
|
||||
|
||||
---@class df_value : table
|
||||
---@field minValue number
|
||||
---@field maxValue number
|
||||
---@field ValueConstructor fun(self: df_value)
|
||||
---@field SetMinMaxValues fun(self: df_value, minValue: number, maxValue: number)
|
||||
---@field GetMinMaxValues fun(self: df_value) : number, number
|
||||
---@field GetMinValue fun(self: df_value) : number
|
||||
---@field GetMaxValue fun(self: df_value) : number
|
||||
---@field SetMinValue fun(self: df_value, minValue: number)
|
||||
---@field SetMinValueIfLower fun(self: df_value, ...: number)
|
||||
---@field SetMaxValue fun(self: df_value, maxValue: number)
|
||||
---@field SetMaxValueIfBigger fun(self: df_value, ...: number)
|
||||
|
||||
---mixin to use with DetailsFramework:Mixin(table, detailsFramework.ValueMixin)
|
||||
---add support to min value and max value into a table or object
|
||||
---@class DetailsFramework.ValueMixin
|
||||
detailsFramework.ValueMixin = {
|
||||
---initialize the value table
|
||||
---@param self table
|
||||
ValueConstructor = function(self)
|
||||
self.minValue = 0
|
||||
self.maxValue = 1
|
||||
end,
|
||||
|
||||
---set the min and max values
|
||||
---@param self table
|
||||
---@param minValue number
|
||||
---@param maxValue number
|
||||
SetMinMaxValues = function(self, minValue, maxValue)
|
||||
self.minValue = minValue
|
||||
self.maxValue = maxValue
|
||||
end,
|
||||
|
||||
---get the min and max values
|
||||
---@param self table
|
||||
---@return number, number
|
||||
GetMinMaxValues = function(self)
|
||||
return self.minValue, self.maxValue
|
||||
end,
|
||||
|
||||
---get the min value
|
||||
---@param self table
|
||||
---@return number
|
||||
GetMinValue = function(self)
|
||||
return self.minValue
|
||||
end,
|
||||
|
||||
---get the max value
|
||||
---@param self table
|
||||
---@return number
|
||||
GetMaxValue = function(self)
|
||||
return self.maxValue
|
||||
end,
|
||||
|
||||
---set the min value
|
||||
---@param self table
|
||||
---@param minValue number
|
||||
SetMinValue = function(self, minValue)
|
||||
self.minValue = minValue
|
||||
end,
|
||||
|
||||
---set the min value if one of the values passed is lower than the current min value
|
||||
---@param self table
|
||||
---@param ... number
|
||||
SetMinValueIfLower = function(self, ...)
|
||||
self.minValue = math.min(self.minValue, ...)
|
||||
end,
|
||||
|
||||
---set the max value
|
||||
---@param self table
|
||||
---@param maxValue number
|
||||
SetMaxValue = function(self, maxValue)
|
||||
self.maxValue = maxValue
|
||||
end,
|
||||
|
||||
---set the max value if one of the values passed is bigger than the current max value
|
||||
---@param self table
|
||||
---@param ... number
|
||||
SetMaxValueIfBigger = function(self, ...)
|
||||
self.maxValue = math.max(self.maxValue, ...)
|
||||
end,
|
||||
}
|
||||
@@ -0,0 +1,861 @@
|
||||
|
||||
local DF = _G["DetailsFramework"]
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local _
|
||||
local _unpack = unpack
|
||||
local type = type
|
||||
local _math_floor = math.floor
|
||||
|
||||
local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0")
|
||||
local APIBarFunctions
|
||||
|
||||
do
|
||||
local metaPrototype = {
|
||||
WidgetType = "normal_bar",
|
||||
dversion = DF.dversion,
|
||||
}
|
||||
|
||||
--check if there's a metaPrototype already existing
|
||||
if (_G[DF.GlobalWidgetControlNames["normal_bar"]]) then
|
||||
--get the already existing metaPrototype
|
||||
local oldMetaPrototype = _G[DF.GlobalWidgetControlNames["normal_bar"]]
|
||||
--check if is older
|
||||
if ( (not oldMetaPrototype.dversion) or (oldMetaPrototype.dversion < DF.dversion) ) then
|
||||
--the version is older them the currently loading one
|
||||
--copy the new values into the old metatable
|
||||
for funcName, _ in pairs(metaPrototype) do
|
||||
oldMetaPrototype[funcName] = metaPrototype[funcName]
|
||||
end
|
||||
end
|
||||
else
|
||||
--first time loading the framework
|
||||
_G[DF.GlobalWidgetControlNames["normal_bar"]] = metaPrototype
|
||||
end
|
||||
end
|
||||
|
||||
local BarMetaFunctions = _G[DF.GlobalWidgetControlNames["normal_bar"]]
|
||||
DF:Mixin(BarMetaFunctions, DF.ScriptHookMixin)
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--metatables
|
||||
|
||||
BarMetaFunctions.__call = function(object, value)
|
||||
if (not value) then
|
||||
return object.statusbar:GetValue()
|
||||
else
|
||||
return object.statusbar:SetValue(value)
|
||||
end
|
||||
end
|
||||
|
||||
BarMetaFunctions.__add = function(v1, v2)
|
||||
if (type(v1) == "table") then
|
||||
local v = v1.statusbar:GetValue()
|
||||
v = v + v2
|
||||
v1.statusbar:SetValue(v)
|
||||
else
|
||||
local v = v2.statusbar:GetValue()
|
||||
v = v + v1
|
||||
v2.statusbar:SetValue(v)
|
||||
end
|
||||
end
|
||||
|
||||
BarMetaFunctions.__sub = function(v1, v2)
|
||||
if (type(v1) == "table") then
|
||||
local v = v1.statusbar:GetValue()
|
||||
v = v - v2
|
||||
v1.statusbar:SetValue(v)
|
||||
else
|
||||
local v = v2.statusbar:GetValue()
|
||||
v = v - v1
|
||||
v2.statusbar:SetValue(v)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--members
|
||||
|
||||
--tooltip
|
||||
local function gmember_tooltip (_object)
|
||||
return _object:GetTooltip()
|
||||
end
|
||||
--shown
|
||||
local gmember_shown = function(_object)
|
||||
return _object.statusbar:IsShown()
|
||||
end
|
||||
--frame width
|
||||
local gmember_width = function(_object)
|
||||
return _object.statusbar:GetWidth()
|
||||
end
|
||||
--frame height
|
||||
local gmember_height = function(_object)
|
||||
return _object.statusbar:GetHeight()
|
||||
end
|
||||
--value
|
||||
local gmember_value = function(_object)
|
||||
return _object.statusbar:GetValue()
|
||||
end
|
||||
--right text
|
||||
local gmember_rtext = function(_object)
|
||||
return _object.textright:GetText()
|
||||
end
|
||||
--left text
|
||||
local gmember_ltext = function(_object)
|
||||
return _object.textleft:GetText()
|
||||
end
|
||||
--left color
|
||||
local gmember_color = function(_object)
|
||||
local r, g, b, a = _object._texture:GetVertexColor()
|
||||
return r, g, b, a
|
||||
end
|
||||
--icon
|
||||
local gmember_icon = function(_object)
|
||||
return _object._icon:GetTexture()
|
||||
end
|
||||
--texture
|
||||
local gmember_texture = function(_object)
|
||||
return _object._texture:GetTexture()
|
||||
end
|
||||
--font size
|
||||
local gmember_textsize = function(_object)
|
||||
local _, fontsize = _object.textleft:GetFont()
|
||||
return fontsize
|
||||
end
|
||||
--font face
|
||||
local gmember_textfont = function(_object)
|
||||
local fontface = _object.textleft:GetFont()
|
||||
return fontface
|
||||
end
|
||||
--font color
|
||||
local gmember_textcolor = function(_object)
|
||||
return _object.textleft:GetTextColor()
|
||||
end
|
||||
--alpha
|
||||
local gmember_alpha= function(_object)
|
||||
return _object:GetAlpha()
|
||||
end
|
||||
|
||||
BarMetaFunctions.GetMembers = BarMetaFunctions.GetMembers or {}
|
||||
BarMetaFunctions.GetMembers ["tooltip"] = gmember_tooltip
|
||||
BarMetaFunctions.GetMembers ["shown"] = gmember_shown
|
||||
BarMetaFunctions.GetMembers ["width"] = gmember_width
|
||||
BarMetaFunctions.GetMembers ["height"] = gmember_height
|
||||
BarMetaFunctions.GetMembers ["value"] = gmember_value
|
||||
BarMetaFunctions.GetMembers ["lefttext"] = gmember_ltext
|
||||
BarMetaFunctions.GetMembers ["righttext"] = gmember_rtext
|
||||
BarMetaFunctions.GetMembers ["color"] = gmember_color
|
||||
BarMetaFunctions.GetMembers ["icon"] = gmember_icon
|
||||
BarMetaFunctions.GetMembers ["texture"] = gmember_texture
|
||||
BarMetaFunctions.GetMembers ["fontsize"] = gmember_textsize
|
||||
BarMetaFunctions.GetMembers ["fontface"] = gmember_textfont
|
||||
BarMetaFunctions.GetMembers ["fontcolor"] = gmember_textcolor
|
||||
BarMetaFunctions.GetMembers ["textsize"] = gmember_textsize --alias
|
||||
BarMetaFunctions.GetMembers ["textfont"] = gmember_textfont --alias
|
||||
BarMetaFunctions.GetMembers ["textcolor"] = gmember_textcolor --alias
|
||||
BarMetaFunctions.GetMembers ["alpha"] = gmember_alpha
|
||||
|
||||
BarMetaFunctions.__index = function(_table, _member_requested)
|
||||
|
||||
local func = BarMetaFunctions.GetMembers [_member_requested]
|
||||
if (func) then
|
||||
return func (_table, _member_requested)
|
||||
end
|
||||
|
||||
local fromMe = rawget (_table, _member_requested)
|
||||
if (fromMe) then
|
||||
return fromMe
|
||||
end
|
||||
|
||||
return BarMetaFunctions [_member_requested]
|
||||
end
|
||||
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--tooltip
|
||||
local smember_tooltip = function(_object, _value)
|
||||
return _object:SetTooltip (_value)
|
||||
end
|
||||
--show
|
||||
local smember_shown = function(_object, _value)
|
||||
if (_value) then
|
||||
return _object:Show()
|
||||
else
|
||||
return _object:Hide()
|
||||
end
|
||||
end
|
||||
--hide
|
||||
local smember_hide = function(_object, _value)
|
||||
if (_value) then
|
||||
return _object:Hide()
|
||||
else
|
||||
return _object:Show()
|
||||
end
|
||||
end
|
||||
--width
|
||||
local smember_width = function(_object, _value)
|
||||
return _object.statusbar:SetWidth(_value)
|
||||
end
|
||||
--height
|
||||
local smember_height = function(_object, _value)
|
||||
return _object.statusbar:SetHeight(_value)
|
||||
end
|
||||
--statusbar value
|
||||
local smember_value = function(_object, _value)
|
||||
_object.statusbar:SetValue(_value)
|
||||
return _object.div:SetPoint("left", _object.statusbar, "left", _value * (_object.statusbar:GetWidth()/100) - 16, 0)
|
||||
end
|
||||
--right text
|
||||
local smember_rtext = function(_object, _value)
|
||||
return _object.textright:SetText(_value)
|
||||
end
|
||||
--left text
|
||||
local smember_ltext = function(_object, _value)
|
||||
return _object.textleft:SetText(_value)
|
||||
end
|
||||
--color
|
||||
local smember_color = function(_object, _value)
|
||||
local _value1, _value2, _value3, _value4 = DF:ParseColors(_value)
|
||||
|
||||
_object.statusbar:SetStatusBarColor(_value1, _value2, _value3, _value4)
|
||||
_object._texture.original_colors = {_value1, _value2, _value3, _value4}
|
||||
_object.timer_texture:SetVertexColor(_value1, _value2, _value3, _value4)
|
||||
|
||||
_object.timer_textureR:SetVertexColor(_value1, _value2, _value3, _value4)
|
||||
|
||||
return _object._texture:SetVertexColor(_value1, _value2, _value3, _value4)
|
||||
end
|
||||
--background color
|
||||
local smember_backgroundcolor = function(_object, _value)
|
||||
local _value1, _value2, _value3, _value4 = DF:ParseColors(_value)
|
||||
return _object.background:SetVertexColor(_value1, _value2, _value3, _value4)
|
||||
end
|
||||
--icon
|
||||
local smember_icon = function(_object, _value)
|
||||
if (type(_value) == "table") then
|
||||
local _value1, _value2 = _unpack(_value)
|
||||
_object._icon:SetTexture(_value1)
|
||||
if (_value2) then
|
||||
_object._icon:SetTexCoord(_unpack(_value2))
|
||||
end
|
||||
else
|
||||
_object._icon:SetTexture(_value)
|
||||
end
|
||||
return
|
||||
end
|
||||
--texture
|
||||
local smember_texture = function(_object, _value)
|
||||
if (type(_value) == "table") then
|
||||
local _value1, _value2 = _unpack(_value)
|
||||
_object._texture:SetTexture(_value1)
|
||||
_object.timer_texture:SetTexture(_value1)
|
||||
_object.timer_textureR:SetTexture(_value1)
|
||||
if (_value2) then
|
||||
_object._texture:SetTexCoord(_unpack(_value2))
|
||||
_object.timer_texture:SetTexCoord(_unpack(_value2))
|
||||
_object.timer_textureR:SetTexCoord(_unpack(_value2))
|
||||
end
|
||||
else
|
||||
if (_value:find("\\")) then
|
||||
_object._texture:SetTexture(_value)
|
||||
else
|
||||
local file = SharedMedia:Fetch ("statusbar", _value)
|
||||
if (file) then
|
||||
_object._texture:SetTexture(file)
|
||||
_object.timer_texture:SetTexture(file)
|
||||
_object.timer_textureR:SetTexture(file)
|
||||
else
|
||||
_object._texture:SetTexture(_value)
|
||||
_object.timer_texture:SetTexture(_value)
|
||||
_object.timer_textureR:SetTexture(_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
--background texture
|
||||
local smember_backgroundtexture = function(_object, _value)
|
||||
if (_value:find("\\")) then
|
||||
_object.background:SetTexture(_value)
|
||||
else
|
||||
local file = SharedMedia:Fetch ("statusbar", _value)
|
||||
if (file) then
|
||||
_object.background:SetTexture(file)
|
||||
else
|
||||
_object.background:SetTexture(_value)
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
--font face
|
||||
local smember_textfont = function(_object, _value)
|
||||
DF:SetFontFace (_object.textleft, _value)
|
||||
return DF:SetFontFace (_object.textright, _value)
|
||||
end
|
||||
--font size
|
||||
local smember_textsize = function(_object, _value)
|
||||
DF:SetFontSize(_object.textleft, _value)
|
||||
return DF:SetFontSize(_object.textright, _value)
|
||||
end
|
||||
--font color
|
||||
local smember_textcolor = function(_object, _value)
|
||||
local _value1, _value2, _value3, _value4 = DF:ParseColors(_value)
|
||||
_object.textleft:SetTextColor(_value1, _value2, _value3, _value4)
|
||||
return _object.textright:SetTextColor(_value1, _value2, _value3, _value4)
|
||||
end
|
||||
--outline (shadow)
|
||||
local smember_outline = function(_object, _value)
|
||||
DF:SetFontOutline (_object.textleft, _value)
|
||||
return DF:SetFontOutline (_object.textright, _value)
|
||||
end
|
||||
--alpha
|
||||
local smember_alpha= function(_object, _value)
|
||||
return _object:SetAlpha(_value)
|
||||
end
|
||||
|
||||
BarMetaFunctions.SetMembers = BarMetaFunctions.SetMembers or {}
|
||||
BarMetaFunctions.SetMembers["tooltip"] = smember_tooltip
|
||||
BarMetaFunctions.SetMembers["shown"] = smember_shown
|
||||
BarMetaFunctions.SetMembers["width"] = smember_width
|
||||
BarMetaFunctions.SetMembers["height"] = smember_height
|
||||
BarMetaFunctions.SetMembers["value"] = smember_value
|
||||
BarMetaFunctions.SetMembers["righttext"] = smember_rtext
|
||||
BarMetaFunctions.SetMembers["lefttext"] = smember_ltext
|
||||
BarMetaFunctions.SetMembers["color"] = smember_color
|
||||
BarMetaFunctions.SetMembers["backgroundcolor"] = smember_backgroundcolor
|
||||
BarMetaFunctions.SetMembers["icon"] = smember_icon
|
||||
BarMetaFunctions.SetMembers["texture"] = smember_texture
|
||||
BarMetaFunctions.SetMembers["backgroundtexture"] = smember_backgroundtexture
|
||||
BarMetaFunctions.SetMembers["fontsize"] = smember_textsize
|
||||
BarMetaFunctions.SetMembers["fontface"] = smember_textfont
|
||||
BarMetaFunctions.SetMembers["fontcolor"] = smember_textcolor
|
||||
BarMetaFunctions.SetMembers["textsize"] = smember_textsize --alias
|
||||
BarMetaFunctions.SetMembers["textfont"] = smember_textfont --alias
|
||||
BarMetaFunctions.SetMembers["textcolor"] = smember_textcolor --alias
|
||||
BarMetaFunctions.SetMembers["shadow"] = smember_outline
|
||||
BarMetaFunctions.SetMembers["outline"] = smember_outline --alias
|
||||
BarMetaFunctions.SetMembers["alpha"] = smember_alpha
|
||||
|
||||
BarMetaFunctions.__newindex = function(_table, _key, _value)
|
||||
|
||||
local func = BarMetaFunctions.SetMembers [_key]
|
||||
if (func) then
|
||||
return func (_table, _value)
|
||||
else
|
||||
return rawset (_table, _key, _value)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--methods
|
||||
|
||||
--show & hide
|
||||
function BarMetaFunctions:Show()
|
||||
self.statusbar:Show()
|
||||
end
|
||||
function BarMetaFunctions:Hide()
|
||||
self.statusbar:Hide()
|
||||
end
|
||||
|
||||
|
||||
--return color
|
||||
function BarMetaFunctions:GetVertexColor()
|
||||
return self._texture:GetVertexColor()
|
||||
end
|
||||
|
||||
--set value (status bar)
|
||||
|
||||
function BarMetaFunctions:SetValue(value)
|
||||
if (not value) then
|
||||
value = 0
|
||||
end
|
||||
self.statusbar:SetValue(value)
|
||||
self.div:SetPoint("left", self.statusbar, "left", value * (self.statusbar:GetWidth()/100) - 16, 0)
|
||||
end
|
||||
|
||||
--set point
|
||||
function BarMetaFunctions:SetPoint(v1, v2, v3, v4, v5)
|
||||
v1, v2, v3, v4, v5 = DF:CheckPoints (v1, v2, v3, v4, v5, self)
|
||||
if (not v1) then
|
||||
print("Invalid parameter for SetPoint")
|
||||
return
|
||||
end
|
||||
return self.widget:SetPoint(v1, v2, v3, v4, v5)
|
||||
end
|
||||
|
||||
--set sizes
|
||||
function BarMetaFunctions:SetSize(w, h)
|
||||
if (w) then
|
||||
self.statusbar:SetWidth(w)
|
||||
end
|
||||
if (h) then
|
||||
self.statusbar:SetHeight(h)
|
||||
end
|
||||
end
|
||||
|
||||
--set texture
|
||||
function BarMetaFunctions:SetTexture(texture)
|
||||
self._texture:SetTexture(texture)
|
||||
end
|
||||
|
||||
--set texts
|
||||
function BarMetaFunctions:SetLeftText (text)
|
||||
self.textleft:SetText(text)
|
||||
end
|
||||
function BarMetaFunctions:SetRightText (text)
|
||||
self.textright:SetText(text)
|
||||
end
|
||||
|
||||
--set color
|
||||
function BarMetaFunctions:SetColor (r, g, b, a)
|
||||
r, g, b, a = DF:ParseColors(r, g, b, a)
|
||||
|
||||
self._texture:SetVertexColor(r, g, b, a)
|
||||
self.statusbar:SetStatusBarColor(r, g, b, a)
|
||||
self._texture.original_colors = {r, g, b, a}
|
||||
end
|
||||
|
||||
--set icons
|
||||
function BarMetaFunctions:SetIcon (texture, ...)
|
||||
self._icon:SetTexture(texture)
|
||||
if (...) then
|
||||
local L, R, U, D = _unpack(...)
|
||||
self._icon:SetTexCoord(L, R, U, D)
|
||||
end
|
||||
end
|
||||
|
||||
--show div
|
||||
function BarMetaFunctions:ShowDiv (bool)
|
||||
if (bool) then
|
||||
self.div:Show()
|
||||
else
|
||||
self.div:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
-- tooltip
|
||||
function BarMetaFunctions:SetTooltip (tooltip)
|
||||
if (tooltip) then
|
||||
return rawset (self, "have_tooltip", tooltip)
|
||||
else
|
||||
return rawset (self, "have_tooltip", nil)
|
||||
end
|
||||
end
|
||||
function BarMetaFunctions:GetTooltip()
|
||||
return rawget (self, "have_tooltip")
|
||||
end
|
||||
|
||||
-- frame levels
|
||||
function BarMetaFunctions:GetFrameLevel()
|
||||
return self.statusbar:GetFrameLevel()
|
||||
end
|
||||
function BarMetaFunctions:SetFrameLevel(level, frame)
|
||||
if (not frame) then
|
||||
return self.statusbar:SetFrameLevel(level)
|
||||
else
|
||||
local framelevel = frame:GetFrameLevel (frame) + level
|
||||
return self.statusbar:SetFrameLevel(framelevel)
|
||||
end
|
||||
end
|
||||
|
||||
-- frame stratas
|
||||
function BarMetaFunctions:SetFrameStrata()
|
||||
return self.statusbar:GetFrameStrata()
|
||||
end
|
||||
function BarMetaFunctions:SetFrameStrata(strata)
|
||||
if (type(strata) == "table") then
|
||||
self.statusbar:SetFrameStrata(strata:GetFrameStrata())
|
||||
else
|
||||
self.statusbar:SetFrameStrata(strata)
|
||||
end
|
||||
end
|
||||
|
||||
--container
|
||||
function BarMetaFunctions:SetContainer (container)
|
||||
self.container = container
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--scripts
|
||||
|
||||
local OnEnter = function(frame)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnEnter", frame, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
frame.MyObject.background:Show()
|
||||
|
||||
if (frame.MyObject.have_tooltip) then
|
||||
GameCooltip2:Reset()
|
||||
GameCooltip2:AddLine(frame.MyObject.have_tooltip)
|
||||
GameCooltip2:ShowCooltip(frame, "tooltip")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local OnLeave = function(frame)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnLeave", frame, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
frame.MyObject.background:Hide()
|
||||
|
||||
if (frame.MyObject.have_tooltip) then
|
||||
GameCooltip2:ShowMe(false)
|
||||
end
|
||||
end
|
||||
|
||||
local OnHide = function(frame)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnHide", frame, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local OnShow = function(frame)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnShow", frame, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local OnMouseDown = function(frame, button)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnMouseDown", frame, button, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
if (not frame.MyObject.container.isLocked and frame.MyObject.container:IsMovable()) then
|
||||
if (not frame.isLocked and frame:IsMovable()) then
|
||||
frame.MyObject.container.isMoving = true
|
||||
frame.MyObject.container:StartMoving()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local OnMouseUp = function(frame, button)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnMouseUp", frame, button, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
if (frame.MyObject.container.isMoving) then
|
||||
frame.MyObject.container:StopMovingOrSizing()
|
||||
frame.MyObject.container.isMoving = false
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--timer
|
||||
|
||||
function BarMetaFunctions:OnTimerEnd()
|
||||
local capsule = self
|
||||
local kill = capsule:RunHooksForWidget("OnTimerEnd", self.widget, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
self.timer_texture:Hide()
|
||||
self.timer_textureR:Hide()
|
||||
self.div_timer:Hide()
|
||||
self:Hide()
|
||||
self.timer = false
|
||||
end
|
||||
|
||||
function BarMetaFunctions:CancelTimerBar(no_timer_end)
|
||||
if (not self.HasTimer) then
|
||||
return
|
||||
end
|
||||
if (self.TimerScheduled) then
|
||||
DF:CancelTimer(self.TimerScheduled)
|
||||
self.TimerScheduled = nil
|
||||
else
|
||||
if (self.statusbar:GetScript("OnUpdate")) then
|
||||
self.statusbar:SetScript("OnUpdate", nil)
|
||||
end
|
||||
end
|
||||
|
||||
self.righttext = ""
|
||||
self.timer_texture:Hide()
|
||||
self.timer_textureR:Hide()
|
||||
|
||||
if (not no_timer_end) then
|
||||
self:OnTimerEnd()
|
||||
end
|
||||
end
|
||||
|
||||
local OnUpdate = function(self, elapsed)
|
||||
--percent of elapsed
|
||||
local pct = abs(self.end_timer - GetTime() - self.tempo) / self.tempo
|
||||
|
||||
if (self.inverse) then
|
||||
self.t:SetWidth(self.total_size * pct)
|
||||
else
|
||||
self.t:SetWidth(self.total_size * abs(pct-1))
|
||||
end
|
||||
|
||||
--right text
|
||||
self.remaining = self.remaining - elapsed
|
||||
if (self.MyObject.RightTextIsTimer) then
|
||||
self.righttext:SetText(DF:IntegerToTimer(self.remaining))
|
||||
else
|
||||
self.righttext:SetText(_math_floor(self.remaining))
|
||||
end
|
||||
|
||||
if (pct >= 1) then
|
||||
self.righttext:SetText("")
|
||||
self:SetScript("OnUpdate", nil)
|
||||
self.MyObject.HasTimer = nil
|
||||
self.MyObject:OnTimerEnd()
|
||||
end
|
||||
end
|
||||
|
||||
function BarMetaFunctions:SetTimer (tempo, end_at)
|
||||
if (end_at) then
|
||||
self.statusbar.tempo = end_at - tempo
|
||||
self.statusbar.remaining = end_at - GetTime()
|
||||
self.statusbar.end_timer = end_at
|
||||
else
|
||||
self.statusbar.tempo = tempo
|
||||
self.statusbar.remaining = tempo
|
||||
self.statusbar.end_timer = GetTime() + tempo
|
||||
end
|
||||
|
||||
self.statusbar.total_size = self.statusbar:GetWidth()
|
||||
self.statusbar.inverse = self.BarIsInverse
|
||||
|
||||
self(0)
|
||||
|
||||
self.div_timer:Show()
|
||||
self.background:Show()
|
||||
self:Show()
|
||||
|
||||
if (self.LeftToRight) then
|
||||
self.timer_texture:Hide()
|
||||
self.timer_textureR:Show()
|
||||
self.statusbar.t = self.timer_textureR
|
||||
self.timer_textureR:ClearAllPoints()
|
||||
self.timer_textureR:SetPoint("right", self.statusbar, "right")
|
||||
self.div_timer:SetPoint("left", self.timer_textureR, "left", -14, -1)
|
||||
else
|
||||
self.timer_texture:Show()
|
||||
self.timer_textureR:Hide()
|
||||
self.statusbar.t = self.timer_texture
|
||||
self.timer_texture:ClearAllPoints()
|
||||
self.timer_texture:SetPoint("left", self.statusbar, "left")
|
||||
self.div_timer:SetPoint("left", self.timer_texture, "right", -16, -1)
|
||||
end
|
||||
|
||||
if (self.BarIsInverse) then
|
||||
self.statusbar.t:SetWidth(1)
|
||||
else
|
||||
self.statusbar.t:SetWidth(self.statusbar.total_size)
|
||||
end
|
||||
|
||||
self.timer = true
|
||||
|
||||
self.HasTimer = true
|
||||
self.TimerScheduled = DF:ScheduleTimer("StartTimeBarAnimation", 0.1, self)
|
||||
end
|
||||
|
||||
function DF:StartTimeBarAnimation (timebar)
|
||||
timebar.TimerScheduled = nil
|
||||
timebar.statusbar:SetScript("OnUpdate", OnUpdate)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--object constructor
|
||||
|
||||
function DetailsFrameworkNormalBar_OnCreate (self)
|
||||
self.texture.original_colors = {1, 1, 1, 1}
|
||||
self.background.original_colors = {.3, .3, .3, .3}
|
||||
self.timertexture.original_colors = {.3, .3, .3, .3}
|
||||
return true
|
||||
end
|
||||
|
||||
local build_statusbar = function(self)
|
||||
|
||||
self:SetSize(300, 14)
|
||||
|
||||
self.background = self:CreateTexture("$parent_background", "BACKGROUND")
|
||||
self.background:Hide()
|
||||
self.background:SetAllPoints()
|
||||
self.background:SetTexture([[Interface\PaperDollInfoFrame\UI-Character-Skills-Bar]])
|
||||
self.background:SetVertexColor(.3, .3, .3, .3)
|
||||
|
||||
self.timertexture = self:CreateTexture("$parent_timerTexture", "ARTWORK")
|
||||
self.timertexture:Hide()
|
||||
self.timertexture:SetSize(300, 14)
|
||||
self.timertexture:SetTexture([[Interface\PaperDollInfoFrame\UI-Character-Skills-Bar]])
|
||||
self.timertexture:SetPoint("LEFT", self, "LEFT")
|
||||
|
||||
self.timertextureR = self:CreateTexture("$parent_timerTextureR", "ARTWORK")
|
||||
self.timertextureR:Hide()
|
||||
self.timertextureR:SetSize(300, 14)
|
||||
self.timertextureR:SetTexture([[Interface\PaperDollInfoFrame\UI-Character-Skills-Bar]])
|
||||
self.timertextureR:SetPoint("TOPRIGHT", self, 0, 0)
|
||||
self.timertextureR:SetPoint("BOTTOMRIGHT", self, 0, 0)
|
||||
|
||||
self.texture = self:CreateTexture("$parent_statusbarTexture", "ARTWORK")
|
||||
self.texture:SetSize(300, 14)
|
||||
self.texture:SetTexture([[Interface\PaperDollInfoFrame\UI-Character-Skills-Bar]])
|
||||
|
||||
self:SetStatusBarTexture(self.texture)
|
||||
|
||||
self.icontexture = self:CreateTexture("$parent_icon", "OVERLAY")
|
||||
self.icontexture:SetSize(14, 14)
|
||||
self.icontexture:SetPoint("LEFT", self, "LEFT")
|
||||
|
||||
self.sparkmouseover = self:CreateTexture("$parent_sparkMouseover", "OVERLAY")
|
||||
self.sparkmouseover:SetSize(32, 32)
|
||||
self.sparkmouseover:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
|
||||
self.sparkmouseover:SetBlendMode("ADD")
|
||||
self.sparkmouseover:SetPoint("LEFT", self, "RIGHT", -16, -1)
|
||||
self.sparkmouseover:Hide()
|
||||
|
||||
self.sparktimer = self:CreateTexture("$parent_sparkTimer", "OVERLAY")
|
||||
self.sparktimer:SetSize(32, 32)
|
||||
self.sparktimer:SetPoint("LEFT", self.timertexture, "RIGHT", -16, -1)
|
||||
self.sparktimer:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
|
||||
self.sparktimer:SetBlendMode("ADD")
|
||||
self.sparktimer:Hide()
|
||||
|
||||
self.lefttext = self:CreateFontString("$parent_TextLeft", "OVERLAY", "GameFontHighlight")
|
||||
self.lefttext:SetJustifyH("LEFT")
|
||||
self.lefttext:SetPoint("LEFT", self.icontexture, "RIGHT", 3, 0)
|
||||
DF:SetFontSize(self.lefttext, 10)
|
||||
|
||||
self.righttext = self:CreateFontString("$parent_TextRight", "OVERLAY", "GameFontHighlight")
|
||||
self.righttext:SetJustifyH("LEFT")
|
||||
DF:SetFontSize(self.righttext, 10)
|
||||
self.righttext:SetPoint("RIGHT", self, "RIGHT", -3, 0)
|
||||
|
||||
DetailsFrameworkNormalBar_OnCreate (self)
|
||||
end
|
||||
|
||||
function DF:CreateBar (parent, texture, w, h, value, member, name)
|
||||
return DF:NewBar (parent, parent, name, member, w, h, value, texture)
|
||||
end
|
||||
|
||||
function DF:NewBar (parent, container, name, member, w, h, value, texture_name)
|
||||
|
||||
if (not name) then
|
||||
name = "DetailsFrameworkBarNumber" .. DF.BarNameCounter
|
||||
DF.BarNameCounter = DF.BarNameCounter + 1
|
||||
|
||||
elseif (not parent) then
|
||||
return error("Details! FrameWork: parent not found.", 2)
|
||||
elseif (not container) then
|
||||
container = parent
|
||||
end
|
||||
|
||||
if (name:find("$parent")) then
|
||||
local parentName = DF.GetParentName(parent)
|
||||
name = name:gsub("$parent", parentName)
|
||||
end
|
||||
|
||||
local BarObject = {type = "bar", dframework = true}
|
||||
|
||||
if (member) then
|
||||
parent [member] = BarObject
|
||||
end
|
||||
|
||||
if (parent.dframework) then
|
||||
parent = parent.widget
|
||||
end
|
||||
if (container.dframework) then
|
||||
container = container.widget
|
||||
end
|
||||
|
||||
value = value or 0
|
||||
w = w or 150
|
||||
h = h or 14
|
||||
|
||||
--default members:
|
||||
--misc
|
||||
BarObject.locked = false
|
||||
|
||||
BarObject.container = container
|
||||
|
||||
--create widgets
|
||||
BarObject.statusbar = CreateFrame("statusbar", name, parent)
|
||||
DF:Mixin(BarObject.statusbar, DF.WidgetFunctions)
|
||||
|
||||
build_statusbar (BarObject.statusbar)
|
||||
|
||||
BarObject.widget = BarObject.statusbar
|
||||
|
||||
if (not APIBarFunctions) then
|
||||
APIBarFunctions = true
|
||||
local idx = getmetatable(BarObject.statusbar).__index
|
||||
for funcName, funcAddress in pairs(idx) do
|
||||
if (not BarMetaFunctions [funcName]) then
|
||||
BarMetaFunctions [funcName] = function(object, ...)
|
||||
local x = loadstring ( "return _G['"..object.statusbar:GetName().."']:"..funcName.."(...)")
|
||||
return x (...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BarObject.statusbar:SetHeight(h)
|
||||
BarObject.statusbar:SetWidth(w)
|
||||
BarObject.statusbar:SetFrameLevel(parent:GetFrameLevel()+1)
|
||||
BarObject.statusbar:SetMinMaxValues(0, 100)
|
||||
BarObject.statusbar:SetValue(value or 50)
|
||||
BarObject.statusbar.MyObject = BarObject
|
||||
|
||||
BarObject.timer_texture = _G [name .. "_timerTexture"]
|
||||
BarObject.timer_texture:SetWidth(w)
|
||||
BarObject.timer_texture:SetHeight(h)
|
||||
|
||||
BarObject.timer_textureR = _G [name .. "_timerTextureR"]
|
||||
BarObject.timer_textureR:Hide()
|
||||
|
||||
BarObject._texture = _G [name .. "_statusbarTexture"]
|
||||
BarObject.background = _G [name .. "_background"]
|
||||
BarObject._icon = _G [name .. "_icon"]
|
||||
BarObject.textleft = _G [name .. "_TextLeft"]
|
||||
BarObject.textright = _G [name .. "_TextRight"]
|
||||
BarObject.div = _G [name .. "_sparkMouseover"]
|
||||
BarObject.div_timer = _G [name .. "_sparkTimer"]
|
||||
|
||||
--hooks
|
||||
BarObject.HookList = {
|
||||
OnEnter = {},
|
||||
OnLeave = {},
|
||||
OnHide = {},
|
||||
OnShow = {},
|
||||
OnMouseDown = {},
|
||||
OnMouseUp = {},
|
||||
OnTimerEnd = {},
|
||||
}
|
||||
|
||||
BarObject.statusbar:SetScript("OnEnter", OnEnter)
|
||||
BarObject.statusbar:SetScript("OnLeave", OnLeave)
|
||||
BarObject.statusbar:SetScript("OnHide", OnHide)
|
||||
BarObject.statusbar:SetScript("OnShow", OnShow)
|
||||
BarObject.statusbar:SetScript("OnMouseDown", OnMouseDown)
|
||||
BarObject.statusbar:SetScript("OnMouseUp", OnMouseUp)
|
||||
|
||||
--set class
|
||||
setmetatable(BarObject, BarMetaFunctions)
|
||||
|
||||
--set texture
|
||||
if (texture_name) then
|
||||
smember_texture (BarObject, texture_name)
|
||||
end
|
||||
|
||||
return BarObject
|
||||
end --endd
|
||||
@@ -0,0 +1,3 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ .. \FrameXML\UI.xsd">
|
||||
<Script file="normal_bar.lua"/>
|
||||
</Ui>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ .. \FrameXML\UI.xsd">
|
||||
<Script file="panel.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,346 @@
|
||||
|
||||
local detailsFramework = _G["DetailsFramework"]
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local _
|
||||
local APIImageFunctions = false
|
||||
|
||||
do
|
||||
local metaPrototype = {
|
||||
WidgetType = "image",
|
||||
dversion = detailsFramework.dversion,
|
||||
}
|
||||
|
||||
--check if there's a metaPrototype already existing
|
||||
if (_G[detailsFramework.GlobalWidgetControlNames["image"]]) then
|
||||
--get the already existing metaPrototype
|
||||
local oldMetaPrototype = _G[detailsFramework.GlobalWidgetControlNames["image"]]
|
||||
--check if is older
|
||||
if ( (not oldMetaPrototype.dversion) or (oldMetaPrototype.dversion < detailsFramework.dversion) ) then
|
||||
--the version is older them the currently loading one
|
||||
--copy the new values into the old metatable
|
||||
for funcName, _ in pairs(metaPrototype) do
|
||||
oldMetaPrototype[funcName] = metaPrototype[funcName]
|
||||
end
|
||||
end
|
||||
else
|
||||
--first time loading the framework
|
||||
_G[detailsFramework.GlobalWidgetControlNames["image"]] = metaPrototype
|
||||
end
|
||||
end
|
||||
|
||||
local ImageMetaFunctions = _G[detailsFramework.GlobalWidgetControlNames["image"]]
|
||||
|
||||
detailsFramework:Mixin(ImageMetaFunctions, detailsFramework.SetPointMixin)
|
||||
detailsFramework:Mixin(ImageMetaFunctions, detailsFramework.ScriptHookMixin)
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--metatables
|
||||
|
||||
ImageMetaFunctions.__call = function(object, value)
|
||||
return object.image:SetTexture(value)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--members
|
||||
|
||||
--frame width
|
||||
local gmember_width = function(object)
|
||||
return object.image:GetWidth()
|
||||
end
|
||||
|
||||
--frame height
|
||||
local gmember_height = function(object)
|
||||
return object.image:GetHeight()
|
||||
end
|
||||
|
||||
--texture
|
||||
local gmember_texture = function(object)
|
||||
return object.image:GetTexture()
|
||||
end
|
||||
|
||||
--alpha
|
||||
local gmember_alpha = function(object)
|
||||
return object.image:GetAlpha()
|
||||
end
|
||||
|
||||
--saturation
|
||||
local gmember_saturation = function(object)
|
||||
return object.image:GetDesaturated()
|
||||
end
|
||||
|
||||
--atlas
|
||||
local gmember_atlas = function(object)
|
||||
return object.image:GetAtlas()
|
||||
end
|
||||
|
||||
--texcoords
|
||||
local gmember_texcoord = function(object)
|
||||
return object.image:GetTexCoord()
|
||||
end
|
||||
|
||||
ImageMetaFunctions.GetMembers = ImageMetaFunctions.GetMembers or {}
|
||||
detailsFramework:Mixin(ImageMetaFunctions.GetMembers, detailsFramework.DefaultMetaFunctionsGet)
|
||||
detailsFramework:Mixin(ImageMetaFunctions.GetMembers, detailsFramework.LayeredRegionMetaFunctionsGet)
|
||||
|
||||
ImageMetaFunctions.GetMembers["alpha"] = gmember_alpha
|
||||
ImageMetaFunctions.GetMembers["width"] = gmember_width
|
||||
ImageMetaFunctions.GetMembers["height"] = gmember_height
|
||||
ImageMetaFunctions.GetMembers["texture"] = gmember_texture
|
||||
ImageMetaFunctions.GetMembers["blackwhite"] = gmember_saturation
|
||||
ImageMetaFunctions.GetMembers["desaturated"] = gmember_saturation
|
||||
ImageMetaFunctions.GetMembers["atlas"] = gmember_atlas
|
||||
ImageMetaFunctions.GetMembers["texcoord"] = gmember_texcoord
|
||||
|
||||
ImageMetaFunctions.__index = function(object, key)
|
||||
local func = ImageMetaFunctions.GetMembers[key]
|
||||
if (func) then
|
||||
return func(object, key)
|
||||
end
|
||||
|
||||
local fromMe = rawget(object, key)
|
||||
if (fromMe) then
|
||||
return fromMe
|
||||
end
|
||||
|
||||
return ImageMetaFunctions[key]
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--texture
|
||||
local smember_texture = function(object, value)
|
||||
if (type(value) == "table") then
|
||||
local red, green, blue, alpha = detailsFramework:ParseColors(value)
|
||||
object.image:SetTexture(red, green, blue, alpha)
|
||||
else
|
||||
if (detailsFramework:IsHtmlColor(value)) then
|
||||
local red, green, blue, alpha = detailsFramework:ParseColors(value)
|
||||
object.image:SetTexture(red, green, blue, alpha)
|
||||
else
|
||||
object.image:SetTexture(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--width
|
||||
local smember_width = function(object, value)
|
||||
return object.image:SetWidth(value)
|
||||
end
|
||||
|
||||
--height
|
||||
local smember_height = function(object, value)
|
||||
return object.image:SetHeight(value)
|
||||
end
|
||||
|
||||
--alpha
|
||||
local smember_alpha = function(object, value)
|
||||
return object.image:SetAlpha(value)
|
||||
end
|
||||
|
||||
--color
|
||||
local smember_color = function(object, value)
|
||||
local red, green, blue, alpha = detailsFramework:ParseColors(value)
|
||||
object.image:SetColorTexture(red, green, blue, alpha)
|
||||
end
|
||||
|
||||
--vertex color
|
||||
local smember_vertexcolor = function(object, value)
|
||||
local red, green, blue, alpha = detailsFramework:ParseColors(value)
|
||||
object.image:SetVertexColor(red, green, blue, alpha)
|
||||
end
|
||||
|
||||
--desaturated
|
||||
local smember_desaturated = function(object, value)
|
||||
if (value) then
|
||||
object:SetDesaturated(true)
|
||||
else
|
||||
object:SetDesaturated(false)
|
||||
end
|
||||
end
|
||||
|
||||
--texcoords
|
||||
local smember_texcoord = function(object, value)
|
||||
if (value) then
|
||||
object:SetTexCoord(unpack(value))
|
||||
else
|
||||
object:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
end
|
||||
|
||||
--atlas
|
||||
local smember_atlas = function(object, value)
|
||||
if (value) then
|
||||
object:SetAtlas(value)
|
||||
end
|
||||
end
|
||||
|
||||
--gradient
|
||||
local smember_gradient = function(object, value)
|
||||
if (type(value) == "table" and value.gradient and value.fromColor and value.toColor) then
|
||||
object.image:SetColorTexture(1, 1, 1, 1)
|
||||
local fromColor = detailsFramework:FormatColor("tablemembers", value.fromColor)
|
||||
local toColor = detailsFramework:FormatColor("tablemembers", value.toColor)
|
||||
object.image:SetGradient(value.gradient, fromColor, toColor)
|
||||
else
|
||||
error("texture.gradient expect a table{gradient = 'gradient type', fromColor = 'color', toColor = 'color'}")
|
||||
end
|
||||
end
|
||||
|
||||
ImageMetaFunctions.SetMembers = ImageMetaFunctions.SetMembers or {}
|
||||
detailsFramework:Mixin(ImageMetaFunctions.SetMembers, detailsFramework.DefaultMetaFunctionsSet)
|
||||
detailsFramework:Mixin(ImageMetaFunctions.SetMembers, detailsFramework.LayeredRegionMetaFunctionsSet)
|
||||
|
||||
ImageMetaFunctions.SetMembers["alpha"] = smember_alpha
|
||||
ImageMetaFunctions.SetMembers["width"] = smember_width
|
||||
ImageMetaFunctions.SetMembers["height"] = smember_height
|
||||
ImageMetaFunctions.SetMembers["texture"] = smember_texture
|
||||
ImageMetaFunctions.SetMembers["texcoord"] = smember_texcoord
|
||||
ImageMetaFunctions.SetMembers["color"] = smember_color
|
||||
ImageMetaFunctions.SetMembers["vertexcolor"] = smember_vertexcolor
|
||||
ImageMetaFunctions.SetMembers["blackwhite"] = smember_desaturated
|
||||
ImageMetaFunctions.SetMembers["desaturated"] = smember_desaturated
|
||||
ImageMetaFunctions.SetMembers["atlas"] = smember_atlas
|
||||
ImageMetaFunctions.SetMembers["gradient"] = smember_gradient
|
||||
|
||||
ImageMetaFunctions.__newindex = function(object, key, value)
|
||||
local func = ImageMetaFunctions.SetMembers[key]
|
||||
if (func) then
|
||||
return func(object, value)
|
||||
else
|
||||
return rawset(object, key, value)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--methods
|
||||
--size
|
||||
function ImageMetaFunctions:SetSize(width, height)
|
||||
if (width) then
|
||||
self.image:SetWidth(width)
|
||||
end
|
||||
if (height) then
|
||||
return self.image:SetHeight(height)
|
||||
end
|
||||
end
|
||||
|
||||
function ImageMetaFunctions:SetGradient(gradientType, fromColor, toColor)
|
||||
fromColor = detailsFramework:FormatColor("tablemembers", fromColor)
|
||||
toColor = detailsFramework:FormatColor("tablemembers", toColor)
|
||||
self.image:SetGradient(gradientType, fromColor, toColor)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--object constructor
|
||||
|
||||
function detailsFramework:CreateTexture(parent, texture, width, height, layer, coords, member, name)
|
||||
return detailsFramework:NewImage(parent, texture, width, height, layer, coords, member, name)
|
||||
end
|
||||
|
||||
function detailsFramework:CreateImage(parent, texture, width, height, layer, coords, member, name)
|
||||
return detailsFramework:NewImage(parent, texture, width, height, layer, coords, member, name)
|
||||
end
|
||||
|
||||
function detailsFramework:NewImage(parent, texture, width, height, layer, texCoord, member, name)
|
||||
if (not parent) then
|
||||
return error("DetailsFrameWork: NewImage() parent not found.", 2)
|
||||
end
|
||||
|
||||
if (not name) then
|
||||
name = "DetailsFrameworkPictureNumber" .. detailsFramework.PictureNameCounter
|
||||
detailsFramework.PictureNameCounter = detailsFramework.PictureNameCounter + 1
|
||||
end
|
||||
|
||||
if (name:find("$parent")) then
|
||||
local parentName = detailsFramework.GetParentName(parent)
|
||||
name = name:gsub("$parent", parentName)
|
||||
end
|
||||
|
||||
local ImageObject = {type = "image", dframework = true}
|
||||
|
||||
if (member) then
|
||||
parent[member] = ImageObject
|
||||
end
|
||||
|
||||
if (parent.dframework) then
|
||||
parent = parent.widget
|
||||
end
|
||||
|
||||
texture = texture or ""
|
||||
|
||||
ImageObject.image = parent:CreateTexture(name, layer or "overlay")
|
||||
ImageObject.widget = ImageObject.image
|
||||
|
||||
detailsFramework:Mixin(ImageObject.image, detailsFramework.WidgetFunctions)
|
||||
|
||||
if (not APIImageFunctions) then
|
||||
APIImageFunctions = true
|
||||
local idx = getmetatable(ImageObject.image).__index
|
||||
for funcName, funcAddress in pairs(idx) do
|
||||
if (not ImageMetaFunctions[funcName]) then
|
||||
ImageMetaFunctions[funcName] = function(object, ...)
|
||||
local x = loadstring( "return _G['" .. object.image:GetName() .. "']:" .. funcName .. "(...)")
|
||||
return x(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ImageObject.image.MyObject = ImageObject
|
||||
|
||||
if (width) then
|
||||
ImageObject.image:SetWidth(width)
|
||||
end
|
||||
if (height) then
|
||||
ImageObject.image:SetHeight(height)
|
||||
end
|
||||
|
||||
if (texture) then
|
||||
if (type(texture) == "table") then
|
||||
if (texture.gradient) then
|
||||
if (detailsFramework.IsDragonflight() or detailsFramework.IsWotLKWowWithRetailAPI()) then
|
||||
ImageObject.image:SetColorTexture(1, 1, 1, 1)
|
||||
local fromColor = detailsFramework:FormatColor("tablemembers", texture.fromColor)
|
||||
local toColor = detailsFramework:FormatColor("tablemembers", texture.toColor)
|
||||
ImageObject.image:SetGradient(texture.gradient, fromColor, toColor)
|
||||
else
|
||||
local fromR, fromG, fromB, fromA = detailsFramework:ParseColors(texture.fromColor)
|
||||
local toR, toG, toB, toA = detailsFramework:ParseColors(texture.toColor)
|
||||
ImageObject.image:SetColorTexture(1, 1, 1, 1)
|
||||
ImageObject.image:SetGradientAlpha(texture.gradient, fromR, fromG, fromB, fromA, toR, toG, toB, toA)
|
||||
end
|
||||
else
|
||||
local r, g, b, a = detailsFramework:ParseColors(texture)
|
||||
ImageObject.image:SetColorTexture(r, g, b, a)
|
||||
end
|
||||
|
||||
elseif (type(texture) == "string") then
|
||||
local isAtlas = C_Texture.GetAtlasInfo(texture)
|
||||
if (isAtlas) then
|
||||
ImageObject.image:SetAtlas(texture)
|
||||
else
|
||||
if (detailsFramework:IsHtmlColor(texture)) then
|
||||
local r, g, b = detailsFramework:ParseColors(texture)
|
||||
ImageObject.image:SetColorTexture(r, g, b)
|
||||
else
|
||||
ImageObject.image:SetTexture(texture)
|
||||
end
|
||||
end
|
||||
else
|
||||
ImageObject.image:SetTexture(texture)
|
||||
end
|
||||
end
|
||||
|
||||
if (texCoord and type(texCoord) == "table" and texCoord[4]) then
|
||||
ImageObject.image:SetTexCoord(unpack(texCoord))
|
||||
end
|
||||
|
||||
ImageObject.HookList = {
|
||||
}
|
||||
|
||||
setmetatable(ImageObject, ImageMetaFunctions)
|
||||
|
||||
return ImageObject
|
||||
end
|
||||
@@ -0,0 +1,607 @@
|
||||
|
||||
local DF = _G["DetailsFramework"]
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local _
|
||||
local texCoordinates
|
||||
|
||||
local CreateImageEditorFrame = function()
|
||||
local editorWindow = DF:NewPanel(UIParent, nil, "DetailsFrameworkImageEdit", nil, 650, 500, false)
|
||||
editorWindow:SetPoint("center", UIParent, "center")
|
||||
editorWindow:SetResizable(true)
|
||||
editorWindow:SetMovable(true)
|
||||
editorWindow:SetClampedToScreen(true)
|
||||
tinsert(UISpecialFrames, "DetailsFrameworkImageEdit")
|
||||
editorWindow:SetFrameStrata("TOOLTIP")
|
||||
|
||||
if (not DetailsFramework.IsDragonflight()) then
|
||||
editorWindow:SetMaxResize(500, 500)
|
||||
else
|
||||
editorWindow:SetResizeBounds(100, 100, 500, 500)
|
||||
end
|
||||
|
||||
_G.DetailsFrameworkImageEditTable = editorWindow
|
||||
|
||||
editorWindow.hooks = {}
|
||||
|
||||
local background = DF:NewImage(editorWindow, nil, nil, nil, "background", nil, "background", "$parentBackground")
|
||||
background:SetAllPoints()
|
||||
background:SetTexture(0, 0, 0, .8)
|
||||
|
||||
local edit_texture = DF:NewImage(editorWindow, nil, 500, 500, "artwork", nil, "edit_texture", "$parentImage")
|
||||
edit_texture:SetAllPoints()
|
||||
_G.DetailsFrameworkImageEdit_EditTexture = edit_texture
|
||||
|
||||
local background_frame = CreateFrame("frame", "DetailsFrameworkImageEditBackground", DetailsFrameworkImageEdit, "BackdropTemplate")
|
||||
background_frame:SetPoint("topleft", DetailsFrameworkImageEdit, "topleft", -10, 30)
|
||||
background_frame:SetFrameStrata("TOOLTIP")
|
||||
background_frame:SetFrameLevel(editorWindow:GetFrameLevel())
|
||||
background_frame:SetSize(790, 560)
|
||||
|
||||
background_frame:SetResizable(true)
|
||||
background_frame:SetMovable(true)
|
||||
|
||||
background_frame:SetScript("OnMouseDown", function()
|
||||
editorWindow:StartMoving()
|
||||
end)
|
||||
background_frame:SetScript("OnMouseUp", function()
|
||||
editorWindow:StopMovingOrSizing()
|
||||
end)
|
||||
|
||||
DF:CreateTitleBar (background_frame, "Image Editor")
|
||||
DF:ApplyStandardBackdrop(background_frame, false, 0.98)
|
||||
DF:CreateStatusBar(background_frame)
|
||||
|
||||
background_frame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||
background_frame:SetBackdropColor(0, 0, 0, 0.9)
|
||||
background_frame:SetBackdropBorderColor(0, 0, 0, 1)
|
||||
|
||||
local haveHFlip = false
|
||||
local haveVFlip = false
|
||||
|
||||
--Top Slider
|
||||
local topCoordTexture = DF:NewImage(editorWindow, nil, nil, nil, "overlay", nil, nil, "$parentImageTopCoord")
|
||||
topCoordTexture:SetPoint("topleft", editorWindow, "topleft")
|
||||
topCoordTexture:SetPoint("topright", editorWindow, "topright")
|
||||
topCoordTexture:SetColorTexture(1, 0, 0)
|
||||
topCoordTexture.height = 1
|
||||
topCoordTexture.alpha = .2
|
||||
|
||||
local topSlider = DF:NewSlider (editorWindow, nil, "$parentTopSlider", "topSlider", 100, 100, 0.1, 100, 0.1, 0)
|
||||
topSlider:SetAllPoints(editorWindow.widget)
|
||||
topSlider:SetOrientation("VERTICAL")
|
||||
topSlider.backdrop = nil
|
||||
topSlider.fractional = true
|
||||
topSlider:SetHook("OnEnter", function() return true end)
|
||||
topSlider:SetHook("OnLeave", function() return true end)
|
||||
|
||||
local topSliderThumpTexture = topSlider:CreateTexture(nil, "overlay")
|
||||
topSliderThumpTexture:SetColorTexture(1, 1, 1)
|
||||
topSliderThumpTexture:SetWidth(512)
|
||||
topSliderThumpTexture:SetHeight(1)
|
||||
topSlider:SetThumbTexture (topSliderThumpTexture)
|
||||
|
||||
topSlider:SetHook("OnValueChange", function(_, _, value)
|
||||
topCoordTexture.image:SetHeight(editorWindow.frame:GetHeight()/100*value)
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
end)
|
||||
|
||||
topSlider:Hide()
|
||||
|
||||
--Bottom Slider
|
||||
local bottomCoordTexture = DF:NewImage(editorWindow, nil, nil, nil, "overlay", nil, nil, "$parentImageBottomCoord")
|
||||
bottomCoordTexture:SetPoint("bottomleft", editorWindow, "bottomleft", 0, 0)
|
||||
bottomCoordTexture:SetPoint("bottomright", editorWindow, "bottomright", 0, 0)
|
||||
bottomCoordTexture:SetColorTexture(1, 0, 0)
|
||||
bottomCoordTexture.height = 1
|
||||
bottomCoordTexture.alpha = .2
|
||||
|
||||
local bottomSlider = DF:NewSlider (editorWindow, nil, "$parentBottomSlider", "bottomSlider", 100, 100, 0.1, 100, 0.1, 100)
|
||||
bottomSlider:SetAllPoints(editorWindow.widget)
|
||||
bottomSlider:SetOrientation("VERTICAL")
|
||||
bottomSlider.backdrop = nil
|
||||
bottomSlider.fractional = true
|
||||
bottomSlider:SetHook("OnEnter", function() return true end)
|
||||
bottomSlider:SetHook("OnLeave", function() return true end)
|
||||
|
||||
local bottomSliderThumpTexture = bottomSlider:CreateTexture(nil, "overlay")
|
||||
bottomSliderThumpTexture:SetColorTexture(1, 1, 1)
|
||||
bottomSliderThumpTexture:SetWidth(512)
|
||||
bottomSliderThumpTexture:SetHeight(1)
|
||||
bottomSlider:SetThumbTexture (bottomSliderThumpTexture)
|
||||
|
||||
bottomSlider:SetHook("OnValueChange", function(_, _, value)
|
||||
value = math.abs(value-100)
|
||||
bottomCoordTexture.image:SetHeight(math.max(editorWindow.frame:GetHeight()/100*value, 1))
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
end)
|
||||
|
||||
bottomSlider:Hide()
|
||||
|
||||
--Left Slider
|
||||
local leftCoordTexture = DF:NewImage(editorWindow, nil, nil, nil, "overlay", nil, nil, "$parentImageLeftCoord")
|
||||
leftCoordTexture:SetPoint("topleft", editorWindow, "topleft", 0, 0)
|
||||
leftCoordTexture:SetPoint("bottomleft", editorWindow, "bottomleft", 0, 0)
|
||||
leftCoordTexture:SetColorTexture(1, 0, 0)
|
||||
leftCoordTexture.width = 1
|
||||
leftCoordTexture.alpha = .2
|
||||
|
||||
local leftSlider = DF:NewSlider (editorWindow, nil, "$parentLeftSlider", "leftSlider", 100, 100, 0.1, 100, 0.1, 0.1)
|
||||
leftSlider:SetAllPoints(editorWindow.widget)
|
||||
leftSlider.backdrop = nil
|
||||
leftSlider.fractional = true
|
||||
leftSlider:SetHook("OnEnter", function() return true end)
|
||||
leftSlider:SetHook("OnLeave", function() return true end)
|
||||
|
||||
local leftSliderThumpTexture = leftSlider:CreateTexture(nil, "overlay")
|
||||
leftSliderThumpTexture:SetColorTexture(1, 1, 1)
|
||||
leftSliderThumpTexture:SetWidth(1)
|
||||
leftSliderThumpTexture:SetHeight(512)
|
||||
leftSlider:SetThumbTexture (leftSliderThumpTexture)
|
||||
|
||||
leftSlider:SetHook("OnValueChange", function(_, _, value)
|
||||
leftCoordTexture.image:SetWidth(editorWindow.frame:GetWidth()/100*value)
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
end)
|
||||
|
||||
leftSlider:Hide()
|
||||
|
||||
--Right Slider
|
||||
local rightCoordTexture = DF:NewImage(editorWindow, nil, nil, nil, "overlay", nil, nil, "$parentImageRightCoord")
|
||||
rightCoordTexture:SetPoint("topright", editorWindow, "topright", 0, 0)
|
||||
rightCoordTexture:SetPoint("bottomright", editorWindow, "bottomright", 0, 0)
|
||||
rightCoordTexture:SetColorTexture(1, 0, 0)
|
||||
rightCoordTexture.width = 1
|
||||
rightCoordTexture.alpha = .2
|
||||
|
||||
local rightSlider = DF:NewSlider (editorWindow, nil, "$parentRightSlider", "rightSlider", 100, 100, 0.1, 100, 0.1, 100)
|
||||
rightSlider:SetAllPoints(editorWindow.widget)
|
||||
rightSlider.backdrop = nil
|
||||
rightSlider.fractional = true
|
||||
rightSlider:SetHook("OnEnter", function() return true end)
|
||||
rightSlider:SetHook("OnLeave", function() return true end)
|
||||
--[
|
||||
local rightSliderThumpTexture = rightSlider:CreateTexture(nil, "overlay")
|
||||
rightSliderThumpTexture:SetColorTexture(1, 1, 1)
|
||||
rightSliderThumpTexture:SetWidth(1)
|
||||
rightSliderThumpTexture:SetHeight(512)
|
||||
rightSlider:SetThumbTexture (rightSliderThumpTexture)
|
||||
--]]
|
||||
rightSlider:SetHook("OnValueChange", function(_, _, value)
|
||||
value = math.abs(value-100)
|
||||
rightCoordTexture.image:SetWidth(math.max(editorWindow.frame:GetWidth()/100*value, 1))
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
end)
|
||||
|
||||
rightSlider:Hide()
|
||||
|
||||
--Edit Buttons
|
||||
local buttonsBackground = DF:NewPanel(UIParent, nil, "DetailsFrameworkImageEditButtonsBg", nil, 115, 230)
|
||||
--buttonsBackground:SetPoint("topleft", window, "topright", 2, 0)
|
||||
buttonsBackground:SetPoint("topright", background_frame, "topright", -8, -10)
|
||||
buttonsBackground:Hide()
|
||||
--buttonsBackground:SetMovable(true)
|
||||
tinsert(UISpecialFrames, "DetailsFrameworkImageEditButtonsBg")
|
||||
buttonsBackground:SetFrameStrata("TOOLTIP")
|
||||
|
||||
local alphaFrameShown = false
|
||||
|
||||
local editingSide = nil
|
||||
local lastButton = nil
|
||||
local alphaFrame
|
||||
local originalColor = {0.9999, 0.8196, 0}
|
||||
|
||||
local enableTexEdit = function(button, bottom, side)
|
||||
|
||||
if (alphaFrameShown) then
|
||||
alphaFrame:Hide()
|
||||
alphaFrameShown = false
|
||||
button.text:SetTextColor(unpack(originalColor))
|
||||
end
|
||||
|
||||
if (ColorPickerFrame:IsShown()) then
|
||||
ColorPickerFrame:Hide()
|
||||
end
|
||||
|
||||
if (lastButton) then
|
||||
lastButton.text:SetTextColor(unpack(originalColor))
|
||||
end
|
||||
|
||||
if (editingSide == side) then
|
||||
editorWindow [editingSide.."Slider"]:Hide()
|
||||
editingSide = nil
|
||||
return
|
||||
|
||||
elseif (editingSide) then
|
||||
editorWindow [editingSide.."Slider"]:Hide()
|
||||
end
|
||||
|
||||
editingSide = side
|
||||
button.text:SetTextColor(1, 1, 1)
|
||||
lastButton = button
|
||||
|
||||
editorWindow [side.."Slider"]:Show()
|
||||
end
|
||||
|
||||
local yMod = -10
|
||||
|
||||
local leftTexCoordButton = DF:NewButton(buttonsBackground, nil, "$parentLeftTexButton", nil, 100, 20, enableTexEdit, "left", nil, nil, "Crop Left", 1)
|
||||
leftTexCoordButton:SetPoint("topright", buttonsBackground, "topright", -8, -10 + yMod)
|
||||
leftTexCoordButton:SetTemplate(DF:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
|
||||
local rightTexCoordButton = DF:NewButton(buttonsBackground, nil, "$parentRightTexButton", nil, 100, 20, enableTexEdit, "right", nil, nil, "Crop Right", 1)
|
||||
rightTexCoordButton:SetPoint("topright", buttonsBackground, "topright", -8, -30 + yMod)
|
||||
rightTexCoordButton:SetTemplate(DF:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
|
||||
local topTexCoordButton = DF:NewButton(buttonsBackground, nil, "$parentTopTexButton", nil, 100, 20, enableTexEdit, "top", nil, nil, "Crop Top", 1)
|
||||
topTexCoordButton:SetPoint("topright", buttonsBackground, "topright", -8, -50 + yMod)
|
||||
topTexCoordButton:SetTemplate(DF:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
|
||||
local bottomTexCoordButton = DF:NewButton(buttonsBackground, nil, "$parentBottomTexButton", nil, 100, 20, enableTexEdit, "bottom", nil, nil, "Crop Bottom", 1)
|
||||
bottomTexCoordButton:SetPoint("topright", buttonsBackground, "topright", -8, -70 + yMod)
|
||||
bottomTexCoordButton:SetTemplate(DF:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
|
||||
local Alpha = DF:NewButton(buttonsBackground, nil, "$parentBottomAlphaButton", nil, 100, 20, alpha, nil, nil, nil, "Alpha", 1)
|
||||
Alpha:SetPoint("topright", buttonsBackground, "topright", -8, -115 + yMod)
|
||||
Alpha:SetTemplate(DF:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
|
||||
--overlay color
|
||||
local selectedColor = function(default)
|
||||
if (default) then
|
||||
edit_texture:SetVertexColor(unpack(default))
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
else
|
||||
edit_texture:SetVertexColor(ColorPickerFrame:GetColorRGB())
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local changeColor = function()
|
||||
|
||||
ColorPickerFrame.func = nil
|
||||
ColorPickerFrame.opacityFunc = nil
|
||||
ColorPickerFrame.cancelFunc = nil
|
||||
ColorPickerFrame.previousValues = nil
|
||||
|
||||
local right, g, bottom = edit_texture:GetVertexColor()
|
||||
ColorPickerFrame:SetColorRGB (right, g, bottom)
|
||||
ColorPickerFrame:SetParent(buttonsBackground.widget)
|
||||
ColorPickerFrame.hasOpacity = false
|
||||
ColorPickerFrame.previousValues = {right, g, bottom}
|
||||
ColorPickerFrame.func = selectedColor
|
||||
ColorPickerFrame.cancelFunc = selectedColor
|
||||
ColorPickerFrame:ClearAllPoints()
|
||||
ColorPickerFrame:SetPoint("left", buttonsBackground.widget, "right")
|
||||
ColorPickerFrame:Show()
|
||||
|
||||
if (alphaFrameShown) then
|
||||
alphaFrame:Hide()
|
||||
alphaFrameShown = false
|
||||
Alpha.button.text:SetTextColor(unpack(originalColor))
|
||||
end
|
||||
|
||||
if (lastButton) then
|
||||
lastButton.text:SetTextColor(unpack(originalColor))
|
||||
if (editingSide) then
|
||||
editorWindow [editingSide.."Slider"]:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local changeColorButton = DF:NewButton(buttonsBackground, nil, "$parentOverlayColorButton", nil, 100, 20, changeColor, nil, nil, nil, "Color", 1)
|
||||
changeColorButton:SetPoint("topright", buttonsBackground, "topright", -8, -95 + yMod)
|
||||
changeColorButton:SetTemplate(DF:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
|
||||
alphaFrame = DF:NewPanel(buttonsBackground, nil, "DetailsFrameworkImageEditAlphaBg", nil, 40, 225)
|
||||
alphaFrame:SetPoint("topleft", buttonsBackground, "topright", 2, 0)
|
||||
alphaFrame:Hide()
|
||||
local alphaSlider = DF:NewSlider (alphaFrame, nil, "$parentAlphaSlider", "alphaSlider", 30, 220, 1, 100, 1, edit_texture:GetAlpha()*100)
|
||||
alphaSlider:SetPoint("top", alphaFrame, "top", 0, -5)
|
||||
alphaSlider:SetOrientation("VERTICAL")
|
||||
alphaSlider.thumb:SetSize(40, 30)
|
||||
--leftSlider.backdrop = nil
|
||||
--leftSlider.fractional = true
|
||||
|
||||
local alpha = function(button)
|
||||
|
||||
if (ColorPickerFrame:IsShown()) then
|
||||
ColorPickerFrame:Hide()
|
||||
end
|
||||
|
||||
if (lastButton) then
|
||||
lastButton.text:SetTextColor(unpack(originalColor))
|
||||
if (editingSide) then
|
||||
editorWindow [editingSide.."Slider"]:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
if (not alphaFrameShown) then
|
||||
alphaFrame:Show()
|
||||
alphaSlider:SetValue(edit_texture:GetAlpha()*100)
|
||||
alphaFrameShown = true
|
||||
button.text:SetTextColor(1, 1, 1)
|
||||
else
|
||||
alphaFrame:Hide()
|
||||
alphaFrameShown = false
|
||||
button.text:SetTextColor(unpack(originalColor))
|
||||
end
|
||||
end
|
||||
|
||||
Alpha.clickfunction = alpha
|
||||
|
||||
alphaSlider:SetHook("OnValueChange", function(_, _, value)
|
||||
edit_texture:SetAlpha(value/100)
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
end)
|
||||
|
||||
local resizer = CreateFrame("Button", nil, editorWindow.widget, "BackdropTemplate")
|
||||
resizer:SetNormalTexture([[Interface\AddOns\Details\images\skins\default_skin]])
|
||||
resizer:SetHighlightTexture([[Interface\AddOns\Details\images\skins\default_skin]])
|
||||
resizer:GetNormalTexture():SetTexCoord(0.00146484375, 0.01513671875, 0.24560546875, 0.25927734375)
|
||||
resizer:GetHighlightTexture():SetTexCoord(0.00146484375, 0.01513671875, 0.24560546875, 0.25927734375)
|
||||
resizer:SetWidth(16)
|
||||
resizer:SetHeight(16)
|
||||
resizer:SetPoint("BOTTOMRIGHT", editorWindow.widget, "BOTTOMRIGHT", 0, 0)
|
||||
resizer:EnableMouse(true)
|
||||
resizer:SetFrameLevel(editorWindow.widget:GetFrameLevel() + 2)
|
||||
|
||||
resizer:SetScript("OnMouseDown", function(self, button)
|
||||
editorWindow.widget:StartSizing("BOTTOMRIGHT")
|
||||
end)
|
||||
|
||||
resizer:SetScript("OnMouseUp", function(self, button)
|
||||
editorWindow.widget:StopMovingOrSizing()
|
||||
end)
|
||||
|
||||
editorWindow.widget:SetScript("OnMouseDown", function()
|
||||
editorWindow.widget:StartMoving()
|
||||
end)
|
||||
editorWindow.widget:SetScript("OnMouseUp", function()
|
||||
editorWindow.widget:StopMovingOrSizing()
|
||||
end)
|
||||
|
||||
editorWindow.widget:SetScript("OnSizeChanged", function()
|
||||
edit_texture.width = editorWindow.width
|
||||
edit_texture.height = editorWindow.height
|
||||
leftSliderThumpTexture:SetHeight(editorWindow.height)
|
||||
rightSliderThumpTexture:SetHeight(editorWindow.height)
|
||||
topSliderThumpTexture:SetWidth(editorWindow.width)
|
||||
bottomSliderThumpTexture:SetWidth(editorWindow.width)
|
||||
|
||||
rightCoordTexture.image:SetWidth(math.max( (editorWindow.frame:GetWidth() / 100 * math.abs(rightSlider:GetValue()-100)), 1))
|
||||
leftCoordTexture.image:SetWidth(editorWindow.frame:GetWidth()/100*leftSlider:GetValue())
|
||||
bottomCoordTexture:SetHeight(math.max( (editorWindow.frame:GetHeight() / 100 * math.abs(bottomSlider:GetValue()-100)), 1))
|
||||
topCoordTexture:SetHeight(editorWindow.frame:GetHeight()/100*topSlider:GetValue())
|
||||
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
end)
|
||||
|
||||
--flip button
|
||||
local flip = function(button, bottom, side)
|
||||
if (side == 1) then
|
||||
haveHFlip = not haveHFlip
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
elseif (side == 2) then
|
||||
haveVFlip = not haveVFlip
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local flipButtonH = DF:NewButton(buttonsBackground, nil, "$parentFlipButton", nil, 100, 20, flip, 1, nil, nil, "Flip H", 1)
|
||||
flipButtonH:SetPoint("topright", buttonsBackground, "topright", -8, -140 + yMod)
|
||||
flipButtonH:SetTemplate(DF:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
|
||||
--select area to crop
|
||||
local dragFrame = CreateFrame("frame", nil, background_frame, "BackdropTemplate")
|
||||
dragFrame:EnableMouse(false)
|
||||
dragFrame:SetFrameStrata("TOOLTIP")
|
||||
dragFrame:SetPoint("topleft", edit_texture.widget, "topleft")
|
||||
dragFrame:SetPoint("bottomright", edit_texture.widget, "bottomright")
|
||||
dragFrame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Worldmap\UI-QuestBlob-Inside]], tileSize = 256, tile = true})
|
||||
dragFrame:SetBackdropColor(1, 1, 1, .2)
|
||||
dragFrame:Hide()
|
||||
|
||||
local selectionBoxUp = dragFrame:CreateTexture(nil, "overlay")
|
||||
selectionBoxUp:SetHeight(1)
|
||||
selectionBoxUp:SetColorTexture(1, 1, 1)
|
||||
|
||||
local selectionBoxDown = dragFrame:CreateTexture(nil, "overlay")
|
||||
selectionBoxDown:SetHeight(1)
|
||||
selectionBoxDown:SetColorTexture(1, 1, 1)
|
||||
|
||||
local selectionBoxLeft = dragFrame:CreateTexture(nil, "overlay")
|
||||
selectionBoxLeft:SetWidth(1)
|
||||
selectionBoxLeft:SetColorTexture(1, 1, 1)
|
||||
|
||||
local selectionBoxRight = dragFrame:CreateTexture(nil, "overlay")
|
||||
selectionBoxRight:SetWidth(1)
|
||||
selectionBoxRight:SetColorTexture(1, 1, 1)
|
||||
|
||||
function dragFrame.ClearSelectionBoxPoints()
|
||||
selectionBoxUp:ClearAllPoints()
|
||||
selectionBoxDown:ClearAllPoints()
|
||||
selectionBoxLeft:ClearAllPoints()
|
||||
selectionBoxRight:ClearAllPoints()
|
||||
end
|
||||
|
||||
local startCropFunc = function()
|
||||
dragFrame:Show()
|
||||
dragFrame:EnableMouse(true)
|
||||
end
|
||||
|
||||
local cropSelection = DF:NewButton(buttonsBackground, nil, "$parentCropSelection", nil, 100, 20, startCropFunc, 2, nil, nil, "Crop Selection", 1)
|
||||
cropSelection:InstallCustomTexture()
|
||||
|
||||
dragFrame.OnTick = function(self, deltaTime)
|
||||
local x1, y1 = unpack(self.ClickedAt)
|
||||
local x2, y2 = GetCursorPosition()
|
||||
dragFrame.ClearSelectionBoxPoints()
|
||||
|
||||
if (x2 > x1) then
|
||||
--right
|
||||
if (y1 > y2) then
|
||||
--top
|
||||
selectionBoxUp:SetPoint("topleft", UIParent, "bottomleft", x1, y1)
|
||||
selectionBoxUp:SetPoint("topright", UIParent, "bottomleft", x2, y1)
|
||||
|
||||
selectionBoxLeft:SetPoint("topleft", UIParent, "bottomleft", x1, y1)
|
||||
selectionBoxLeft:SetPoint("bottomleft", UIParent, "bottomleft", x1, y2)
|
||||
|
||||
else
|
||||
--bottom
|
||||
end
|
||||
else
|
||||
--left
|
||||
if (y2 > y1) then
|
||||
--top
|
||||
else
|
||||
--bottom
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
dragFrame:SetScript("OnMouseDown", function(self, MouseButton)
|
||||
if (MouseButton == "LeftButton") then
|
||||
self.ClickedAt = {GetCursorPosition()}
|
||||
dragFrame:SetScript("OnUpdate", dragFrame.OnTick)
|
||||
end
|
||||
end)
|
||||
|
||||
dragFrame:SetScript("OnMouseUp", function(self, MouseButton)
|
||||
if (MouseButton == "LeftButton") then
|
||||
self.ReleaseAt = {GetCursorPosition()}
|
||||
dragFrame:EnableMouse(false)
|
||||
dragFrame:Hide()
|
||||
dragFrame:SetScript("OnUpdate", nil)
|
||||
print(self.ClickedAt[1], self.ClickedAt[2], self.ReleaseAt[1], self.ReleaseAt[2])
|
||||
end
|
||||
end)
|
||||
|
||||
--accept
|
||||
editorWindow.accept = function(self, bottom, keepEditing)
|
||||
if (not keepEditing) then
|
||||
buttonsBackground:Hide()
|
||||
editorWindow:Hide()
|
||||
alphaFrame:Hide()
|
||||
ColorPickerFrame:Hide()
|
||||
end
|
||||
|
||||
local coords = {}
|
||||
local left, right, top, bottom = leftSlider.value/100, rightSlider.value/100, topSlider.value/100, bottomSlider.value/100
|
||||
|
||||
if (haveHFlip) then
|
||||
coords [1] = right
|
||||
coords [2] = left
|
||||
else
|
||||
coords [1] = left
|
||||
coords [2] = right
|
||||
end
|
||||
|
||||
if (haveVFlip) then
|
||||
coords [3] = bottom
|
||||
coords [4] = top
|
||||
else
|
||||
coords [3] = top
|
||||
coords [4] = bottom
|
||||
end
|
||||
|
||||
return editorWindow.callback_func(edit_texture.width, edit_texture.height, {edit_texture:GetVertexColor()}, edit_texture:GetAlpha(), coords, editorWindow.extra_param)
|
||||
end
|
||||
|
||||
local acceptButton = DF:NewButton(buttonsBackground, nil, "$parentAcceptButton", nil, 100, 20, editorWindow.accept, nil, nil, nil, "Done", 1)
|
||||
acceptButton:SetPoint("topright", buttonsBackground, "topright", -8, -200)
|
||||
acceptButton:SetTemplate(DF:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
|
||||
function DF:RefreshImageEditor()
|
||||
if (edit_texture.maximize) then
|
||||
DetailsFrameworkImageEdit:SetSize(266, 226)
|
||||
else
|
||||
DetailsFrameworkImageEdit:SetSize(edit_texture.width, edit_texture.height)
|
||||
end
|
||||
|
||||
local left, right, top, bottom = unpack(texCoordinates)
|
||||
|
||||
if (left > right) then
|
||||
haveHFlip = true
|
||||
leftSlider:SetValue(right * 100)
|
||||
rightSlider:SetValue(left * 100)
|
||||
else
|
||||
haveHFlip = false
|
||||
leftSlider:SetValue(left * 100)
|
||||
rightSlider:SetValue(right * 100)
|
||||
end
|
||||
|
||||
if (top > bottom) then
|
||||
haveVFlip = true
|
||||
topSlider:SetValue(bottom * 100)
|
||||
bottomSlider:SetValue(top * 100)
|
||||
else
|
||||
haveVFlip = false
|
||||
topSlider:SetValue(top * 100)
|
||||
bottomSlider:SetValue(bottom * 100)
|
||||
end
|
||||
|
||||
if (editorWindow.callback_func) then
|
||||
editorWindow.accept(nil, nil, true)
|
||||
end
|
||||
end
|
||||
|
||||
editorWindow:Hide()
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
function DF:ImageEditor(callback, texture, texcoord, colors, width, height, extraParam, alpha, maximize)
|
||||
if (not _G.DetailsFrameworkImageEdit) then
|
||||
CreateImageEditorFrame()
|
||||
end
|
||||
|
||||
local window = _G.DetailsFrameworkImageEditTable
|
||||
|
||||
texcoord = texcoord or {0, 1, 0, 1}
|
||||
texCoordinates = texcoord
|
||||
|
||||
colors = colors or {1, 1, 1, 1}
|
||||
|
||||
alpha = alpha or 1
|
||||
|
||||
_G.DetailsFrameworkImageEdit_EditTexture:SetTexture(texture)
|
||||
_G.DetailsFrameworkImageEdit_EditTexture.width = width
|
||||
_G.DetailsFrameworkImageEdit_EditTexture.height = height
|
||||
_G.DetailsFrameworkImageEdit_EditTexture.maximize = maximize
|
||||
|
||||
_G.DetailsFrameworkImageEdit_EditTexture:SetVertexColor(colors [1], colors [2], colors [3])
|
||||
_G.DetailsFrameworkImageEdit_EditTexture:SetAlpha(alpha)
|
||||
|
||||
DF.Schedules.NewTimer(0.2, DF.RefreshImageEditor)
|
||||
|
||||
window:Show()
|
||||
window.callback_func = callback
|
||||
window.extra_param = extraParam
|
||||
DetailsFrameworkImageEditButtonsBg:Show()
|
||||
DetailsFrameworkImageEditButtonsBg:SetBackdrop(nil)
|
||||
|
||||
table.wipe(window.hooks)
|
||||
end
|
||||
@@ -0,0 +1,219 @@
|
||||
|
||||
--stopped doing the duplicate savedTable
|
||||
|
||||
local DF = _G ["DetailsFramework"]
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
--create namespace
|
||||
DF.SavedVars = {}
|
||||
|
||||
function DF.SavedVars.CreateNewSavedTable(dbTable, savedTableName)
|
||||
local defaultVars = dbTable.defaultSavedVars
|
||||
local newSavedTable = DF.table.deploy({}, defaultVars)
|
||||
|
||||
dbTable.profiles[savedTableName] = newSavedTable
|
||||
return newSavedTable
|
||||
end
|
||||
|
||||
function DF.SavedVars.GetOrCreateAddonSavedTablesPlayerList(addonFrame)
|
||||
local addonGlobalSavedTable = _G[addonFrame.__savedVarsName]
|
||||
|
||||
--player list
|
||||
local playerList = addonGlobalSavedTable.__savedVarsByGUID
|
||||
if (not playerList) then
|
||||
addonGlobalSavedTable.__savedVarsByGUID = {}
|
||||
end
|
||||
|
||||
--saved variables table
|
||||
if (not addonGlobalSavedTable.__savedVars) then
|
||||
addonGlobalSavedTable.__savedVars = {}
|
||||
end
|
||||
|
||||
return addonGlobalSavedTable.__savedVarsByGUID
|
||||
end
|
||||
|
||||
--addon statup
|
||||
function DF.SavedVars.LoadSavedVarsForPlayer(addonFrame)
|
||||
local playerSerial = UnitGUID("player")
|
||||
|
||||
--savedTableObject is equivalent of "addon.db"
|
||||
local dbTable = DF.SavedVars.CreateSavedVarsTable(addonFrame, addonFrame.__savedVarsDefaultTemplate)
|
||||
addonFrame.__savedVarsDefaultTemplate = nil
|
||||
addonFrame.db = dbTable
|
||||
|
||||
--load players list
|
||||
local savedVarsName = DF.SavedVars.GetOrCreateAddonSavedTablesPlayerList(addonFrame)
|
||||
|
||||
local playerSavedTableName = savedVarsName[playerSerial]
|
||||
if (not playerSavedTableName) then
|
||||
savedVarsName[playerSerial] = "Default"
|
||||
playerSavedTableName = savedVarsName[playerSerial]
|
||||
end
|
||||
|
||||
local savedTable = addonFrame.db:GetSavedTable(playerSavedTableName)
|
||||
if (not savedTable) then
|
||||
--create a new saved table for this character
|
||||
savedTable = addonFrame.db:CreateNewSavedTable(playerSavedTableName)
|
||||
end
|
||||
|
||||
DF.SavedVars.SetSavedTable(dbTable, playerSavedTableName, true, true)
|
||||
return savedTable
|
||||
end
|
||||
|
||||
function DF.SavedVars.TableCleanUpRecursive(t, default)
|
||||
for key, value in pairs(t) do
|
||||
if (type(value) == "table") then
|
||||
DF.SavedVars.TableCleanUpRecursive(value, default[key])
|
||||
else
|
||||
if (value == default[key]) then
|
||||
t[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DF.SavedVars.CloseSavedTable(dbTable)
|
||||
local currentSavedTable = dbTable:GetSavedTable(dbTable:GetCurrentSavedTableName())
|
||||
|
||||
local default = dbTable.defaultSavedVars
|
||||
if (type(currentSavedTable) == "table") then
|
||||
DF.SavedVars.TableCleanUpRecursive(currentSavedTable, default)
|
||||
|
||||
--save
|
||||
local addonGlobalSavedTable = _G[dbTable.addonFrame.__savedVarsName]
|
||||
addonGlobalSavedTable.__savedVars[dbTable:GetCurrentSavedTableName()] = currentSavedTable
|
||||
end
|
||||
end
|
||||
|
||||
--base functions
|
||||
function DF.SavedVars.SetSavedTable(dbTable, savedTableName, createIfNonExistant, isFromInit)
|
||||
local savedTableToBeApplied = dbTable:GetSavedTable(savedTableName)
|
||||
|
||||
if (savedTableToBeApplied) then
|
||||
if (not isFromInit) then
|
||||
--callback unload profile table
|
||||
local currentSavedTable = dbTable:GetSavedTable(dbTable:GetCurrentSavedTableName())
|
||||
dbTable:TriggerCallback("OnProfileUnload", currentSavedTable)
|
||||
DF.SavedVars.CloseSavedTable(dbTable, currentSavedTable)
|
||||
end
|
||||
|
||||
dbTable.profile = savedTableToBeApplied
|
||||
dbTable.currentSavedTableName = savedTableName
|
||||
|
||||
dbTable:TriggerCallback("OnProfileLoad", savedTableToBeApplied)
|
||||
|
||||
else
|
||||
if (createIfNonExistant) then
|
||||
local newSavedTable = dbTable:CreateNewSavedTable(savedTableName)
|
||||
|
||||
--callback unload profile table
|
||||
local currentSavedTable = dbTable:GetSavedTable(dbTable:GetCurrentSavedTableName())
|
||||
dbTable:TriggerCallback("OnProfileUnload", currentSavedTable)
|
||||
DF.SavedVars.CloseSavedTable(dbTable, currentSavedTable)
|
||||
|
||||
dbTable.profile = newSavedTable
|
||||
dbTable.currentSavedTableName = savedTableName
|
||||
dbTable:TriggerCallback("OnProfileLoad", newSavedTable)
|
||||
else
|
||||
DF:Msg("profile does not exists", savedTableName)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DF.SavedVars.GetSavedTables(dbTable)
|
||||
return dbTable.profiles
|
||||
end
|
||||
|
||||
function DF.SavedVars.GetSavedTable(dbTable, savedTableName)
|
||||
local profiles = dbTable:GetSavedTables()
|
||||
return profiles[savedTableName]
|
||||
end
|
||||
|
||||
function DF.SavedVars.GetCurrentSavedTableName(dbTable)
|
||||
return dbTable.currentSavedTableName
|
||||
end
|
||||
|
||||
--duplicate savedTable
|
||||
function DF.SavedVars.DuplicateSavedTable(dbTable, savedTableName)
|
||||
local originalSavedTable = dbTable:GetSavedTable(savedTableName)
|
||||
if (originalSavedTable) then
|
||||
local newSavedTable = DF.table.copy({}, originalSavedTable)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--callbacks
|
||||
function DF.SavedVars.TriggerCallback(dbTable, callbackName, savedTable)
|
||||
local registeredCallbacksTable = dbTable.registeredCallbacks[callbackName]
|
||||
for i = 1, #registeredCallbacksTable do
|
||||
local callback = registeredCallbacksTable[i]
|
||||
DF:CoreDispatch(dbTable.addonFrame.__name, callback.func, savedTable, unpack(callback.payload))
|
||||
end
|
||||
end
|
||||
|
||||
function DF.SavedVars.RegisterCallback(dbTable, callbackName, func, ...)
|
||||
local registeredCallbacksTable = dbTable.registeredCallbacks[callbackName]
|
||||
if (registeredCallbacksTable) then
|
||||
--check for duplicates
|
||||
for i = 1, #registeredCallbacksTable do
|
||||
if (registeredCallbacksTable[i].func == func) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--register
|
||||
registeredCallbacksTable[#registeredCallbacksTable+1] = {func = func, payload = {...}}
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function DF.SavedVars.UnregisterCallback(dbTable, callbackName, func)
|
||||
local registeredCallbacksTable = dbTable.registeredCallbacks[callbackName]
|
||||
if (registeredCallbacksTable) then
|
||||
for i = 1, #registeredCallbacksTable do
|
||||
if (registeredCallbacksTable[i].func == func) then
|
||||
tremove(registeredCallbacksTable, i)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DF.SavedVars.CreateSavedVarsTable(addonFrame, templateTable)
|
||||
local dbTable = {
|
||||
profiles = {},
|
||||
defaultSavedVars = templateTable,
|
||||
currentSavedTableName = "",
|
||||
addonFrame = addonFrame,
|
||||
|
||||
--methods
|
||||
GetSavedTable = DF.SavedVars.GetSavedTable,
|
||||
SetSavedTable = DF.SavedVars.SetSavedTable,
|
||||
GetSavedTables = DF.SavedVars.GetSavedTables,
|
||||
GetCurrentSavedTableName = DF.SavedVars.GetCurrentSavedTableName,
|
||||
CreateNewSavedTable = DF.SavedVars.CreateNewSavedTable,
|
||||
TriggerCallback = DF.SavedVars.TriggerCallback,
|
||||
|
||||
--back compatibility with ace3DB
|
||||
GetCurrentProfile = DF.SavedVars.GetCurrentSavedTableName,
|
||||
GetProfile = DF.SavedVars.GetSavedTable,
|
||||
GetProfiles = DF.SavedVars.GetSavedTables,
|
||||
SetProfile = DF.SavedVars.SetSavedTable,
|
||||
RegisterCallback = DF.SavedVars.RegisterCallback,
|
||||
|
||||
registeredCallbacks = {
|
||||
["OnProfileLoad"] = {},
|
||||
["OnProfileUnload"] = {},
|
||||
["OnProfileCopied"] = {},
|
||||
["OnProfileReset"] = {},
|
||||
["OnDatabaseLoad"] = {},
|
||||
["OnDatabaseShutdown"] = {},
|
||||
},
|
||||
}
|
||||
|
||||
return dbTable
|
||||
end
|
||||
@@ -0,0 +1,73 @@
|
||||
|
||||
local DF = _G["DetailsFramework"]
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local C_Timer = _G.C_Timer
|
||||
local unpack = table.unpack or _G.unpack
|
||||
|
||||
--make a namespace for schedules
|
||||
DF.Schedules = DF.Schedules or {}
|
||||
|
||||
--run a scheduled function with its payload
|
||||
local triggerScheduledTick = function(tickerObject)
|
||||
local payload = tickerObject.payload
|
||||
local callback = tickerObject.callback
|
||||
|
||||
local result, errortext = pcall(callback, unpack(payload))
|
||||
if (not result) then
|
||||
DF:Msg("error on scheduler: ", tickerObject.path, tickerObject.name, errortext)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--schedule to repeat a task with an interval of @time
|
||||
function DF.Schedules.NewTicker(time, callback, ...)
|
||||
local payload = {...}
|
||||
local newTicker = C_Timer.NewTicker(time, triggerScheduledTick)
|
||||
newTicker.payload = payload
|
||||
newTicker.callback = callback
|
||||
newTicker.expireAt = GetTime() + time
|
||||
|
||||
--debug
|
||||
newTicker.path = debugstack()
|
||||
--
|
||||
return newTicker
|
||||
end
|
||||
|
||||
--schedule a task with an interval of @time
|
||||
function DF.Schedules.NewTimer(time, callback, ...)
|
||||
local payload = {...}
|
||||
local newTimer = C_Timer.NewTimer(time, triggerScheduledTick)
|
||||
newTimer.payload = payload
|
||||
newTimer.callback = callback
|
||||
newTimer.expireAt = GetTime() + time
|
||||
|
||||
--debug
|
||||
newTimer.path = debugstack()
|
||||
--
|
||||
|
||||
return newTimer
|
||||
end
|
||||
|
||||
--cancel an ongoing ticker
|
||||
function DF.Schedules.Cancel(tickerObject)
|
||||
--ignore if there's no ticker object
|
||||
if (tickerObject) then
|
||||
return tickerObject:Cancel()
|
||||
end
|
||||
end
|
||||
|
||||
--schedule a task with an interval of @time without payload
|
||||
function DF.Schedules.After(time, callback)
|
||||
C_Timer.After(time, callback)
|
||||
end
|
||||
|
||||
function DF.Schedules.SetName(object, name)
|
||||
object.name = name
|
||||
end
|
||||
|
||||
function DF.Schedules.RunNextTick(callback)
|
||||
return DF.Schedules.After(0, callback)
|
||||
end
|
||||
@@ -0,0 +1,132 @@
|
||||
|
||||
local detailsFramework = DetailsFramework
|
||||
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local unpack = unpack
|
||||
local CreateFrame = CreateFrame
|
||||
local geterrorhandler = geterrorhandler
|
||||
local wipe = wipe
|
||||
|
||||
local parseCodeForNamedLocalFunctions = function(codeBlock, startIndex, listOfFunctionsFound)
|
||||
local nestedLevel = 0
|
||||
local endIndex = startIndex
|
||||
local currentQuote = ""
|
||||
---@type number for the 'function' keyword, need to ignore the one that started the 'local function' capture
|
||||
local ignoreFunctionIndex = startIndex + 6
|
||||
|
||||
---@type boolean
|
||||
local bFoundEnd = false
|
||||
---@type boolean
|
||||
local bIsInString = false
|
||||
---@type boolean
|
||||
local bIsInComment = false
|
||||
|
||||
while (endIndex <= #codeBlock) do
|
||||
local char = string.sub(codeBlock, endIndex, endIndex)
|
||||
|
||||
--check if the character is inside a comment
|
||||
if (char == "-") then
|
||||
local nextChar = string.sub(codeBlock, endIndex + 1, endIndex + 1)
|
||||
if nextChar == "-" then
|
||||
bIsInComment = true
|
||||
end
|
||||
|
||||
elseif (char == "\n") then
|
||||
bIsInComment = false
|
||||
end
|
||||
|
||||
if (not bIsInComment) then
|
||||
--check if it is inside a string
|
||||
if (char == "'" or char == '"') then
|
||||
if (not bIsInString) then
|
||||
bIsInString = true
|
||||
currentQuote = char
|
||||
|
||||
elseif (bIsInString and currentQuote == char) then
|
||||
bIsInString = false
|
||||
currentQuote = ""
|
||||
end
|
||||
end
|
||||
|
||||
if (not bIsInString) then
|
||||
--check if the word starts with "i", "f", "d" or "e"
|
||||
if (char == "i") then
|
||||
local nextChars = string.sub(codeBlock, endIndex, endIndex + 1)
|
||||
if (nextChars == "if") then
|
||||
nestedLevel = nestedLevel + 1
|
||||
end
|
||||
|
||||
elseif (char == "f") then
|
||||
local nextChars = string.sub(codeBlock, endIndex, endIndex + 7)
|
||||
--also check if the index isn't the one that started the 'local function' capture
|
||||
if (nextChars == "function" and endIndex ~= ignoreFunctionIndex) then
|
||||
nestedLevel = nestedLevel + 1
|
||||
end
|
||||
|
||||
--for 'do' keyword, used by for and while and also by the 'do' keyword itself creating a block
|
||||
elseif (char == "d") then
|
||||
local nextChars = string.sub(codeBlock, endIndex, endIndex + 1)
|
||||
if (nextChars == "do") then
|
||||
nestedLevel = nestedLevel + 1
|
||||
end
|
||||
|
||||
elseif (char == "e") then
|
||||
local nextChars = string.sub(codeBlock, endIndex, endIndex + 2)
|
||||
if (nextChars == "end") then
|
||||
if (nestedLevel > 0) then
|
||||
--reduce the nested level by 1
|
||||
nestedLevel = nestedLevel - 1
|
||||
else
|
||||
--if the nested level is zero then the end of the function got found
|
||||
bFoundEnd = true
|
||||
endIndex = endIndex + 2 --adjust endIndex to include the 'end' keyword
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endIndex = endIndex + 1
|
||||
end
|
||||
|
||||
if (bFoundEnd) then
|
||||
---@type string get the function body
|
||||
local functionBody = string.sub(codeBlock, startIndex, endIndex)
|
||||
table.insert(listOfFunctionsFound, functionBody)
|
||||
return endIndex
|
||||
end
|
||||
end
|
||||
|
||||
---search a code block for named local functions and bring them to the top of the code block
|
||||
---this is useful for when you want to call a function before it's defined
|
||||
---same thing as been implemented in Lua 5.2 but not in WoW Lua
|
||||
---@param codeBlock string
|
||||
function detailsFramework:BringNamedLocalFunctionToTop(codeBlock)
|
||||
---@type string[]
|
||||
local listOfFunctionsFound = {}
|
||||
---@type number|nil
|
||||
local startIndex = string.find(codeBlock, "local function")
|
||||
|
||||
while startIndex do
|
||||
startIndex = parseCodeForNamedLocalFunctions(codeBlock, startIndex, listOfFunctionsFound)
|
||||
if (not startIndex) then
|
||||
break
|
||||
end
|
||||
startIndex = string.find(codeBlock, "local function", startIndex + 1)
|
||||
end
|
||||
|
||||
for i = #listOfFunctionsFound, 1, -1 do
|
||||
local thisMatch = listOfFunctionsFound[i]
|
||||
local blockStartIndex = thisMatch[2]
|
||||
local blockEndIndex = thisMatch[3]
|
||||
codeBlock = codeBlock:sub(1, blockStartIndex - 1) .. codeBlock:sub(blockEndIndex + 1)
|
||||
end
|
||||
|
||||
for i = #listOfFunctionsFound, 1, -1 do
|
||||
codeBlock = listOfFunctionsFound[i][1] .. "\n\n" .. codeBlock
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,233 @@
|
||||
|
||||
--note: this scroll bar is using legacy code and shouldn't be used on creating new stuff
|
||||
|
||||
local DF = _G["DetailsFramework"]
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
function DF:CreateScrollBar(master, scrollContainer, x, y)
|
||||
return DF:NewScrollBar(master, scrollContainer, x, y)
|
||||
end
|
||||
|
||||
function DF:NewScrollBar(parent, scrollContainer, x, y)
|
||||
local newSlider = CreateFrame("Slider", nil, parent, "BackdropTemplate")
|
||||
newSlider.scrollMax = 560
|
||||
|
||||
newSlider:SetPoint("TOPLEFT", parent, "TOPRIGHT", x, y)
|
||||
newSlider.ativo = true
|
||||
|
||||
newSlider.bg = newSlider:CreateTexture(nil, "BACKGROUND")
|
||||
newSlider.bg:SetAllPoints(true)
|
||||
newSlider.bg:SetTexture(0, 0, 0, 0)
|
||||
|
||||
newSlider.thumb = newSlider:CreateTexture(nil, "OVERLAY")
|
||||
newSlider.thumb:SetTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
|
||||
newSlider.thumb:SetSize(29, 30)
|
||||
newSlider:SetThumbTexture(newSlider.thumb)
|
||||
newSlider:SetOrientation("VERTICAL")
|
||||
newSlider:SetSize(16, 100)
|
||||
newSlider:SetMinMaxValues(0, newSlider.scrollMax)
|
||||
newSlider:SetValue(0)
|
||||
newSlider.ultimo = 0
|
||||
|
||||
local upButton = CreateFrame("Button", nil, parent,"BackdropTemplate")
|
||||
|
||||
upButton:SetPoint("BOTTOM", newSlider, "TOP", 0, -12)
|
||||
upButton.x = 0
|
||||
upButton.y = -12
|
||||
|
||||
upButton:SetWidth(29)
|
||||
upButton:SetHeight(32)
|
||||
upButton:SetNormalTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollUpButton-Up")
|
||||
upButton:SetPushedTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollUpButton-Down")
|
||||
upButton:SetDisabledTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollUpButton-Disabled")
|
||||
upButton:Show()
|
||||
upButton:Disable()
|
||||
|
||||
local downDutton = CreateFrame("Button", nil, parent,"BackdropTemplate")
|
||||
downDutton:SetPoint("TOP", newSlider, "BOTTOM", 0, 12)
|
||||
downDutton.x = 0
|
||||
downDutton.y = 12
|
||||
|
||||
downDutton:SetWidth(29)
|
||||
downDutton:SetHeight(32)
|
||||
downDutton:SetNormalTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollDownButton-Up")
|
||||
downDutton:SetPushedTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollDownButton-Down")
|
||||
downDutton:SetDisabledTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollDownButton-Disabled")
|
||||
downDutton:Show()
|
||||
downDutton:Disable()
|
||||
|
||||
parent.baixo = downDutton
|
||||
parent.cima = upButton
|
||||
parent.slider = newSlider
|
||||
|
||||
downDutton:SetScript("OnMouseDown", function(self)
|
||||
if (not newSlider:IsEnabled()) then
|
||||
return
|
||||
end
|
||||
|
||||
local current = newSlider:GetValue()
|
||||
local minValue, maxValue = newSlider:GetMinMaxValues()
|
||||
if (current + 5 < maxValue) then
|
||||
newSlider:SetValue(current + 5)
|
||||
else
|
||||
newSlider:SetValue(maxValue)
|
||||
end
|
||||
self.precionado = true
|
||||
self.last_up = -0.3
|
||||
self:SetScript("OnUpdate", function(self, elapsed)
|
||||
self.last_up = self.last_up + elapsed
|
||||
if (self.last_up > 0.03) then
|
||||
self.last_up = 0
|
||||
local current = newSlider:GetValue()
|
||||
local minValue, maxValue = newSlider:GetMinMaxValues()
|
||||
if (current + 2 < maxValue) then
|
||||
newSlider:SetValue(current + 2)
|
||||
else
|
||||
newSlider:SetValue(maxValue)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
downDutton:SetScript("OnMouseUp", function(self)
|
||||
self.precionado = false
|
||||
self:SetScript("OnUpdate", nil)
|
||||
end)
|
||||
|
||||
upButton:SetScript("OnMouseDown", function(self)
|
||||
if (not newSlider:IsEnabled()) then
|
||||
return
|
||||
end
|
||||
|
||||
local current = newSlider:GetValue()
|
||||
if (current - 5 > 0) then
|
||||
newSlider:SetValue(current - 5)
|
||||
else
|
||||
newSlider:SetValue(0)
|
||||
end
|
||||
|
||||
self.precionado = true
|
||||
self.last_up = -0.3
|
||||
self:SetScript("OnUpdate", function(self, elapsed)
|
||||
self.last_up = self.last_up + elapsed
|
||||
if (self.last_up > 0.03) then
|
||||
self.last_up = 0
|
||||
local current = newSlider:GetValue()
|
||||
if (current - 2 > 0) then
|
||||
newSlider:SetValue(current - 2)
|
||||
else
|
||||
newSlider:SetValue(0)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
upButton:SetScript("OnMouseUp", function(self)
|
||||
self.precionado = false
|
||||
self:SetScript("OnUpdate", nil)
|
||||
end)
|
||||
|
||||
upButton:SetScript("OnEnable", function(self)
|
||||
local current = newSlider:GetValue()
|
||||
if (current == 0) then
|
||||
upButton:Disable()
|
||||
end
|
||||
end)
|
||||
|
||||
newSlider:SetScript("OnValueChanged", function(self)
|
||||
local current = self:GetValue()
|
||||
parent:SetVerticalScroll(current)
|
||||
|
||||
local minValue, maxValue = newSlider:GetMinMaxValues()
|
||||
|
||||
if (current == minValue) then
|
||||
upButton:Disable()
|
||||
elseif (not upButton:IsEnabled()) then
|
||||
upButton:Enable()
|
||||
end
|
||||
|
||||
if (current == maxValue) then
|
||||
downDutton:Disable()
|
||||
elseif (not downDutton:IsEnabled()) then
|
||||
downDutton:Enable()
|
||||
end
|
||||
end)
|
||||
|
||||
newSlider:SetScript("OnShow", function(self)
|
||||
upButton:Show()
|
||||
downDutton:Show()
|
||||
end)
|
||||
|
||||
newSlider:SetScript("OnDisable", function(self)
|
||||
upButton:Disable()
|
||||
downDutton:Disable()
|
||||
end)
|
||||
|
||||
newSlider:SetScript("OnEnable", function(self)
|
||||
upButton:Enable()
|
||||
downDutton:Enable()
|
||||
end)
|
||||
|
||||
parent:SetScript("OnMouseWheel", function(self, delta)
|
||||
if (not newSlider:IsEnabled()) then
|
||||
return
|
||||
end
|
||||
|
||||
local current = newSlider:GetValue()
|
||||
if (delta < 0) then
|
||||
local minValue, maxValue = newSlider:GetMinMaxValues()
|
||||
if (current + (parent.wheel_jump or 20) < maxValue) then
|
||||
newSlider:SetValue(current + (parent.wheel_jump or 20))
|
||||
else
|
||||
newSlider:SetValue(maxValue)
|
||||
end
|
||||
elseif (delta > 0) then
|
||||
if (current + (parent.wheel_jump or 20) > 0) then
|
||||
newSlider:SetValue(current - (parent.wheel_jump or 20))
|
||||
else
|
||||
newSlider:SetValue(0)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function newSlider:Altura(height)
|
||||
self:SetHeight(height)
|
||||
end
|
||||
|
||||
function newSlider:Update(desativar)
|
||||
if (desativar) then
|
||||
newSlider:Disable()
|
||||
newSlider:SetValue(0)
|
||||
newSlider.ativo = false
|
||||
parent:EnableMouseWheel(false)
|
||||
return
|
||||
end
|
||||
|
||||
self.scrollMax = scrollContainer:GetHeight() - parent:GetHeight()
|
||||
if (self.scrollMax > 0) then
|
||||
newSlider:SetMinMaxValues(0, self.scrollMax)
|
||||
if (not newSlider.ativo) then
|
||||
newSlider:Enable()
|
||||
newSlider.ativo = true
|
||||
parent:EnableMouseWheel(true)
|
||||
end
|
||||
else
|
||||
newSlider:Disable()
|
||||
newSlider:SetValue(0)
|
||||
newSlider.ativo = false
|
||||
parent:EnableMouseWheel(false)
|
||||
end
|
||||
end
|
||||
|
||||
function newSlider:cimaPoint(x, y)
|
||||
upButton:SetPoint("BOTTOM", newSlider, "TOP", x, y - 12)
|
||||
end
|
||||
|
||||
function newSlider:baixoPoint(x, y)
|
||||
downDutton:SetPoint("TOP", newSlider, "BOTTOM", x, y + 12)
|
||||
end
|
||||
|
||||
return newSlider
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,810 @@
|
||||
|
||||
local DF = _G ["DetailsFramework"]
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local _
|
||||
local rawset = rawset --lua local
|
||||
local rawget = rawget --lua local
|
||||
local setmetatable = setmetatable --lua local
|
||||
local _unpack = unpack --lua local
|
||||
local type = type --lua local
|
||||
local _math_floor = math.floor --lua local
|
||||
|
||||
local maxStatusBarValue = 100000000
|
||||
|
||||
local cleanfunction = function() end
|
||||
local APISplitBarFunctions
|
||||
|
||||
do
|
||||
local metaPrototype = {
|
||||
WidgetType = "split_bar",
|
||||
dversion = DF.dversion,
|
||||
}
|
||||
|
||||
--check if there's a metaPrototype already existing
|
||||
if (_G[DF.GlobalWidgetControlNames["split_bar"]]) then
|
||||
--get the already existing metaPrototype
|
||||
local oldMetaPrototype = _G[DF.GlobalWidgetControlNames["split_bar"]]
|
||||
--check if is older
|
||||
if ( (not oldMetaPrototype.dversion) or (oldMetaPrototype.dversion < DF.dversion) ) then
|
||||
--the version is older them the currently loading one
|
||||
--copy the new values into the old metatable
|
||||
for funcName, _ in pairs(metaPrototype) do
|
||||
oldMetaPrototype[funcName] = metaPrototype[funcName]
|
||||
end
|
||||
end
|
||||
else
|
||||
--first time loading the framework
|
||||
_G[DF.GlobalWidgetControlNames["split_bar"]] = metaPrototype
|
||||
end
|
||||
end
|
||||
|
||||
local SplitBarMetaFunctions = _G[DF.GlobalWidgetControlNames["split_bar"]]
|
||||
DF:Mixin(SplitBarMetaFunctions, DF.ScriptHookMixin)
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--metatables
|
||||
|
||||
SplitBarMetaFunctions.__call = function(_table, value)
|
||||
if (not value) then
|
||||
return _table.statusbar:GetValue()
|
||||
else
|
||||
_table.spark:SetPoint("left", _table.statusbar, "left", value * (_table.statusbar:GetWidth()/100) - 18, 0)
|
||||
return _table.statusbar:SetValue(value)
|
||||
end
|
||||
end
|
||||
|
||||
SplitBarMetaFunctions.__add = function(v1, v2)
|
||||
if (type(v1) == "table") then
|
||||
local v = v1.statusbar:GetValue()
|
||||
v = v + v2
|
||||
v1.spark:SetPoint("left", v1.statusbar, "left", value * (v1.statusbar:GetWidth()/100) - 18, 0)
|
||||
v1.statusbar:SetValue(v)
|
||||
else
|
||||
local v = v2.statusbar:GetValue()
|
||||
v = v + v1
|
||||
v2.spark:SetPoint("left", v2.statusbar, "left", value * (v2.statusbar:GetWidth()/100) - 18, 0)
|
||||
v2.statusbar:SetValue(v)
|
||||
end
|
||||
end
|
||||
|
||||
SplitBarMetaFunctions.__sub = function(v1, v2)
|
||||
if (type(v1) == "table") then
|
||||
local v = v1.statusbar:GetValue()
|
||||
v = v - v2
|
||||
v1.spark:SetPoint("left", v1.statusbar, "left", value * (v1.statusbar:GetWidth()/100) - 18, 0)
|
||||
v1.statusbar:SetValue(v)
|
||||
else
|
||||
local v = v2.statusbar:GetValue()
|
||||
v = v - v1
|
||||
v2.spark:SetPoint("left", v2.statusbar, "left", value * (v2.statusbar:GetWidth()/100) - 18, 0)
|
||||
v2.statusbar:SetValue(v)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--members
|
||||
|
||||
--tooltip
|
||||
local function gmember_tooltip (_object)
|
||||
return _object:GetTooltip()
|
||||
end
|
||||
--shown
|
||||
local gmember_shown = function(_object)
|
||||
return _object.statusbar:IsShown()
|
||||
end
|
||||
--frame width
|
||||
local gmember_width = function(_object)
|
||||
return _object.statusbar:GetWidth()
|
||||
end
|
||||
--frame height
|
||||
local gmember_height = function(_object)
|
||||
return _object.statusbar:GetHeight()
|
||||
end
|
||||
--value
|
||||
local gmember_value = function(_object)
|
||||
return _object.statusbar:GetValue()
|
||||
end
|
||||
--right text
|
||||
local gmember_rtext = function(_object)
|
||||
return _object.textright:GetText()
|
||||
end
|
||||
--left text
|
||||
local gmember_ltext = function(_object)
|
||||
return _object.textleft:GetText()
|
||||
end
|
||||
--right color
|
||||
local gmember_rcolor = function(_object)
|
||||
return _object.rightTexture.original_colors
|
||||
end
|
||||
--left color
|
||||
local gmember_lcolor = function(_object)
|
||||
return _object.texture.original_colors
|
||||
end
|
||||
--right icon
|
||||
local gmember_ricon = function(_object)
|
||||
return _object.iconright:GetTexture()
|
||||
end
|
||||
--left icon
|
||||
local gmember_licon = function(_object)
|
||||
return _object.iconleft:GetTexture()
|
||||
end
|
||||
--texture
|
||||
local gmember_texture = function(_object)
|
||||
return _object.texture:GetTexture()
|
||||
end
|
||||
--font size
|
||||
local gmember_textsize = function(_object)
|
||||
local _, fontsize = _object.textleft:GetFont()
|
||||
return fontsize
|
||||
end
|
||||
--font face
|
||||
local gmember_textfont = function(_object)
|
||||
local fontface = _object.textleft:GetFont()
|
||||
return fontface
|
||||
end
|
||||
--font color
|
||||
local gmember_textcolor = function(_object)
|
||||
return _object.textleft:GetTextColor()
|
||||
end
|
||||
|
||||
SplitBarMetaFunctions.GetMembers = SplitBarMetaFunctions.GetMembers or {}
|
||||
SplitBarMetaFunctions.GetMembers ["tooltip"] = gmember_tooltip
|
||||
SplitBarMetaFunctions.GetMembers ["shown"] = gmember_shown
|
||||
SplitBarMetaFunctions.GetMembers ["width"] = gmember_width
|
||||
SplitBarMetaFunctions.GetMembers ["height"] = gmember_height
|
||||
SplitBarMetaFunctions.GetMembers ["value"] = gmember_value
|
||||
SplitBarMetaFunctions.GetMembers ["righttext"] = gmember_rtext
|
||||
SplitBarMetaFunctions.GetMembers ["lefttext"] = gmember_ltext
|
||||
SplitBarMetaFunctions.GetMembers ["rightcolor"] = gmember_rcolor
|
||||
SplitBarMetaFunctions.GetMembers ["leftcolor"] = gmember_lcolor
|
||||
SplitBarMetaFunctions.GetMembers ["righticon"] = gmember_ricon
|
||||
SplitBarMetaFunctions.GetMembers ["lefticon"] = gmember_licon
|
||||
SplitBarMetaFunctions.GetMembers ["texture"] = gmember_texture
|
||||
SplitBarMetaFunctions.GetMembers ["fontsize"] = gmember_textsize
|
||||
SplitBarMetaFunctions.GetMembers ["fontface"] = gmember_textfont
|
||||
SplitBarMetaFunctions.GetMembers ["fontcolor"] = gmember_textcolor
|
||||
SplitBarMetaFunctions.GetMembers ["textsize"] = gmember_textsize --alias
|
||||
SplitBarMetaFunctions.GetMembers ["textfont"] = gmember_textfont --alias
|
||||
SplitBarMetaFunctions.GetMembers ["textcolor"] = gmember_textcolor --alias
|
||||
|
||||
SplitBarMetaFunctions.__index = function(_table, _member_requested)
|
||||
|
||||
local func = SplitBarMetaFunctions.GetMembers [_member_requested]
|
||||
if (func) then
|
||||
return func (_table, _member_requested)
|
||||
end
|
||||
|
||||
local fromMe = rawget (_table, _member_requested)
|
||||
if (fromMe) then
|
||||
return fromMe
|
||||
end
|
||||
|
||||
return SplitBarMetaFunctions [_member_requested]
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
--tooltip
|
||||
local smember_tooltip = function(_object, _value)
|
||||
return _object:SetTooltip (_value)
|
||||
end
|
||||
--show
|
||||
local smember_shown = function(_object, _value)
|
||||
if (_value) then
|
||||
return _object:Show()
|
||||
else
|
||||
return _object:Hide()
|
||||
end
|
||||
end
|
||||
--hide
|
||||
local smember_hide = function(_object, _value)
|
||||
if (_value) then
|
||||
return _object:Hide()
|
||||
else
|
||||
return _object:Show()
|
||||
end
|
||||
end
|
||||
--width
|
||||
local smember_width = function(_object, _value)
|
||||
return _object.statusbar:SetWidth(_value)
|
||||
end
|
||||
--height
|
||||
local smember_height = function(_object, _value)
|
||||
return _object.statusbar:SetHeight(_value)
|
||||
end
|
||||
--statusbar value
|
||||
local smember_value = function(_object, _value)
|
||||
_object.statusbar:SetValue(_value)
|
||||
return _object.spark:SetPoint("left", _object.statusbar, "left", _value * (_object.statusbar:GetWidth()/100) - 18, 0)
|
||||
end
|
||||
--right text
|
||||
local smember_rtext = function(_object, _value)
|
||||
return _object.textright:SetText(_value)
|
||||
end
|
||||
--left text
|
||||
local smember_ltext = function(_object, _value)
|
||||
return _object.textleft:SetText(_value)
|
||||
end
|
||||
--right color
|
||||
local smember_rcolor = function(_object, _value)
|
||||
local _value1, _value2, _value3, _value4 = DF:ParseColors(_value)
|
||||
_object.rightTexture.original_colors = {_value1, _value2, _value3, _value4}
|
||||
return _object.rightTexture:SetVertexColor(_value1, _value2, _value3, _value4)
|
||||
end
|
||||
--left color
|
||||
local smember_lcolor = function(_object, _value)
|
||||
local _value1, _value2, _value3, _value4 = DF:ParseColors(_value)
|
||||
|
||||
_object.statusbar:SetStatusBarColor(_value1, _value2, _value3, _value4)
|
||||
_object.texture.original_colors = {_value1, _value2, _value3, _value4}
|
||||
return _object.texture:SetVertexColor(_value1, _value2, _value3, _value4)
|
||||
end
|
||||
--right icon
|
||||
local smember_ricon = function(_object, _value)
|
||||
if (type(_value) == "table") then
|
||||
local _value1, _value2 = _unpack(_value)
|
||||
_object.iconright:SetTexture(_value1)
|
||||
if (_value2) then
|
||||
_object.iconright:SetTexCoord(_unpack(_value2))
|
||||
end
|
||||
else
|
||||
_object.iconright:SetTexture(_value)
|
||||
end
|
||||
return
|
||||
end
|
||||
--left icon
|
||||
local smember_licon = function(_object, _value)
|
||||
if (type(_value) == "table") then
|
||||
local _value1, _value2 = _unpack(_value)
|
||||
_object.iconleft:SetTexture(_value1)
|
||||
if (_value2) then
|
||||
_object.iconleft:SetTexCoord(_unpack(_value2))
|
||||
end
|
||||
else
|
||||
_object.iconleft:SetTexture(_value)
|
||||
end
|
||||
return
|
||||
end
|
||||
--texture
|
||||
local smember_texture = function(_object, _value)
|
||||
if (type(_value) == "table") then
|
||||
local _value1, _value2 = _unpack(_value)
|
||||
_object.texture:SetTexture(_value1)
|
||||
_object.rightTexture:SetTexture(_value1)
|
||||
if (_value2) then
|
||||
_object.texture:SetTexCoord(_unpack(_value2))
|
||||
_object.rightTexture:SetTexCoord(_unpack(_value2))
|
||||
end
|
||||
else
|
||||
_object.texture:SetTexture(_value)
|
||||
_object.rightTexture:SetTexture(_value)
|
||||
end
|
||||
return
|
||||
end
|
||||
--font face
|
||||
local smember_textfont = function(_object, _value)
|
||||
DF:SetFontFace (_object.textleft, _value)
|
||||
return DF:SetFontFace (_object.textright, _value)
|
||||
end
|
||||
--font size
|
||||
local smember_textsize = function(_object, _value)
|
||||
DF:SetFontSize(_object.textleft, _value)
|
||||
return DF:SetFontSize(_object.textright, _value)
|
||||
end
|
||||
--font color
|
||||
local smember_textcolor = function(_object, _value)
|
||||
local _value1, _value2, _value3, _value4 = DF:ParseColors(_value)
|
||||
_object.textleft:SetTextColor(_value1, _value2, _value3, _value4)
|
||||
return _object.textright:SetTextColor(_value1, _value2, _value3, _value4)
|
||||
end
|
||||
|
||||
SplitBarMetaFunctions.SetMembers = SplitBarMetaFunctions.SetMembers or {}
|
||||
SplitBarMetaFunctions.SetMembers ["tooltip"] = smember_tooltip
|
||||
SplitBarMetaFunctions.SetMembers ["shown"] = smember_shown
|
||||
SplitBarMetaFunctions.SetMembers ["width"] = smember_width
|
||||
SplitBarMetaFunctions.SetMembers ["height"] = smember_height
|
||||
SplitBarMetaFunctions.SetMembers ["value"] = smember_value
|
||||
SplitBarMetaFunctions.SetMembers ["righttext"] = smember_rtext
|
||||
SplitBarMetaFunctions.SetMembers ["lefttext"] = smember_ltext
|
||||
SplitBarMetaFunctions.SetMembers ["rightcolor"] = smember_rcolor
|
||||
SplitBarMetaFunctions.SetMembers ["leftcolor"] = smember_lcolor
|
||||
SplitBarMetaFunctions.SetMembers ["righticon"] = smember_ricon
|
||||
SplitBarMetaFunctions.SetMembers ["lefticon"] = smember_licon
|
||||
SplitBarMetaFunctions.SetMembers ["texture"] = smember_texture
|
||||
SplitBarMetaFunctions.SetMembers ["fontsize"] = smember_textsize
|
||||
SplitBarMetaFunctions.SetMembers ["fontface"] = smember_textfont
|
||||
SplitBarMetaFunctions.SetMembers ["fontcolor"] = smember_textcolor
|
||||
SplitBarMetaFunctions.SetMembers ["textsize"] = smember_textsize --alias
|
||||
SplitBarMetaFunctions.SetMembers ["textfont"] = smember_textfont --alias
|
||||
SplitBarMetaFunctions.SetMembers ["textcolor"] = smember_textcolor --alias
|
||||
|
||||
SplitBarMetaFunctions.__newindex = function(_table, _key, _value)
|
||||
local func = SplitBarMetaFunctions.SetMembers [_key]
|
||||
if (func) then
|
||||
return func (_table, _value)
|
||||
else
|
||||
return rawset (_table, _key, _value)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--methods
|
||||
|
||||
--show & hide
|
||||
function SplitBarMetaFunctions:Show()
|
||||
return self.statusbar:Show()
|
||||
end
|
||||
function SplitBarMetaFunctions:Hide()
|
||||
return self.statusbar:Hide()
|
||||
end
|
||||
|
||||
-- set split
|
||||
function SplitBarMetaFunctions:SetSplit (value)
|
||||
if (not value) then
|
||||
value = self.statusbar:GetValue()
|
||||
elseif (value < 0 or value > 100) then
|
||||
return
|
||||
end
|
||||
self.statusbar:SetValue(value)
|
||||
self.spark:SetPoint("left", self.statusbar, "left", value * (self.statusbar:GetWidth()/100) - 18, 0)
|
||||
end
|
||||
|
||||
-- setpoint
|
||||
function SplitBarMetaFunctions:SetPoint(v1, v2, v3, v4, v5)
|
||||
v1, v2, v3, v4, v5 = DF:CheckPoints (v1, v2, v3, v4, v5, self)
|
||||
if (not v1) then
|
||||
print("Invalid parameter for SetPoint")
|
||||
return
|
||||
end
|
||||
return self.widget:SetPoint(v1, v2, v3, v4, v5)
|
||||
end
|
||||
|
||||
-- sizes
|
||||
function SplitBarMetaFunctions:SetSize(w, h)
|
||||
if (w) then
|
||||
self.statusbar:SetWidth(w)
|
||||
end
|
||||
if (h) then
|
||||
self.statusbar:SetHeight(h)
|
||||
end
|
||||
end
|
||||
|
||||
-- texture
|
||||
function SplitBarMetaFunctions:SetTexture(texture)
|
||||
self.rightTexture:SetTexture(texture)
|
||||
self.texture:SetTexture(texture)
|
||||
end
|
||||
|
||||
function SplitBarMetaFunctions:SetBackgroundTexture(texture)
|
||||
self.background:SetTexture(texture)
|
||||
end
|
||||
|
||||
-- texts
|
||||
function SplitBarMetaFunctions:SetLeftText (text)
|
||||
self.textleft:SetText(text)
|
||||
end
|
||||
function SplitBarMetaFunctions:SetRightText (text)
|
||||
self.textright:SetText(text)
|
||||
end
|
||||
|
||||
-- colors
|
||||
function SplitBarMetaFunctions:SetLeftColor (r, g, b, a)
|
||||
r, g, b, a = DF:ParseColors(r, g, b, a)
|
||||
self.texture:SetVertexColor(r, g, b, a)
|
||||
self.texture.original_colors = {r, g, b, a}
|
||||
end
|
||||
function SplitBarMetaFunctions:SetRightColor (r, g, b, a)
|
||||
r, g, b, a = DF:ParseColors(r, g, b, a)
|
||||
self.rightTexture:SetVertexColor(r, g, b, a)
|
||||
self.rightTexture.original_colors = {r, g, b, a}
|
||||
end
|
||||
|
||||
function SplitBarMetaFunctions:SetBackgroundColor (r, g, b, a)
|
||||
r, g, b, a = DF:ParseColors(r, g, b, a)
|
||||
self.background:SetVertexColor(r, g, b, a)
|
||||
self.background.original_colors = {r, g, b, a}
|
||||
end
|
||||
|
||||
function SplitBarMetaFunctions:GetLeftColor()
|
||||
return self.texture:GetVertexColor()
|
||||
end
|
||||
|
||||
function SplitBarMetaFunctions:GetRightColor()
|
||||
return self.rightTexture:GetVertexColor()
|
||||
end
|
||||
|
||||
-- icons
|
||||
function SplitBarMetaFunctions:SetLeftIcon (texture, ...)
|
||||
self.iconleft:SetTexture(texture)
|
||||
if (...) then
|
||||
local L, R, U, D = unpack(...)
|
||||
self.iconleft:SetTexCoord(L, R, U, D)
|
||||
end
|
||||
end
|
||||
function SplitBarMetaFunctions:SetRightIcon (texture, ...)
|
||||
self.iconright:SetTexture(texture)
|
||||
if (...) then
|
||||
local L, R, U, D = unpack(...)
|
||||
self.iconright:SetTexCoord(L, R, U, D)
|
||||
end
|
||||
end
|
||||
|
||||
-- tooltip
|
||||
function SplitBarMetaFunctions:SetTooltip (tooltip)
|
||||
if (tooltip) then
|
||||
return rawset (self, "have_tooltip", tooltip)
|
||||
else
|
||||
return rawset (self, "have_tooltip", nil)
|
||||
end
|
||||
end
|
||||
function SplitBarMetaFunctions:GetTooltip()
|
||||
return rawget (self, "have_tooltip")
|
||||
end
|
||||
|
||||
-- frame levels
|
||||
function SplitBarMetaFunctions:GetFrameLevel()
|
||||
return self.statusbar:GetFrameLevel()
|
||||
end
|
||||
function SplitBarMetaFunctions:SetFrameLevel(level, frame)
|
||||
if (not frame) then
|
||||
return self.statusbar:SetFrameLevel(level)
|
||||
else
|
||||
local framelevel = frame:GetFrameLevel (frame) + level
|
||||
return self.statusbar:SetFrameLevel(framelevel)
|
||||
end
|
||||
end
|
||||
|
||||
-- frame stratas
|
||||
function SplitBarMetaFunctions:SetFrameStrata(strata)
|
||||
if (type(strata) == "table") then
|
||||
self.statusbar:SetFrameStrata(strata:GetFrameStrata())
|
||||
else
|
||||
self.statusbar:SetFrameStrata(strata)
|
||||
end
|
||||
end
|
||||
|
||||
-- animation
|
||||
--animation with acceleration ~animation ~healthbaranimation
|
||||
local animateLeftWithAccel = function(self, deltaTime)
|
||||
local currentPercent = DetailsFramework:GetRangePercent(self.targetValue, self.startValue, self.currentValue)
|
||||
currentPercent = abs(currentPercent - 1)
|
||||
currentPercent = min(0.9, currentPercent)
|
||||
currentPercent = max(0.5, currentPercent)
|
||||
|
||||
local animationMultiplier = math.sin(currentPercent * math.pi)
|
||||
local valueChange = self.step * (deltaTime * animationMultiplier)
|
||||
self.currentValue = self.currentValue - valueChange
|
||||
|
||||
local barWidth = self:GetWidth()
|
||||
self.currentValue = Clamp(self.currentValue, 0, maxStatusBarValue)
|
||||
self.statusbar:SetValue(self.currentValue)
|
||||
self.rightTexture:SetWidth(barWidth - barWidth*self.currentValue)
|
||||
|
||||
if (self.currentValue - 0.001 <= self.targetValue) then
|
||||
self.targetValue = Clamp(self.targetValue, 0, maxStatusBarValue)
|
||||
self:SetValue(self.targetValue)
|
||||
self.currentValue = self.targetValue
|
||||
if (not self.SparkAlwaysShow) then
|
||||
self.spark:Hide()
|
||||
end
|
||||
self.widget:SetScript("OnUpdate", nil)
|
||||
return
|
||||
end
|
||||
|
||||
self.spark:SetPoint("center", self.widget, "left", self.currentValue * barWidth, 0)
|
||||
self.spark:Show()
|
||||
end
|
||||
|
||||
local animateRightWithAccel = function(self, deltaTime)
|
||||
--get the animation elapsed percent
|
||||
local currentPercent = DetailsFramework:GetRangePercent(self.startValue, self.targetValue, self.currentValue)
|
||||
currentPercent = min(0.9, currentPercent) --slow down the animation but avoid very slow
|
||||
currentPercent = max(0.5, currentPercent) --default: 0.1, using 0.5 makes the animation start fast and go slow
|
||||
|
||||
--get the sine value and scale time with it
|
||||
local animationMultiplier = math.sin(currentPercent * math.pi)
|
||||
local valueChange = self.step * (deltaTime * animationMultiplier)
|
||||
self.currentValue = self.currentValue + valueChange
|
||||
|
||||
local barWidth = self:GetWidth()
|
||||
self.currentValue = Clamp(self.currentValue, 0, maxStatusBarValue)
|
||||
self.statusbar:SetValue(self.currentValue)
|
||||
local rightTextureSize = barWidth - barWidth*self.currentValue
|
||||
self.rightTexture:SetWidth(rightTextureSize)
|
||||
|
||||
if (self.currentValue + 0.001 >= self.targetValue) then
|
||||
self.targetValue = Clamp(self.targetValue, 0, maxStatusBarValue)
|
||||
self:SetValue(self.targetValue)
|
||||
self.currentValue = self.targetValue
|
||||
if (not self.SparkAlwaysShow) then
|
||||
self.spark:Hide()
|
||||
end
|
||||
self.widget:SetScript("OnUpdate", nil)
|
||||
return
|
||||
end
|
||||
|
||||
self.spark:SetPoint("center", self.widget, "left", self.currentValue * barWidth, 0)
|
||||
self.spark:Show()
|
||||
end
|
||||
|
||||
local onUpdate = function(self, deltaTime)
|
||||
self = self.MyObject
|
||||
--select the animation function
|
||||
--target is always equal to current
|
||||
if (self.targetValue > self.currentValue) then
|
||||
animateRightWithAccel(self, deltaTime)
|
||||
else
|
||||
animateLeftWithAccel(self, deltaTime)
|
||||
end
|
||||
end
|
||||
|
||||
function SplitBarMetaFunctions:EnableAnimations()
|
||||
return
|
||||
end
|
||||
|
||||
function SplitBarMetaFunctions:DisableAnimations()
|
||||
self.widget:SetScript("OnUpdate", nil)
|
||||
end
|
||||
|
||||
function SplitBarMetaFunctions:SetValueWithAnimation(value)
|
||||
if (self.widget:GetScript("OnUpdate") == nil) then
|
||||
self.widget:SetScript("OnUpdate", onUpdate)
|
||||
self.widget:SetMinMaxValues(0, 1)
|
||||
self.spark:ClearAllPoints()
|
||||
self.spark:SetHeight(self:GetHeight() * 2.6)
|
||||
self.spark:SetAlpha(0.4)
|
||||
end
|
||||
self.startValue = self.currentValue
|
||||
self.step = abs(value - self.currentValue)
|
||||
self.targetValue = value
|
||||
self.rightTexture:Show()
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--scripts
|
||||
|
||||
local OnEnter = function(frame)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnEnter", frame, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
if (frame.MyObject.have_tooltip) then
|
||||
GameCooltip2:Reset()
|
||||
GameCooltip2:AddLine(frame.MyObject.have_tooltip)
|
||||
GameCooltip2:ShowCooltip(frame, "tooltip")
|
||||
end
|
||||
end
|
||||
|
||||
local OnLeave = function(frame)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnLeave", frame, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
if (frame.MyObject.have_tooltip) then
|
||||
DF.popup:ShowMe(false)
|
||||
end
|
||||
end
|
||||
|
||||
local OnHide = function(frame)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnHide", frame, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local OnShow = function(frame)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnShow", frame, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local OnMouseDown = function(frame, button)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnMouseDown", frame, button, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
if (not frame.MyObject.container.isLocked and frame.MyObject.container:IsMovable()) then
|
||||
if (not frame.isLocked and frame:IsMovable()) then
|
||||
frame.MyObject.container.isMoving = true
|
||||
frame.MyObject.container:StartMoving()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local OnMouseUp = function(frame, button)
|
||||
local capsule = frame.MyObject
|
||||
local kill = capsule:RunHooksForWidget("OnMouseUp", frame, button, capsule)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
if (frame.MyObject.container.isMoving) then
|
||||
frame.MyObject.container:StopMovingOrSizing()
|
||||
frame.MyObject.container.isMoving = false
|
||||
end
|
||||
end
|
||||
|
||||
local OnSizeChanged = function(statusbar)
|
||||
statusbar.MyObject.spark:SetPoint("left", statusbar, "left", statusbar:GetValue() * (statusbar:GetWidth()/100) - 18, 0)
|
||||
statusbar.MyObject.rightTexture:SetWidth(statusbar:GetWidth() - statusbar.MyObject.texture:GetWidth())
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------
|
||||
--object constructor
|
||||
|
||||
function DetailsFrameworkSplitlBar_OnCreate (self)
|
||||
self.texture.original_colors = {1, 1, 1, 1}
|
||||
self.rightTexture.original_colors = {.5, .5, .5, 1}
|
||||
self.spark:SetPoint("left", self, "left", self:GetValue() * (self:GetWidth()/100) - 18, 0)
|
||||
return true
|
||||
end
|
||||
|
||||
function DF:CreateSplitBar(parent, width, height, member, name)
|
||||
return DF:NewSplitBar(parent, nil, name, member, width, height)
|
||||
end
|
||||
|
||||
local build_statusbar = function(self)
|
||||
|
||||
self:SetSize(300, 14)
|
||||
|
||||
self.background = self:CreateTexture("$parent_StatusBarBackground", "BACKGROUND")
|
||||
self.background:SetPoint("topright", self, "topright")
|
||||
self.background:SetPoint("bottomright", self, "bottomright")
|
||||
self.background:SetPoint("topleft", self, "topleft")
|
||||
self.background:SetPoint("bottomleft", self, "bottomleft")
|
||||
self.background:SetTexture([[Interface\PaperDollInfoFrame\UI-Character-Skills-Bar]])
|
||||
self.background:SetVertexColor(.3, .3, .3, 1)
|
||||
|
||||
--this is the left texture and it grows to the right, it is embed within the bar by SetStatusBarTexture
|
||||
self.texture = self:CreateTexture("$parent_StatusBarTexture", "ARTWORK", nil, 1)
|
||||
self.texture:Hide()
|
||||
self.texture:SetSize(300, 14)
|
||||
self.texture:SetTexture([[Interface\PaperDollInfoFrame\UI-Character-Skills-Bar]])
|
||||
|
||||
--this is the right texture and its size is the bar:GetWidth() - self.texture:GetWidth()
|
||||
self.rightTexture = self:CreateTexture("$parent_StatusBarTextureRight", "ARTWORK", nil, 2)
|
||||
self.rightTexture:Hide()
|
||||
self.rightTexture:SetSize(300, 14)
|
||||
self.rightTexture:SetTexture([[Interface\PaperDollInfoFrame\UI-Character-Skills-Bar]])
|
||||
self.rightTexture:SetPoint("topright", self, "topright")
|
||||
self.rightTexture:SetPoint("bottomright", self, "bottomright")
|
||||
self.rightTexture:SetVertexColor(1, 0, 0)
|
||||
|
||||
self.lefticon = self:CreateTexture("$parent_IconLeft", "OVERLAY")
|
||||
self.lefticon:SetSize(14, 14)
|
||||
self.lefticon:SetPoint("LEFT", self, "LEFT")
|
||||
|
||||
self.righticon = self:CreateTexture("$parent_IconRight", "OVERLAY")
|
||||
self.righticon:SetSize(14, 14)
|
||||
self.righticon:SetPoint("RIGHT", self, "RIGHT")
|
||||
|
||||
self.spark = self:CreateTexture("$parent_Spark", "OVERLAY")
|
||||
self.spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
|
||||
self.spark:SetBlendMode("ADD")
|
||||
self.spark:SetSize(32, 32)
|
||||
self.spark:SetPoint("LEFT", self, "RIGHT", -17, -1)
|
||||
|
||||
self.lefttext = self:CreateFontString("$parent_TextLeft", "OVERLAY", "GameFontHighlight")
|
||||
DF:SetFontSize(self.lefttext, 10)
|
||||
self.lefttext:SetJustifyH("left")
|
||||
self.lefttext:SetPoint("LEFT", self.lefticon, "RIGHT", 3, 0)
|
||||
|
||||
self.righttext = self:CreateFontString("$parent_TextRight", "OVERLAY", "GameFontHighlight")
|
||||
DF:SetFontSize(self.righttext, 10)
|
||||
self.righttext:SetJustifyH("right")
|
||||
self.righttext:SetPoint("RIGHT", self.righticon, "LEFT", -3, 0)
|
||||
|
||||
self:SetStatusBarTexture(self.texture)
|
||||
self:SetMinMaxValues(1, 100)
|
||||
self:SetValue(50)
|
||||
DetailsFrameworkSplitlBar_OnCreate (self)
|
||||
end
|
||||
|
||||
|
||||
function DF:NewSplitBar (parent, container, name, member, w, h)
|
||||
|
||||
if (not name) then
|
||||
name = "DetailsFrameworkSplitbar" .. DF.SplitBarCounter
|
||||
DF.SplitBarCounter = DF.SplitBarCounter + 1
|
||||
end
|
||||
if (not parent) then
|
||||
return error("Details! FrameWork: parent not found.", 2)
|
||||
end
|
||||
if (not container) then
|
||||
container = parent
|
||||
end
|
||||
|
||||
if (name:find("$parent")) then
|
||||
local parentName = DF.GetParentName(parent)
|
||||
name = name:gsub("$parent", parentName)
|
||||
end
|
||||
|
||||
local SplitBarObject = {type = "barsplit", dframework = true}
|
||||
|
||||
if (member) then
|
||||
parent [member] = SplitBarObject
|
||||
end
|
||||
|
||||
if (parent.dframework) then
|
||||
parent = parent.widget
|
||||
end
|
||||
if (container.dframework) then
|
||||
container = container.widget
|
||||
end
|
||||
|
||||
--default members:
|
||||
--misc
|
||||
SplitBarObject.locked = false
|
||||
SplitBarObject.container = container
|
||||
SplitBarObject.currentValue = 0.5
|
||||
|
||||
--create widgets
|
||||
SplitBarObject.statusbar = CreateFrame("statusbar", name, parent, "BackdropTemplate")
|
||||
build_statusbar (SplitBarObject.statusbar)
|
||||
SplitBarObject.spark = SplitBarObject.statusbar.spark
|
||||
SplitBarObject.widget = SplitBarObject.statusbar
|
||||
|
||||
if (not APISplitBarFunctions) then
|
||||
APISplitBarFunctions = true
|
||||
local idx = getmetatable(SplitBarObject.statusbar).__index
|
||||
for funcName, funcAddress in pairs(idx) do
|
||||
if (not SplitBarMetaFunctions [funcName]) then
|
||||
SplitBarMetaFunctions [funcName] = function(object, ...)
|
||||
local x = loadstring ( "return _G['"..object.statusbar:GetName().."']:"..funcName.."(...)")
|
||||
return x (...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SplitBarObject.statusbar:SetHeight(h or 200)
|
||||
SplitBarObject.statusbar:SetWidth(w or 14)
|
||||
SplitBarObject.statusbar:SetValue(0.5)
|
||||
|
||||
SplitBarObject.statusbar.MyObject = SplitBarObject
|
||||
|
||||
SplitBarObject.textleft = _G [name .. "_TextLeft"]
|
||||
SplitBarObject.textright = _G [name .. "_TextRight"]
|
||||
|
||||
SplitBarObject.iconleft = _G [name .. "_IconLeft"]
|
||||
SplitBarObject.iconright = _G [name .. "_IconRight"]
|
||||
|
||||
SplitBarObject.background = _G [name .. "_StatusBarBackground"]
|
||||
SplitBarObject.texture = _G [name .. "_StatusBarTexture"]
|
||||
SplitBarObject.rightTexture = _G [name .. "_StatusBarTextureRight"]
|
||||
|
||||
--hooks
|
||||
SplitBarObject.HookList = {
|
||||
OnEnter = {},
|
||||
OnLeave = {},
|
||||
OnHide = {},
|
||||
OnShow = {},
|
||||
OnMouseDown = {},
|
||||
OnMouseUp = {},
|
||||
OnSizeChanged = {},
|
||||
}
|
||||
|
||||
SplitBarObject.statusbar:SetScript("OnEnter", OnEnter)
|
||||
SplitBarObject.statusbar:SetScript("OnLeave", OnLeave)
|
||||
SplitBarObject.statusbar:SetScript("OnHide", OnHide)
|
||||
SplitBarObject.statusbar:SetScript("OnShow", OnShow)
|
||||
SplitBarObject.statusbar:SetScript("OnMouseDown", OnMouseDown)
|
||||
SplitBarObject.statusbar:SetScript("OnMouseUp", OnMouseUp)
|
||||
SplitBarObject.statusbar:SetScript("OnSizeChanged", OnSizeChanged)
|
||||
|
||||
setmetatable(SplitBarObject, SplitBarMetaFunctions)
|
||||
|
||||
return SplitBarObject
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ .. \FrameXML\UI.xsd">
|
||||
<Script file="split_bar.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,422 @@
|
||||
|
||||
local detailsFramework = DetailsFramework
|
||||
|
||||
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local unpack = unpack
|
||||
local CreateFrame = CreateFrame
|
||||
local PixelUtil = PixelUtil
|
||||
|
||||
---@class df_tabinfotable : {name: string, text: string}
|
||||
|
||||
---@class df_tabcontainer : frame
|
||||
---@field AllFrames df_tabcontainerframe[]
|
||||
---@field AllButtons df_tabcontainerbutton[]
|
||||
---@field AllFramesByName table<string, df_tabcontainerframe>
|
||||
---@field AllButtonsByName table<string, df_tabcontainerbutton>
|
||||
---@field hookList table
|
||||
---@field CurrentIndex number
|
||||
---@field IsContainer boolean
|
||||
---@field ButtonSelectedBorderColor table
|
||||
---@field ButtonNotSelectedBorderColor table
|
||||
---@field CanCloseWithRightClick boolean
|
||||
---@field SetIndex fun(self: df_tabcontainer, index: number)
|
||||
---@field SelectTabByIndex fun(self: df_tabcontainer, menuIndex: number)
|
||||
---@field SelectTabByName fun(self: df_tabcontainer, name: string)
|
||||
---@field CreateUnderlineGlow fun(button: button)
|
||||
---@field OnShow fun(self: df_tabcontainer)
|
||||
---@field GetTabFrameByName fun(self: df_tabcontainer, name: string): df_tabcontainerframe
|
||||
---@field GetTabFrameByIndex fun(self: df_tabcontainer, index: number): df_tabcontainerframe
|
||||
---@field GetTabButtonByName fun(self: df_tabcontainer, name: string): df_tabcontainerbutton
|
||||
---@field GetTabButtonByIndex fun(self: df_tabcontainer, index: number): df_tabcontainerbutton
|
||||
|
||||
---@class df_tabcontainerframe : frame
|
||||
---@field bIsFrontPage boolean
|
||||
---@field titleText fontstring
|
||||
---@field tabIndex number
|
||||
---@field OnMouseDown fun(self: df_tabcontainerframe, button: string)
|
||||
---@field OnMouseUp fun(self: df_tabcontainerframe, button: string)
|
||||
---@field RefreshOptions fun(self: df_tabcontainerframe)|nil
|
||||
|
||||
---@class df_tabcontainerbutton : button
|
||||
---@field selectedUnderlineGlow texture
|
||||
---@field textsize number
|
||||
---@field mainFrame df_tabcontainer
|
||||
---@field leftSelectionIndicator texture
|
||||
|
||||
--create a template for the tab buttons
|
||||
local tabTemplate = detailsFramework.table.copy({}, detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"))
|
||||
tabTemplate.backdropbordercolor = nil
|
||||
|
||||
detailsFramework.TabContainerMixin = {
|
||||
---@param self df_tabcontainer
|
||||
---@param tabIndex number
|
||||
---@return df_tabcontainerframe
|
||||
GetTabFrameByIndex = function(self, tabIndex)
|
||||
return self.AllFrames[tabIndex]
|
||||
end,
|
||||
|
||||
---@param self df_tabcontainer
|
||||
---@param name string
|
||||
---@return df_tabcontainerframe
|
||||
GetTabFrameByName = function(self, name)
|
||||
return self.AllFramesByName[name]
|
||||
end,
|
||||
|
||||
---@param self df_tabcontainer
|
||||
---@param tabIndex number
|
||||
---@return df_tabcontainerbutton
|
||||
GetTabButtonByIndex = function(self, tabIndex)
|
||||
return self.AllButtons[tabIndex]
|
||||
end,
|
||||
|
||||
---@param self df_tabcontainer
|
||||
---@param name string
|
||||
---@return df_tabcontainerbutton
|
||||
GetTabButtonByName = function(self, name)
|
||||
return self.AllButtonsByName[name]
|
||||
end,
|
||||
|
||||
---@param self df_tabcontainer
|
||||
---@param backdropTable backdrop|nil
|
||||
---@param backdropColorTable table|string|nil
|
||||
---@param backdropBorderColorTable table|string|nil
|
||||
SetTabFramesBackdrop = function(self, backdropTable, backdropColorTable, backdropBorderColorTable)
|
||||
for tabIndex, tabFrame in ipairs(self.AllFrames) do
|
||||
if (backdropTable) then
|
||||
tabFrame:SetBackdrop(backdropTable)
|
||||
end
|
||||
if (backdropColorTable) then
|
||||
local r, g, b, a = detailsFramework:ParseColors(backdropColorTable)
|
||||
tabFrame:SetBackdropColor(r, g, b, a)
|
||||
end
|
||||
if (backdropBorderColorTable) then
|
||||
local r, g, b, a = detailsFramework:ParseColors(backdropColorTable)
|
||||
tabFrame:SetBackdropBorderColor(r, g, b, a)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
---create a underglow texture for the selected tab, this texture is a small yellow bright gradient below the button
|
||||
---@param self df_tabcontainerbutton
|
||||
CreateUnderlineGlow = function(self)
|
||||
local selectedGlow = self:CreateTexture(nil, "background", nil, -4)
|
||||
selectedGlow:SetPoint("topleft", self["widget"], "bottomleft", -7, 0)
|
||||
selectedGlow:SetPoint("topright", self["widget"], "bottomright", 7, 0)
|
||||
selectedGlow:SetTexture([[Interface\BUTTONS\UI-Panel-Button-Glow]])
|
||||
selectedGlow:SetTexCoord(0, 95/128, 30/64, 38/64)
|
||||
selectedGlow:SetBlendMode("ADD")
|
||||
selectedGlow:SetHeight(8)
|
||||
selectedGlow:SetAlpha(.75)
|
||||
selectedGlow:Hide()
|
||||
self.selectedUnderlineGlow = selectedGlow
|
||||
end,
|
||||
|
||||
---@param tabContainer df_tabcontainer
|
||||
---@param menuIndex number
|
||||
SelectTabByIndex = function(tabContainer, menuIndex)
|
||||
---@type df_tabcontainerbutton
|
||||
local tabButton = tabContainer.AllButtons[menuIndex]
|
||||
---@type df_tabcontainerframe
|
||||
local tabFrame = tabContainer.AllFrames[menuIndex]
|
||||
|
||||
--hide all tab frame and hide the selection glow from tab buttons
|
||||
for i = 1, #tabContainer.AllFrames do
|
||||
---@type df_tabcontainerframe
|
||||
local thisTabFrame = tabContainer.AllFrames[i]
|
||||
thisTabFrame:Hide()
|
||||
|
||||
---@type df_tabcontainerbutton
|
||||
local thisTabButton = tabContainer.AllButtons[i]
|
||||
if (tabContainer.ButtonNotSelectedBorderColor) then
|
||||
thisTabButton:SetBackdropBorderColor(unpack(tabContainer.ButtonNotSelectedBorderColor))
|
||||
end
|
||||
if (thisTabButton.selectedUnderlineGlow) then
|
||||
thisTabButton.selectedUnderlineGlow:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
tabFrame:Show()
|
||||
if (tabFrame.RefreshOptions) then
|
||||
tabFrame:RefreshOptions()
|
||||
end
|
||||
|
||||
if (tabContainer.ButtonSelectedBorderColor) then
|
||||
tabButton:SetBackdropBorderColor(unpack(tabContainer.ButtonSelectedBorderColor))
|
||||
end
|
||||
|
||||
if (tabButton.selectedUnderlineGlow) then
|
||||
tabButton.selectedUnderlineGlow:Show()
|
||||
end
|
||||
|
||||
tabContainer.CurrentIndex = menuIndex
|
||||
|
||||
if (tabContainer.hookList.OnSelectIndex) then
|
||||
detailsFramework:QuickDispatch(tabContainer.hookList.OnSelectIndex, tabContainer, tabButton)
|
||||
end
|
||||
end,
|
||||
|
||||
---@param tabContainer df_tabcontainer
|
||||
---@param name string
|
||||
SelectTabByName = function(tabContainer, name)
|
||||
---@type df_tabcontainerframe
|
||||
local tabFrame = tabContainer.AllFramesByName[name]
|
||||
if (tabFrame) then
|
||||
local tabIndex = tabFrame.tabIndex
|
||||
tabContainer:SelectTabByIndex(tabIndex)
|
||||
else
|
||||
error("df_tabcontainer:SelectTabByName(name): param #2 'name' not found within 'tabContainer.AllFramesByName'.")
|
||||
end
|
||||
end,
|
||||
|
||||
---@param self df_tabcontainer
|
||||
---@param index number
|
||||
SetIndex = function(self, index)
|
||||
self.CurrentIndex = index
|
||||
end,
|
||||
|
||||
---@param self df_tabcontainer
|
||||
OnShow = function(self)
|
||||
local index = self.CurrentIndex
|
||||
self:SelectTabByIndex(index)
|
||||
end
|
||||
}
|
||||
|
||||
detailsFramework.TabContainerFrameMixin = {
|
||||
---@param self df_tabcontainerframe
|
||||
---@param button string
|
||||
OnMouseDown = function(self, button)
|
||||
--search for UIParent
|
||||
---@type frame
|
||||
local highestParent = detailsFramework:FindHighestParent(self)
|
||||
local tabContainer = self:GetParent()
|
||||
---@cast tabContainer df_tabcontainer
|
||||
|
||||
if (button == "LeftButton") then
|
||||
if (not highestParent.IsMoving and highestParent:IsMovable()) then
|
||||
highestParent:StartMoving()
|
||||
highestParent.IsMoving = true
|
||||
end
|
||||
|
||||
elseif (button == "RightButton") then
|
||||
if (not highestParent.IsMoving and tabContainer.IsContainer) then
|
||||
if (self.bIsFrontPage) then
|
||||
if (tabContainer.CanCloseWithRightClick) then
|
||||
if (highestParent["CloseFunction"]) then
|
||||
highestParent["CloseFunction"](highestParent)
|
||||
else
|
||||
highestParent:Hide()
|
||||
end
|
||||
end
|
||||
else
|
||||
--goes back to front page
|
||||
tabContainer:SelectTabByIndex(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
---@param self df_tabcontainerframe
|
||||
---@param button string
|
||||
OnMouseUp = function(self, button)
|
||||
local frame = detailsFramework:FindHighestParent(self)
|
||||
if (frame.IsMoving) then
|
||||
frame:StopMovingOrSizing()
|
||||
frame.IsMoving = false
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
---creates a frame called tabContainer which is used as base for the tab container object
|
||||
---the function receives a table called tabList which contains sub tables with two keys 'name' and 'text', name is the frame name and text is the text displayed on the button
|
||||
---then the function iterate amongst the tabList and create a frame and a button for each entry using the value of the 'text' key as the text for the button and 'name' for the name of the frame
|
||||
---when the user click on a button, the tabContainer hide all frames and show the frame which was created together with that button
|
||||
---@param parent frame the parent frame
|
||||
---@param title string a string to use as the title of the tab container, the title is always shown
|
||||
---@param frameName string the frame name to pass into the CreateFrame function
|
||||
---@param tabList df_tabinfotable[] the list of tabs to create, each entry has a 'name' and 'text' keys
|
||||
---@param optionsTable {button_border_color: table, button_selected_border_color: table, right_click_y: number, hide_click_label: boolean, close_text_alpha: number, rightbutton_always_close: boolean, right_click_interact: boolean, y_offset: number, button_width: number, button_height: number, button_x: number, button_y: number, button_text_size: number, container_width_offset: number}|nil
|
||||
---@param hookList table<string, function>|nil
|
||||
---@param languageInfo any
|
||||
---@return df_tabcontainer
|
||||
function detailsFramework:CreateTabContainer(parent, title, frameName, tabList, optionsTable, hookList, languageInfo)
|
||||
optionsTable = optionsTable or {}
|
||||
|
||||
local parentFrameWidth = parent:GetWidth()
|
||||
local yOffset = optionsTable.y_offset or 0
|
||||
local buttonWidth = optionsTable.button_width or 160
|
||||
local buttonHeight = optionsTable.button_height or 20
|
||||
local buttonAnchorX = optionsTable.button_x or 230
|
||||
local buttonAnchorY = optionsTable.button_y or 0
|
||||
local buttonTextSize = optionsTable.button_text_size or 10
|
||||
local containerWidthOffset = optionsTable.container_width_offset or 0
|
||||
|
||||
--create the base frame
|
||||
---@type df_tabcontainer
|
||||
local tabContainer = CreateFrame("frame", frameName, parent["widget"] or parent, "BackdropTemplate")
|
||||
tabContainer.hookList = hookList or {}
|
||||
|
||||
detailsFramework:Mixin(tabContainer, detailsFramework.TabContainerMixin)
|
||||
|
||||
--create the fontstring which show the title
|
||||
---@type fontstring
|
||||
local mainTitle = detailsFramework:CreateLabel(tabContainer, title, 24, "white")
|
||||
mainTitle:SetPoint("topleft", tabContainer, "topleft", 10, -30 + yOffset)
|
||||
|
||||
tabContainer.AllFrames = {}
|
||||
tabContainer.AllButtons = {}
|
||||
tabContainer.AllFramesByName = {}
|
||||
tabContainer.AllButtonsByName = {}
|
||||
tabContainer.CurrentIndex = 1
|
||||
tabContainer.IsContainer = true
|
||||
tabContainer.ButtonSelectedBorderColor = optionsTable.button_selected_border_color or {1, 1, 0, 1}
|
||||
tabContainer.ButtonNotSelectedBorderColor = optionsTable.button_border_color or {0, 0, 0, 0}
|
||||
|
||||
if (optionsTable.right_click_interact ~= nil) then
|
||||
tabContainer.CanCloseWithRightClick = optionsTable.right_click_interact
|
||||
else
|
||||
tabContainer.CanCloseWithRightClick = true
|
||||
end
|
||||
|
||||
--languageInfo
|
||||
local addonId = languageInfo and languageInfo.language_addonId or "none"
|
||||
|
||||
for tabIndex, tabInfo in ipairs(tabList) do
|
||||
--create a frame which will be shown when the tabButton is clicked
|
||||
--when this tab isn't selected, this frame is hidden
|
||||
---@type df_tabcontainerframe
|
||||
local tabFrame = CreateFrame("frame", "$parent" .. tabInfo.name, tabContainer, "BackdropTemplate")
|
||||
detailsFramework:Mixin(tabFrame, detailsFramework.TabContainerFrameMixin)
|
||||
tabFrame:SetAllPoints()
|
||||
tabFrame:SetFrameLevel(210)
|
||||
tabFrame:SetScript("OnMouseDown", tabFrame.OnMouseDown)
|
||||
tabFrame:SetScript("OnMouseUp", tabFrame.OnMouseUp)
|
||||
tabFrame.tabIndex = tabIndex
|
||||
tabFrame:Hide()
|
||||
|
||||
--attempt to get the localized text from the language system using the addonId and the frameInfo.text
|
||||
local phraseId = tabInfo.text
|
||||
local bIsLanguagePrahseID = detailsFramework.Language.DoesPhraseIDExistsInDefaultLanguage(addonId, phraseId)
|
||||
|
||||
--create the fontstring which show this tab text, this text is only shown when the tab is shown
|
||||
local titleLabel = detailsFramework:CreateLabel(tabFrame, "", 16, "silver")
|
||||
if (bIsLanguagePrahseID) then
|
||||
DetailsFramework.Language.RegisterObjectWithDefault(addonId, titleLabel, tabInfo.text, tabInfo.text)
|
||||
else
|
||||
titleLabel:SetText(tabInfo.text)
|
||||
end
|
||||
titleLabel:SetPoint("topleft", mainTitle, "bottomleft", 0, 0)
|
||||
tabFrame.titleText = titleLabel
|
||||
|
||||
---@type df_tabcontainerbutton
|
||||
local tabButton = detailsFramework:CreateButton(tabContainer, function() tabContainer:SelectTabByIndex(tabIndex) end, buttonWidth, buttonHeight, tabInfo.text, tabIndex, nil, nil, nil, "$parentTabButton" .. tabInfo.name, false, tabTemplate)
|
||||
PixelUtil.SetSize(tabButton, buttonWidth, buttonHeight)
|
||||
tabButton:SetFrameLevel(220)
|
||||
tabButton.textsize = buttonTextSize
|
||||
tabButton.mainFrame = tabContainer
|
||||
tabContainer.CreateUnderlineGlow(tabButton)
|
||||
|
||||
--register the fontstring with the language system
|
||||
if (bIsLanguagePrahseID) then
|
||||
DetailsFramework.Language.RegisterObjectWithDefault(addonId, tabButton["widget"], tabInfo.text, tabInfo.text)
|
||||
end
|
||||
|
||||
local rightClickToBack
|
||||
if (tabIndex == 1 or optionsTable.rightbutton_always_close) then
|
||||
rightClickToBack = detailsFramework:CreateLabel(tabFrame, "right click to close", 10, "gray")
|
||||
rightClickToBack:SetPoint("bottomright", tabFrame, "bottomright", -1, optionsTable.right_click_y or 0)
|
||||
if (optionsTable.close_text_alpha) then
|
||||
rightClickToBack:SetAlpha(optionsTable.close_text_alpha)
|
||||
end
|
||||
tabFrame.bIsFrontPage = true
|
||||
else
|
||||
rightClickToBack = detailsFramework:CreateLabel(tabFrame, "right click to go back to main menu", 10, "gray")
|
||||
rightClickToBack:SetPoint("bottomright", tabFrame, "bottomright", -1, optionsTable.right_click_y or 0)
|
||||
if (optionsTable.close_text_alpha) then
|
||||
rightClickToBack:SetAlpha(optionsTable.close_text_alpha)
|
||||
end
|
||||
end
|
||||
|
||||
if (optionsTable.hide_click_label) then
|
||||
rightClickToBack:Hide()
|
||||
end
|
||||
|
||||
table.insert(tabContainer.AllFrames, tabFrame)
|
||||
table.insert(tabContainer.AllButtons, tabButton)
|
||||
tabContainer.AllFramesByName[tabInfo.name] = tabFrame
|
||||
tabContainer.AllFramesByName[tabInfo.text] = tabFrame
|
||||
tabContainer.AllButtonsByName[tabInfo.name] = tabButton
|
||||
tabContainer.AllButtonsByName[tabInfo.text] = tabButton
|
||||
end
|
||||
|
||||
--order buttons
|
||||
local x = buttonAnchorX
|
||||
local y = buttonAnchorY
|
||||
local spaceBetweenButtons = 3
|
||||
|
||||
local allocatedSpaceForButtons = parentFrameWidth - ((#tabList - 2) * spaceBetweenButtons) - buttonAnchorX + containerWidthOffset
|
||||
local amountButtonsPerRow = math.floor(allocatedSpaceForButtons / buttonWidth)
|
||||
|
||||
tabContainer.AllButtons[1]:SetPoint("topleft", mainTitle, "topleft", x, y)
|
||||
x = x + buttonWidth + 2
|
||||
|
||||
for i = 2, #tabContainer.AllButtons do
|
||||
local button = tabContainer.AllButtons[i]
|
||||
PixelUtil.SetPoint(button, "topleft", mainTitle, "topleft", x, y)
|
||||
x = x + buttonWidth + 2
|
||||
|
||||
if (i % amountButtonsPerRow == 0) then
|
||||
x = buttonAnchorX
|
||||
y = y - buttonHeight - 1
|
||||
end
|
||||
end
|
||||
|
||||
--when show the frame, reset to the current internal index
|
||||
tabContainer:SetScript("OnShow", tabContainer.OnShow)
|
||||
--select the first frame
|
||||
local defaultTab = 1
|
||||
tabContainer:SelectTabByIndex(defaultTab)
|
||||
|
||||
return tabContainer
|
||||
end
|
||||
|
||||
|
||||
--[=[example:
|
||||
|
||||
local parent = UIParent
|
||||
local title = "My AddOn Options"
|
||||
local frameName = "MyAddOnOptionsFrame"
|
||||
local tabList = {
|
||||
{name = "GeneralSettings", text = "General Settings"},
|
||||
{name = "AdvancedSettings", text = "Advanced Settings"},
|
||||
{name = "AboutTheAddon", text = "Addon Info"},
|
||||
}
|
||||
local optionsTable = {}
|
||||
local hookList = {}
|
||||
local languageInfo = {language_addonId = "MyAddOnTocName"}
|
||||
|
||||
local tabContainer = DetailsFramework:CreateTabContainer(parent, title, frameName, tabList, optionsTable, hookList, languageInfo)
|
||||
tabContainer:SetPoint("center", UIParent, "center", 0, 0)
|
||||
tabContainer:SetSize(750, 450)
|
||||
tabContainer:Show()
|
||||
|
||||
--ways for getting a tab frame and start to create widgets inside it
|
||||
local tabIndex = 1
|
||||
local generalSettingsTabFrame = tabContainer:GetTabFrameByIndex(tabIndex) --using a tabIndex
|
||||
local advancedSettingsTabFrame = tabContainer:GetTabFrameByName("Advanced Settings") --using the tab text
|
||||
local aboutTabFrame = tabContainer:GetTabFrameByName("AboutTheAddon") --using the tab name
|
||||
|
||||
--clicking on tab buttons will automatically show the tab frame, to select a tab frame without clicking on the button, use:
|
||||
tabContainer:SelectTabByIndex(tabIndex) --using a tabIndex
|
||||
tabContainer:SelectTabByName("Advanced Settings") --using the tab text
|
||||
tabContainer:SelectTabByName("AdvancedSettings") --using the tab name
|
||||
|
||||
--modify the background color by applying a backdrop
|
||||
local backdropTable = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}
|
||||
local backdropColor = {DetailsFramework:GetDefaultBackdropColor()}
|
||||
local backdropBorderColor = {0, 0, 0, 1}
|
||||
tabContainer:SetTabFramesBackdrop(backdropTable, backdropColor, backdropBorderColor)
|
||||
|
||||
--]=]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
|
||||
<Script file="textentry.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,462 @@
|
||||
|
||||
local DF = _G["DetailsFramework"]
|
||||
if (not DF or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
|
||||
local _
|
||||
local type = type
|
||||
local floor = math.floor
|
||||
local GetTime = GetTime
|
||||
|
||||
local APITimeBarFunctions
|
||||
|
||||
do
|
||||
local metaPrototype = {
|
||||
WidgetType = "timebar",
|
||||
dversion = DF.dversion,
|
||||
}
|
||||
|
||||
--check if there's a metaPrototype already existing
|
||||
if (_G[DF.GlobalWidgetControlNames["timebar"]]) then
|
||||
--get the already existing metaPrototype
|
||||
local oldMetaPrototype = _G[DF.GlobalWidgetControlNames["timebar"]]
|
||||
--check if is older
|
||||
if ( (not oldMetaPrototype.dversion) or (oldMetaPrototype.dversion < DF.dversion) ) then
|
||||
--the version is older them the currently loading one
|
||||
--copy the new values into the old metatable
|
||||
for funcName, _ in pairs(metaPrototype) do
|
||||
oldMetaPrototype[funcName] = metaPrototype[funcName]
|
||||
end
|
||||
end
|
||||
else
|
||||
--first time loading the framework
|
||||
_G[DF.GlobalWidgetControlNames["timebar"]] = metaPrototype
|
||||
end
|
||||
end
|
||||
|
||||
local TimeBarMetaFunctions = _G[DF.GlobalWidgetControlNames["timebar"]]
|
||||
DF:Mixin(TimeBarMetaFunctions, DF.ScriptHookMixin)
|
||||
|
||||
--methods
|
||||
TimeBarMetaFunctions.SetMembers = TimeBarMetaFunctions.SetMembers or {}
|
||||
TimeBarMetaFunctions.GetMembers = TimeBarMetaFunctions.GetMembers or {}
|
||||
|
||||
TimeBarMetaFunctions.__index = function(table, key)
|
||||
local func = TimeBarMetaFunctions.GetMembers[key]
|
||||
if (func) then
|
||||
return func(table, key)
|
||||
end
|
||||
|
||||
local fromMe = rawget(table, key)
|
||||
if (fromMe) then
|
||||
return fromMe
|
||||
end
|
||||
|
||||
return TimeBarMetaFunctions[key]
|
||||
end
|
||||
|
||||
TimeBarMetaFunctions.__newindex = function(table, key, value)
|
||||
local func = TimeBarMetaFunctions.SetMembers[key]
|
||||
if (func) then
|
||||
return func(table, value)
|
||||
else
|
||||
return rawset(table, key, value)
|
||||
end
|
||||
end
|
||||
|
||||
--scripts
|
||||
local OnEnterFunc = function(statusBar)
|
||||
local kill = statusBar.MyObject:RunHooksForWidget("OnEnter", statusBar, statusBar.MyObject)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
if (statusBar.MyObject.tooltip) then
|
||||
GameCooltip2:Reset()
|
||||
GameCooltip2:AddLine(statusBar.MyObject.tooltip)
|
||||
GameCooltip2:ShowCooltip(statusBar, "tooltip")
|
||||
end
|
||||
end
|
||||
|
||||
local OnLeaveFunc = function(statusBar)
|
||||
local kill = statusBar.MyObject:RunHooksForWidget("OnLeave", statusBar, statusBar.MyObject)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
|
||||
if (statusBar.MyObject.tooltip) then
|
||||
GameCooltip2:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local OnHideFunc = function(statusBar)
|
||||
local kill = statusBar.MyObject:RunHooksForWidget("OnHide", statusBar, statusBar.MyObject)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local OnShowFunc = function(statusBar)
|
||||
local kill = statusBar.MyObject:RunHooksForWidget("OnShow", statusBar, statusBar.MyObject)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local OnMouseDownFunc = function(statusBar, mouseButton)
|
||||
local kill = statusBar.MyObject:RunHooksForWidget("OnMouseDown", statusBar, statusBar.MyObject)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local OnMouseUpFunc = function(statusBar, mouseButton)
|
||||
local kill = statusBar.MyObject:RunHooksForWidget("OnMouseUp", statusBar, statusBar.MyObject)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--timer functions
|
||||
function TimeBarMetaFunctions:SetIconSize(width, height)
|
||||
if (width and not height) then
|
||||
self.statusBar.icon:SetWidth(width)
|
||||
|
||||
elseif (not width and height) then
|
||||
self.statusBar.icon:SetHeight(height)
|
||||
|
||||
elseif (width and height) then
|
||||
self.statusBar.icon:SetSize(width, height)
|
||||
end
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:SetIcon(texture, L, R, T, B)
|
||||
if (texture) then
|
||||
self.statusBar.icon:Show()
|
||||
self.statusBar.icon:SetPoint("left", self.statusBar, "left", 2, 0)
|
||||
self.statusBar.icon:SetSize(self.statusBar:GetHeight()-2, self.statusBar:GetHeight()-2)
|
||||
self.statusBar.leftText:ClearAllPoints()
|
||||
self.statusBar.leftText:SetPoint("left", self.statusBar.icon, "right", 2, 0)
|
||||
self.statusBar.icon:SetTexture(texture)
|
||||
|
||||
if (L) then
|
||||
self.statusBar.icon:SetTexCoord(L, R, T, B)
|
||||
end
|
||||
else
|
||||
self.statusBar.icon:Hide()
|
||||
self.statusBar.leftText:ClearAllPoints()
|
||||
self.statusBar.leftText:SetPoint("left", self.statusBar, "left", 2, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:GetIcon()
|
||||
return self.statusBar.icon
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:SetTexture(texture)
|
||||
self.statusBar.barTexture:SetTexture(texture)
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:SetColor(color, green, blue, alpha)
|
||||
local r, g, b, a = DF:ParseColors(color, green, blue, alpha)
|
||||
self.statusBar.barTexture:SetVertexColor(r, g, b, a)
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:SetLeftText(text)
|
||||
self.statusBar.leftText:SetText(text)
|
||||
end
|
||||
function TimeBarMetaFunctions:SetRightText(text)
|
||||
self.statusBar.rightText:SetText(text)
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:SetFont(font, size, color, shadow)
|
||||
if (font) then
|
||||
DF:SetFontFace(self.statusBar.leftText, font)
|
||||
end
|
||||
|
||||
if (size) then
|
||||
DF:SetFontSize(self.statusBar.leftText, size)
|
||||
end
|
||||
|
||||
if (color) then
|
||||
DF:SetFontColor(self.statusBar.leftText, color)
|
||||
end
|
||||
|
||||
if (shadow) then
|
||||
DF:SetFontOutline(self.statusBar.leftText, shadow)
|
||||
end
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:SetThrottle(seconds)
|
||||
if (seconds and seconds > 0) then
|
||||
self.statusBar.isUsingThrottle = true
|
||||
self.statusBar.amountThrottle = seconds
|
||||
else
|
||||
self.statusBar.isUsingThrottle = false
|
||||
end
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:SetDirection(direction)
|
||||
direction = direction or "right"
|
||||
self.direction = direction
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:HasTimer()
|
||||
return self.statusBar.hasTimer
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:StopTimer()
|
||||
if (self.statusBar.hasTimer) then
|
||||
self.statusBar.hasTimer = nil
|
||||
local kill = self:RunHooksForWidget("OnTimerEnd", self.statusBar, self)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local statusBar = self.statusBar
|
||||
statusBar:SetScript("OnUpdate", nil)
|
||||
|
||||
statusBar:SetMinMaxValues(0, 100)
|
||||
statusBar:SetValue(100)
|
||||
statusBar.rightText:SetText("")
|
||||
|
||||
statusBar.spark:Hide()
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:ShowSpark(state, alpha, color)
|
||||
if (type(state) == "boolean" and state == false) then
|
||||
self.statusBar.dontShowSpark = true
|
||||
else
|
||||
self.statusBar.dontShowSpark = nil
|
||||
end
|
||||
|
||||
if (alpha) then
|
||||
self.statusBar.sparkAlpha = alpha
|
||||
else
|
||||
self.statusBar.sparkAlpha = nil
|
||||
end
|
||||
|
||||
if (color) then
|
||||
local r, g, b = DF:ParseColors(color)
|
||||
if (r and g and b) then
|
||||
self.statusBar.sparkColorR = r
|
||||
self.statusBar.sparkColorG = g
|
||||
self.statusBar.sparkColorB = b
|
||||
end
|
||||
else
|
||||
self.statusBar.sparkColorR = nil
|
||||
self.statusBar.sparkColorG = nil
|
||||
self.statusBar.sparkColorB = nil
|
||||
end
|
||||
end
|
||||
|
||||
local OnUpdateFunc = function(self, deltaTime)
|
||||
if (self.isUsingThrottle) then
|
||||
self.throttle = self.throttle + deltaTime
|
||||
if (self.throttle < self.amountThrottle) then
|
||||
return
|
||||
end
|
||||
self.throttle = 0
|
||||
end
|
||||
|
||||
local timeNow = GetTime()
|
||||
self:SetValue(timeNow)
|
||||
|
||||
--adjust the spark
|
||||
local spark = self.spark
|
||||
local startTime, endTime = self:GetMinMaxValues()
|
||||
|
||||
if (not self.dontShowSpark) then
|
||||
if (self.direction == "right") then
|
||||
local pct = abs((timeNow - endTime) / (endTime - startTime))
|
||||
pct = abs(1 - pct)
|
||||
spark:SetPoint("left", self, "left", (self:GetWidth() * pct) - 16, 0)
|
||||
spark:Show()
|
||||
else
|
||||
spark:SetPoint("right", self, "right", self:GetWidth() * (timeNow/self.endTime), 0)
|
||||
end
|
||||
end
|
||||
|
||||
local timeLeft = floor(endTime - timeNow)
|
||||
local formatedTimeLeft = DF:IntegerToTimer(timeLeft)
|
||||
self.rightText:SetText(formatedTimeLeft)
|
||||
|
||||
--check if finished
|
||||
if (timeNow >= self.endTime) then
|
||||
self.MyObject:StopTimer()
|
||||
end
|
||||
end
|
||||
|
||||
function TimeBarMetaFunctions:SetTimer(currentTime, startTime, endTime)
|
||||
self.statusBar:Show()
|
||||
|
||||
if (not currentTime or currentTime == 0) then
|
||||
self:StopTimer()
|
||||
return
|
||||
end
|
||||
|
||||
if (startTime and endTime) then
|
||||
if (self.statusBar.hasTimer and currentTime == self.statusBar.timeLeft1) then
|
||||
--it is the same timer called again
|
||||
return
|
||||
end
|
||||
self.statusBar.startTime = startTime
|
||||
self.statusBar.endTime = endTime
|
||||
else
|
||||
local bForceNewTimer = type(startTime) == "boolean" and startTime
|
||||
if (self.statusBar.hasTimer and currentTime == self.statusBar.timeLeft2 and not bForceNewTimer) then
|
||||
--it is the same timer called again
|
||||
return
|
||||
end
|
||||
self.statusBar.startTime = GetTime()
|
||||
self.statusBar.endTime = GetTime() + currentTime
|
||||
self.statusBar.timeLeft2 = currentTime
|
||||
end
|
||||
|
||||
self.statusBar:SetMinMaxValues(self.statusBar.startTime, self.statusBar.endTime)
|
||||
|
||||
if (self.direction == "right") then
|
||||
self.statusBar:SetReverseFill(false)
|
||||
else
|
||||
self.statusBar:SetReverseFill(true)
|
||||
end
|
||||
|
||||
if (self.statusBar.dontShowSpark) then
|
||||
self.statusBar.spark:Hide()
|
||||
else
|
||||
self.statusBar.spark:Show()
|
||||
self.statusBar.spark:SetHeight(self.statusBar:GetHeight()+20)
|
||||
|
||||
if (self.statusBar.sparkAlpha) then
|
||||
self.statusBar.spark:SetAlpha(self.statusBar.sparkAlpha)
|
||||
else
|
||||
self.statusBar.spark:SetAlpha(1)
|
||||
end
|
||||
|
||||
if (self.statusBar.sparkColorR) then
|
||||
self.statusBar.spark:SetVertexColor(self.statusBar.sparkColorR, self.statusBar.sparkColorG, self.statusBar.sparkColorB)
|
||||
else
|
||||
self.statusBar.spark:SetVertexColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
self.statusBar.hasTimer = true
|
||||
self.statusBar.direction = self.direction
|
||||
self.statusBar.throttle = 0
|
||||
|
||||
self.statusBar:SetScript("OnUpdate", OnUpdateFunc)
|
||||
|
||||
local kill = self:RunHooksForWidget("OnTimerStart", self.statusBar, self)
|
||||
if (kill) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function DF:CreateTimeBar(parent, texture, width, height, value, member, name)
|
||||
if (not name) then
|
||||
name = "DetailsFrameworkBarNumber" .. DF.BarNameCounter
|
||||
DF.BarNameCounter = DF.BarNameCounter + 1
|
||||
|
||||
elseif (not parent) then
|
||||
return error("Details! FrameWork: parent not found.", 2)
|
||||
end
|
||||
|
||||
if (name:find("$parent")) then
|
||||
local parentName = DF.GetParentName(parent)
|
||||
name = name:gsub("$parent", parentName)
|
||||
end
|
||||
|
||||
local timeBar = {
|
||||
type = "timebar",
|
||||
dframework = true
|
||||
}
|
||||
|
||||
if (member) then
|
||||
parent[member] = timeBar
|
||||
end
|
||||
if (parent.dframework) then
|
||||
parent = parent.widget
|
||||
end
|
||||
|
||||
value = value or 0
|
||||
width = width or 150
|
||||
height = height or 14
|
||||
timeBar.locked = false
|
||||
|
||||
timeBar.statusBar = CreateFrame("statusbar", name, parent, "BackdropTemplate")
|
||||
timeBar.widget = timeBar.statusBar
|
||||
DF:Mixin(timeBar.statusBar, DF.WidgetFunctions)
|
||||
timeBar.statusBar.MyObject = timeBar
|
||||
timeBar.direction = "right"
|
||||
|
||||
if (not APITimeBarFunctions) then
|
||||
APITimeBarFunctions = true
|
||||
local idx = getmetatable(timeBar.statusBar).__index
|
||||
for funcName, funcAddress in pairs(idx) do
|
||||
if (not TimeBarMetaFunctions[funcName]) then
|
||||
TimeBarMetaFunctions[funcName] = function(object, ...)
|
||||
local x = loadstring("return _G['"..object.statusBar:GetName().."']:"..funcName.."(...)")
|
||||
return x(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--create widgets
|
||||
timeBar.statusBar:SetWidth(width)
|
||||
timeBar.statusBar:SetHeight(height)
|
||||
timeBar.statusBar:SetFrameLevel(parent:GetFrameLevel()+1)
|
||||
timeBar.statusBar:SetMinMaxValues(0, 100)
|
||||
timeBar.statusBar:SetValue(value or 100)
|
||||
timeBar.statusBar:EnableMouse(false)
|
||||
|
||||
timeBar.statusBar.backgroundTexture = timeBar.statusBar:CreateTexture(nil, "border")
|
||||
timeBar.statusBar.backgroundTexture:SetColorTexture(.1, .1, .1, .6)
|
||||
timeBar.statusBar.backgroundTexture:SetAllPoints()
|
||||
|
||||
timeBar.statusBar.barTexture = timeBar.statusBar:CreateTexture(nil, "artwork")
|
||||
timeBar.statusBar.barTexture:SetTexture(texture or [[Interface\WorldStateFrame\WORLDSTATEFINALSCORE-HIGHLIGHT]])
|
||||
timeBar.statusBar:SetStatusBarTexture(timeBar.statusBar.barTexture)
|
||||
|
||||
timeBar.statusBar.spark = timeBar.statusBar:CreateTexture(nil, "overlay", nil, 7)
|
||||
timeBar.statusBar.spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
|
||||
timeBar.statusBar.spark:SetBlendMode("ADD")
|
||||
timeBar.statusBar.spark:Hide()
|
||||
|
||||
timeBar.statusBar.icon = timeBar.statusBar:CreateTexture(nil, "overlay", nil, 5)
|
||||
timeBar.statusBar.icon:SetPoint("left", timeBar.statusBar, "left", 2, 0)
|
||||
|
||||
timeBar.statusBar.leftText = timeBar.statusBar:CreateFontString("$parentLeftText", "overlay", "GameFontNormal", 4)
|
||||
timeBar.statusBar.leftText:SetPoint("left", timeBar.statusBar.icon, "right", 2, 0)
|
||||
|
||||
timeBar.statusBar.rightText = timeBar.statusBar:CreateFontString(nil, "overlay", "GameFontNormal", 4)
|
||||
timeBar.statusBar.rightText:SetPoint("right", timeBar.statusBar, "right", -2, 0)
|
||||
timeBar.statusBar.rightText:SetJustifyH("left")
|
||||
|
||||
--hooks
|
||||
timeBar.HookList = {
|
||||
OnEnter = {},
|
||||
OnLeave = {},
|
||||
OnHide = {},
|
||||
OnShow = {},
|
||||
OnMouseDown = {},
|
||||
OnMouseUp = {},
|
||||
OnTimerStart = {},
|
||||
OnTimerEnd = {},
|
||||
}
|
||||
|
||||
timeBar.statusBar:SetScript("OnEnter", OnEnterFunc)
|
||||
timeBar.statusBar:SetScript("OnLeave", OnLeaveFunc)
|
||||
timeBar.statusBar:SetScript("OnHide", OnHideFunc)
|
||||
timeBar.statusBar:SetScript("OnShow", OnShowFunc)
|
||||
timeBar.statusBar:SetScript("OnMouseDown", OnMouseDownFunc)
|
||||
timeBar.statusBar:SetScript("OnMouseUp", OnMouseUpFunc)
|
||||
|
||||
--set class
|
||||
setmetatable(timeBar, TimeBarMetaFunctions)
|
||||
|
||||
return timeBar
|
||||
end
|
||||
@@ -0,0 +1,2 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd">
|
||||
</Ui>
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
local DetailsFramework = _G["DetailsFramework"]
|
||||
if (not DetailsFramework or not DetailsFrameworkCanLoad) then
|
||||
return
|
||||
end
|
||||
local _
|
||||
|
||||
local DF = DetailsFramework
|
||||
|
||||
--backdrop namespace
|
||||
DF.BackdropUtil = {}
|
||||
|
||||
function DF.BackdropUtil:SetColorStripe(frame, index, backdrop, color1, color2)
|
||||
if (backdrop == nil or type(backdrop) == "table") then
|
||||
frame:SetBackdrop(backdrop and {bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||
end
|
||||
if (index % 2 == 0) then
|
||||
local r, g, b, a = DF:ParseColors(color1 or {.2, .2, .2, 0.5})
|
||||
frame:SetBackdropColor(r, g, b, a)
|
||||
else
|
||||
local r, g, b, a = DF:ParseColors(color2 or {.3, .3, .3, 0.5})
|
||||
frame:SetBackdropColor(r, g, b, a)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,401 @@
|
||||
|
||||
--uiobject: is an object that represents a UI element, such as a frame, a texture, or a button. UIObjects are the base class for all UI elements in the WoW API.
|
||||
--3D World: is an object which is placed behind|below all UI elements, cannot be parent of any object, in the 3D World object is where the game world is rendered
|
||||
--size: corresponds to the height and height of an object, it is measure in pixels, must be bigger than zero.
|
||||
--scale: the size of an object is multiplied by this value, it is measure in percentage, must be between 0.65 and 2.40.
|
||||
--alpha: corresponds to the transparency of an object, the bigger is the value less transparent is the object, it is measure in percentage, must be between 0 and 1, zero is fully transparent and one is fully opaque.
|
||||
--controller: abstract term to define who's in control of an entity, can be the server or a player.
|
||||
--npc: an entity shown in the 3d world with a name and a health bar, can be friendly or hostile, can be interacted with, always controlled by the server.
|
||||
--player: is an entity that represents a player character, the controller is always player.
|
||||
--pet: represents a npc controlled by the server and can accept commands from the player.
|
||||
--guadians: represents a npc, the server has the possess of the controller, don't accept commands like pets, helps attacking the enemies of the npc or player.
|
||||
--role: is a string that represents the role of a unit, such as tank, healer, or damage dealer. only players can have a role.
|
||||
|
||||
---@alias role
|
||||
---| "TANK"
|
||||
---| "HEALER"
|
||||
---| "DAMAGER"
|
||||
---| "NONE"
|
||||
|
||||
---@alias anchorpoint
|
||||
---| "topleft"
|
||||
---| "topright"
|
||||
---| "bottomleft"
|
||||
---| "bottomright"
|
||||
---| "top"
|
||||
---| "bottom"
|
||||
---| "left"
|
||||
---| "right"
|
||||
---| "center"
|
||||
|
||||
---@alias framestrata
|
||||
---| "background"
|
||||
---| "low"
|
||||
---| "medium"
|
||||
---| "high"
|
||||
---| "dialog"
|
||||
---| "fullscreen"
|
||||
---| "fullscreen_dialog"
|
||||
---| "tooltip"
|
||||
---| "BACKGROUND"
|
||||
---| "LOW"
|
||||
---| "MEDIUM"
|
||||
---| "HIGH"
|
||||
---| "DIALOG"
|
||||
---| "FULLSCREEN"
|
||||
---| "FULLSCREEN_DIALOG"
|
||||
---| "TOOLTIP"
|
||||
|
||||
---@alias sizingpoint
|
||||
---| "top"
|
||||
---| "topright"
|
||||
---| "right"
|
||||
---| "bottomright"
|
||||
---| "bottom"
|
||||
---| "bottomleft"
|
||||
---| "left"
|
||||
---| "topleft"
|
||||
|
||||
---@alias drawlayer
|
||||
---| "background"
|
||||
---| "border"
|
||||
---| "artwork"
|
||||
---| "overlay"
|
||||
---| "highlight"
|
||||
|
||||
---@alias buttontype
|
||||
---| "AnyUp"
|
||||
---| "AnyDown"
|
||||
---| "LeftButtonDown"
|
||||
---| "LeftButtonUp"
|
||||
---| "MiddleButtonUp"
|
||||
---| "MiddleButtonDown"
|
||||
---| "RightButtonDown"
|
||||
---| "RightButtonUp"
|
||||
---| "Button4Up"
|
||||
---| "Button4Down"
|
||||
---| "Button5Up"
|
||||
---| "Button5Down"
|
||||
|
||||
---@alias justifyh
|
||||
---| "left"
|
||||
---| "right"
|
||||
---| "center"
|
||||
|
||||
---@alias justifyv
|
||||
---| "top"
|
||||
---| "bottom"
|
||||
---| "middle"
|
||||
|
||||
---@alias orientation
|
||||
---| "HORIZONTAL"
|
||||
---| "VERTICAL"
|
||||
|
||||
---@alias width number property that represents the horizontal size of a UI element, such as a frame or a texture. Gotten from the first result of GetWidth() or from the first result of GetSize(). It is expected a GetWidth() or GetSize() when the type 'height' is used.
|
||||
---@alias height number property that represents the vertical size of a UI element, such as a frame or a texture. Gotten from the first result of GetHeight() or from the second result of GetSize(). It is expected a GetHeight() or GetSize() when the type 'height' is used.
|
||||
---@alias red number color value representing the red component of a color, the value must be between 0 and 1. To retrieve a color from a string or table use: local red, green, blue, alpha = DetailsFramework:ParseColors(color)
|
||||
---@alias green number color value representing the green component of a color, the value must be between 0 and 1. To retrieve a color from a string or table use: local red, green, blue, alpha = DetailsFramework:ParseColors(color)
|
||||
---@alias blue number color value representing the blue component of a color, the value must be between 0 and 1. To retrieve a color from a string or table use: local red, green, blue, alpha = DetailsFramework:ParseColors(color)
|
||||
---@alias alpha number @number(0-1.0) value representing the alpha (transparency) of a UIObject, the value must be between 0 and 1. 0 is fully transparent, 1 is fully opaque.
|
||||
---@alias unit string string that represents a unit in the game, such as the player, a party member, or a raid member.
|
||||
---@alias health number amount of hit points (health) of a unit. This value can be changed by taking damage or healing.
|
||||
---@alias spellid number each spell in the game has a unique spell id, this id can be used to identify a spell.
|
||||
---@alias actorname string name of a unit
|
||||
---@alias spellname string name of a spell
|
||||
---@alias spellschool number each spell in the game has a school, such as fire, frost, shadow and many others. This value can be used to identify the school of a spell.
|
||||
---@alias actorid string unique id of a unit (GUID)
|
||||
---@alias serial string unique id of a unit (GUID)
|
||||
---@alias color table, string @table(r: red|number, g: green|number, b: blue|number, a: alpha|number) @string(color name) @hex (000000-ffffff) value representing a color, the value must be a table with the following fields: r, g, b, a. r, g, b are numbers between 0 and 1, a is a number between 0 and 1. To retrieve a color from a string or table use: local red, green, blue, alpha = DetailsFramework:ParseColors(color)
|
||||
---@alias scale number @number(0.65-2.40) value representing the scale factor of the UIObject, the value must be between 0.65 and 2.40, the width and height of the UIObject will be multiplied by this value.
|
||||
---@alias script string, function is a piece of code that is executed in response to a specific event, such as a button click or a frame update. Scripts can be used to implement behavior and logic for UI elements.
|
||||
---@alias event string is a notification that is sent to a frame when something happens, such as a button click or a frame update. Events can be used to trigger scripts.
|
||||
---@alias backdrop table @table(bgFile: string, edgeFile: string, tile: edgeSize: number, backgroundColor: color, borderColor: color) is a table that contains information about the backdrop of a frame. The backdrop is the background of a frame, which can be a solid color, a gradient, or a texture.
|
||||
---@alias npcid number a number that identifies a specific npc in the game.
|
||||
---@alias textureid number each texture from the game client has an id.
|
||||
---@alias texturepath string access textures from addons.
|
||||
---@alias unixtime number
|
||||
---@alias valueamount number used to represent a value, such as a damage amount, a healing amount, or a resource amount.
|
||||
|
||||
---@class _G
|
||||
---@field RegisterAttributeDriver fun(statedriver: frame, attribute: string, conditional: string)
|
||||
---@field RegisterStateDriver fun(statedriver: frame, attribute: string, conditional: string)
|
||||
---@field UnitGUID fun(unit: string): string
|
||||
---@field UnitName fun(unit: string): string
|
||||
---@field GetCursorPosition fun(): number, number return the position of the cursor on the screen, in pixels, relative to the bottom left corner of the screen.
|
||||
---@field C_Timer C_Timer
|
||||
|
||||
---@class timer : table
|
||||
---@field Cancel fun(self: timer)
|
||||
---@field IsCancelled fun(self: timer): boolean
|
||||
|
||||
---@class C_Timer : table
|
||||
---@field After fun(delay: number, func: function)
|
||||
---@field NewTimer fun(delay: number, func: function): timer
|
||||
---@field NewTicker fun(interval: number, func: function, iterations: number|nil): timer
|
||||
|
||||
---@class C_ChallengeMode : table
|
||||
---@field GetActiveKeystoneInfo fun(): number, number[], boolean @returns keystoneLevel, affixIDs, wasActive
|
||||
|
||||
---@class tablesize : {H: number, W: number}
|
||||
---@class tablecoords : {L: number, R: number, T: number, B: number}
|
||||
---@class texturecoords: {left: number, right: number, top: number, bottom: number}
|
||||
---@class objectsize : {height: number, width: number}
|
||||
---@class texturetable : {texture: string, coords: texturecoords, size: objectsize}
|
||||
|
||||
---@class uiobject
|
||||
---@field GetObjectType fun(self: uiobject) : string
|
||||
---@field Show fun(self: uiobject) make the object be shown on the user screen
|
||||
---@field Hide fun(self: uiobject) make the object be hidden from the user screen
|
||||
---@field SetShown fun(self: uiobject, state: boolean) show or hide the object
|
||||
---@field IsShown fun(self: uiobject) : boolean return if the object is shown or not
|
||||
---@field SetAllPoints fun(self: uiobject, target: uiobject|nil) set the object to be the same size as its parent or the target object
|
||||
---@field SetParent fun(self: uiobject, parent: frame) set the parent object of the object
|
||||
---@field SetSize fun(self: uiobject, width: width|number, height: height|number) set the width and height of the object
|
||||
---@field SetWidth fun(self: uiobject, width: width|number) set only the width of the object
|
||||
---@field SetHeight fun(self: uiobject, height: height|number) set only the height of the object
|
||||
---@field SetAlpha fun(self: uiobject, alpha: alpha|number) set the transparency of the object
|
||||
---@field SetScale fun(self: uiobject, scale: scale|number)
|
||||
---@field GetWidth fun(self: uiobject) : width|number
|
||||
---@field GetHeight fun(self: uiobject) : height|number
|
||||
---@field GetScale fun(self: uiobject) : scale|number
|
||||
---@field GetAlpha fun(self: uiobject) : alpha|number
|
||||
---@field GetSize fun(self: uiobject) : width|number, height|number
|
||||
---@field GetParent fun(self: uiobject) : frame
|
||||
---@field GetPoint fun(self: uiobject, index: number): string, frame, string, number, number
|
||||
---@field GetCenter fun(self: uiobject): number, number
|
||||
---@field SetPoint fun(self: uiobject, point: anchorpoint, relativeFrame: uiobject, relativePoint: anchorpoint, xOffset: number, yOffset: number)
|
||||
---@field ClearAllPoints fun(self: uiobject)
|
||||
---@field CreateAnimationGroup fun(self: uiobject, name: string|nil, templateName: string|nil) : animationgroup
|
||||
|
||||
---@class animationgroup : uiobject
|
||||
---@field CreateAnimation fun(self: animationgroup, animationType: string, name: string|nil, inheritsFrom: string|nil) : animation
|
||||
---@field GetAnimation fun(self: animationgroup, name: string) : animation
|
||||
---@field GetAnimations fun(self: animationgroup) : table
|
||||
---@field GetDuration fun(self: animationgroup) : number
|
||||
---@field GetEndDelay fun(self: animationgroup) : number
|
||||
---@field GetLoopState fun(self: animationgroup) : boolean
|
||||
---@field GetScript fun(self: animationgroup, event: string) : function
|
||||
---@field GetSmoothProgress fun(self: animationgroup) : boolean
|
||||
---@field IsDone fun(self: animationgroup) : boolean
|
||||
---@field IsPaused fun(self: animationgroup) : boolean
|
||||
---@field IsPlaying fun(self: animationgroup) : boolean
|
||||
---@field Pause fun(self: animationgroup)
|
||||
---@field Play fun(self: animationgroup)
|
||||
---@field Resume fun(self: animationgroup)
|
||||
---@field SetDuration fun(self: animationgroup, duration: number)
|
||||
---@field SetEndDelay fun(self: animationgroup, delay: number)
|
||||
---@field SetLooping fun(self: animationgroup, loop: boolean)
|
||||
---@field SetScript fun(self: animationgroup, event: string, handler: function|nil) "OnEvent"|"OnShow"
|
||||
---@field SetSmoothProgress fun(self: animationgroup, smooth: boolean)
|
||||
---@field Stop fun(self: animationgroup)
|
||||
|
||||
---@class animation : uiobject
|
||||
---@field GetDuration fun(self: animation) : number
|
||||
---@field GetEndDelay fun(self: animation) : number
|
||||
---@field GetOrder fun(self: animation) : number
|
||||
---@field GetScript fun(self: animation, event: string) : function
|
||||
---@field GetSmoothing fun(self: animation) : string
|
||||
---@field IsDone fun(self: animation) : boolean
|
||||
---@field IsPaused fun(self: animation) : boolean
|
||||
---@field IsPlaying fun(self: animation) : boolean
|
||||
---@field Pause fun(self: animation)
|
||||
---@field Play fun(self: animation)
|
||||
---@field Resume fun(self: animation)
|
||||
---@field SetDuration fun(self: animation, duration: number)
|
||||
---@field SetEndDelay fun(self: animation, delay: number)
|
||||
---@field SetOrder fun(self: animation, order: number)
|
||||
---@field SetScript fun(self: animation, event: string, handler: function|nil)
|
||||
---@field SetSmoothing fun(self: animation, smoothing: string)
|
||||
---@field Stop fun(self: animation)
|
||||
|
||||
---@class line : uiobject
|
||||
---@field GetEndPoint fun(self: line) : relativePoint: anchorpoint, relativeTo: anchorpoint, offsetX: number, offsetY: number
|
||||
---@field GetStartPoint fun(self: line) : relativePoint: anchorpoint, relativeTo: anchorpoint, offsetX: number, offsetY: number
|
||||
---@field GetThickness fun(self: line) : number
|
||||
---@field SetStartPoint fun(self: line, point: anchorpoint, relativeFrame: uiobject|number, relativePoint: anchorpoint|number, xOffset: number|nil, yOffset: number|nil)
|
||||
---@field SetEndPoint fun(self: line, point: anchorpoint, relativeFrame: uiobject|number, relativePoint: anchorpoint|number, xOffset: number|nil, yOffset: number|nil)
|
||||
---@field SetColorTexture fun(self: line, red: number, green: number, blue: number, alpha: number)
|
||||
---@field SetThickness fun(self: line, thickness: number)
|
||||
|
||||
---@class frame : uiobject
|
||||
---@field CreateLine fun(self: frame, name: string|nil, drawLayer: drawlayer, templateName: string|nil, subLevel: number|nil) : line
|
||||
---@field SetID fun(self: frame, id: number) set an ID for the frame
|
||||
---@field SetAttribute fun(self: frame, name: string, value: any)
|
||||
---@field SetScript fun(self: frame, event: string, handler: function|nil)
|
||||
---@field GetScript fun(self: frame, event: string) : function
|
||||
---@field SetFrameStrata fun(self: frame, strata: framestrata)
|
||||
---@field SetFrameLevel fun(self: frame, level: number)
|
||||
---@field SetClampedToScreen fun(self: frame, clamped: boolean)
|
||||
---@field SetClampRectInsets fun(self: frame, left: number, right: number, top: number, bottom: number)
|
||||
---@field SetMovable fun(self: frame, movable: boolean)
|
||||
---@field SetUserPlaced fun(self: frame, userPlaced: boolean)
|
||||
---@field SetBackdrop fun(self: frame, backdrop: backdrop|table)
|
||||
---@field SetBackdropColor fun(self: frame, red: red|number, green: green|number, blue: blue|number, alpha: alpha|number)
|
||||
---@field SetBackdropBorderColor fun(self: frame, red: red|number, green: green|number, blue: blue|number, alpha: alpha|number)
|
||||
---@field SetHitRectInsets fun(self: frame, left: number, right: number, top: number, bottom: number)
|
||||
---@field SetToplevel fun(self: frame, toplevel: boolean)
|
||||
---@field SetPropagateKeyboardInput fun(self: frame, propagate: boolean)
|
||||
---@field SetPropagateGamepadInput fun(self: frame, propagate: boolean)
|
||||
---@field StartMoving fun(self: frame)
|
||||
---@field IsMovable fun(self: frame) : boolean
|
||||
---@field StartSizing fun(self: frame, sizingpoint: sizingpoint|nil)
|
||||
---@field StopMovingOrSizing fun(self: frame)
|
||||
---@field GetAttribute fun(self: frame, name: string) : any
|
||||
---@field GetFrameLevel fun(self: frame) : number
|
||||
---@field GetFrameStrata fun(self: frame) : framestrata
|
||||
---@field GetNumChildren fun(self: frame) : number
|
||||
---@field GetNumPoints fun(self: frame) : number
|
||||
---@field GetNumRegions fun(self: frame) : number
|
||||
---@field GetName fun(self: frame) : string
|
||||
---@field GetChildren fun(self: frame) : frame[]
|
||||
---@field GetRegions fun(self: frame) : region[]
|
||||
---@field CreateTexture fun(self: frame, name: string|nil, layer: drawlayer, inherits: string|nil, subLayer: number|nil) : texture
|
||||
---@field CreateFontString fun(self: frame, name: string|nil, layer: drawlayer, inherits: string|nil, subLayer: number|nil) : fontstring
|
||||
---@field EnableMouse fun(self: frame, enable: boolean) enable mouse interaction
|
||||
---@field SetResizable fun(self: frame, enable: boolean) enable resizing of the frame
|
||||
---@field EnableMouseWheel fun(self: frame, enable: boolean) enable mouse wheel scrolling
|
||||
---@field RegisterForDrag fun(self: frame, button: string) register the frame for drag events, allowing it to be dragged by the mouse
|
||||
---@field SetResizeBounds fun(self: frame, minWidth: number, minHeight: number, maxWidth: number, maxHeight: number) set the minimum and maximum size of the frame
|
||||
---@field RegisterEvent fun(self: frame, event: string) register for an event, trigers "OnEvent" script when the event is fired
|
||||
---@field HookScript fun(self: frame, event: string, handler: function) run a function after the frame's script has been executed, carrying the same arguments
|
||||
|
||||
---@class button : frame
|
||||
---@field Click fun(self: button)
|
||||
---@field SetNormalTexture fun(self: button, texture: textureid|texturepath)
|
||||
---@field SetPushedTexture fun(self: button, texture: textureid|texturepath)
|
||||
---@field SetHighlightTexture fun(self: button, texture: textureid|texturepath)
|
||||
---@field SetDisabledTexture fun(self: button, texture: textureid|texturepath)
|
||||
---@field SetCheckedTexture fun(self: button, texture: textureid|texturepath)
|
||||
---@field SetNormalFontObject fun(self: button, fontString: fontstring)
|
||||
---@field SetHighlightFontObject fun(self: button, fontString: fontstring)
|
||||
---@field SetDisabledFontObject fun(self: button, fontString: fontstring)
|
||||
---@field SetText fun(self: button, text: string)
|
||||
---@field GetText fun(self: button) : string
|
||||
---@field SetTextInsets fun(self: button, left: number, right: number, top: number, bottom: number)
|
||||
---@field GetTextInsets fun(self: button) : number, number, number, number
|
||||
---@field SetDisabledTextColor fun(self: button, r: red|number, g: green|number, b: blue|number, a: alpha|number)
|
||||
---@field GetDisabledTextColor fun(self: button) : number, number, number, number
|
||||
---@field SetFontString fun(self: button, fontString: fontstring)
|
||||
---@field GetFontString fun(self: button) : fontstring
|
||||
---@field SetButtonState fun(self: button, state: string, enable: boolean)
|
||||
---@field GetButtonState fun(self: button, state: string) : boolean
|
||||
---@field RegisterForClicks fun(self: button, button1: nil|buttontype, button2: nil|buttontype, button3: nil|buttontype, button4: nil|buttontype)
|
||||
---@field GetNormalTexture fun(self: button) : texture
|
||||
---@field GetPushedTexture fun(self: button) : texture
|
||||
---@field GetHighlightTexture fun(self: button) : texture
|
||||
---@field GetDisabledTexture fun(self: button) : texture
|
||||
|
||||
---@class statusbar : frame
|
||||
---@field SetStatusBarColor fun(self: statusbar, r: red|number, g: green|number, b: blue|number, a: alpha|number)
|
||||
---@field SetStatusBarTexture fun(self: statusbar, path: string|texture)
|
||||
---@field GetStatusBarTexture fun(self: statusbar) : texture
|
||||
---@field SetMinMaxValues fun(self: statusbar, minValue: number, maxValue: number)
|
||||
---@field SetValue fun(self: statusbar, value: number)
|
||||
---@field SetValueStep fun(self: statusbar, valueStep: number)
|
||||
---@field SetOrientation fun(self: statusbar, orientation: orientation)
|
||||
---@field SetReverseFill fun(self: statusbar, reverseFill: boolean)
|
||||
---@field GetMinMaxValues fun(self: statusbar) : number, number
|
||||
---@field GetValue fun(self: statusbar) : number
|
||||
---@field GetValueStep fun(self: statusbar) : number
|
||||
---@field GetOrientation fun(self: statusbar) : orientation
|
||||
---@field GetReverseFill fun(self: statusbar) : boolean
|
||||
|
||||
---@class scrollframe : frame
|
||||
---@field SetScrollChild fun(self: scrollframe, child: frame)
|
||||
---@field GetScrollChild fun(self: scrollframe) : frame
|
||||
---@field SetHorizontalScroll fun(self: scrollframe, offset: number)
|
||||
---@field SetVerticalScroll fun(self: scrollframe, offset: number)
|
||||
---@field GetHorizontalScroll fun(self: scrollframe) : number
|
||||
---@field GetVerticalScroll fun(self: scrollframe) : number
|
||||
---@field GetHorizontalScrollRange fun(self: scrollframe) : number
|
||||
---@field GetVerticalScrollRange fun(self: scrollframe) : number
|
||||
|
||||
---@class region : uiobject
|
||||
|
||||
---@class fontstring : region
|
||||
---@field SetDrawLayer fun(self: fontstring, layer: drawlayer, subLayer: number|nil)
|
||||
---@field SetFont fun(self: fontstring, font: string, size: number, flags: string)
|
||||
---@field SetText fun(self: fontstring, text: string|number)
|
||||
---@field GetText fun(self: fontstring) : string
|
||||
---@field GetFont fun(self: fontstring) : string, number, string
|
||||
---@field GetStringWidth fun(self: fontstring) : number return the width of the string in pixels
|
||||
---@field SetShadowColor fun(self: fontstring, r: red|number, g: green|number, b: blue|number, a: alpha|number)
|
||||
---@field GetShadowColor fun(self: fontstring) : number, number, number, number
|
||||
---@field SetShadowOffset fun(self: fontstring, offsetX: number, offsetY: number)
|
||||
---@field GetShadowOffset fun(self: fontstring) : number, number
|
||||
---@field SetTextColor fun(self: fontstring, r: red|number, g: green|number, b: blue|number, a: alpha|number)
|
||||
---@field GetTextColor fun(self: fontstring) : number, number, number, number
|
||||
---@field SetJustifyH fun(self: fontstring, justifyH: justifyh)
|
||||
---@field GetJustifyH fun(self: fontstring) : string
|
||||
---@field SetJustifyV fun(self: fontstring, justifyV: justifyv)
|
||||
---@field GetJustifyV fun(self: fontstring) : string
|
||||
---@field SetNonSpaceWrap fun(self: fontstring, nonSpaceWrap: boolean)
|
||||
---@field GetNonSpaceWrap fun(self: fontstring) : boolean
|
||||
---@field SetIndentedWordWrap fun(self: fontstring, indentedWordWrap: boolean)
|
||||
---@field GetIndentedWordWrap fun(self: fontstring) : boolean
|
||||
---@field SetMaxLines fun(self: fontstring, maxLines: number)
|
||||
---@field GetMaxLines fun(self: fontstring) : number
|
||||
---@field SetWordWrap fun(self: fontstring, wordWrap: boolean)
|
||||
---@field GetWordWrap fun(self: fontstring) : boolean
|
||||
---@field SetSpacing fun(self: fontstring, spacing: number)
|
||||
---@field GetSpacing fun(self: fontstring) : number
|
||||
---@field SetLineSpacing fun(self: fontstring, lineSpacing: number)
|
||||
---@field GetLineSpacing fun(self: fontstring) : number
|
||||
---@field SetMaxLetters fun(self: fontstring, maxLetters: number)
|
||||
---@field GetMaxLetters fun(self: fontstring) : number
|
||||
---@field SetTextInsets fun(self: fontstring, left: number, right: number, top: number, bottom: number)
|
||||
---@field GetTextInsets fun(self: fontstring) : number, number, number, number
|
||||
---@field SetTextJustification fun(self: fontstring, justifyH: string, justifyV: string)
|
||||
---@field GetTextJustification fun(self: fontstring) : string, string
|
||||
---@field SetTextShadowColor fun(self: fontstring, r: red|number, g: green|number, b: blue|number, a: alpha|number)
|
||||
---@field GetTextShadowColor fun(self: fontstring) : number, number, number, number
|
||||
---@field SetTextShadowOffset fun(self: fontstring, offsetX: number, offsetY: number)
|
||||
---@field GetTextShadowOffset fun(self: fontstring) : number, number
|
||||
---@field SetTextShadow fun(self: fontstring, offsetX: number, offsetY: number, r: red|number, g: green|number, b: blue|number, a: alpha|number)
|
||||
---@field SetTextTruncate fun(self: fontstring, truncate: string)
|
||||
---@field GetTextTruncate fun(self: fontstring) : string
|
||||
---@field SetTextTruncateWidth fun(self: fontstring, width: number)
|
||||
---@field GetTextTruncateWidth fun(self: fontstring) : number
|
||||
---@field SetTextTruncateLines fun(self: fontstring, lines: number)
|
||||
---@field GetTextTruncateLines fun(self: fontstring) : number
|
||||
|
||||
---@class texture : region
|
||||
---@field SetDrawLayer fun(self: texture, layer: drawlayer, subLayer: number|nil)
|
||||
---@field SetTexture fun(self: texture, path: string)
|
||||
---@field SetAtlas fun(self: texture, atlas: string)
|
||||
---@field SetColorTexture fun(self: texture, r: red|number, g: green|number, b: blue|number, a: alpha|number|nil)
|
||||
---@field SetDesaturated fun(self: texture, desaturate: boolean)
|
||||
---@field SetBlendMode fun(self: texture, mode: "ADD"|"BLEND"|"DISABLE"|"MOD"|"MOD2X"|"OVERLAY"|"REPLACE"|"SUBTRACT")
|
||||
---@field SetVertexColor fun(self: texture, r: red|number, g: green|number, b: blue|number, a: alpha|number|nil)
|
||||
---@field GetPoint fun(self: texture, index: number) : string, table, string, number, number
|
||||
---@field SetShown fun(self: texture, state: boolean)
|
||||
---@field IsShown fun(self: texture) : boolean
|
||||
---@field GetParent fun(self: texture) : table
|
||||
---@field SetTexCoord fun(self: texture, left: number, right: number, top: number, bottom: number)
|
||||
---@field GetTexCoord fun(self: texture) : number, number, number, number
|
||||
---@field SetRotation fun(self: texture, rotation: number)
|
||||
---@field GetRotation fun(self: texture) : number
|
||||
---@field SetRotationRadians fun(self: texture, rotation: number)
|
||||
---@field GetRotationRadians fun(self: texture) : number
|
||||
---@field SetRotationDegrees fun(self: texture, rotation: number)
|
||||
---@field GetRotationDegrees fun(self: texture) : number
|
||||
---@field SetMask fun(self: texture, mask: table)
|
||||
---@field GetMask fun(self: texture) : table
|
||||
---@field SetMaskTexture fun(self: texture, maskTexture: table)
|
||||
---@field GetMaskTexture fun(self: texture) : table
|
||||
---@field GetDesaturated fun(self: texture) : boolean
|
||||
---@field SetGradient fun(self: texture, gradient: string)
|
||||
---@field GetGradient fun(self: texture) : string
|
||||
---@field SetGradientAlpha fun(self: texture, gradient: string)
|
||||
---@field GetGradientAlpha fun(self: texture) : string
|
||||
---@field SetGradientRotation fun(self: texture, rotation: number)
|
||||
---@field GetGradientRotation fun(self: texture) : number
|
||||
---@field SetGradientRotationRadians fun(self: texture, rotation: number)
|
||||
---@field GetGradientRotationRadians fun(self: texture) : number
|
||||
---@field SetGradientRotationDegrees fun(self: texture, rotation: number)
|
||||
---@field GetGradientRotationDegrees fun(self: texture) : number
|
||||
---@field SetGradientColors fun(self: texture, ...)
|
||||
---@field GetGradientColors fun(self: texture) : number, number, number, number, number, number, number, number, number, number, number, number
|
||||
---@field GetBlendMode fun(self: texture) : string
|
||||
---@field GetVertexColor fun(self: texture) : number, number, number, number
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
||||
..\FrameXML\UI.xsd">
|
||||
|
||||
<Script file="Libs\LibStub\LibStub.lua"/>
|
||||
<Include file="Libs\AceLocale-3.0\AceLocale-3.0.xml" />
|
||||
</Ui>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,419 @@
|
||||
|
||||
local addonId, edTable = ...
|
||||
local Details = _G._detalhes
|
||||
local AceLocale = LibStub("AceLocale-3.0")
|
||||
local Loc = AceLocale:GetLocale("Details_EncounterDetails")
|
||||
local Graphics = LibStub:GetLibrary("LibGraph-2.0")
|
||||
local ipairs = ipairs
|
||||
local _GetSpellInfo = Details.getspellinfo
|
||||
local unpack = unpack
|
||||
local detailsFramework = DetailsFramework
|
||||
local CreateFrame = CreateFrame
|
||||
local GameCooltip = GameCooltip
|
||||
local GameTooltip = GameTooltip
|
||||
local wipe = table.wipe
|
||||
local _
|
||||
|
||||
local encounterDetails = _G.EncounterDetailsGlobal
|
||||
local edFrame = encounterDetails.Frame
|
||||
|
||||
edFrame.EnemySpellsWidgets = {}
|
||||
|
||||
local CONST_MAX_AURA_LINES = 21
|
||||
|
||||
local aurasButtonTemplate = {
|
||||
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
||||
backdropcolor = {.3, .3, .3, .5},
|
||||
onentercolor = {1, 1, 1, .5},
|
||||
backdropbordercolor = {0, 0, 0, 1},
|
||||
}
|
||||
|
||||
local spell_blocks = {}
|
||||
local bossmods_blocks = {}
|
||||
|
||||
local on_focus_gain = function(self)
|
||||
self:HighlightText()
|
||||
end
|
||||
|
||||
local on_focus_lost = function(self)
|
||||
self:HighlightText(0, 0)
|
||||
end
|
||||
|
||||
local on_enter_spell = function(self)
|
||||
if (self.MyObject._spellid) then
|
||||
GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT")
|
||||
|
||||
if (type(self.MyObject._spellid) == "string") then
|
||||
local spellId = self.MyObject._spellid:gsub("%a", "")
|
||||
spellId = tonumber(spellId)
|
||||
if (spellId) then
|
||||
GameTooltip:SetSpellByID(spellId)
|
||||
end
|
||||
else
|
||||
GameTooltip:SetSpellByID(self.MyObject._spellid)
|
||||
end
|
||||
GameTooltip:Show()
|
||||
|
||||
self:SetBackdropColor(1, 1, 1, .5)
|
||||
self:SetBackdropBorderColor(0, 0, 0, 1)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local on_leave_spell = function(self, capsule)
|
||||
GameTooltip:Hide()
|
||||
self:SetBackdropColor(.3, .3, .3, .5)
|
||||
end
|
||||
|
||||
local create_aura_func = function(self, button, spellid, encounter_id)
|
||||
local name, _, icon = encounterDetails.getspellinfo(spellid)
|
||||
encounterDetails:OpenAuraPanel(spellid, name, self and self.MyObject._icon.texture, encounter_id)
|
||||
end
|
||||
|
||||
local info_onenter = function(self)
|
||||
local spellid = self._spellid
|
||||
|
||||
local info = encounterDetails.EnemySpellPool[spellid]
|
||||
if (info) then
|
||||
Details:CooltipPreset(2)
|
||||
GameCooltip:SetOption("FixedWidth", false)
|
||||
|
||||
for token, _ in pairs(info.token) do
|
||||
GameCooltip:AddLine("event:", token, 1, nil, "white")
|
||||
end
|
||||
|
||||
GameCooltip:AddLine("source:", info.source, 1, nil, "white")
|
||||
GameCooltip:AddLine("school:", encounterDetails:GetSpellSchoolFormatedName(info.school), 1, nil, "white")
|
||||
|
||||
if (info.type) then
|
||||
GameCooltip:AddLine("aura type:", info.type, 1, nil, "white")
|
||||
end
|
||||
GameCooltip:ShowCooltip(self, "tooltip")
|
||||
end
|
||||
|
||||
self:SetBackdropColor(1, 1, 1, .5)
|
||||
end
|
||||
local info_onleave = function(self)
|
||||
GameCooltip:Hide()
|
||||
self:SetBackdropColor(.3, .3, .3, .5)
|
||||
end
|
||||
|
||||
local bossModsTitle = detailsFramework:CreateLabel(edFrame, "Boss Mods Time Bars:", 12, "orange")
|
||||
bossModsTitle:SetPoint(10, -85)
|
||||
table.insert(edFrame.EnemySpellsWidgets, bossModsTitle)
|
||||
bossModsTitle:Hide()
|
||||
|
||||
local bossSpellsTitle = detailsFramework:CreateLabel(edFrame, "Boss Spells and Auras:", 12, "orange")
|
||||
bossSpellsTitle:SetPoint(444, -85)
|
||||
table.insert(edFrame.EnemySpellsWidgets, bossSpellsTitle)
|
||||
bossSpellsTitle:Hide()
|
||||
|
||||
--create boss mods list
|
||||
for i = 1, CONST_MAX_AURA_LINES do
|
||||
local anchor_frame = CreateFrame("frame", "BossFrameBossModsAnchor" .. i, edFrame, "BackdropTemplate")
|
||||
|
||||
local spellicon = detailsFramework:NewImage(anchor_frame, [[Interface\ICONS\TEMP]], 19, 19, "background", nil, "icon", "$parentIcon")
|
||||
|
||||
--timerId
|
||||
local spellid = detailsFramework:CreateTextEntry(anchor_frame, encounterDetails.empty_function, 80, 20, nil, "$parentSpellId")
|
||||
spellid:SetTemplate(aurasButtonTemplate)
|
||||
spellid:SetHook("OnEditFocusGained", on_focus_gain)
|
||||
spellid:SetHook("OnEditFocusLost", on_focus_lost)
|
||||
spellid:SetHook("OnEnter", on_enter_spell)
|
||||
spellid:SetHook("OnLeave", on_leave_spell)
|
||||
|
||||
--ability name
|
||||
local spellname = detailsFramework:CreateTextEntry(anchor_frame, encounterDetails.empty_function, 180, 20, nil, "$parentSpellName")
|
||||
spellname:SetTemplate(aurasButtonTemplate)
|
||||
spellname:SetHook("OnEditFocusGained", on_focus_gain)
|
||||
spellname:SetHook("OnEditFocusLost", on_focus_lost)
|
||||
spellname:SetHook("OnEnter", on_enter_spell)
|
||||
spellname:SetHook("OnLeave", on_leave_spell)
|
||||
|
||||
local create_aura = detailsFramework:NewButton(anchor_frame, nil, "$parentCreateAuraButton", "AuraButton", 90, 18, create_aura_func, nil, nil, nil, "Make Aura")
|
||||
create_aura:SetTemplate(aurasButtonTemplate)
|
||||
|
||||
spellicon:SetPoint("topleft", edFrame, "topleft", 10, -85 +(i * 21 * -1))
|
||||
spellid:SetPoint("left", spellicon, "right", 4, 0)
|
||||
spellname:SetPoint("left", spellid, "right", 4, 0)
|
||||
create_aura:SetPoint("left", spellname, "right", 4, 0)
|
||||
|
||||
spellid:SetBackdropBorderColor(0, 0, 0)
|
||||
spellname:SetBackdropBorderColor(0, 0, 0)
|
||||
|
||||
anchor_frame.icon = spellicon
|
||||
anchor_frame.spellid = spellid
|
||||
anchor_frame.spellname = spellname
|
||||
anchor_frame.aurabutton = create_aura
|
||||
anchor_frame.aurabutton._icon = spellicon
|
||||
|
||||
table.insert(bossmods_blocks, anchor_frame)
|
||||
table.insert(edFrame.EnemySpellsWidgets, anchor_frame)
|
||||
|
||||
anchor_frame:Hide()
|
||||
end
|
||||
|
||||
--create buff list
|
||||
for i = 1, CONST_MAX_AURA_LINES do
|
||||
local anchor_frame = CreateFrame("frame", "BossFrameSpellAnchor" .. i, edFrame, "BackdropTemplate")
|
||||
|
||||
local spellicon = detailsFramework:NewImage(anchor_frame, [[Interface\ICONS\TEMP]], 19, 19, "background", nil, "icon", "$parentIcon")
|
||||
|
||||
local spellid = detailsFramework:CreateTextEntry(anchor_frame, encounterDetails.empty_function, 80, 20)
|
||||
spellid:SetTemplate(aurasButtonTemplate)
|
||||
spellid:SetHook("OnEditFocusGained", on_focus_gain)
|
||||
spellid:SetHook("OnEditFocusLost", on_focus_lost)
|
||||
spellid:SetHook("OnEnter", on_enter_spell)
|
||||
spellid:SetHook("OnLeave", on_leave_spell)
|
||||
|
||||
local spellname = detailsFramework:CreateTextEntry(anchor_frame, encounterDetails.empty_function, 160, 20)
|
||||
spellname:SetTemplate(aurasButtonTemplate)
|
||||
spellname:SetHook("OnEditFocusGained", on_focus_gain)
|
||||
spellname:SetHook("OnEditFocusLost", on_focus_lost)
|
||||
spellname:SetHook("OnEnter", on_enter_spell)
|
||||
spellname:SetHook("OnLeave", on_leave_spell)
|
||||
|
||||
--spellicon_button:SetPoint("topleft", BossFrame, "topleft", 255, -65 +(i * 21 * -1))
|
||||
spellicon:SetPoint("topleft", edFrame, "topleft", 443, -85 +(i * 21 * -1))
|
||||
spellid:SetPoint("left", spellicon, "right", 4, 0)
|
||||
spellname:SetPoint("left", spellid, "right", 4, 0)
|
||||
|
||||
local spellinfo = CreateFrame("frame", nil, anchor_frame,"BackdropTemplate")
|
||||
spellinfo:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||
spellinfo:SetBackdropColor(.3, .3, .3, .5)
|
||||
spellinfo:SetBackdropBorderColor(0, 0, 0, 1)
|
||||
spellinfo:SetSize(80, 20)
|
||||
spellinfo:SetScript("OnEnter", info_onenter)
|
||||
spellinfo:SetScript("OnLeave", info_onleave)
|
||||
|
||||
local spellinfotext = spellinfo:CreateFontString(nil, "overlay", "GameFontNormal")
|
||||
spellinfotext:SetPoint("center", spellinfo, "center")
|
||||
spellinfotext:SetText("info")
|
||||
spellinfo:SetPoint("left", spellname.widget, "right", 4, 0)
|
||||
|
||||
local create_aura = detailsFramework:NewButton(anchor_frame, nil, "$parentCreateAuraButton", "AuraButton", 90, 18, create_aura_func, nil, nil, nil, "Make Aura")
|
||||
create_aura:SetPoint("left", spellinfo, "right", 4, 0)
|
||||
create_aura:SetTemplate(aurasButtonTemplate)
|
||||
|
||||
anchor_frame.icon = spellicon
|
||||
anchor_frame.spellid = spellid
|
||||
anchor_frame.spellname = spellname
|
||||
anchor_frame.aurabutton = create_aura
|
||||
anchor_frame.aurabutton._icon = spellicon
|
||||
anchor_frame.info = spellinfo
|
||||
|
||||
table.insert(spell_blocks, anchor_frame)
|
||||
table.insert(edFrame.EnemySpellsWidgets, anchor_frame)
|
||||
|
||||
anchor_frame:Hide()
|
||||
end
|
||||
|
||||
local update_enemy_spells = function()
|
||||
local combat = encounterDetails:GetCombat(encounterDetails._segment)
|
||||
local spell_list = {}
|
||||
|
||||
if (combat) then
|
||||
for i, npc in combat[1]:ListActors() do
|
||||
--damage
|
||||
if (npc:IsNeutralOrEnemy()) then
|
||||
for spellid, spell in pairs(npc.spells._ActorTable) do
|
||||
if (spellid > 10) then
|
||||
local name, _, icon = encounterDetails.getspellinfo(spellid)
|
||||
table.insert(spell_list, {spellid, name, icon, nil, npc.serial})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i, npc in combat[2]:ListActors() do
|
||||
--heal
|
||||
if (npc:IsNeutralOrEnemy()) then
|
||||
for spellid, spell in pairs(npc.spells._ActorTable) do
|
||||
if (spellid > 10) then
|
||||
local name, _, icon = encounterDetails.getspellinfo(spellid)
|
||||
table.insert(spell_list, {spellid, name, icon, true, npc.serial})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(spell_list, function(t1, t2)
|
||||
return t1[2] < t2[2]
|
||||
end)
|
||||
|
||||
encounterDetails.SpellScrollframe.spell_pool = spell_list
|
||||
encounterDetails.SpellScrollframe.encounter_id = combat.is_boss and combat.is_boss.id
|
||||
encounterDetails.SpellScrollframe:Update()
|
||||
end
|
||||
end
|
||||
|
||||
local refresh_bossmods_timers = function(self)
|
||||
local combat = encounterDetails:GetCombat(encounterDetails._segment)
|
||||
local offset = FauxScrollFrame_GetOffset(self)
|
||||
local already_added = {}
|
||||
local db = Details.boss_mods_timers
|
||||
local encounter_id = combat.is_boss and combat.is_boss.id
|
||||
|
||||
if (db) then
|
||||
wipe(already_added)
|
||||
local timersToAdd = {}
|
||||
|
||||
for timerId, timerTable in pairs(db.encounter_timers_dbm) do
|
||||
if (timerTable.id == encounter_id) then
|
||||
local spellId = timerTable [7]
|
||||
local spellIcon = timerTable [5]
|
||||
local spellName
|
||||
|
||||
local spell = timerId
|
||||
spell = spell:gsub("ej", "")
|
||||
spell = tonumber(spell)
|
||||
|
||||
if (spell and not already_added[spell]) then
|
||||
if (spell > 40000) then
|
||||
local spellname, _, spellicon = _GetSpellInfo(spell)
|
||||
table.insert(timersToAdd, {label = spellname, value = {timerTable[2], spellname, spellIcon or spellicon, timerTable.id, timerTable[7]}, icon = spellIcon or spellicon})
|
||||
|
||||
else
|
||||
--local title, description, depth, abilityIcon, displayInfo, siblingID, nextSectionID, filteredByDifficulty, link, startsOpen, flag1, flag2, flag3, flag4 = C_EncounterJournal.GetSectionInfo(spell)
|
||||
local sectionInfo = C_EncounterJournal.GetSectionInfo(spell)
|
||||
table.insert(timersToAdd, {label = sectionInfo.title, value = {timerTable[2], sectionInfo.title, spellIcon or sectionInfo.abilityIcon, timerTable.id, timerTable[7]}, icon = spellIcon or sectionInfo.abilityIcon})
|
||||
end
|
||||
|
||||
already_added[spell] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(timersToAdd, function(t1, t2)
|
||||
return t1.label < t2.label
|
||||
end)
|
||||
|
||||
local offset = FauxScrollFrame_GetOffset(self)
|
||||
|
||||
for barIndex = 1, CONST_MAX_AURA_LINES do
|
||||
|
||||
local data = timersToAdd[barIndex + offset]
|
||||
local bar = bossmods_blocks[barIndex]
|
||||
|
||||
if (data) then
|
||||
bar:Show()
|
||||
|
||||
bar.icon.texture = data.icon
|
||||
bar.icon:SetTexCoord(.1, .9, .1, .9)
|
||||
bar.spellid.text = data.value[1] or "--x--x--"
|
||||
bar.spellname.text = data.label or "--x--x--"
|
||||
|
||||
bar.spellid._spellid = data.value[1]
|
||||
bar.spellname._spellid = data.value[1]
|
||||
|
||||
local func = function()
|
||||
local timerId, spellname, spellicon, encounterid, spellid = unpack(data.value)
|
||||
encounterDetails:OpenAuraPanel(timerId, spellname, spellicon, encounterid, DETAILS_WA_TRIGGER_DBM_TIMER, DETAILS_WA_AURATYPE_TEXT, {dbm_timer_id = timerId, spellid = spellid, text = "Next " .. spellname .. " In", text_size = 72, icon = spellicon})
|
||||
end
|
||||
|
||||
bar.aurabutton:SetClickFunction(func)
|
||||
else
|
||||
bar:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
FauxScrollFrame_Update(self, #timersToAdd, CONST_MAX_AURA_LINES, 20)
|
||||
|
||||
if (#timersToAdd > 0) then
|
||||
self:Show()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local refresh_spellauras = function(self)
|
||||
local pool = encounterDetails.SpellScrollframe.spell_pool
|
||||
local encounter_id = encounterDetails.SpellScrollframe.encounter_id
|
||||
local offset = FauxScrollFrame_GetOffset(self)
|
||||
|
||||
for bar_index = 1, CONST_MAX_AURA_LINES do
|
||||
local data = pool[bar_index + offset]
|
||||
local bar = spell_blocks[bar_index]
|
||||
|
||||
if (data) then
|
||||
bar:Show()
|
||||
|
||||
bar.icon.texture = data[3]
|
||||
bar.icon:SetTexCoord(.1, .9, .1, .9)
|
||||
bar.spellid.text = data[1]
|
||||
bar.spellname.text = data[2]
|
||||
|
||||
bar.spellid._spellid = data[1]
|
||||
bar.spellname._spellid = data[1]
|
||||
bar.info._spellid = data[1]
|
||||
|
||||
local is_heal = data[4]
|
||||
if (is_heal) then
|
||||
bar.spellid:SetBackdropBorderColor(0, 1, 0)
|
||||
bar.spellname:SetBackdropBorderColor(0, 1, 0)
|
||||
else
|
||||
bar.spellid:SetBackdropBorderColor(0, 0, 0)
|
||||
bar.spellname:SetBackdropBorderColor(0, 0, 0)
|
||||
end
|
||||
|
||||
bar.aurabutton:SetClickFunction(create_aura_func, data [1], encounter_id)
|
||||
else
|
||||
bar:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
FauxScrollFrame_Update(self, #pool, CONST_MAX_AURA_LINES, 20)
|
||||
end
|
||||
|
||||
local spellScrollFrame = CreateFrame("ScrollFrame", "EncounterDetails_SpellAurasScroll", edFrame, "FauxScrollFrameTemplate, BackdropTemplate")
|
||||
spellScrollFrame:SetScript("OnVerticalScroll", function(self, offset) FauxScrollFrame_OnVerticalScroll(self, offset, 14, refresh_spellauras) end)
|
||||
spellScrollFrame:SetPoint("topleft", edFrame, "topleft", 200, -75)
|
||||
spellScrollFrame:SetPoint("bottomright", edFrame, "bottomright", -33, 42)
|
||||
spellScrollFrame.Update = refresh_spellauras
|
||||
spellScrollFrame:Hide()
|
||||
encounterDetails.SpellScrollframe = spellScrollFrame
|
||||
detailsFramework:ReskinSlider(spellScrollFrame)
|
||||
|
||||
table.insert(edFrame.EnemySpellsWidgets, spellScrollFrame)
|
||||
encounterDetails.update_enemy_spells = update_enemy_spells
|
||||
|
||||
local bossmodsScrollFrame = CreateFrame("ScrollFrame", "EncounterDetails_BossModsScroll", edFrame, "FauxScrollFrameTemplate, BackdropTemplate")
|
||||
bossmodsScrollFrame:SetScript("OnVerticalScroll", function(self, offset) FauxScrollFrame_OnVerticalScroll(self, offset, 14, refresh_bossmods_timers) end)
|
||||
bossmodsScrollFrame:SetPoint("topleft", edFrame, "topleft", 10, -75)
|
||||
bossmodsScrollFrame:SetPoint("bottomleft", edFrame, "bottomleft", 250, 42)
|
||||
bossmodsScrollFrame.Update = refresh_bossmods_timers
|
||||
bossmodsScrollFrame:Hide()
|
||||
encounterDetails.BossModsScrollframe = bossmodsScrollFrame
|
||||
|
||||
table.insert(edFrame.EnemySpellsWidgets, bossmodsScrollFrame)
|
||||
encounterDetails.update_bossmods = function() bossmodsScrollFrame:Update() end
|
||||
|
||||
local build_bigwigs_bars = function()
|
||||
local t = {}
|
||||
local db = Details.boss_mods_timers
|
||||
if (db) then
|
||||
wipe(already_added)
|
||||
local encounter_id = encounterDetails.SpellScrollframe.encounter_id
|
||||
|
||||
for timer_id, timer_table in pairs(db.encounter_timers_bw) do
|
||||
if (timer_table.id == encounter_id) then
|
||||
local spell = timer_id
|
||||
if (spell and not already_added [spell]) then
|
||||
local int_spell = tonumber(spell)
|
||||
if (not int_spell) then
|
||||
local spellname = timer_table [2]:gsub(" %(.%)", "")
|
||||
table.insert(t, {label = spellname, value = {timer_table [2], spellname, timer_table [5], timer_table.id}, icon = timer_table [5], onclick = on_select_bw_bar})
|
||||
elseif (int_spell < 0) then
|
||||
local title, description, depth, abilityIcon, displayInfo, siblingID, nextSectionID, filteredByDifficulty, link, startsOpen, flag1, flag2, flag3, flag4 = C_EncounterJournal.GetSectionInfo(abs(int_spell))
|
||||
table.insert(t, {label = title, value = {timer_table [2], title, timer_table [5] or abilityIcon, timer_table.id}, icon = timer_table [5] or abilityIcon, onclick = on_select_bw_bar})
|
||||
else
|
||||
local spellname, _, spellicon = _GetSpellInfo(int_spell)
|
||||
table.insert(t, {label = spellname, value = {timer_table [2], spellname, timer_table [5] or spellicon, timer_table.id}, icon = timer_table [5] or spellicon, onclick = on_select_bw_bar})
|
||||
end
|
||||
|
||||
already_added [spell] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
@@ -0,0 +1,698 @@
|
||||
|
||||
local addonId, edTable = ...
|
||||
local Details = _G._detalhes
|
||||
local AceLocale = LibStub("AceLocale-3.0")
|
||||
local Loc = AceLocale:GetLocale("Details_EncounterDetails")
|
||||
local Graphics = LibStub:GetLibrary("LibGraph-2.0")
|
||||
local ipairs = ipairs
|
||||
local _GetSpellInfo = Details.getspellinfo
|
||||
local unpack = unpack
|
||||
local detailsFramework = DetailsFramework
|
||||
local CreateFrame = CreateFrame
|
||||
local GameCooltip = GameCooltip
|
||||
local wipe = table.wipe
|
||||
local _
|
||||
|
||||
--VerticalLines são os indicatores de onde aconteceram mortes, precisa ser renomeados e criar uma classe pra eles
|
||||
--precisa fazer um indicator genérico na classe df_chart para ser usado como indicador de bloodlust ou qualquer coisa que indica um evento por x tempo
|
||||
|
||||
---@class ed_phaseframe : frame
|
||||
---@field texture texture
|
||||
|
||||
local encounterDetails = _G.EncounterDetailsGlobal
|
||||
local edFrame = encounterDetails.Frame
|
||||
|
||||
--an auxiliary table to store things related to df_chartmulti but can't be stored in 'chartPanel'
|
||||
encounterDetails.chartFrameAux = {}
|
||||
|
||||
local CONST_CHART_WIDTH = 921
|
||||
local CONST_CHART_HEIGHT = 524
|
||||
local CONST_CHART_LENGTH = 810
|
||||
local CONST_CHART_TIMELINE_Y_POSITION = -540
|
||||
local CONST_CHART_MAX_DEATHS_ICONS = 6
|
||||
|
||||
local CONST_PHASE_PANEL_WIDTH = 451
|
||||
local CONST_PHASE_BAR_HEIGHT = 16
|
||||
|
||||
local DETAILS_ATTRIBUTE_DAMAGE = 1
|
||||
|
||||
local phaseAlpha = 0.5
|
||||
local lastBoss = nil
|
||||
local chartLineColors = {{1, 1, 1, 1}, {1, 0.5, 0.3, 1}, {0.75, 0.7, 0.1, 1}, {0.2, 0.9, 0.2, 1}, {0.2, 0.5, 0.9, 1}}
|
||||
encounterDetails.CombatsAlreadyDrew = {}
|
||||
|
||||
---create a multi chart frame
|
||||
---@return df_chartmulti
|
||||
local createMultiChartFrame = function()
|
||||
---@type df_chartmulti
|
||||
local chartPanel = detailsFramework:CreateGraphicMultiLineFrame(edFrame, "EncounterDetailsChartPanel")
|
||||
chartPanel.xAxisLabelsYOffset = -9
|
||||
chartPanel:CreateAxesLines(48, 28, "left", 1, 10, 10, 1, 1, 1, 1)
|
||||
chartPanel:SetXAxisDataType("time")
|
||||
chartPanel:SetSize(CONST_CHART_WIDTH, CONST_CHART_HEIGHT)
|
||||
chartPanel:SetPoint("topleft", encounterDetails.Frame, "topleft", 2, -76)
|
||||
chartPanel:SetLineThickness(3)
|
||||
encounterDetails.chartPanel = chartPanel
|
||||
|
||||
detailsFramework:ApplyStandardBackdrop(chartPanel)
|
||||
|
||||
---@type ed_phaseframe[]
|
||||
encounterDetails.chartFrameAux.PhaseFrames = {}
|
||||
encounterDetails.chartFrameAux.VerticalLines = {}
|
||||
|
||||
local phaseTooltip = encounterDetails:CreatePhaseTooltip(chartPanel)
|
||||
encounterDetails:CreatePhaseIndicators(chartPanel, phaseTooltip)
|
||||
|
||||
detailsFramework:NewLabel(chartPanel, chartPanel, nil, "phases_string", "phases:", "GameFontHighlightSmall")
|
||||
chartPanel["phases_string"]:SetPoint("bottomleft", chartPanel, "bottomleft", 5, 10)
|
||||
|
||||
chartPanel:SetScript("OnShow", function()
|
||||
chartPanel["phases_string"]:Show()
|
||||
end)
|
||||
|
||||
chartPanel:SetScript("OnHide", function()
|
||||
chartPanel["phases_string"]:Hide()
|
||||
end)
|
||||
|
||||
return chartPanel
|
||||
end
|
||||
|
||||
function encounterDetails:ShowChartFrame()
|
||||
local segment = encounterDetails._segment
|
||||
if (not segment) then
|
||||
return
|
||||
end
|
||||
|
||||
---@type df_chartmulti
|
||||
local multiChartPanel = encounterDetails.chartPanel
|
||||
|
||||
if (not multiChartPanel) then
|
||||
---@type df_chartmulti
|
||||
multiChartPanel = createMultiChartFrame()
|
||||
end
|
||||
multiChartPanel:Reset()
|
||||
|
||||
---@type combat
|
||||
local combatObject = encounterDetails:GetCombat(segment)
|
||||
--elapsed combat time
|
||||
if (combatObject:GetCombatTime() < 12) then
|
||||
return
|
||||
end
|
||||
|
||||
local uniqueCombatId = combatObject:GetCombatUID()
|
||||
local chartData = EncounterDetailsDB.chartData[uniqueCombatId]
|
||||
local currentChartData = chartData and chartData["Raid Damage Done"]
|
||||
|
||||
if (not currentChartData or not combatObject.start_time or not combatObject.end_time) then
|
||||
encounterDetails:Msg("This segment doesn't have chart data.")
|
||||
return
|
||||
|
||||
elseif (currentChartData.max_value and currentChartData.max_value == 0) then
|
||||
return
|
||||
end
|
||||
|
||||
encounterDetails.Frame.linhas = 1 --can't find references to this variable
|
||||
if (encounterDetails.Frame.linhas > 5) then
|
||||
encounterDetails.Frame.linhas = 1
|
||||
end
|
||||
|
||||
for _, line in ipairs(encounterDetails.chartFrameAux.VerticalLines) do
|
||||
line:Hide()
|
||||
end
|
||||
|
||||
local encounterId = combatObject.is_boss and combatObject.is_boss.id
|
||||
local chartIndex = 2
|
||||
local smoothnessLevel = 3
|
||||
|
||||
---draw the damage line from the 5th combat to 2nd combat
|
||||
for i = segment + 4, segment + 1, -1 do
|
||||
---@type combat
|
||||
local thisCombatObject = encounterDetails:GetCombat(i)
|
||||
if (thisCombatObject) then
|
||||
local elapsedTime = thisCombatObject:GetCombatTime()
|
||||
if (elapsedTime > 12 and thisCombatObject.is_boss and thisCombatObject.is_boss.id == encounterId) then --is the same boss
|
||||
local thisUniqueCombatId = thisCombatObject:GetCombatUID()
|
||||
local thisChartData = EncounterDetailsDB.chartData[thisUniqueCombatId] and EncounterDetailsDB.chartData[thisUniqueCombatId]["Raid Damage Done"]
|
||||
|
||||
--check if this is a valid chart data
|
||||
if (thisChartData and thisChartData.max_value and thisChartData.max_value > 0) then
|
||||
local tryNumber = thisCombatObject.is_boss.try_number or i
|
||||
multiChartPanel:AddData(thisChartData, smoothnessLevel, "Try #" .. tryNumber, chartLineColors[chartIndex])
|
||||
multiChartPanel:SetXAxisData(elapsedTime)
|
||||
chartIndex = chartIndex + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@type number[]
|
||||
local bloodLustTimers = combatObject.bloodlust or {}
|
||||
|
||||
for index, bloodlustCombatTime in ipairs(bloodLustTimers) do
|
||||
multiChartPanel:AddBackdropIndicator("Bloodlust #" .. index, bloodlustCombatTime, bloodlustCombatTime + 40, {0, 0, 1, 0.2})
|
||||
end
|
||||
|
||||
encounterDetails:UpdatePhaseIndicators(multiChartPanel, combatObject)
|
||||
|
||||
multiChartPanel:AddData(currentChartData, smoothnessLevel, "current", chartLineColors[1])
|
||||
multiChartPanel:SetXAxisData(combatObject:GetCombatTime())
|
||||
multiChartPanel:Plot()
|
||||
multiChartPanel:Show()
|
||||
end
|
||||
|
||||
|
||||
function encounterDetails:UpdatePhaseIndicators(chartPanel, combatObject)
|
||||
encounterDetails:ClearPhaseIndicators()
|
||||
|
||||
--update phase indicators
|
||||
local phaseData = combatObject.PhaseData
|
||||
local plotFrameWidth = chartPanel.plotFrame:GetWidth()
|
||||
local scale = (plotFrameWidth) / combatObject:GetCombatTime()
|
||||
|
||||
for i = 1, #phaseData do
|
||||
local phase = phaseData[i][1]
|
||||
local phaseStartAt = phaseData[i][2]
|
||||
local phaseIndicator = encounterDetails:GetPhaseIndicator(i, phase)
|
||||
|
||||
if (phaseStartAt == 1) then
|
||||
phaseStartAt = 0
|
||||
end
|
||||
|
||||
phaseIndicator:SetPoint("topleft", chartPanel.plotFrame, "bottomleft", (phaseStartAt * scale), -6)
|
||||
phaseIndicator.phase = phase
|
||||
phaseIndicator.start_at = phaseStartAt
|
||||
|
||||
local nextPhase = phaseData[i+1]
|
||||
if (nextPhase) then
|
||||
local duration = nextPhase[2] - phaseStartAt
|
||||
phaseIndicator:SetWidth(scale * duration)
|
||||
phaseIndicator.elapsed = duration
|
||||
else
|
||||
local duration = combatObject:GetCombatTime() - phaseStartAt
|
||||
phaseIndicator:SetWidth(scale * duration)
|
||||
phaseIndicator.elapsed = duration
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---tooltip frame on hovering over
|
||||
---@param chartPanel df_chartmulti
|
||||
---@return frame
|
||||
function encounterDetails:CreatePhaseTooltip(chartPanel)
|
||||
---@type frame
|
||||
local phaseTooltip = CreateFrame("frame", "EncounterDetailsPhasePanel", chartPanel, "BackdropTemplate")
|
||||
phaseTooltip:SetFrameStrata("TOOLTIP")
|
||||
phaseTooltip:SetFrameLevel(1000)
|
||||
phaseTooltip:SetWidth(450)
|
||||
detailsFramework:ApplyStandardBackdrop(phaseTooltip)
|
||||
|
||||
local damageTexture = detailsFramework:CreateImage(phaseTooltip,[[Interface\AddOns\Details\images\skins\classic_skin_v1]], 16, 16, "overlay", {11/1024, 24/1024, 376/1024, 390/1024})
|
||||
local damageLabel = detailsFramework:CreateLabel(phaseTooltip, "Damage Done:")
|
||||
damageTexture:SetPoint("topleft", phaseTooltip, "topleft", 10, -10)
|
||||
damageLabel:SetPoint("left", damageTexture, "right", 4, 0)
|
||||
|
||||
local healingTexture = detailsFramework:CreateImage(phaseTooltip,[[Interface\AddOns\Details\images\skins\classic_skin_v1]], 16, 16, "overlay", {43/1024, 57/1024, 376/1024, 390/1024})
|
||||
local healingLabel = detailsFramework:CreateLabel(phaseTooltip, "Healing Done:")
|
||||
healingTexture:SetPoint("topleft", phaseTooltip, "topleft", 250, -10)
|
||||
healingLabel:SetPoint("left", healingTexture, "right", 4, 0)
|
||||
|
||||
phaseTooltip.phase_label = detailsFramework:CreateLabel(phaseTooltip, "")
|
||||
phaseTooltip.phase_label.fontsize = 10
|
||||
phaseTooltip.time_label = detailsFramework:CreateLabel(phaseTooltip, "")
|
||||
phaseTooltip.time_label.fontsize = 10
|
||||
phaseTooltip.report_label = detailsFramework:CreateLabel(phaseTooltip, "|cFFffb400Left Click|r: Report Damage |cFFffb400Right Click|r: Report Heal")
|
||||
phaseTooltip.report_label.fontsize = 10
|
||||
|
||||
phaseTooltip.phase_label:SetPoint("bottomleft", phaseTooltip, "bottomleft", 10, 5)
|
||||
phaseTooltip.time_label:SetPoint("left", phaseTooltip.phase_label, "right", 5, 0)
|
||||
phaseTooltip.report_label:SetPoint("bottomright", phaseTooltip, "bottomright", -10, 5)
|
||||
|
||||
local phaseFrameBackgroundTexture = detailsFramework:CreateImage(phaseTooltip,[[Interface\Tooltips\UI-Tooltip-Background]], nil, nil, "artwork")
|
||||
phaseFrameBackgroundTexture:SetPoint("left", phaseTooltip.phase_label, "left")
|
||||
phaseFrameBackgroundTexture.height = 16
|
||||
phaseFrameBackgroundTexture:SetPoint("right", phaseTooltip.report_label, "right")
|
||||
phaseFrameBackgroundTexture:SetVertexColor(0, 0, 0, 1)
|
||||
|
||||
phaseTooltip.damage_labels = {}
|
||||
phaseTooltip.heal_labels = {}
|
||||
|
||||
function phaseTooltip:ClearLabels()
|
||||
for i, tooltipBar in ipairs(phaseTooltip.damage_labels) do
|
||||
tooltipBar:Hide()
|
||||
end
|
||||
for i, tooltipBar in ipairs(phaseTooltip.heal_labels) do
|
||||
tooltipBar:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local createTooltipBar = function(index, xOffset)
|
||||
---@type statusbar
|
||||
local newtooltipBar = CreateFrame("statusbar", nil, phaseTooltip, "BackdropTemplate")
|
||||
newtooltipBar:SetSize(200, 16)
|
||||
newtooltipBar:SetFrameLevel(phaseTooltip:GetFrameLevel() + 50 - index)
|
||||
newtooltipBar:SetMinMaxValues(0, 1)
|
||||
newtooltipBar:SetPoint("topleft", phaseTooltip, "topleft", 5 + xOffset, ((index * 16) * -1) - 30)
|
||||
|
||||
local playerName = detailsFramework:CreateLabel(newtooltipBar, "", 11, "white", nil, nil, nil, "overlay")
|
||||
|
||||
local amountLabel = detailsFramework:CreateLabel(newtooltipBar, "", 11, nil, nil, nil, nil, "overlay")
|
||||
amountLabel:SetJustifyH("right")
|
||||
|
||||
local iconTexture = detailsFramework:CreateImage(newtooltipBar, "", 16, 16, "overlay")
|
||||
|
||||
local backgroundTexture = detailsFramework:CreateImage(newtooltipBar, [[Interface\AddOns\Details\images\bar_serenity]], nil, nil, "border")
|
||||
backgroundTexture.height = 16
|
||||
backgroundTexture:SetVertexColor(.1, .1, .1, 0.834)
|
||||
|
||||
local statusBarTexture = newtooltipBar:CreateTexture(nil, "artwork")
|
||||
statusBarTexture:SetTexture([[Interface\AddOns\Details\images\bar_serenity]])
|
||||
statusBarTexture:SetVertexColor(.3, .3, .3, 1)
|
||||
statusBarTexture:SetAllPoints()
|
||||
newtooltipBar:SetStatusBarTexture(statusBarTexture)
|
||||
|
||||
backgroundTexture:SetAllPoints()
|
||||
iconTexture:SetPoint("left", newtooltipBar, "left", 0, 0)
|
||||
playerName:SetPoint("left", iconTexture, "right", 2, 0)
|
||||
amountLabel:SetPoint("right", newtooltipBar, "right", -2, 0)
|
||||
|
||||
newtooltipBar.lefttext = playerName
|
||||
newtooltipBar.righttext = amountLabel
|
||||
newtooltipBar.icon = iconTexture
|
||||
newtooltipBar.bg = backgroundTexture
|
||||
newtooltipBar.statusBarTexture = statusBarTexture
|
||||
|
||||
return newtooltipBar
|
||||
end
|
||||
|
||||
function phaseTooltip:GetTooltipBar(index, barType)
|
||||
local thisBar
|
||||
|
||||
if (barType == "damage") then
|
||||
thisBar = phaseTooltip.damage_labels[index]
|
||||
if (not thisBar) then
|
||||
thisBar = createTooltipBar(index, 0)
|
||||
phaseTooltip.damage_labels[index] = thisBar
|
||||
end
|
||||
|
||||
elseif (barType == "healing") then
|
||||
thisBar = phaseTooltip.heal_labels[index]
|
||||
if (not thisBar) then
|
||||
thisBar = createTooltipBar(index, 235)
|
||||
phaseTooltip.heal_labels[index] = thisBar
|
||||
end
|
||||
end
|
||||
|
||||
thisBar:Show()
|
||||
return thisBar
|
||||
end
|
||||
|
||||
return phaseTooltip
|
||||
end
|
||||
|
||||
---phase indicators below the x axis
|
||||
---@param chartPanel df_chartmulti
|
||||
function encounterDetails:CreatePhaseIndicators(chartPanel, phaseTooltip)
|
||||
local sparkContainer = {}
|
||||
local phaseColors = {{0.2, 1, 0.2, phaseAlpha}, {1, 1, 0.2, phaseAlpha}, {1, 0.2, 0.2, phaseAlpha}, {0.2, 1, 1, phaseAlpha}, {0.2, 0.2, 1, phaseAlpha},
|
||||
[1.5] = {0.25, 0.95, 0.25, phaseAlpha},[2.5] = {0.95, 0.95, 0.25, phaseAlpha},[3.5] = {0.95, 0.25, 0.25, phaseAlpha}
|
||||
}
|
||||
|
||||
local createSpark = function()
|
||||
local newSpark = phaseTooltip:CreateTexture(nil, "overlay")
|
||||
newSpark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
|
||||
newSpark:SetBlendMode("ADD")
|
||||
newSpark:Hide()
|
||||
table.insert(sparkContainer, newSpark)
|
||||
end
|
||||
|
||||
local getSpark = function(index)
|
||||
local spark = sparkContainer[index]
|
||||
if (not spark) then
|
||||
createSpark()
|
||||
spark = sparkContainer[index]
|
||||
end
|
||||
spark:ClearAllPoints()
|
||||
return spark
|
||||
end
|
||||
|
||||
local hideSparks = function()
|
||||
for _, spark in ipairs(sparkContainer) do
|
||||
spark:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local onClickPhase = function(self, button)
|
||||
---@type combat
|
||||
local combatObject = encounterDetails:GetCombat(encounterDetails._segment)
|
||||
|
||||
if (button == "LeftButton") then
|
||||
local result = {}
|
||||
local reportFunc = function(IsCurrent, IsReverse, AmtLines)
|
||||
AmtLines = AmtLines + 1
|
||||
if (#result > AmtLines) then
|
||||
for i = #result, AmtLines+1, -1 do
|
||||
table.remove(result, i)
|
||||
end
|
||||
end
|
||||
encounterDetails:SendReportLines(result)
|
||||
end
|
||||
|
||||
--need to build here because the mouse will leave the block to click in the send button
|
||||
table.insert(result, "Details!: Damage for Phase " .. self.phase .. " of " .. (combatObject and combatObject.is_boss and combatObject.is_boss.name or "Unknown") .. ":")
|
||||
for i = 1, #self.damage_actors do
|
||||
table.insert(result, encounterDetails:GetOnlyName(self.damage_actors[i][1]) .. ": " .. Details:ToK(math.floor(self.damage_actors[i][2])))
|
||||
end
|
||||
encounterDetails:SendReportWindow(reportFunc, nil, nil, true)
|
||||
|
||||
elseif (button == "RightButton") then
|
||||
local result = {}
|
||||
local reportFunc = function(IsCurrent, IsReverse, AmtLines)
|
||||
AmtLines = AmtLines + 1
|
||||
if (#result > AmtLines) then
|
||||
for i = #result, AmtLines+1, -1 do
|
||||
table.remove(result, i)
|
||||
end
|
||||
end
|
||||
encounterDetails:SendReportLines(result)
|
||||
end
|
||||
|
||||
table.insert(result, "Details!: Healing for Phase " .. self.phase .. " of " ..(combatObject and combatObject.is_boss and combatObject.is_boss.name or "Unknown") .. ":")
|
||||
for i = 1, #self.heal_actors do
|
||||
table.insert(result, encounterDetails:GetOnlyName(self.heal_actors[i][1]) .. ": " .. Details:ToK(math.floor(self.heal_actors[i][2])))
|
||||
end
|
||||
encounterDetails:SendReportWindow(reportFunc, nil, nil, true)
|
||||
end
|
||||
end
|
||||
|
||||
local onEnterPhase = function(self)
|
||||
local leftSpark = getSpark(1)
|
||||
local rightSpark = getSpark(2)
|
||||
leftSpark:SetPoint("left", self.texture, "left", -16, 0)
|
||||
rightSpark:SetPoint("right", self.texture, "right", 16, 0)
|
||||
leftSpark:Show()
|
||||
rightSpark:Show()
|
||||
self.texture:SetBlendMode("ADD")
|
||||
|
||||
local phase = self.phase
|
||||
local sparkIndex = 3
|
||||
|
||||
self.texture:SetVertexColor(1, 1, 1)
|
||||
|
||||
for _, thisPhaseFrame in ipairs(encounterDetails.chartFrameAux.PhaseFrames) do
|
||||
if (thisPhaseFrame ~= self and thisPhaseFrame.phase == phase) then
|
||||
local thisPhaseLeftSpark = getSpark(sparkIndex)
|
||||
local thisPhaseRightSpark = getSpark(sparkIndex+1)
|
||||
thisPhaseLeftSpark:SetPoint("left", thisPhaseFrame.texture, "left", -16, 0)
|
||||
thisPhaseRightSpark:SetPoint("right", thisPhaseFrame.texture, "right", 16, 0)
|
||||
thisPhaseLeftSpark:Show()
|
||||
thisPhaseRightSpark:Show()
|
||||
thisPhaseFrame.texture:SetBlendMode("ADD")
|
||||
thisPhaseFrame.texture:SetVertexColor(1, 1, 1)
|
||||
sparkIndex = sparkIndex + 2
|
||||
end
|
||||
end
|
||||
|
||||
---@type combat
|
||||
local combatObject = encounterDetails:GetCombat(encounterDetails._segment)
|
||||
|
||||
if (combatObject) then
|
||||
phaseTooltip:ClearLabels()
|
||||
|
||||
--damage
|
||||
---@type table<number, table<string, number>>
|
||||
local listOfPlayers = {}
|
||||
for playerName, damageDone in pairs(combatObject.PhaseData.damage[self.phase]) do
|
||||
table.insert(listOfPlayers, {playerName, damageDone})
|
||||
end
|
||||
table.sort(listOfPlayers, Details.Sort2)
|
||||
local topDamage = listOfPlayers[1] and listOfPlayers[1][2]
|
||||
|
||||
for index, playerTable in ipairs(listOfPlayers) do
|
||||
local playerName = playerTable[1]
|
||||
local damageDone = playerTable[2]
|
||||
|
||||
local tooltipBar = phaseTooltip:GetTooltipBar(index, "damage")
|
||||
tooltipBar:SetValue(damageDone / topDamage)
|
||||
|
||||
tooltipBar.lefttext.text = encounterDetails:GetOnlyName(playerName)
|
||||
tooltipBar.righttext.text = Details:ToK(math.floor(damageDone))
|
||||
|
||||
---@type actor
|
||||
local actor = combatObject:GetActor(DETAILS_ATTRIBUTE_DAMAGE, playerName)
|
||||
|
||||
local class = encounterDetails:GetClass(playerName)
|
||||
local spec = encounterDetails:GetSpec(playerName) or actor and actor.spec
|
||||
|
||||
--get the class color for the actor
|
||||
local red, green, blue = Details:GetClassColor(class)
|
||||
tooltipBar:SetStatusBarColor(red, green, blue)
|
||||
|
||||
if (spec) then
|
||||
tooltipBar.icon.texture = [[Interface\AddOns\Details\images\spec_icons_normal]]
|
||||
tooltipBar.icon.texcoord = encounterDetails.class_specs_coords[spec]
|
||||
|
||||
elseif (class) then
|
||||
tooltipBar.icon.texture = [[Interface\AddOns\Details\images\classes_small_alpha]]
|
||||
tooltipBar.icon.texcoord = Details.class_coords[class]
|
||||
|
||||
else
|
||||
tooltipBar.icon.texture = [[Interface\LFGFRAME\LFGROLE_BW]]
|
||||
tooltipBar.icon:SetTexCoord(.25, .5, 0, 1)
|
||||
end
|
||||
|
||||
tooltipBar:Show()
|
||||
end
|
||||
|
||||
local damage_players = #listOfPlayers
|
||||
self.damage_actors = listOfPlayers
|
||||
|
||||
--healing
|
||||
---@type table<number, table<string, number>>
|
||||
local listOfPlayersHeal = {}
|
||||
for playerName, heal in pairs(combatObject.PhaseData.heal[self.phase]) do
|
||||
table.insert(listOfPlayersHeal, {playerName, heal})
|
||||
end
|
||||
table.sort(listOfPlayersHeal, Details.Sort2)
|
||||
local topHealing = listOfPlayersHeal[1] and listOfPlayersHeal[1][2]
|
||||
|
||||
for index, playerTable in ipairs(listOfPlayersHeal) do
|
||||
local playerName = playerTable[1]
|
||||
local healingDone = playerTable[2]
|
||||
|
||||
local tooltipBar = phaseTooltip:GetTooltipBar(index, "healing")
|
||||
tooltipBar:SetValue(healingDone / topHealing)
|
||||
|
||||
tooltipBar.lefttext.text = encounterDetails:GetOnlyName(playerName)
|
||||
tooltipBar.righttext.text = Details:ToK(math.floor(healingDone))
|
||||
|
||||
---@type actor
|
||||
local actor = combatObject:GetActor(DETAILS_ATTRIBUTE_DAMAGE, playerName)
|
||||
|
||||
local class = encounterDetails:GetClass(playerName)
|
||||
local spec = encounterDetails:GetSpec(playerName) or actor and actor.spec
|
||||
|
||||
--get the class color for the actor
|
||||
local red, green, blue = Details:GetClassColor(class)
|
||||
tooltipBar:SetStatusBarColor(red, green, blue)
|
||||
|
||||
if (spec) then
|
||||
tooltipBar.icon.texture = [[Interface\AddOns\Details\images\spec_icons_normal]]
|
||||
tooltipBar.icon.texcoord = encounterDetails.class_specs_coords[spec]
|
||||
|
||||
elseif (class) then
|
||||
tooltipBar.icon:SetTexture([[Interface\AddOns\Details\images\classes_small_alpha]])
|
||||
tooltipBar.icon:SetTexCoord(unpack(Details.class_coords[class]))
|
||||
|
||||
else
|
||||
tooltipBar.icon:SetTexture([[Interface\LFGFRAME\LFGROLE_BW]])
|
||||
tooltipBar.icon:SetTexCoord(.25, .5, 0, 1)
|
||||
end
|
||||
|
||||
tooltipBar:Show()
|
||||
end
|
||||
|
||||
local heal_players = #listOfPlayersHeal
|
||||
self.heal_actors = listOfPlayersHeal
|
||||
|
||||
--show the panel
|
||||
phaseTooltip:SetHeight((math.max(damage_players, heal_players) * 16) + 60)
|
||||
phaseTooltip:SetPoint("bottom", self, "top", 0, 10)
|
||||
phaseTooltip:Show()
|
||||
|
||||
phaseTooltip.phase_label.text = "|cFFffb400Phase|r: " .. self.phase
|
||||
|
||||
local m, s = math.floor(self.elapsed / 60), math.floor(self.elapsed % 60)
|
||||
phaseTooltip.time_label.text = "|cFFffb400Elapsed|r: " .. m .. "m " .. s .. "s"
|
||||
end
|
||||
end
|
||||
|
||||
local onLeavePhase = function(self)
|
||||
wipe(self.damage_actors)
|
||||
wipe(self.heal_actors)
|
||||
|
||||
for _, phaseTextureFrame in ipairs(encounterDetails.chartFrameAux.PhaseFrames) do
|
||||
phaseTextureFrame.texture:SetBlendMode("BLEND")
|
||||
phaseTextureFrame.texture:SetVertexColor(unpack(phaseTextureFrame.texture.original_color))
|
||||
end
|
||||
|
||||
hideSparks()
|
||||
phaseTooltip:Hide()
|
||||
end
|
||||
|
||||
function encounterDetails:GetPhaseIndicator(index, phase)
|
||||
local phaseIndicatorFrame = encounterDetails.chartFrameAux.PhaseFrames[index]
|
||||
|
||||
if (not phaseIndicatorFrame) then
|
||||
---@type ed_phaseframe
|
||||
phaseIndicatorFrame = CreateFrame("frame", "EncounterDetailsPhaseTexture" .. index, chartPanel, "BackdropTemplate")
|
||||
phaseIndicatorFrame:SetHeight(CONST_PHASE_BAR_HEIGHT)
|
||||
|
||||
local phaseTexture = phaseIndicatorFrame:CreateTexture(nil, "artwork")
|
||||
phaseTexture:SetAllPoints()
|
||||
phaseTexture:SetColorTexture(1, 1, 1, phaseAlpha)
|
||||
phaseTexture.original_color = {1, 1, 1}
|
||||
phaseIndicatorFrame.texture = phaseTexture
|
||||
|
||||
phaseIndicatorFrame:SetScript("OnEnter", onEnterPhase)
|
||||
phaseIndicatorFrame:SetScript("OnLeave", onLeavePhase)
|
||||
phaseIndicatorFrame:SetScript("OnMouseUp", onClickPhase)
|
||||
|
||||
phaseIndicatorFrame = phaseIndicatorFrame
|
||||
table.insert(encounterDetails.chartFrameAux.PhaseFrames, phaseIndicatorFrame)
|
||||
end
|
||||
|
||||
phaseIndicatorFrame:ClearAllPoints()
|
||||
|
||||
phase = math.min(phase, 5)
|
||||
if (not phaseColors[phase]) then
|
||||
Details:Msg("Phase out of range:", phase)
|
||||
phase = math.max(phase, 1)
|
||||
end
|
||||
|
||||
local phaseColor = phaseColors[phase]
|
||||
if (not phaseColor) then
|
||||
phaseColor = {1, 1, 1}
|
||||
end
|
||||
|
||||
phaseIndicatorFrame.texture:SetVertexColor(unpack(phaseColor))
|
||||
local originalColor = phaseIndicatorFrame.texture.original_color
|
||||
originalColor[1], originalColor[2], originalColor[3] = unpack(phaseColors[phase])
|
||||
|
||||
phaseIndicatorFrame:Show()
|
||||
|
||||
return phaseIndicatorFrame
|
||||
end
|
||||
|
||||
function encounterDetails:ClearPhaseIndicators()
|
||||
for i, texture in pairs(encounterDetails.chartFrameAux.PhaseFrames) do
|
||||
texture:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---not in use at the moment
|
||||
---@param self any
|
||||
---@param chartPanel df_chart
|
||||
---@param detailsGraphicData any
|
||||
---@param combatObject combat
|
||||
---@param drawDeathsCombat combat
|
||||
function encounterDetails:DrawSegmentGraphic(chartPanel, detailsGraphicData, combatObject, drawDeathsCombat)
|
||||
|
||||
--> add death icons for the first deaths in the segment
|
||||
if (drawDeathsCombat) then
|
||||
local mortes = drawDeathsCombat.last_events_tables
|
||||
local scaleG = CONST_CHART_LENGTH / drawDeathsCombat:GetCombatTime()
|
||||
|
||||
for _, row in ipairs(encounterDetails.chartFrameAux.VerticalLines) do
|
||||
row:Hide()
|
||||
end
|
||||
|
||||
for i = 1, math.min(CONST_CHART_MAX_DEATHS_ICONS, #mortes) do
|
||||
|
||||
local vRowFrame = encounterDetails.chartFrameAux.VerticalLines[i]
|
||||
|
||||
if (not vRowFrame) then
|
||||
vRowFrame = CreateFrame("frame", "DetailsEncountersVerticalLine"..i, chartPanel, "BackdropTemplate")
|
||||
vRowFrame:SetWidth(20)
|
||||
vRowFrame:SetHeight(43)
|
||||
vRowFrame:SetFrameLevel(chartPanel:GetFrameLevel()+2)
|
||||
|
||||
vRowFrame:SetScript("OnEnter", function(frame)
|
||||
if (vRowFrame.dead[1] and vRowFrame.dead[1][3] and vRowFrame.dead[1][3][2]) then
|
||||
GameCooltip:Reset()
|
||||
|
||||
--time of death and player name
|
||||
GameCooltip:AddLine(vRowFrame.dead[6].." "..vRowFrame.dead[3])
|
||||
local class, l, r, t, b = Details:GetClass(vRowFrame.dead[3])
|
||||
if (class) then
|
||||
GameCooltip:AddIcon([[Interface\AddOns\Details\images\classes_small]], 1, 1, 12, 12, l, r, t, b)
|
||||
end
|
||||
GameCooltip:AddLine("")
|
||||
|
||||
--last hits:
|
||||
local death = vRowFrame.dead
|
||||
local amt = 0
|
||||
for i = #death[1], 1, -1 do
|
||||
local this_hit = death[1][i]
|
||||
if (type(this_hit[1]) == "boolean" and this_hit[1]) then
|
||||
local spellname, _, spellicon = _GetSpellInfo(this_hit[2])
|
||||
local t = death[2] - this_hit[4]
|
||||
GameCooltip:AddLine("-" .. string.format("%.1f", t) .. " " .. spellname .. "(" .. this_hit[6] .. ")", encounterDetails:comma_value(this_hit[3]))
|
||||
GameCooltip:AddIcon(spellicon, 1, 1, 12, 12, 0.1, 0.9, 0.1, 0.9)
|
||||
amt = amt + 1
|
||||
if (amt == 3) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
GameCooltip:SetOption("TextSize", 9.5)
|
||||
GameCooltip:SetOption("HeightAnchorMod", -15)
|
||||
|
||||
GameCooltip:SetWallpaper(1,[[Interface\SPELLBOOK\Spellbook-Page-1]], {.6, 0.1, 0, 0.64453125}, {1, 1, 1, 0.1}, true)
|
||||
GameCooltip:ShowCooltip(frame, "tooltip")
|
||||
end
|
||||
end)
|
||||
|
||||
vRowFrame:SetScript("OnLeave", function(frame)
|
||||
Details.popup:ShowMe(false)
|
||||
end)
|
||||
|
||||
vRowFrame.texture = vRowFrame:CreateTexture(nil, "overlay")
|
||||
vRowFrame.texture:SetTexture("Interface\\AddOns\\Details\\images\\verticalline")
|
||||
vRowFrame.texture:SetWidth(3)
|
||||
vRowFrame.texture:SetHeight(20)
|
||||
vRowFrame.texture:SetPoint("center", "DetailsEncountersVerticalLine"..i, "center")
|
||||
vRowFrame.texture:SetPoint("bottom", "DetailsEncountersVerticalLine"..i, "bottom", 0, 0)
|
||||
vRowFrame.texture:SetVertexColor(1, 1, 1, .5)
|
||||
|
||||
vRowFrame.icon = vRowFrame:CreateTexture(nil, "overlay")
|
||||
vRowFrame.icon:SetTexture("Interface\\WorldStateFrame\\SkullBones")
|
||||
vRowFrame.icon:SetTexCoord(0.046875, 0.453125, 0.046875, 0.46875)
|
||||
vRowFrame.icon:SetWidth(16)
|
||||
vRowFrame.icon:SetHeight(16)
|
||||
vRowFrame.icon:SetPoint("center", "DetailsEncountersVerticalLine"..i, "center")
|
||||
vRowFrame.icon:SetPoint("bottom", "DetailsEncountersVerticalLine"..i, "bottom", 0, 20)
|
||||
|
||||
encounterDetails.chartFrameAux.VerticalLines[i] = vRowFrame
|
||||
end
|
||||
|
||||
local deadTime = mortes[i].dead_at
|
||||
vRowFrame:SetPoint("topleft", encounterDetails.Frame, "topleft",(deadTime*scaleG)+70, -CONST_CHART_HEIGHT-22)
|
||||
vRowFrame.dead = mortes[i]
|
||||
vRowFrame:Show()
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function encounterDetails:CreateGraphPanel() --not in use
|
||||
--bloodlust indicators
|
||||
chartPanel.bloodlustIndicators = {}
|
||||
for i = 1, 5 do
|
||||
local bloodlustTexture = chartPanel:CreateTexture(nil, "overlay")
|
||||
bloodlustTexture:SetColorTexture(0, 1, 0, 0,6)
|
||||
chartPanel.bloodlustIndicators[#chartPanel.bloodlustIndicators+1] = bloodlustTexture
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,361 @@
|
||||
|
||||
local addonId, edTable = ...
|
||||
local Details = _G._detalhes
|
||||
local AceLocale = LibStub("AceLocale-3.0")
|
||||
local Loc = AceLocale:GetLocale("Details_EncounterDetails")
|
||||
local Graphics = LibStub:GetLibrary("LibGraph-2.0")
|
||||
local ipairs = ipairs
|
||||
local _GetSpellInfo = Details.getspellinfo
|
||||
local unpack = unpack
|
||||
local detailsFramework = DetailsFramework
|
||||
local CreateFrame = CreateFrame
|
||||
local GameCooltip = GameCooltip
|
||||
local _
|
||||
|
||||
local encounterDetails = _G.EncounterDetailsGlobal
|
||||
local edFrame = encounterDetails.Frame
|
||||
|
||||
local emote_segment_index = 1
|
||||
local searching
|
||||
local emoteLines = {}
|
||||
local emoteSearchTable = {}
|
||||
local CONST_EMOTES_MAX_LINES = 32
|
||||
|
||||
encounterDetails.emoteSegmentIndex = emote_segment_index
|
||||
|
||||
--emotes frame
|
||||
local emoteFrame = CreateFrame("frame", "DetailsEncountersEmoteFrame", UIParent, "BackdropTemplate")
|
||||
emoteFrame:RegisterEvent("CHAT_MSG_RAID_BOSS_EMOTE")
|
||||
emoteFrame:RegisterEvent("CHAT_MSG_RAID_BOSS_WHISPER")
|
||||
emoteFrame:RegisterEvent("CHAT_MSG_MONSTER_EMOTE")
|
||||
emoteFrame:RegisterEvent("CHAT_MSG_MONSTER_SAY")
|
||||
emoteFrame:RegisterEvent("CHAT_MSG_MONSTER_WHISPER")
|
||||
emoteFrame:RegisterEvent("CHAT_MSG_MONSTER_PARTY")
|
||||
emoteFrame:RegisterEvent("CHAT_MSG_MONSTER_YELL")
|
||||
encounterDetails.EmoteFrame = emoteFrame
|
||||
|
||||
local emoteTable = {
|
||||
["CHAT_MSG_RAID_BOSS_EMOTE"] = 1,
|
||||
["CHAT_MSG_RAID_BOSS_WHISPER"] = 2,
|
||||
["CHAT_MSG_MONSTER_EMOTE"] = 3,
|
||||
["CHAT_MSG_MONSTER_SAY"] = 4,
|
||||
["CHAT_MSG_MONSTER_WHISPER"] = 5,
|
||||
["CHAT_MSG_MONSTER_PARTY"] = 6,
|
||||
["CHAT_MSG_MONSTER_YELL"] = 7,
|
||||
}
|
||||
|
||||
emoteFrame:SetScript("OnEvent", function(...)
|
||||
if (not encounterDetails.current_whisper_table) then
|
||||
return
|
||||
end
|
||||
|
||||
local combat = encounterDetails:GetCombat("current")
|
||||
--local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 = ...
|
||||
--print("2 =", arg2, "3 =", arg3, "4 =", arg4, "5 =", arg5, "6 =", arg6, "7 =", arg7, "8 =", arg8, "9 =", arg9)
|
||||
if (combat and encounterDetails:IsInCombat() and encounterDetails:GetZoneType() == "raid") then
|
||||
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 = ...
|
||||
table.insert(encounterDetails.current_whisper_table, {combat:GetCombatTime(), arg3, arg4, emoteTable [arg2]})
|
||||
end
|
||||
end)
|
||||
|
||||
local refresh_emotes = function(self)
|
||||
local offset = FauxScrollFrame_GetOffset(self)
|
||||
local emotePool = encounterDetails.charsaved.emotes[emote_segment_index]
|
||||
|
||||
if (searching) then
|
||||
local i = 0
|
||||
local lower = string.lower
|
||||
|
||||
for index, data in ipairs(emotePool) do
|
||||
if (lower(data[2]):find(lower(searching))) then
|
||||
i = i + 1
|
||||
emoteSearchTable[i] = data
|
||||
end
|
||||
for o = #emoteSearchTable, i + 1, -1 do
|
||||
emoteSearchTable[o] = nil
|
||||
end
|
||||
emotePool = emoteSearchTable
|
||||
end
|
||||
|
||||
edFrame.SearchResults:Show()
|
||||
edFrame.SearchResults:SetText("Found " .. i .. " matches")
|
||||
|
||||
if (i > 0) then
|
||||
edFrame.ReportEmoteButton:Enable()
|
||||
elseif (i == 0) then
|
||||
edFrame.ReportEmoteButton:Disable()
|
||||
end
|
||||
else
|
||||
edFrame.SearchResults:Hide()
|
||||
end
|
||||
|
||||
if (emotePool) then
|
||||
for barIndex = 1, CONST_EMOTES_MAX_LINES do
|
||||
local data = emotePool[barIndex + offset]
|
||||
local bar = emoteLines[barIndex]
|
||||
|
||||
if (data) then
|
||||
bar:Show()
|
||||
|
||||
local min, sec = math.floor(data[1] / 60), math.floor(data[1] % 60)
|
||||
bar.leftText:SetText(min .. "m" .. sec .. "s:")
|
||||
|
||||
if (data[2] == "") then
|
||||
bar.rightText:SetText("--x--x--")
|
||||
else
|
||||
bar.rightText:SetText(string.format(data[2], data[3]))
|
||||
end
|
||||
|
||||
local colorString = encounterDetails.BossWhispColors[data[4]]
|
||||
local colorTable = _G.ChatTypeInfo[colorString]
|
||||
|
||||
bar.rightText:SetTextColor(colorTable.r, colorTable.g, colorTable.b)
|
||||
bar.icon:SetTexture([[Interface\CHARACTERFRAME\UI-StateIcon]])
|
||||
bar.icon:SetTexCoord(0, 0.5, 0.5, 1)
|
||||
bar.icon:SetBlendMode("ADD")
|
||||
else
|
||||
bar:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
FauxScrollFrame_Update(self, #emotePool, CONST_EMOTES_MAX_LINES, 15)
|
||||
else
|
||||
for barIndex = 1, CONST_EMOTES_MAX_LINES do
|
||||
local bar = emoteLines[barIndex]
|
||||
bar:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
edFrame.EmoteWidgets = {}
|
||||
--~emotes ~whispers
|
||||
|
||||
local barDivEmotes = detailsFramework:CreateImage(edFrame, "Interface\\AddOns\\Details_EncounterDetails\\images\\boss_bg", 4, 480, "artwork", {724/1024, 728/1024, 0, 245/512})
|
||||
barDivEmotes:SetPoint("TOPLEFT", edFrame, "TOPLEFT", 244, -74)
|
||||
barDivEmotes:Hide()
|
||||
table.insert(edFrame.EmoteWidgets, barDivEmotes)
|
||||
|
||||
local emoteScrollFrame = CreateFrame("ScrollFrame", "EncounterDetails_EmoteScroll", edFrame, "FauxScrollFrameTemplate, BackdropTemplate")
|
||||
emoteScrollFrame:SetScript("OnVerticalScroll", function(self, offset) FauxScrollFrame_OnVerticalScroll(self, offset, 14, refresh_emotes) end)
|
||||
emoteScrollFrame:SetPoint("topleft", edFrame, "topleft", 249, -75)
|
||||
emoteScrollFrame:SetPoint("bottomright", edFrame, "bottomright", -33, 42)
|
||||
emoteScrollFrame.Update = refresh_emotes
|
||||
emoteScrollFrame:Hide()
|
||||
detailsFramework:ReskinSlider(emoteScrollFrame, 3)
|
||||
encounterDetails.EmoteScrollFrame = emoteScrollFrame
|
||||
|
||||
table.insert(edFrame.EmoteWidgets, emoteScrollFrame)
|
||||
|
||||
local onEnterRow = function(self)
|
||||
self:SetBackdrop({bgFile = [[Interface\AddOns\Details\images\background]], tile = true, tileSize = 16})
|
||||
self:SetBackdropColor(1, 1, 1, .6)
|
||||
if (self.rightText:IsTruncated()) then
|
||||
GameCooltip:Reset()
|
||||
GameCooltip:AddLine(self.rightText:GetText())
|
||||
GameCooltip:SetOwner(self, "bottomleft", "topleft", 42, -9)
|
||||
GameCooltip:Show()
|
||||
end
|
||||
end
|
||||
local onLeaveRow = function(self)
|
||||
self:SetBackdrop({bgFile = [[Interface\AddOns\Details\images\background]], tile = true, tileSize = 16})
|
||||
self:SetBackdropColor(1, 1, 1, .3)
|
||||
GameCooltip:Hide()
|
||||
end
|
||||
|
||||
local onMouseUpRow = function(self)
|
||||
--report
|
||||
local text = self.rightText:GetText()
|
||||
local time = self.leftText:GetText()
|
||||
|
||||
local reportFunc = function()
|
||||
-- remove textures
|
||||
text = text:gsub("(|T).*(|t)", "")
|
||||
-- remove colors
|
||||
text = text:gsub("|c%x?%x?%x?%x?%x?%x?%x?%x?", "")
|
||||
text = text:gsub("|r", "")
|
||||
-- replace links
|
||||
for _, spellid in text:gmatch("(|Hspell:)(.-)(|h)") do
|
||||
local spell = tonumber(spellid)
|
||||
local link = GetSpellLink(spell)
|
||||
text = text:gsub("(|Hspell).*(|h)", link)
|
||||
end
|
||||
-- remove unit links
|
||||
text = text:gsub("(|Hunit).-(|h)", "")
|
||||
-- remove the left space
|
||||
text = text:gsub("^%s$", "")
|
||||
|
||||
encounterDetails:SendReportLines({"Details! Encounter Emote at " .. time, "\"" .. text .. "\""})
|
||||
end
|
||||
|
||||
encounterDetails:SendReportWindow(reportFunc)
|
||||
end
|
||||
|
||||
for i = 1, CONST_EMOTES_MAX_LINES do
|
||||
local line = CreateFrame("frame", nil, edFrame,"BackdropTemplate")
|
||||
local y = (i-1) * 15 * -1
|
||||
line:SetPoint("topleft", emoteScrollFrame, "topleft", 0, y)
|
||||
line:SetPoint("topright", emoteScrollFrame, "topright", 0, y)
|
||||
line:SetHeight(14)
|
||||
line:SetBackdrop({bgFile = [[Interface\AddOns\Details\images\background]], tile = true, tileSize = 16})
|
||||
line:SetBackdropColor(1, 1, 1, .3)
|
||||
|
||||
line.icon = line:CreateTexture(nil, "overlay")
|
||||
line.icon:SetPoint("left", line, "left", 2, 0)
|
||||
line.icon:SetSize(14, 14)
|
||||
|
||||
line.leftText = line:CreateFontString(nil, "overlay", "GameFontHighlightSmall")
|
||||
line.leftText:SetPoint("left", line.icon, "right", 2, 0)
|
||||
line.leftText:SetHeight(14)
|
||||
line.leftText:SetJustifyH("left")
|
||||
|
||||
line.rightText = line:CreateFontString(nil, "overlay", "GameFontHighlightSmall")
|
||||
line.rightText:SetPoint("left", line.icon, "right", 46, 0)
|
||||
line.rightText:SetHeight(14)
|
||||
line.rightText:SetJustifyH("left")
|
||||
|
||||
line:SetFrameLevel(emoteScrollFrame:GetFrameLevel()+1)
|
||||
|
||||
line:SetScript("OnEnter", onEnterRow)
|
||||
line:SetScript("OnLeave", onLeaveRow)
|
||||
line:SetScript("OnMouseUp", onMouseUpRow)
|
||||
table.insert(emoteLines, line)
|
||||
table.insert(edFrame.EmoteWidgets, line)
|
||||
line:Hide()
|
||||
end
|
||||
|
||||
--select emote segment
|
||||
local emotesSegmentLabel = detailsFramework:CreateLabel(edFrame, "Segment:", 11, nil, "GameFontHighlightSmall")
|
||||
emotesSegmentLabel:SetPoint("topleft", edFrame, "topleft", 10, -85)
|
||||
|
||||
local onEmoteSegmentSelected = function(_, _, segment)
|
||||
FauxScrollFrame_SetOffset(emoteScrollFrame, 0)
|
||||
emote_segment_index = segment
|
||||
encounterDetails.emoteSegmentIndex = segment
|
||||
emoteScrollFrame:Update()
|
||||
end
|
||||
|
||||
function encounterDetails:SetEmoteSegment(segment)
|
||||
emote_segment_index = segment
|
||||
encounterDetails.emoteSegmentIndex = segment
|
||||
end
|
||||
|
||||
local segmentIcon = [[Interface\AddOns\Details\images\icons]]
|
||||
local segmentIconCoords = {0.7373046875, 0.9912109375, 0.6416015625, 0.7978515625}
|
||||
local segmentIconColor = {1, 1, 1, 0.5}
|
||||
|
||||
local buildEmoteSementsList = function()
|
||||
local resultTable = {}
|
||||
if (not encounterDetails.charsaved) then
|
||||
return resultTable
|
||||
end
|
||||
for index, segment in ipairs(encounterDetails.charsaved.emotes) do
|
||||
local bossIcon, iconWidth, iconHeight, iconL, iconR, iconT, iconB = Details:GetBossEncounterTexture(segment.boss or "unknown")
|
||||
table.insert(resultTable, {label = "#" .. index .. " " ..(segment.boss or "unknown"), value = index, icon = bossIcon, iconsize = {iconWidth, iconHeight}, texcoord = {iconL, iconR, iconT, iconB}, onclick = onEmoteSegmentSelected, iconcolor = segmentIconColor})
|
||||
end
|
||||
return resultTable
|
||||
end
|
||||
|
||||
local emoteSegmentsDropdown = detailsFramework:NewDropDown(edFrame, _, "$parentEmotesSegmentDropdown", "EmotesSegment", 180, 20, buildEmoteSementsList, 1)
|
||||
emoteSegmentsDropdown:SetPoint("topleft", emotesSegmentLabel, "bottomleft", -1, -2)
|
||||
emoteSegmentsDropdown:SetTemplate(detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
encounterDetails.emoteSegmentsDropdown = emoteSegmentsDropdown
|
||||
|
||||
table.insert(edFrame.EmoteWidgets, emoteSegmentsDropdown)
|
||||
table.insert(edFrame.EmoteWidgets, emotesSegmentLabel)
|
||||
|
||||
--search box
|
||||
local emotesSearchLabel = detailsFramework:CreateLabel(edFrame, "Search:", 11, nil, "GameFontHighlightSmall")
|
||||
emotesSearchLabel:SetPoint("topleft", edFrame, "topleft", 10, -130)
|
||||
|
||||
local emotesSearchResultsLabel = detailsFramework:CreateLabel(edFrame, "", 11, nil, "GameFontNormal", "SearchResults")
|
||||
emotesSearchResultsLabel:SetPoint("topleft", edFrame, "topleft", 10, -190)
|
||||
|
||||
local searchTextEntry = detailsFramework:NewTextEntry(edFrame, nil, "$parentEmoteSearchBox", nil, 180, 20)
|
||||
searchTextEntry:SetTemplate(detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
searchTextEntry:SetPoint("topleft",emotesSearchLabel, "bottomleft", -1, -2)
|
||||
searchTextEntry:SetJustifyH("left")
|
||||
searchTextEntry:SetAsSearchBox()
|
||||
|
||||
searchTextEntry:SetHook("OnTextChanged", function()
|
||||
searching = searchTextEntry:GetText()
|
||||
if (searching == "") then
|
||||
searching = nil
|
||||
FauxScrollFrame_SetOffset(emoteScrollFrame, 0)
|
||||
edFrame.ReportEmoteButton:Disable()
|
||||
emoteScrollFrame:Update()
|
||||
else
|
||||
FauxScrollFrame_SetOffset(emoteScrollFrame, 0)
|
||||
edFrame.ReportEmoteButton:Enable()
|
||||
emoteScrollFrame:Update()
|
||||
end
|
||||
end)
|
||||
|
||||
table.insert(edFrame.EmoteWidgets, searchTextEntry)
|
||||
table.insert(edFrame.EmoteWidgets, emotesSearchLabel)
|
||||
|
||||
-- report button
|
||||
local reportEmoteButton = detailsFramework:NewButton(edFrame, nil, "$parentReportEmoteButton", "ReportEmoteButton", 180, 20, function()
|
||||
local reportFunc = function(IsCurrent, IsReverse, AmtLines)
|
||||
local segment = encounterDetails.charsaved.emotes and encounterDetails.charsaved.emotes[emote_segment_index]
|
||||
|
||||
if (segment) then
|
||||
encounterDetails.report_lines = {"Details!: Emotes for " .. segment.boss}
|
||||
local added = 0
|
||||
|
||||
for index = 1, 16 do
|
||||
local bar = emoteLines[index]
|
||||
if (bar:IsShown() and added < AmtLines) then
|
||||
local time = bar.leftText:GetText()
|
||||
local text = bar.rightText:GetText()
|
||||
|
||||
--"|Hunit:77182:Oregorger|hOregorger prepares to cast |cFFFF0000|Hspell:156879|h[Blackrock Barrage]|h|r."
|
||||
|
||||
-- remove textures
|
||||
text = text:gsub("(|T).*(|t)", "")
|
||||
-- remove colors
|
||||
text = text:gsub("|c%x?%x?%x?%x?%x?%x?%x?%x?", "")
|
||||
text = text:gsub("|r", "")
|
||||
-- replace links
|
||||
for _, spellid in text:gmatch("(|Hspell:)(.-)(|h)") do
|
||||
local spell = tonumber(spellid)
|
||||
local link = GetSpellLink(spell)
|
||||
text = text:gsub("(|Hspell).*(|h)", link)
|
||||
end
|
||||
-- remove unit links
|
||||
text = text:gsub("(|Hunit).-(|h)", "")
|
||||
-- remove the left space
|
||||
text = text:gsub("^%s$", "")
|
||||
|
||||
table.insert(encounterDetails.report_lines, time .. " " .. text)
|
||||
added = added + 1
|
||||
|
||||
if (added == AmtLines) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
encounterDetails:SendReportLines(encounterDetails.report_lines)
|
||||
else
|
||||
encounterDetails:Msg("There is nothing to report.")
|
||||
end
|
||||
end
|
||||
|
||||
local use_slider = true
|
||||
encounterDetails:SendReportWindow(reportFunc, nil, nil, use_slider)
|
||||
end, nil, nil, nil, "Report Results")
|
||||
|
||||
reportEmoteButton:SetIcon([[Interface\AddOns\Details\images\report_button]], 8, 14, nil, {0, 1, 0, 1}, nil, 4, 2)
|
||||
reportEmoteButton:SetTemplate(detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
||||
|
||||
reportEmoteButton:SetPoint("topleft", searchTextEntry, "bottomleft", 0, -4)
|
||||
reportEmoteButton:Disable()
|
||||
|
||||
table.insert(edFrame.EmoteWidgets, reportEmoteButton)
|
||||
|
||||
for _, widget in pairs(edFrame.EmoteWidgets) do
|
||||
widget:Hide()
|
||||
end
|
||||
|
||||
local emoteReportLabel = detailsFramework:NewLabel(searchTextEntry.widget, searchTextEntry.widget, nil, "report_click", "|cFFffb400Left Click|r: Report Line")
|
||||
emoteReportLabel:SetPoint("topleft", searchTextEntry.widget, "bottomleft", 1, -61)
|
||||
@@ -0,0 +1,471 @@
|
||||
|
||||
local addonId, edTable = ...
|
||||
local Details = _G._detalhes
|
||||
local AceLocale = LibStub("AceLocale-3.0")
|
||||
local Loc = AceLocale:GetLocale("Details_EncounterDetails")
|
||||
local Graphics = LibStub:GetLibrary("LibGraph-2.0")
|
||||
local ipairs = ipairs
|
||||
local _GetSpellInfo = Details.getspellinfo
|
||||
local unpack = unpack
|
||||
local detailsFramework = DetailsFramework
|
||||
local CreateFrame = CreateFrame
|
||||
local GameCooltip = GameCooltip
|
||||
local wipe = table.wipe
|
||||
local _
|
||||
|
||||
local encounterDetails = _G.EncounterDetailsGlobal
|
||||
local edFrame = encounterDetails.Frame
|
||||
|
||||
local phaseFrame = CreateFrame("frame", "EncounterDetailsPhaseFrame", edFrame, "BackdropTemplate")
|
||||
phaseFrame:SetAllPoints()
|
||||
phaseFrame:SetFrameLevel(edFrame:GetFrameLevel()+1)
|
||||
phaseFrame.DamageTable = {}
|
||||
phaseFrame.HealingTable = {}
|
||||
phaseFrame.LastPhaseSelected = 1
|
||||
phaseFrame.CurrentSegment = {}
|
||||
phaseFrame.PhaseButtons = {}
|
||||
EncounterDetailsPhaseFrame:Hide()
|
||||
|
||||
local phaseButtonTemplateHighlight = {
|
||||
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
||||
backdropcolor = {.7, .7, .7, .5},
|
||||
onentercolor = {1, 1, 1, .5},
|
||||
backdropbordercolor = {.70, .70, .70, 1},
|
||||
}
|
||||
|
||||
local phaseButtonTemplate = {
|
||||
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
||||
backdropcolor = {.7, .7, .7, .5},
|
||||
onentercolor = {1, 1, 1, .5},
|
||||
backdropbordercolor = {0, 0, 0, 1},
|
||||
}
|
||||
|
||||
local scrollWidth, scrollHeight, scrollLineAmount, scrollLineHeight = 250, 420, 20, 20
|
||||
local phasesY = -88
|
||||
local anchorY = -120
|
||||
|
||||
phaseFrame:SetScript("OnShow", function()
|
||||
phaseFrame.OnSelectPhase(1)
|
||||
end)
|
||||
|
||||
function phaseFrame:ClearAll()
|
||||
--disable all buttons
|
||||
for i = 1, #phaseFrame.PhaseButtons do
|
||||
phaseFrame.PhaseButtons[i]:SetTemplate(phaseButtonTemplate)
|
||||
phaseFrame.PhaseButtons[i]:Disable()
|
||||
end
|
||||
|
||||
--update damage and healing scrolls
|
||||
wipe(phaseFrame.DamageTable)
|
||||
wipe(phaseFrame.HealingTable)
|
||||
|
||||
--refresh the scroll
|
||||
phaseFrame.Damage_Scroll:Refresh()
|
||||
phaseFrame.Heal_Scroll:Refresh()
|
||||
|
||||
--clear phase bars
|
||||
phaseFrame:ClearPhaseBars()
|
||||
end
|
||||
|
||||
local selectSegment = function(_, _, phaseSelected)
|
||||
phaseFrame["OnSelectPhase"](phaseSelected)
|
||||
end
|
||||
|
||||
function phaseFrame.OnSelectPhase(phaseSelected)
|
||||
|
||||
phaseFrame:ClearAll()
|
||||
|
||||
--get the selected segment
|
||||
phaseFrame.CurrentSegment = encounterDetails:GetCombat(encounterDetails._segment)
|
||||
if (not phaseFrame.CurrentSegment) then
|
||||
return
|
||||
end
|
||||
|
||||
--get the heal and damage for phase selected
|
||||
local phaseData = phaseFrame.CurrentSegment.PhaseData
|
||||
if (not phaseData) then
|
||||
return
|
||||
end
|
||||
|
||||
phaseSelected = phaseSelected or phaseFrame.LastPhaseSelected
|
||||
phaseFrame.LastPhaseSelected = phaseSelected
|
||||
|
||||
local phases = phaseFrame:GetPhaseTimers(phaseFrame.CurrentSegment, true)
|
||||
for buttonIndex, phase in ipairs(phases) do
|
||||
local button = phaseFrame.PhaseButtons[buttonIndex]
|
||||
if (phase == phaseSelected) then
|
||||
button:SetTemplate(phaseButtonTemplateHighlight)
|
||||
else
|
||||
button:SetTemplate(phaseButtonTemplate)
|
||||
if (phaseFrame.CurrentSegment.PhaseData.damage[phase]) then
|
||||
button:Enable()
|
||||
else
|
||||
button:Disable()
|
||||
end
|
||||
end
|
||||
button:SetText(phase)
|
||||
button:SetClickFunction(selectSegment, phase)
|
||||
end
|
||||
|
||||
if (not phaseData.damage[phaseSelected]) then
|
||||
phaseFrame:ClearAll()
|
||||
return
|
||||
end
|
||||
|
||||
--update damage and healing scrolls
|
||||
wipe(phaseFrame.DamageTable)
|
||||
for charName, amount in pairs(phaseData.damage[phaseSelected]) do
|
||||
table.insert(phaseFrame.DamageTable, {charName, amount})
|
||||
end
|
||||
table.sort(phaseFrame.DamageTable, function(a, b) return a[2] > b[2] end)
|
||||
|
||||
wipe(phaseFrame.HealingTable)
|
||||
for charName, amount in pairs(phaseData.heal[phaseSelected]) do
|
||||
table.insert(phaseFrame.HealingTable, {charName, amount})
|
||||
end
|
||||
table.sort(phaseFrame.HealingTable, function(a, b) return a[2] > b[2] end)
|
||||
|
||||
--refresh the scroll
|
||||
phaseFrame.Damage_Scroll:Refresh()
|
||||
phaseFrame.Heal_Scroll:Refresh()
|
||||
|
||||
phaseFrame:UpdatePhaseBars()
|
||||
end
|
||||
|
||||
local PhaseSelectLabel = detailsFramework:CreateLabel(phaseFrame, "Select Phase:", 12, "orange")
|
||||
local DamageLabel = detailsFramework:CreateLabel(phaseFrame, "Damage Done")
|
||||
local HealLabel = detailsFramework:CreateLabel(phaseFrame, "Healing Done")
|
||||
local PhaseTimersLabel = detailsFramework:CreateLabel(phaseFrame, "Time Spent on Each Phase")
|
||||
|
||||
local report_damage = function(IsCurrent, IsReverse, AmtLines)
|
||||
local result = {}
|
||||
local reportFunc = function(IsCurrent, IsReverse, AmtLines)
|
||||
AmtLines = AmtLines + 1
|
||||
if (#result > AmtLines) then
|
||||
for i = #result, AmtLines+1, -1 do
|
||||
table.remove(result, i)
|
||||
end
|
||||
end
|
||||
encounterDetails:SendReportLines(result)
|
||||
end
|
||||
|
||||
table.insert(result, "Details!: Damage for Phase " .. phaseFrame.LastPhaseSelected .. " of " ..(phaseFrame.CurrentSegment and phaseFrame.CurrentSegment.is_boss and phaseFrame.CurrentSegment.is_boss.name or "Unknown") .. ":")
|
||||
for i = 1, #phaseFrame.DamageTable do
|
||||
table.insert(result, encounterDetails:GetOnlyName(phaseFrame.DamageTable[i][1]) .. ": " .. Details:ToK(math.floor(phaseFrame.DamageTable[i][2])))
|
||||
end
|
||||
|
||||
encounterDetails:SendReportWindow(reportFunc, nil, nil, true)
|
||||
end
|
||||
|
||||
local Report_DamageButton = detailsFramework:CreateButton(phaseFrame, report_damage, 16, 16, "report")
|
||||
Report_DamageButton:SetPoint("left", DamageLabel, "left", scrollWidth-44, 0)
|
||||
Report_DamageButton.textcolor = "gray"
|
||||
Report_DamageButton.textsize = 9
|
||||
|
||||
local report_healing = function()
|
||||
local result = {}
|
||||
local reportFunc = function(IsCurrent, IsReverse, AmtLines)
|
||||
AmtLines = AmtLines + 1
|
||||
if (#result > AmtLines) then
|
||||
for i = #result, AmtLines+1, -1 do
|
||||
table.remove(result, i)
|
||||
end
|
||||
end
|
||||
encounterDetails:SendReportLines(result)
|
||||
end
|
||||
|
||||
table.insert(result, "Details!: Healing for Phase " .. phaseFrame.LastPhaseSelected .. " of " ..(phaseFrame.CurrentSegment and phaseFrame.CurrentSegment.is_boss and phaseFrame.CurrentSegment.is_boss.name or "Unknown") .. ":")
|
||||
for i = 1, #phaseFrame.HealingTable do
|
||||
table.insert(result, encounterDetails:GetOnlyName(phaseFrame.HealingTable[i][1]) .. ": " .. Details:ToK(math.floor(phaseFrame.HealingTable[i][2])))
|
||||
end
|
||||
|
||||
encounterDetails:SendReportWindow(reportFunc, nil, nil, true)
|
||||
end
|
||||
local Report_HealingButton = detailsFramework:CreateButton(phaseFrame, report_healing, 16, 16, "report")
|
||||
Report_HealingButton:SetPoint("left", HealLabel, "left", scrollWidth-44, 0)
|
||||
Report_HealingButton.textcolor = "gray"
|
||||
Report_HealingButton.textsize = 9
|
||||
|
||||
|
||||
PhaseSelectLabel:SetPoint("topleft", phaseFrame, "topleft", 10, phasesY)
|
||||
|
||||
DamageLabel:SetPoint("topleft", phaseFrame, "topleft", 10, anchorY)
|
||||
HealLabel:SetPoint("topleft", phaseFrame, "topleft", scrollWidth + 40, anchorY)
|
||||
PhaseTimersLabel:SetPoint("topleft", phaseFrame, "topleft",(scrollWidth * 2) +(40*2), anchorY)
|
||||
|
||||
for i = 1, 10 do
|
||||
local button = detailsFramework:CreateButton(phaseFrame, phaseFrame.OnSelectPhase, 60, 20, "", i)
|
||||
button:SetPoint("left", PhaseSelectLabel, "right", 8 +((i-1) * 61), 0)
|
||||
table.insert(phaseFrame.PhaseButtons, button)
|
||||
end
|
||||
|
||||
|
||||
|
||||
local ScrollRefresh = function(self, data, offset, total_lines)
|
||||
local formatToK = Details:GetCurrentToKFunction()
|
||||
local removeRealm = Details.GetOnlyName
|
||||
|
||||
local topValue = data[1] and data[1][2]
|
||||
|
||||
for i = 1, scrollLineAmount do
|
||||
local index = i + offset
|
||||
local player = data[index]
|
||||
if (player) then
|
||||
local line = self:GetLine(i)
|
||||
local texture, L, R, T, B = Details:GetPlayerIcon(player[1], phaseFrame.CurrentSegment)
|
||||
|
||||
line.icon:SetTexture(texture)
|
||||
line.icon:SetTexCoord(L, R, T, B)
|
||||
line.name:SetText(index .. ". " .. removeRealm(_, player[1]))
|
||||
line.done:SetText(formatToK(_, player[2]) .. " (" .. string.format("%.1f", player[2] / topValue * 100) .. "%)")
|
||||
line.statusbar:SetValue(player[2] / topValue * 100)
|
||||
local actorClass = Details:GetClass(player[1])
|
||||
if (actorClass) then
|
||||
line.statusbar:SetColor(actorClass)
|
||||
else
|
||||
line.statusbar:SetColor("silver")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local onEnterLine = function(self)
|
||||
self:SetBackdropColor(unpack(edTable.defaultBackgroundColor_OnEnter))
|
||||
end
|
||||
|
||||
local onLeaveLine = function(self)
|
||||
self:SetBackdropColor(unpack(edTable.defaultBackgroundColor))
|
||||
end
|
||||
|
||||
local scrollCreateLine = function(self, index)
|
||||
local line = CreateFrame("button", "$parentLine" .. index, self,"BackdropTemplate")
|
||||
line:SetPoint("topleft", self, "topleft", 0, -((index-1)*(scrollLineHeight+1)))
|
||||
line:SetSize(scrollWidth, scrollLineHeight)
|
||||
line:SetScript("OnEnter", onEnterLine)
|
||||
line:SetScript("OnLeave", onLeaveLine)
|
||||
line:SetScript("OnClick", line_onclick)
|
||||
|
||||
line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||
line:SetBackdropColor(unpack(edTable.defaultBackgroundColor))
|
||||
|
||||
local statusBar = detailsFramework:CreateBar(line, encounterDetails.Frame.DefaultBarTexture, 1, 1, 100)
|
||||
statusBar:SetAllPoints(line)
|
||||
statusBar.backgroundtexture = encounterDetails.Frame.DefaultBarTexture
|
||||
statusBar.backgroundcolor = {.3, .3, .3, .3}
|
||||
|
||||
local icon = statusBar:CreateTexture("$parentIcon", "overlay")
|
||||
icon:SetSize(scrollLineHeight, scrollLineHeight)
|
||||
|
||||
local name = statusBar:CreateFontString("$parentName", "overlay", "GameFontNormal")
|
||||
detailsFramework:SetFontSize(name, 10)
|
||||
icon:SetPoint("left", line, "left", 2, 0)
|
||||
name:SetPoint("left", icon, "right", 2, 0)
|
||||
detailsFramework:SetFontColor(name, "white")
|
||||
|
||||
local done = statusBar:CreateFontString("$parentDone", "overlay", "GameFontNormal")
|
||||
detailsFramework:SetFontSize(done, 10)
|
||||
detailsFramework:SetFontColor(done, "white")
|
||||
done:SetPoint("right", line, "right", -2, 0)
|
||||
|
||||
line.icon = icon
|
||||
line.name = name
|
||||
line.done = done
|
||||
line.statusbar = statusBar
|
||||
name:SetHeight(10)
|
||||
name:SetJustifyH("left")
|
||||
return line
|
||||
end
|
||||
|
||||
local damageScroll = detailsFramework:CreateScrollBox(phaseFrame, "$parentDamageScroll", ScrollRefresh, phaseFrame.DamageTable, scrollWidth, scrollHeight, scrollLineAmount, scrollLineHeight)
|
||||
local healScroll = detailsFramework:CreateScrollBox(phaseFrame, "$parentHealScroll", ScrollRefresh, phaseFrame.HealingTable, scrollWidth, scrollHeight, scrollLineAmount, scrollLineHeight)
|
||||
|
||||
damageScroll:SetPoint("topleft", DamageLabel.widget, "bottomleft", 0, -4)
|
||||
healScroll:SetPoint("topleft", HealLabel.widget, "bottomleft", 0, -4)
|
||||
|
||||
detailsFramework:ReskinSlider(damageScroll, 4)
|
||||
detailsFramework:ReskinSlider(healScroll, 4)
|
||||
|
||||
for i = 1, scrollLineAmount do
|
||||
damageScroll:CreateLine(scrollCreateLine)
|
||||
end
|
||||
|
||||
phaseFrame.Damage_Scroll = damageScroll
|
||||
damageScroll:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16})
|
||||
damageScroll:SetBackdropColor(0, 0, 0, .4)
|
||||
|
||||
for i = 1, scrollLineAmount do
|
||||
healScroll:CreateLine(scrollCreateLine)
|
||||
end
|
||||
|
||||
phaseFrame.Heal_Scroll = healScroll
|
||||
healScroll:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16})
|
||||
healScroll:SetBackdropColor(0, 0, 0, .4)
|
||||
|
||||
|
||||
phaseFrame.PhasesBars = {}
|
||||
phaseFrame.PhasesSegmentCompare = {}
|
||||
|
||||
local PhaseBarOnEnter = function(self)
|
||||
phaseFrame:UpdateSegmentCompareBars(self.phase)
|
||||
self:SetBackdropColor(unpack(edTable.defaultBackgroundColor_OnEnter))
|
||||
end
|
||||
|
||||
local PhaseBarOnLeave = function(self)
|
||||
phaseFrame:ClearSegmentCompareBars()
|
||||
self:SetBackdropColor(unpack(edTable.defaultBackgroundColor))
|
||||
end
|
||||
|
||||
local PhaseBarOnClick = function(self)
|
||||
--report
|
||||
end
|
||||
|
||||
--cria as linhas mostrando o tempo decorride de cada phase
|
||||
for i = 1, 10 do
|
||||
local line = CreateFrame("button", "$parentPhaseBar" .. i, phaseFrame,"BackdropTemplate")
|
||||
line:SetPoint("topleft", PhaseTimersLabel.widget, "bottomleft", 0, -((i-1)*(31)) - 4)
|
||||
line:SetSize(175, 30)
|
||||
line:SetScript("OnEnter", PhaseBarOnEnter)
|
||||
line:SetScript("OnLeave", PhaseBarOnLeave)
|
||||
line:SetScript("OnClick", PhaseBarOnClick)
|
||||
|
||||
line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||
line:SetBackdropColor(unpack(edTable.defaultBackgroundColor))
|
||||
|
||||
local icon = line:CreateTexture("$parentIcon", "overlay")
|
||||
icon:SetSize(16, 16)
|
||||
icon:SetTexture([[Interface\AddOns\Details\images\clock]])
|
||||
local name = line:CreateFontString("$parentName", "overlay", "GameFontNormal")
|
||||
detailsFramework:SetFontSize(name, 10)
|
||||
local done = line:CreateFontString("$parentDone", "overlay", "GameFontNormal")
|
||||
detailsFramework:SetFontSize(done, 10)
|
||||
|
||||
icon:SetPoint("left", line, "left", 2, 0)
|
||||
name:SetPoint("left", icon, "right", 2, 0)
|
||||
done:SetPoint("right", line, "right", -3, 0)
|
||||
|
||||
line.icon = icon
|
||||
line.name = name
|
||||
line.done = done
|
||||
name:SetHeight(10)
|
||||
name:SetJustifyH("left")
|
||||
|
||||
table.insert(phaseFrame.PhasesBars, line)
|
||||
end
|
||||
|
||||
--cria a linha do segmento para a compara��o, � o que fica na parte direita da tela
|
||||
--ele � acessado para mostrar quando passar o mouse sobre uma das barras de phase
|
||||
for i = 1, 20 do
|
||||
local line = CreateFrame("button", "$parentSegmentCompareBar" .. i, phaseFrame,"BackdropTemplate")
|
||||
line:SetPoint("topleft", PhaseTimersLabel.widget, "bottomleft", 175+10, -((i-1)*(scrollLineHeight+1)) - 4)
|
||||
line:SetSize(150, scrollLineHeight)
|
||||
|
||||
line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||
line:SetBackdropColor(unpack(edTable.defaultBackgroundColor))
|
||||
line:Hide()
|
||||
local name = line:CreateFontString("$parentName", "overlay", "GameFontNormal")
|
||||
detailsFramework:SetFontSize(name, 9)
|
||||
name:SetPoint("left", line, "left", 2, 0)
|
||||
|
||||
local done = line:CreateFontString("$parentDone", "overlay", "GameFontNormal")
|
||||
detailsFramework:SetFontSize(done, 9)
|
||||
done:SetPoint("right", line, "right", -2, 0)
|
||||
|
||||
line.name = name
|
||||
line.done = done
|
||||
name:SetHeight(10)
|
||||
name:SetJustifyH("left")
|
||||
|
||||
table.insert(phaseFrame.PhasesSegmentCompare, line)
|
||||
end
|
||||
|
||||
function phaseFrame:ClearPhaseBars()
|
||||
for i = 1, #phaseFrame.PhasesBars do
|
||||
local bar = phaseFrame.PhasesBars[i]
|
||||
bar.name:SetText("")
|
||||
bar.done:SetText("")
|
||||
bar.phase = nil
|
||||
bar:Hide()
|
||||
end
|
||||
end
|
||||
function phaseFrame:ClearSegmentCompareBars()
|
||||
for i = 1, #phaseFrame.PhasesSegmentCompare do
|
||||
phaseFrame.PhasesSegmentCompare[i]:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
function phaseFrame:GetPhaseTimers(segment, ordered)
|
||||
local t = {}
|
||||
|
||||
segment = segment or phaseFrame.CurrentSegment
|
||||
|
||||
for phaseIT = 1, #segment.PhaseData do
|
||||
local phase, startAt = unpack(segment.PhaseData[phaseIT]) --phase iterator
|
||||
local endAt = segment.PhaseData[phaseIT+1] and segment.PhaseData[phaseIT+1][2] or segment:GetCombatTime()
|
||||
local elapsed = endAt - startAt
|
||||
t[phase] = (t[phase] or 0) + elapsed
|
||||
end
|
||||
|
||||
if (ordered) then
|
||||
local order = {}
|
||||
for phase, _ in pairs(t) do
|
||||
table.insert(order, phase)
|
||||
end
|
||||
table.sort(order, function(a, b) return a < b end)
|
||||
return order, t
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
--executa quando atualizar o segment geral
|
||||
function phaseFrame:UpdatePhaseBars()
|
||||
local timers, hash = phaseFrame:GetPhaseTimers(phaseFrame.CurrentSegment, true)
|
||||
local i = 1
|
||||
for index, phase in ipairs(timers) do
|
||||
local timer = hash[phase]
|
||||
phaseFrame.PhasesBars[i].name:SetText("|cFFC0C0C0Phase:|r |cFFFFFFFF" .. phase)
|
||||
phaseFrame.PhasesBars[i].done:SetText(detailsFramework:IntegerToTimer(timer))
|
||||
phaseFrame.PhasesBars[i].phase = phase
|
||||
phaseFrame.PhasesBars[i]:Show()
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
--executa quando passar o mouse sobre uma bnarra de phase
|
||||
function phaseFrame:UpdateSegmentCompareBars(phase)
|
||||
--segmento atual(numero)
|
||||
local segmentNumber = encounterDetails._segment
|
||||
local segmentTable = phaseFrame.CurrentSegment
|
||||
local bossID = segmentTable:GetBossInfo() and segmentTable:GetBossInfo().id
|
||||
|
||||
local index = 1
|
||||
for i, segment in ipairs(Details:GetCombatSegments()) do
|
||||
if (segment:GetBossInfo() and segment:GetBossInfo().id == bossID) then
|
||||
|
||||
local bar = phaseFrame.PhasesSegmentCompare [index]
|
||||
local timers = phaseFrame:GetPhaseTimers(segment)
|
||||
|
||||
if (timers [phase]) then
|
||||
if (segment ~= segmentTable) then
|
||||
bar.name:SetText("Segment " .. i .. ":")
|
||||
detailsFramework:SetFontColor(bar.name, "orange")
|
||||
bar.done:SetText(detailsFramework:IntegerToTimer(timers [phase]))
|
||||
detailsFramework:SetFontColor(bar.done, "orange")
|
||||
else
|
||||
bar.name:SetText("Segment " .. i .. ":")
|
||||
detailsFramework:SetFontColor(bar.name, "white")
|
||||
bar.done:SetText(detailsFramework:IntegerToTimer(timers [phase]))
|
||||
detailsFramework:SetFontColor(bar.done, "white")
|
||||
end
|
||||
else
|
||||
bar.name:SetText("Segment " .. i .. ":")
|
||||
detailsFramework:SetFontColor(bar.name, "red")
|
||||
bar.done:SetText("--x--x--")
|
||||
end
|
||||
|
||||
bar:Show()
|
||||
index = index + 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
## Interface: 100100
|
||||
## Interface: 100105
|
||||
## Title: Details!: Raid Check (plugin)
|
||||
## Notes: Show talents and item level for all members in your group, also shows food and flask state.
|
||||
## RequiredDeps: Details
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Interface: 100100
|
||||
## Interface: 100105
|
||||
## Title: Details!: Streamer (plugin)
|
||||
## Notes: Show which spells you are casting, viewers can see what are you doing and follow your steps.
|
||||
## RequiredDeps: Details
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
## Interface: 100100
|
||||
## Interface: 100105
|
||||
## Title: Details!: Tiny Threat (plugin)
|
||||
## Notes: Threat meter plugin, show threat for group members in the window. Select it from the Plugin menu in the Orange Cogwheel.
|
||||
## RequiredDeps: Details
|
||||
## OptionalDeps: Ace3
|
||||
## IconTexture: Interface\AddOns\Details\images\minimap
|
||||
|
||||
## X-Wago-ID: Rn6VJW6d
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Interface: 100100
|
||||
## Interface: 100105
|
||||
## Title: Details!: Vanguard (plugin)
|
||||
## Notes: Show the health and debuffs for tanks in your group.
|
||||
## SavedVariablesPerCharacter: _detalhes_databaseVanguard
|
||||
|
||||
Reference in New Issue
Block a user