Backport of 5.19.1

More Information can be found on the Discord
This commit is contained in:
NoM0Re
2025-02-18 18:20:19 +01:00
committed by GitHub
300 changed files with 58850 additions and 58990 deletions
+24
View File
@@ -0,0 +1,24 @@
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[{babelfish.lua,ForAllIndentsAndPurposes.lua}]
indent_style = space
indent_size = 4
[.luacheckrc]
indent_style = tab
indent_size = 4
[{*.pkgmeta,*.pkgmeta-classic}]
indent_style = space
indent_size = 2
+7 -1
View File
@@ -7,6 +7,12 @@
*ISSUE_TEMPLATE.md export-ignore
*readme.md export-ignore
*README.md export-ignore
*README.textile export-ignore
*CODE_OF_CONDUCT.md export-ignore
*LICENSE export-ignore
*LICENSE.md export-ignore
*LICENSE.txt export-ignore
*CONTRIBUTING.md export-ignore
* text=auto
@@ -30,4 +36,4 @@
# Textures
*.blp binary
*.tga binary
*.tga binary
+14
View File
@@ -0,0 +1,14 @@
# These are supported funding model platforms
github: [NoM0Re] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: https://streamelements.com/noom0re/tip
-40
View File
@@ -1,40 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
## Describe the bug
<!-- What did you expect to happen and what happened instead? -->
**Do you have an error log of what happened?**
<!-- If you don't see any errors, make sure that error reporting is enabled (`/console scriptErrors 1`) or install https://www.curseforge.com/wow/addons/bugsack & https://www.curseforge.com/wow/addons/bug-grabber, yes both are needed.
Note that if the error looks like `[string "--[[ Error in ' my awesome aura' ]` then the bug is in the aura that got mentioned, not in WeakAuras itself -->
```
PASTE ERROR HERE
```
### To Reproduce
<!-- Describe what you clicked or did when the problem occurred -->
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Which version of WeakAuras are you using?**
<!-- You can see the current version in the title bar of the options window, if the options do not open, check the Twitch app or the `## Version:` field in the WeakAuras.toc file -->
### Additional Info
<!--
If you do not know which aura is causing issues for you, please attach a ZIP archive of your WeakAuras SavedVariables file, it's the `WeakAuras.lua` file in `World of Warcraft\_retail_\WTF\Account\YOUR_ACCOUNT\SavedVariables\`. In case you do, please export the string and paste it below.
-->
+116
View File
@@ -0,0 +1,116 @@
name: "Bug Report"
description: Create a report to help us improve
labels: ['🐛 Bug']
type: Bug
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please [search for existing issues](https://github.com/NoM0Re/WeakAuras-WotLK/issues) to see if an open or closed one already exists for the bug you encountered. If a bug exists and it is closed as complete it may not yet be in a stable release.
options:
- label: I have searched the existing open and closed issues.
required: true
- type: textarea
attributes:
label: Description
description: What did you expect to happen and what happened instead?
validations:
required: true
- type: input
attributes:
label: WeakAuras Version
description: |
You can see the current version in the title bar of the options window, if the options do not open, check the `## Version:` field in the WeakAuras.toc file.
placeholder: "WeakAuras 5.0.0"
validations:
required: true
- type: dropdown
id: flavor
attributes:
label: World of Warcraft Flavor
description: What version of World of Warcraft are are you running?
options:
- WotLK 3.3.5a
validations:
required: true
- type: dropdown
id: language
attributes:
label: World of Warcraft Language
description: In which language do you play World of Warcraft?
options:
- enGB/enUS
- deDE
- frFR
- itIT
- esES
- esMX
- koKR
- ptBR
- ruRU
- zhCN
- zhTW
validations:
required: true
- type: checkboxes
id: testing
attributes:
label: Tested with only WeakAuras
description: Sometimes, other addons can interfere with WeakAuras. We recommend testing with only WeakAuras enabled to see if the issue persists.
options:
- label: I got this issue with only WeakAuras enabled
required: true
- type: textarea
attributes:
label: Lua Error
description: |
Do you have an error log of what happened? If you don't see any errors, make sure that error reporting is enabled (`/console scriptErrors 1`) or install [BugSack](https://www.curseforge.com/wow/addons/bugsack) & [BugGrabber](https://www.curseforge.com/wow/addons/bug-grabber), yes both are needed.
Note that if the error looks like `[string "--[[ Error in ' my awesome aura' ]` then the bug is in the aura that got mentioned, not in WeakAuras itself.
render: Text
validations:
required: false
- type: textarea
attributes:
label: Reproduction Steps
description: Please list out the steps to reproduce your bug. Please verify that your reproduction steps are enough to reproduce the problem.
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
- type: input
attributes:
label: Last Good Version
description: |
Was it working in a previous version? If yes, which was the last good one?
placeholder: "WeakAuras 5.0.0"
validations:
required: false
- type: textarea
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
placeholder: Click here to attach your screenshots via the editor button in the top right.
validations:
required: false
- type: textarea
attributes:
label: Export String
description: If you do not know which aura is causing issues for you, please attach a ZIP archive of your WeakAuras SavedVariables file, it's the `WeakAuras.lua` file in `World of Warcraft\_retail_\WTF\Account\YOUR_ACCOUNT\SavedVariables\`. In case you do, please export the string and paste it below.
placeholder: Paste your exported WeakAuras string here.
render: Text
validations:
required: false
+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Question
url: https://discord.gg/UXSc7nt
about: Please ask and answer questions here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: "\U0001F3A8 Feature Request"
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+4 -4
View File
@@ -11,14 +11,14 @@ jobs:
env:
LUA_VERSION: 5.1.5
LUAROCKS_VERSION: 2.4.2
LUAROCKS_VERSION: 3.11.1
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Cache Lua
uses: actions/cache@v1
uses: actions/cache@v3
id: luacache
with:
path: .lua
@@ -27,7 +27,7 @@ jobs:
${{ runner.os }}-lua-${{ env.LUA_VERSION }}
- name: Cache LuaRocks
uses: actions/cache@v1
uses: actions/cache@v3
id: luarockscache
with:
path: .luarocks
+4 -4
View File
@@ -12,14 +12,14 @@ jobs:
env:
LUA_VERSION: 5.1.5
LUAROCKS_VERSION: 2.4.2
LUAROCKS_VERSION: 3.11.1
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Cache Lua
uses: actions/cache@v1
uses: actions/cache@v3
id: luacache
with:
path: .lua
@@ -28,7 +28,7 @@ jobs:
${{ runner.os }}-lua-${{ env.LUA_VERSION }}
- name: Cache LuaRocks
uses: actions/cache@v1
uses: actions/cache@v3
id: luarockscache
with:
path: .luarocks
+17818 -40432
View File
File diff suppressed because it is too large Load Diff
+76
View File
@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at staneck@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
+104
View File
@@ -0,0 +1,104 @@
# Contributing to WeakAuras
## Code Standards
There are a few things which we require in any contribution:
- This repository comes with a `.editorconfig` file, so the following requirements will be taken care of if you have [EditorConfig](https://editorconfig.org/) installed:
- Tabs consist of 2 spaces.
- Files end with a newline.
- No trailing whitespace at the end of a line.
- All user-facing strings (`names` and `desc` fields in AceConfig tables, mostly) must be localized:
- We use a locale scraper to find translation phrases and automatically export them to CurseForge for translation. This scraper parses the addon files, looking for tokens that look like: `L["some translation phrase"]`. You must use double quoted strings, and name the localization table (found at `WeakAuras.L`) `L` in your code for this to work properly.
- When writing a new file, avoid using semicolons. When modifying code in an existing file, try to be consistent, but err on the side of no semicolons.
- New features should be indicated by concatenating `WeakAuras.newFeatureString` onto the associated translation phrase. We will remove the new feature indicator approximately 3 months after the first release.
## Pull Requests
If you want to help, here's what you need to do:
1. Make sure you have a [GitHub account](https://github.com/signup/free).
1. [Fork](https://github.com/WeakAuras/WeakAuras2/fork) our repository.
1. Create a new topic branch (based on the `main` branch) to contain your feature, change, or fix.
```bash
git checkout -b my-topic-branch
```
1. Set `core.autocrlf` to true.
```bash
git config core.autocrlf true
```
1. Set `pull.rebase`to true.
```bash
git config pull.rebase true
```
1. Set up your [Git identity](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup) so your commits are attributed to your name and email address properly.
1. Take a look at our [Wiki](https://github.com/WeakAuras/WeakAuras2/wiki/Lua-Dev-Environment) page on how to setup a Lua dev environment.
1. Install an [EditorConfig](https://editorconfig.org/) plugin for your text editor to automatically follow our indenting rules.
1. Commit and push your changes to your new branch.
```bash
git commit -a -m "commit-description"
git push
```
1. [Open a Pull Request](https://github.com/WeakAuras/WeakAuras2/pulls) with a clear title and description.
### Keeping your fork updated
- Specify a new remote upstream repository that will be used to sync your fork (you only need to do this once).
```bash
git remote add upstream https://github.com/WeakAuras/WeakAuras2.git
```
- In order to sync your fork with the upstream WeakAuras repository you would do
```bash
git fetch upstream
git checkout main
git rebase upstream/main
```
- You are now all synced up.
### Keeping your pull request updated
- In order to sync your pull request with the upstream WeakAuras repository in case there are any conflicts you would do
```bash
git fetch upstream
git checkout my-topic-branch
git rebase upstream/main
```
- In case there are any conflicts, you will now have to [fix them manually](https://help.github.com/articles/resolving-merge-conflicts-after-a-git-rebase/).
- After you're done with that, you are ready to force-push your changes.
```bash
git push --force
```
- Note: Force-pushing is a destructive operation, so make sure you don't lose something in the progress.
- If you want to know more about force-pushing and why we do it, there are a two good posts about it: one by [Atlassian](https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing) and one on [Reddit](https://www.reddit.com/r/git/comments/6jzogp/why_am_i_force_pushing_after_a_rebase/).
- Your pull request should now have no conflicts and be ready for review and merging.
## Reporting Issues and Requesting Features
1. Please check our [issue tracker](https://github.com/WeakAuras/WeakAuras2/issues) for your problem since there's a good
chance that someone has already reported it.
1. If you find a match, please try to provide as much info as you can,
so that we have a better picture about what the real problem is and how to fix it ASAP.
1. If you didn't find any tickets with a problem similar to yours then please open a
[new ticket](https://github.com/WeakAuras/WeakAuras2/issues/new/choose).
- Be descriptive as much as you can.
- Provide everything the template text asks you for.
+30 -2
View File
@@ -1,4 +1,11 @@
# WeakAuras 2 WotLK (3.3.5a)
<div align="center">
# WeakAuras WotLK (3.3.5a)
[![Discord](https://img.shields.io/discord/259362419372064778?style=flat&logo=discord&label=Discord)](https://discord.gg/UXSc7nt) [![Wiki](https://img.shields.io/badge/wiki-grey?style=flat&logo=github)](https://github.com/NoM0Re/WeakAuras-WotLK/wiki) [![GitHub Issues](https://img.shields.io/github/issues/NoM0Re/WeakAuras-WotLK)](https://github.com/NoM0Re/WeakAuras-WotLK/issues) [![PayPal](https://img.shields.io/badge/Buy_me_a_coffee-100000?style=flat&logo=PayPal&logoColor=white&labelColor=3b7bbf&color=grey)](https://streamelements.com/noom0re/tip)
![Logo](https://i.imgur.com/wwbxeCG.jpeg)
</div>
WeakAuras is a powerful and flexible framework that allows the display of highly customizable graphics on World of Warcraft's user interface to indicate buffs, debuffs, and other relevant information. This addon was created to be a lightweight replacement for Power Auras but has since introduced more functionalities while remaining efficient and easy to use.
@@ -18,6 +25,27 @@ WeakAuras is a powerful and flexible framework that allows the display of highly
To open the options window, type `/wa` or `/weakauras` into your chat and hit enter or use the minimap icon.
## Extensions
* [WeakAuras Companion](https://weakauras.wtf): This application adds the missing link between Wago.io and the World of Warcraft addon, enabling you to update your auras in a convenient fashion. (Folder Structure: `World of Warcraft/_retail_/Wow.exe` and backup WTF)
* [WeakAuras_StopMotion](https://www.curseforge.com/wow/addons/weakauras-stop-motion): This addon adds a new region type to WeakAuras that allows for stop motion animations. Stop Motion textures contain each frame of the animation as a separate image. The addon ships with a number of animations and it supports custom textures.
* [SharedMedia](https://github.com/bkader/SharedMedia) for more bar textures.
* [SharedMediaAdditionalFonts](https://drive.google.com/file/d/1xDCpDpStRbXdSBKYOeZHpYBt_dRDqb3g/view?usp=sharing) for more fonts.
* [ColorPickerPlus](https://drive.google.com/file/d/1ymNYizWp2TxIS1a6hLg7bT9YoJ3E-8Na/view?usp=sharing) for a better version of the WoW color picker that includes class color templates and a copy and paste function.
## Documentation
For in-depth documentation, see the [wiki](https://github.com/WeakAuras/WeakAuras2/wiki) page.
For in-depth documentation, see the [wiki](https://github.com/NoM0Re/WeakAuras-WotLK/wiki) page.
## Examples
For some examples of what WeakAuras can do, take a look at [wago.io](https://wago.io/search/imports/wow/all?q=3.3.5) where tons of people upload their creations and even feature complete interfaces utilizing WeakAuras!
## Problems
* Please see the [wiki](https://github.com/NoM0Re/WeakAuras-WotLK/wiki) page.
* If you've discovered something that's clearly wrong, or if you get an error, please create a [ticket](https://github.com/NoM0Re/WeakAuras-WotLK/issues).
* You're a programmer yourself and want to contribute? Check out our [contributing guidelines](CONTRIBUTING.md) to get started!
* Feel free to join our [Discord Community](https://discord.gg/UXSc7nt) to talk, get help and discuss everything WeakAuras!
+72
View File
@@ -0,0 +1,72 @@
--- @type string, Private
local AddonName, Private = ...
--- @type table<auraId, auraId>
local attachedToTarget = {}
--- @type table<auraId, table<auraId, boolean>>
local targetToAttached = {}
-- Handles
--- @type fun(_: any, uid: uid, id: auraId)
local function OnDelete(_, uid, id)
local target = attachedToTarget[id]
if target then
if targetToAttached[target] then
targetToAttached[target][id] = nil
end
attachedToTarget[id] = nil
end
end
--- @type fun(_: any, uid: uid, oldId: auraId, newId: auraId)
local function OnRename(_, uid, oldId, newId)
local target = attachedToTarget[oldId]
if target then
-- renamed aura is an attached aura
attachedToTarget[newId] = attachedToTarget[oldId]
attachedToTarget[oldId] = nil
targetToAttached[target][oldId] = nil
targetToAttached[target][newId] = true
end
-- renamed aura is a targeted aura
if targetToAttached[oldId] then
for attached in pairs(targetToAttached[oldId]) do
local data = WeakAuras.GetData(attached)
if data then
data.anchorFrameFrame = "WeakAuras:" .. newId
WeakAuras.Add(data, true)
end
attachedToTarget[attached] = newId
end
targetToAttached[newId] = targetToAttached[oldId]
targetToAttached[oldId] = nil
end
end
--- @type fun(_: any, uid: uid, id: auraId, data: auraData, simpleChange: boolean)
local function OnAdd(_, uid, id, data, simpleChange)
if simpleChange then
return
end
OnDelete(nil, uid, id)
if data.anchorFrameType == "SELECTFRAME"
and data.anchorFrameFrame
and data.anchorFrameFrame:sub(1, 10) == "WeakAuras:"
then
local target = data.anchorFrameFrame:sub(11)
attachedToTarget[data.id] = target
targetToAttached[target] = targetToAttached[target] or {}
targetToAttached[target][data.id] = true
end
end
Private.callbacks:RegisterCallback("Delete", OnDelete)
Private.callbacks:RegisterCallback("Rename", OnRename)
Private.callbacks:RegisterCallback("Add", OnAdd)
+186 -162
View File
@@ -1,5 +1,6 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L
-- Animations
local animations = {}
@@ -8,13 +9,178 @@ local anim_function_strings = Private.anim_function_strings;
local function noopErrorHandler() end
local frame = WeakAuras.frames["WeakAuras Main Frame"]
local function RunAnimation(key, anim, elapsed, time)
Private.StartProfileUID(anim.auraUID)
local finished = false
if(anim.duration_type == "seconds") then
if anim.duration > 0 then
anim.progress = anim.progress + (elapsed / anim.duration)
else
anim.progress = anim.progress + (elapsed / 1)
end
if(anim.progress >= 1) then
anim.progress = 1
finished = true
end
elseif(anim.duration_type == "relative") then
local region = anim.region
if ((region.progressType == "timed" and region.duration < 0.01)
or (region.progressType == "static" and region.value < 0.01))
then
anim.progress = 0
if(anim.type == "start" or anim.type == "finish") then
finished = true
end
else
local relativeProgress = 0
if(region.progressType == "static") then
relativeProgress = region.value / region.total
elseif (region.progressType == "timed") then
relativeProgress = 1 - ((region.expirationTime - time) / region.duration)
end
relativeProgress = region.inverse and (1 - relativeProgress) or relativeProgress
anim.progress = anim.duration > 0 and relativeProgress / anim.duration or 0
local iteration = math.floor(anim.progress)
--anim.progress = anim.progress - iteration
if not(anim.iteration) then
anim.iteration = iteration
elseif(anim.iteration ~= iteration) then
anim.iteration = nil
finished = true
end
end
else
anim.progress = 1
end
local progress = anim.inverse and (1 - anim.progress) or anim.progress
progress = anim.easeFunc(progress, anim.easeStrength or 3)
Private.ActivateAuraEnvironmentForRegion(anim.region)
if(anim.translateFunc) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Slide Animation"])
if (anim.region.SetOffsetAnim) then
local ok, x, y = pcall(anim.translateFunc, progress, 0, 0, anim.dX, anim.dY)
if not ok then
errorHandler()
else
anim.region:SetOffsetAnim(x, y)
end
else
anim.region:ClearAllPoints()
local ok, x, y = pcall(anim.translateFunc, progress, anim.startX, anim.startY, anim.dX, anim.dY)
if not ok then
errorHandler()
else
anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, x, y)
end
end
end
if(anim.alphaFunc) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or Private.GetErrorHandlerUid(anim.auraUID, L["Fade Animation"])
local ok, alpha = pcall(anim.alphaFunc, progress, anim.startAlpha, anim.dAlpha)
if not ok then
errorHandler()
else
if (anim.region.SetAnimAlpha) then
anim.region:SetAnimAlpha(alpha)
else
anim.region:SetAlpha(alpha)
end
end
end
if(anim.scaleFunc) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler
or Private.GetErrorHandlerUid(anim.auraUID, L["Zoom Animation"])
local ok, scaleX, scaleY = pcall(anim.scaleFunc, progress, 1, 1, anim.scaleX, anim.scaleY)
if not ok then
errorHandler()
else
if(anim.region.Scale) then
anim.region:Scale(scaleX, scaleY)
else
anim.region:SetWidth(anim.startWidth * scaleX)
anim.region:SetHeight(anim.startHeight * scaleY)
end
end
end
if(anim.rotateFunc and anim.region.Rotate) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler
or Private.GetErrorHandlerUid(anim.auraUID, L["Rotate Animation"])
local ok, rotate = pcall(anim.rotateFunc, anim.rotateFunc, progress, anim.startRotation, anim.rotate)
if not ok then
errorHandler()
else
anim.region:Rotate(rotate)
end
end
if(anim.colorFunc and anim.region.ColorAnim) then
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler
or Private.GetErrorHandlerUid(anim.auraUID, L["Color Animation"])
local startR, startG, startB, startA = anim.region:GetColor()
startR, startG, startB, startA = startR or 1, startG or 1, startB or 1, startA or 1
local ok, r, g, b, a = pcall(anim.colorFunc, progress, startR, startG, startB, startA,
anim.colorR, anim.colorG, anim.colorB, anim.colorA)
if not ok then
errorHandler()
else
local errorHandler = Private.GetErrorHandlerId(anim.region.id, "Custom Color")
local success = pcall(anim.region.ColorAnim, anim.region, r, g, b, a)
if not success then
errorHandler()
end
end
end
Private.ActivateAuraEnvironment(nil)
if(finished) then
if not(anim.loop) then
if (anim.region.SetOffsetAnim) then
anim.region:SetOffsetAnim(0, 0)
else
if(anim.startX) then
anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, anim.startX, anim.startY)
end
end
if (anim.region.SetAnimAlpha) then
anim.region:SetAnimAlpha(nil)
elseif(anim.startAlpha) then
anim.region:SetAlpha(anim.startAlpha)
end
if(anim.startWidth) then
if(anim.region.Scale) then
anim.region:Scale(1, 1)
else
anim.region:SetWidth(anim.startWidth)
anim.region:SetHeight(anim.startHeight)
end
end
if(anim.startRotation) then
if(anim.region.Rotate) then
anim.region:Rotate(anim.startRotation);
end
end
if(anim.region.ColorAnim) then
anim.region:ColorAnim(nil)
end
animations[key] = nil
end
if(anim.loop) then
Private.Animate(anim.namespace, anim.auraUID, anim.type, anim.anim, anim.region, anim.inverse, anim.onFinished,
anim.loop, anim.region.cloneId)
elseif(anim.onFinished) then
anim.onFinished()
end
end
Private.StopProfileUID(anim.auraUID)
end
local updatingAnimations;
local last_update = GetTime();
local function UpdateAnimations()
if not updatingAnimations then
return
end
Private.StartProfileSystem("animations");
local errorHandler = WeakAuras.IsOptionsOpen() and noopErrorHandler or geterrorhandler()
for groupUid, groupRegion in pairs(pending_controls) do
pending_controls[groupUid] = nil;
groupRegion:DoPositionChildren();
@@ -23,169 +189,27 @@ local function UpdateAnimations()
local time = GetTime();
local elapsed = time - last_update;
last_update = time;
local num = 0;
for key, anim in pairs(animations) do
Private.StartProfileUID(anim.auraUID);
num = num + 1;
local finished = false;
if(anim.duration_type == "seconds") then
if anim.duration > 0 then
anim.progress = anim.progress + (elapsed / anim.duration);
else
anim.progress = anim.progress + (elapsed / 1);
end
if(anim.progress >= 1) then
anim.progress = 1;
finished = true;
end
elseif(anim.duration_type == "relative") then
local state = anim.region.state;
if (not state
or (state.progressType == "timed" and state.duration < 0.01)
or (state.progressType == "static" and state.value < 0.01)) then
anim.progress = 0;
if(anim.type == "start" or anim.type == "finish") then
finished = true;
end
else
local relativeProgress = 0;
if(state.progressType == "static") then
relativeProgress = state.value / state.total;
elseif (state.progressType == "timed") then
relativeProgress = 1 - ((state.expirationTime - time) / state.duration);
end
relativeProgress = state.inverse and (1 - relativeProgress) or relativeProgress;
anim.progress = anim.duration > 0 and relativeProgress / anim.duration or 0
local iteration = math.floor(anim.progress);
--anim.progress = anim.progress - iteration;
if not(anim.iteration) then
anim.iteration = iteration;
elseif(anim.iteration ~= iteration) then
anim.iteration = nil;
finished = true;
end
end
else
anim.progress = 1;
end
local progress = anim.inverse and (1 - anim.progress) or anim.progress;
progress = anim.easeFunc(progress, anim.easeStrength or 3)
Private.ActivateAuraEnvironmentForRegion(anim.region)
if(anim.translateFunc) then
if (anim.region.SetOffsetAnim) then
local ok, x, y = pcall(anim.translateFunc, progress, 0, 0, anim.dX, anim.dY);
if not ok then
errorHandler(x)
else
anim.region:SetOffsetAnim(x, y);
end
else
anim.region:ClearAllPoints();
local ok, x, y = pcall(anim.translateFunc, progress, anim.startX, anim.startY, anim.dX, anim.dY);
if not ok then
errorHandler(x)
else
anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, x, y);
end
end
end
if(anim.alphaFunc) then
local ok, alpha = pcall(anim.alphaFunc, progress, anim.startAlpha, anim.dAlpha);
if not ok then
errorHandler(alpha)
else
if (anim.region.SetAnimAlpha) then
anim.region:SetAnimAlpha(alpha);
else
anim.region:SetAlpha(alpha);
end
end
end
if(anim.scaleFunc) then
local ok, scaleX, scaleY = pcall(anim.scaleFunc, progress, 1, 1, anim.scaleX, anim.scaleY);
if not ok then
errorHandler(scaleX)
else
if(anim.region.Scale) then
anim.region:Scale(scaleX, scaleY);
else
anim.region:SetWidth(anim.startWidth * scaleX);
anim.region:SetHeight(anim.startHeight * scaleY);
end
end
end
if(anim.rotateFunc and anim.region.Rotate) then
local ok, rotate = pcall(anim.rotateFunc, progress, anim.startRotation, anim.rotate);
if not ok then
errorHandler(rotate)
else
anim.region:Rotate(rotate);
end
end
if(anim.colorFunc and anim.region.ColorAnim) then
local startR, startG, startB, startA = anim.region:GetColor();
startR, startG, startB, startA = startR or 1, startG or 1, startB or 1, startA or 1;
local ok, r, g, b, a = pcall(anim.colorFunc, progress, startR, startG, startB, startA, anim.colorR, anim.colorG, anim.colorB, anim.colorA);
if not ok then
errorHandler(r)
else
anim.region:ColorAnim(r, g, b, a);
end
end
Private.ActivateAuraEnvironment(nil);
if(finished) then
if not(anim.loop) then
if (anim.region.SetOffsetAnim) then
anim.region:SetOffsetAnim(0, 0);
else
if(anim.startX) then
anim.region:SetPoint(anim.selfPoint, anim.anchor, anim.anchorPoint, anim.startX, anim.startY);
end
end
if (anim.region.SetAnimAlpha) then
anim.region:SetAnimAlpha(nil);
elseif(anim.startAlpha) then
anim.region:SetAlpha(anim.startAlpha);
end
if(anim.startWidth) then
if(anim.region.Scale) then
anim.region:Scale(1, 1);
else
anim.region:SetWidth(anim.startWidth);
anim.region:SetHeight(anim.startHeight);
end
end
if(anim.startRotation) then
if(anim.region.Rotate) then
anim.region:Rotate(anim.startRotation);
end
end
if(anim.region.ColorAnim) then
anim.region:ColorAnim(nil);
end
animations[key] = nil;
end
if(anim.loop) then
Private.Animate(anim.namespace, anim.auraUID, anim.type, anim.anim, anim.region, anim.inverse, anim.onFinished, anim.loop, anim.region.cloneId);
elseif(anim.onFinished) then
anim.onFinished();
end
end
Private.StopProfileUID(anim.auraUID);
for key, anim in pairs(animations) do
RunAnimation(key, anim, elapsed, time)
end
Private.StopProfileSystem("animations");
end
local frame = CreateFrame("Frame")
Private.frames["WeakAuras Animation Frame"] = frame
frame:SetScript("OnUpdate", UpdateAnimations)
function Private.RegisterGroupForPositioning(uid, region)
pending_controls[uid] = region
updatingAnimations = true
frame:SetScript("OnUpdate", UpdateAnimations)
if not updatingAnimations then
updatingAnimations = true
last_update = GetTime()
end
end
function Private.Animate(namespace, uid, type, anim, region, inverse, onFinished, loop, cloneId)
local auraDisplayName = Private.UIDtoID(uid)
local key = tostring(region);
local valid;
if(anim and anim.type == "custom" and (anim.use_translate or anim.use_alpha or (anim.use_scale and region.Scale) or (anim.use_rotate and region.Rotate) or (anim.use_color and region.Color))) then
@@ -240,7 +264,7 @@ function Private.Animate(namespace, uid, type, anim, region, inverse, onFinished
anim.translateFunc = anim_function_strings[anim.translateType]
end
if (anim.translateFunc) then
translateFunc = WeakAuras.LoadFunction("return " .. anim.translateFunc, auraDisplayName, "translate animation");
translateFunc = WeakAuras.LoadFunction("return " .. anim.translateFunc);
else
if (region.SetOffsetAnim) then
region:SetOffsetAnim(0, 0);
@@ -261,7 +285,7 @@ function Private.Animate(namespace, uid, type, anim, region, inverse, onFinished
anim.alphaFunc = anim_function_strings[anim.alphaType]
end
if (anim.alphaFunc) then
alphaFunc = WeakAuras.LoadFunction("return " .. anim.alphaFunc, auraDisplayName, "alpha animation");
alphaFunc = WeakAuras.LoadFunction("return " .. anim.alphaFunc);
else
if (region.SetAnimAlpha) then
region:SetAnimAlpha(nil);
@@ -282,7 +306,7 @@ function Private.Animate(namespace, uid, type, anim, region, inverse, onFinished
anim.scaleFunc = anim_function_strings[anim.scaleType]
end
if (anim.scaleFunc) then
scaleFunc = WeakAuras.LoadFunction("return " .. anim.scaleFunc, auraDisplayName, "scale animation");
scaleFunc = WeakAuras.LoadFunction("return " .. anim.scaleFunc);
else
region:Scale(1, 1);
end
@@ -295,7 +319,7 @@ function Private.Animate(namespace, uid, type, anim, region, inverse, onFinished
anim.rotateFunc = anim_function_strings[anim.rotateType]
end
if (anim.rotateFunc) then
rotateFunc = WeakAuras.LoadFunction("return " .. anim.rotateFunc, auraDisplayName, "rotate animation");
rotateFunc = WeakAuras.LoadFunction("return " .. anim.rotateFunc);
else
region:Rotate(startRotation);
end
@@ -308,7 +332,7 @@ function Private.Animate(namespace, uid, type, anim, region, inverse, onFinished
anim.colorFunc = anim_function_strings[anim.colorType]
end
if (anim.colorFunc) then
colorFunc = WeakAuras.LoadFunction("return " .. anim.colorFunc, auraDisplayName, "color animation");
colorFunc = WeakAuras.LoadFunction("return " .. anim.colorFunc);
else
region:ColorAnim(nil);
end
@@ -379,7 +403,7 @@ function Private.Animate(namespace, uid, type, anim, region, inverse, onFinished
animation.auraUID = uid
if not(updatingAnimations) then
frame:SetScript("OnUpdate", UpdateAnimations);
last_update = GetTime()
updatingAnimations = true;
end
return true;
@@ -436,4 +460,4 @@ function Private.CancelAnimation(region, resetPos, resetAlpha, resetScale, reset
else
return false;
end
end
end
+249 -49
View File
@@ -1,9 +1,11 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local WeakAuras = WeakAuras
local L = WeakAuras.L
local prettyPrint = WeakAuras.prettyPrint
local LibSerialize = LibStub("LibSerialize")
local LibDeflate = LibStub:GetLibrary("LibDeflate")
local UnitAura = UnitAura
-- Unit Aura functions that return info about the first Aura matching the spellName or spellID given on the unit.
@@ -50,7 +52,7 @@ end
-- Wrapping a unit's name in its class colour is very common in custom Auras
local WA_ClassColorName = function(unit)
if unit and UnitExists(unit) then
local name = UnitName(unit)
local name = WeakAuras.UnitName(unit)
local _, class = UnitClass(unit)
if not class then
return name
@@ -139,13 +141,17 @@ local blockedFunctions = {
EditMacro = true,
DevTools_DumpCommand = true,
hash_SlashCmdList = true,
RegisterNewSlashCommand = true,
CreateMacro = true,
SetBindingMacro = true,
GuildDisband = true,
GuildUninvite = true,
securecall = true,
DeleteCursorItem = true,
ChatEdit_SendText = true
ChatEdit_SendText = true,
ChatEdit_ActivateChat = true,
ChatEdit_ParseText = true,
ChatEdit_OnEnterPressed = true,
}
local blockedTables = {
@@ -153,7 +159,9 @@ local blockedTables = {
SendMailMailButton = true,
SendMailMoneyGold = true,
MailFrameTab2 = true,
DEFAULT_CHAT_FRAME = true,
ChatFrame1 = true,
WeakAurasSaved = true,
WeakAurasOptions = true,
WeakAurasOptionsSaved = true
}
@@ -163,6 +171,7 @@ local aura_environments = {}
-- 1 == config initialized
-- 2 == fully initialized
local environment_initialized = {}
local getDataCallCounts = {}
function Private.IsEnvironmentInitialized(id)
return environment_initialized[id] == 2
@@ -171,11 +180,13 @@ end
function Private.DeleteAuraEnvironment(id)
aura_environments[id] = nil
environment_initialized[id] = nil
getDataCallCounts[id] = nil
end
function Private.RenameAuraEnvironment(oldid, newid)
aura_environments[oldid], aura_environments[newid] = nil, aura_environments[oldid]
environment_initialized[oldid], environment_initialized[newid] = nil, environment_initialized[oldid]
getDataCallCounts[oldid], getDataCallCounts[newid] = nil, getDataCallCounts[oldid]
end
local current_uid = nil
@@ -183,8 +194,72 @@ local current_aura_env = nil
-- Stack of of aura environments/uids, allows use of recursive aura activations through calls to WeakAuras.ScanEvents().
local aura_env_stack = {}
local function UpdateSavedDataWarning(uid, size)
local savedDataWarning = 16 * 1024 * 1024 -- 16 KB, but it's only a warning
if size > savedDataWarning then
Private.AuraWarnings.UpdateWarning(uid, "CustomSavedData", "warning",
L["This aura is saving %s KB of data"]:format(ceil(size / 1024)))
else
Private.AuraWarnings.UpdateWarning(uid, "CustomSavedData")
end
end
function Private.SaveAuraEnvironment(id)
local data = WeakAuras.GetData(id)
if not data then
return
end
local input = aura_environments[id] and aura_environments[id].saved
if input then
local serialized = LibSerialize:SerializeEx({errorOnUnserializableType = false}, input)
-- We use minimal compression, since that already achieves a reasonable compression ratio,
-- but takes significant less time
local compressed = LibDeflate:CompressDeflate(serialized, {level = 1})
local encoded = LibDeflate:EncodeForPrint(compressed)
UpdateSavedDataWarning(data.uid, #encoded)
data.information.saved = encoded
else
data.information.saved = nil
end
end
function Private.RestoreAuraEnvironment(id)
local data = WeakAuras.GetData(id)
if not data then
return
end
local input = data.information.saved
if input then
local decoded = LibDeflate:DecodeForPrint(input)
local decompressed = LibDeflate:DecompressDeflate(decoded)
local success, deserialized = LibSerialize:Deserialize(decompressed)
if success then
aura_environments[id].saved = deserialized
else
aura_environments[id].saved = nil
end
UpdateSavedDataWarning(data.uid, #input)
else
aura_environments[id].saved = nil
end
end
function Private.ClearAuraEnvironmentSavedData(id)
if environment_initialized[id] == 2 then
aura_environments[id].saved = nil
end
end
function Private.ClearAuraEnvironment(id)
environment_initialized[id] = nil;
if environment_initialized[id] == 2 then
Private.SaveAuraEnvironment(id)
environment_initialized[id] = nil
aura_environments[id] = nil
getDataCallCounts[id] = nil
end
end
function Private.ActivateAuraEnvironmentForRegion(region, onlyConfig)
@@ -193,7 +268,6 @@ end
function Private.ActivateAuraEnvironment(id, cloneId, state, states, onlyConfig)
local data = id and WeakAuras.GetData(id)
local region = id and Private.EnsureRegion(id, cloneId)
if not data then
-- Pop the last aura_env from the stack, and update current_aura_env appropriately.
tremove(aura_env_stack)
@@ -206,6 +280,7 @@ function Private.ActivateAuraEnvironment(id, cloneId, state, states, onlyConfig)
else
-- Existing config is initialized to a high enough value
if environment_initialized[id] == 2 or (onlyConfig and environment_initialized[id] == 1) then
local region = WeakAuras.GetRegion(id, cloneId)
-- Point the current environment to the correct table
current_uid = data.uid
current_aura_env = aura_environments[id]
@@ -219,13 +294,13 @@ function Private.ActivateAuraEnvironment(id, cloneId, state, states, onlyConfig)
elseif onlyConfig then
environment_initialized[id] = 1
aura_environments[id] = {}
getDataCallCounts[id] = 0
current_uid = data.uid
current_aura_env = aura_environments[id]
current_aura_env.id = id
current_aura_env.cloneId = cloneId
current_aura_env.state = state
current_aura_env.states = states
current_aura_env.region = region
tinsert(aura_env_stack, {current_aura_env, data.uid})
if not data.controlledChildren then
@@ -233,8 +308,10 @@ function Private.ActivateAuraEnvironment(id, cloneId, state, states, onlyConfig)
end
else
-- Either this aura environment has not yet been initialized, or it was reset via an edit in WeakaurasOptions
local region = id and Private.EnsureRegion(id, cloneId)
environment_initialized[id] = 2
aura_environments[id] = aura_environments[id] or {}
getDataCallCounts[id] = getDataCallCounts[id] or 0
current_uid = data.uid
current_aura_env = aura_environments[id]
current_aura_env.id = id
@@ -242,6 +319,7 @@ function Private.ActivateAuraEnvironment(id, cloneId, state, states, onlyConfig)
current_aura_env.state = state
current_aura_env.states = states
current_aura_env.region = region
Private.RestoreAuraEnvironment(id)
-- push new environment onto the stack
tinsert(aura_env_stack, {current_aura_env, data.uid})
@@ -251,7 +329,7 @@ function Private.ActivateAuraEnvironment(id, cloneId, state, states, onlyConfig)
local childData = WeakAuras.GetData(childID)
if childData then
if not environment_initialized[childID] then
Private.ActivateAuraEnvironment(childID)
Private.ActivateAuraEnvironment(childID, nil, nil, nil, true)
Private.ActivateAuraEnvironment()
end
current_aura_env.child_envs[dataIndex] = aura_environments[childID]
@@ -269,13 +347,17 @@ function Private.ActivateAuraEnvironment(id, cloneId, state, states, onlyConfig)
if(actions and actions.do_custom and actions.custom) then
local func = Private.customActionsFunctions[id]["init"]
if func then
xpcall(func, geterrorhandler())
xpcall(func, Private.GetErrorHandlerId(id, "init"))
end
end
end
end
end
local function DebugPrint(...)
Private.DebugLog.Print(current_uid, ...)
end
local function blocked(key)
Private.AuraWarnings.UpdateWarning(current_uid, "SandboxForbidden", "error",
string.format(L["Forbidden function or table: %s"], key))
@@ -302,18 +384,29 @@ local function MakeReadOnly(input, options)
})
end
--- Wraps a table, so that accessing any key in it creates a deprecated warning
local function MakeDeprecated(input, name, warningMsg)
return setmetatable({},
{
__index = function(t, k)
Private.AuraWarnings.UpdateWarning(current_uid, "Deprecated_" .. name, "warning", warningMsg)
return input[k]
end,
__metatable = false
})
end
local FakeWeakAurasMixin = {
blockedFunctions = {
-- Other addons might use these, so before moving them to the Private space, we need
-- to discuss these. But Auras have no purpose for calling these
Add = true,
AddMany = true,
Delete = true,
HideOptions = true,
Rename = true,
NewAura = true,
OptionsFrame = true,
RegisterDisplay = true,
Import = true,
PreAdd = true,
RegisterRegionOptions = true,
RegisterSubRegionOptions = true,
RegisterSubRegionType = true,
@@ -323,43 +416,63 @@ local FakeWeakAurasMixin = {
ShowOptions = true,
-- Note these shouldn't exist in the WeakAuras namespace, but moving them takes a bit of effort,
-- so for now just block them and clean them up later
createSpinner = true,
ClearAndUpdateOptions = true,
CloseImportExport = true,
CreateTemplateView = true,
FillOptions = true,
FindUnusedId = true,
GetMoverSizerId = true,
GetDisplayButton = true,
Import = true,
GetNameAndIcon = true,
GetTriggerCategoryFor = true,
NewDisplayButton = true,
OpenOptions = true,
PickDisplay = true,
setTile = true,
SetMoverSizer = true,
SetModel = true,
Toggle = true,
ToggleOptions = true,
UpdateGroupOrders = true,
UpdateThumbnail = true,
validate = true,
getDefaultGlow = true,
},
blockedTables = {
AuraWarnings = true,
ModelPaths = true,
regionPrototype = true,
RealTimeProfilingWindow = true,
-- Note these shouldn't exist in the WeakAuras namespace, but moving them takes a bit of effort,
-- so for now just block them and clean them up later
data_stub = true,
displayButtons = true,
regionTypes = true,
regionOptions = true,
genericTriggerTypes = true,
spellCache = true,
triggerTemplates = true,
frames = true,
loadFrame = true,
unitLoadFrame = true,
StopMotion = true,
-- We block the loaded table, even though it doesn't exist anymore,
-- because some versions of ZT Tracker overwrote region:Collpase() and
-- checked for WeakAuras.loaded in there
loaded = true
},
override = {
me = UnitName("player"),
myGUID = UnitGUID("player")
myGUID = UnitGUID("player"),
GetData = function(id)
local currentId = Private.UIDtoID(current_uid)
getDataCallCounts[currentId] = getDataCallCounts[currentId] + 1
if getDataCallCounts[currentId] > 99 then
Private.AuraWarnings.UpdateWarning(current_uid, "FakeWeakAurasGetData", "warning",
L["This aura calls GetData a lot, which is a slow function."])
end
local data = WeakAuras.GetData(id)
return data and CopyTable(data) or nil
end,
clones = MakeDeprecated(Private.clones, "clones",
L["Using WeakAuras.clones is deprecated. Use WeakAuras.GetRegion(id, cloneId) instead."]),
regions = MakeDeprecated(Private.regions, "regions",
L["Using WeakAuras.regions is deprecated. Use WeakAuras.GetRegion(id) instead."]),
GetAllDBMTimers = function() return Private.ExecEnv.BossMods.DBM:GetAllTimers() end,
GetDBMTimerById = function(...) return Private.ExecEnv.BossMods.DBM:GetTimerById(...) end,
GetDBMTimer = function(...) return Private.ExecEnv.BossMods.DBM:GetTimer(...) end,
GetBigWigsTimerById = function(...) return Private.ExecEnv.BossMods.BigWigs:GetTimerById(...) end,
GetAllBigWigsTimers = function() return Private.ExecEnv.BossMods.BigWigs:GetAllTimers() end,
GetBigWigsStage = function(...) return Private.ExecEnv.BossMods.BigWigs:GetStage(...) end,
RegisterBigWigsTimer = function() Private.ExecEnv.BossMods.BigWigs:RegisterTimer() end,
RegisterDBMCallback = function() Private.ExecEnv.BossMods.DBM:RegisterTimer() end,
GetBossStage = function() return Private.ExecEnv.BossMods.Generic:GetStage() end
},
blocked = blocked,
setBlocked = function()
@@ -382,19 +495,79 @@ local overridden = {
WeakAuras = FakeWeakAuras
}
local env_getglobal
local exec_env = setmetatable({},
local env_getglobal_custom
local exec_env_custom = setmetatable({},
{
__index = function(t, k)
if k == "_G" then
return t
elseif k == "getglobal" then
return env_getglobal
return env_getglobal_custom
elseif k == "aura_env" then
return current_aura_env
elseif k == "DebugPrint" then
return DebugPrint
elseif blockedFunctions[k] then
blocked(k)
return function() end
return function(_) end
elseif blockedTables[k] then
blocked(k)
return {}
elseif overridden[k] then
return overridden[k]
elseif _G[k] then
return _G[k]
elseif k:find(".", 1, true) then
local f
for i, n in ipairs{strsplit(".", k)} do
if i == 1 then
f = _G[n]
elseif f then
f = f[n]
else
return
end
end
return f
end
end,
__newindex = function(table, key, value)
if _G[key] then
Private.AuraWarnings.UpdateWarning(current_uid, "OverridingGlobal", "warning",
string.format(L["The aura has overwritten the global '%s', this might affect other auras."], key))
end
rawset(table, key, value)
end,
__metatable = false
})
function env_getglobal_custom(k)
return exec_env_custom[k]
end
local PrivateForBuiltIn = {
ExecEnv = Private.ExecEnv
}
local env_getglobal_builtin
local exec_env_builtin = setmetatable({},
{
__index = function(t, k)
if k == "_G" then
return t
elseif k == "getglobal" then
return env_getglobal_builtin
elseif k == "aura_env" then
return current_aura_env
elseif k == "DebugPrint" then
return DebugPrint
elseif k == "Private" then
-- Built in code has access to Private.ExecEnv
-- Which contains a bunch of internal helpers
return PrivateForBuiltIn
elseif blockedFunctions[k] then
blocked(k)
return function(_) end
elseif blockedTables[k] then
blocked(k)
return {}
@@ -414,29 +587,56 @@ local exec_env = setmetatable({},
__metatable = false
})
function env_getglobal(k)
return exec_env[k]
function env_getglobal_builtin(k)
return exec_env_builtin[k]
end
local function_cache = {}
function WeakAuras.LoadFunction(string, id, inTrigger)
if function_cache[string] then
return function_cache[string]
else
local loadedFunction, errorString = loadstring(string, "Error in: " .. (id or "Unknown") .. (inTrigger and ("':'".. inTrigger) or ""))
if errorString then
print(errorString)
local function firstLine(string)
local lineBreak = string:find('\n', 1, true)
if lineBreak then
return string:sub(1, lineBreak - 1)
end
return string
end
local function CreateFunctionCache(exec_env)
local cache = {
funcs = setmetatable({}, {__mode = "v"})
}
cache.Load = function(self, string, silent)
if self.funcs[string] then
return self.funcs[string]
else
setfenv(loadedFunction, exec_env)
local success, func = pcall(assert(loadedFunction))
if success then
function_cache[string] = func
return func
local loadedFunction, errorString = loadstring(string, firstLine(string))
if errorString then
if not silent then
print(errorString)
end
return nil, errorString
elseif loadedFunction then
setfenv(loadedFunction, exec_env)
local success, func = pcall(assert(loadedFunction))
if success then
self.funcs[string] = func
return func
end
end
end
end
return cache
end
local function_cache_custom = CreateFunctionCache(exec_env_custom)
local function_cache_builtin = CreateFunctionCache(exec_env_builtin)
function WeakAuras.LoadFunction(string)
return function_cache_custom:Load(string)
end
function Private.LoadFunction(string, silent)
return function_cache_builtin:Load(string, silent)
end
function Private.GetSanitizedGlobal(key)
return exec_env[key]
return exec_env_custom[key]
end
+16 -22
View File
@@ -1,20 +1,21 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local WeakAuras = WeakAuras
local L = WeakAuras.L
-- keyed on uid, key, { severity, message }
local warnings = {}
local printedWarnings = {}
local function OnDelete(event, uid)
warnings[uid] = nil
printedWarnings[uid] = nil
end
Private.callbacks:RegisterCallback("Delete", OnDelete)
Private.AuraWarnings = {}
local function UpdateWarning(uid, key, severity, message, printOnConsole)
function Private.AuraWarnings.UpdateWarning(uid, key, severity, message, printOnConsole)
if not uid then
WeakAuras.prettyPrint(L["Warning for unknown aura:"], message)
return
@@ -37,6 +38,9 @@ local function UpdateWarning(uid, key, severity, message, printOnConsole)
else
if warnings[uid][key] then
warnings[uid][key] = nil
if printedWarnings[uid] then
printedWarnings[uid][key] = nil
end
Private.callbacks:Fire("AuraWarningsUpdated", uid)
end
end
@@ -50,17 +54,17 @@ local severityLevel = {
}
local icons = {
info = { path = [[Interface\friendsframe\informationicon]] },
sound = { path = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\ChatFrame", texCoords = {0.757812, 0.871094, 0.0078125, 0.234375} },
warning = { path = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\ServicesAtlas", texCoords = {0.000976562, 0.0419922, 0.961914, 0.998047} },
error = { path = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\HelpIcon-Bug" },
info = [[Interface\FriendsFrame\InformationIcon]],
sound = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\ChatFrame",
warning = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\ServicesAtlas",
error = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\HelpIcon-Bug",
}
local titles = {
info = L["Information"],
sound = L["Sound"],
warning = L["Warning"],
error = L["Error"]
error = L["Error"],
}
local function AddMessages(result, messages, icon, mixedSeverity)
@@ -72,20 +76,14 @@ local function AddMessages(result, messages, icon, mixedSeverity)
result = result .. "\n\n"
end
if mixedSeverity then
local iconPath = icon.path
local texCoords = icon.texCoords
if texCoords then
result = result .. string.format("|T%s:12:12:0:0:64:64:%d:%d:%d:%d|t", iconPath, texCoords[1] * 64, texCoords[2] * 64, texCoords[3] * 64, texCoords[4] * 64)
else
result = result .. string.format("|T%s:12:12:0:0:64:64:4:60:4:60|t", iconPath)
end
result = result .. "|T" .. icon .. ":12:12:0:0:64:64:4:60:4:60|t"
end
result = result .. message
end
return result
end
local function FormatWarnings(uid)
function Private.AuraWarnings.FormatWarnings(uid)
if not warnings[uid] then
return
end
@@ -119,7 +117,7 @@ local function FormatWarnings(uid)
return icons[maxSeverity], titles[maxSeverity], result
end
local function GetAllWarnings(uid)
function Private.AuraWarnings.GetAllWarnings(uid)
local results = {}
local thisWarnings
local data = Private.GetDataByUID(uid)
@@ -146,6 +144,7 @@ local function GetAllWarnings(uid)
thisWarnings[key].auraId = auraId
end
end
-- Order them by severity, keeping just one per severity
for key, warning in pairs(thisWarnings) do
results[warning.severity] = {
@@ -159,8 +158,3 @@ local function GetAllWarnings(uid)
end
return results
end
Private.AuraWarnings = {}
Private.AuraWarnings.UpdateWarning = UpdateWarning
Private.AuraWarnings.FormatWarnings = FormatWarnings
Private.AuraWarnings.GetAllWarnings = GetAllWarnings
+355
View File
@@ -0,0 +1,355 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L
local texture_data = WeakAuras.StopMotion.texture_data
Private.StopMotionBase = {}
-- Helper method for Options
function Private.StopMotionBase.textureNameHasData(textureName)
if not textureName then
return false
end
local pattern = "%.x(%d+)y(%d+)f(%d+)%.[tb][gl][ap]$"
local pattern2 = "%.x(%d+)y(%d+)f(%d+)w(%d+)h(%d+)W(%d+)H(%d+)%.[tb][gl][ap]$"
local ok = textureName:lower():match(pattern)
if ok then return true end
local ok2 = textureName:match(pattern2)
if ok2 then
return true
else
return false
end
end
local function setTile(texture, frame, rows, columns, frameScaleW, frameScaleH)
frame = frame - 1
local row = floor(frame / columns)
local column = frame % columns
local deltaX = frameScaleW / columns
local deltaY = frameScaleH / rows
local left = deltaX * column
local right = left + deltaX
local top = deltaY * row
local bottom = top + deltaY
pcall(function() texture:SetTexCoord(left, right, top, bottom) end)
end
WeakAuras.setTile = setTile
-- Helper method for Options
function Private.StopMotionBase.setTextureFunc(textureWidget, texturePath, textureName)
local data = texture_data[texturePath]
if not(data) then
local pattern = "%.x(%d+)y(%d+)f(%d+)%.[tb][gl][ap]"
local pattern2 = "%.x(%d+)y(%d+)f(%d+)w(%d+)h(%d+)W(%d+)H(%d+)%.[tb][gl][ap]"
local rows, columns, frames = texturePath:lower():match(pattern)
if rows then
data = {
count = tonumber(frames),
rows = tonumber(rows),
columns = tonumber(columns)
}
else
local rows, columns, frames, frameWidth, frameHeight, fileWidth, fileHeight = texturePath:match(pattern2)
if rows then
rows, columns, frames, frameWidth, frameHeight, fileWidth, fileHeight
= tonumber(rows), tonumber(columns), tonumber(frames), tonumber(frameWidth), tonumber(frameHeight),
tonumber(fileWidth), tonumber(fileHeight)
local frameScaleW = 1
local frameScaleH = 1
if fileWidth > 0 and frameWidth > 0 then
frameScaleW = (frameWidth * columns) / fileWidth
end
if fileHeight > 0 and frameHeight > 0 then
frameScaleH = (frameHeight * rows) / fileHeight
end
data = {
count = frames,
rows = rows,
columns = columns,
frameScaleW = frameScaleW,
frameScaleH = frameScaleH
}
end
end
end
textureWidget.frameNr = 0
if (data) then
if (data.rows and data.columns) then
-- Texture Atlas
textureWidget:SetTexture(texturePath, textureName)
setTile(textureWidget, data.count, data.rows, data.columns, data.frameScaleW or 1, data.frameScaleH or 1)
textureWidget:SetOnUpdate(function(self, elapsed)
self.elapsed = (self.elapsed or 0) + elapsed
if(self.elapsed > 0.1) then
self.elapsed = self.elapsed - 0.1
textureWidget.frameNr = textureWidget.frameNr + 1
if (textureWidget.frameNr == data.count) then
textureWidget.frameNr = 1
end
setTile(textureWidget, textureWidget.frameNr, data.rows, data.columns, data.frameScaleW or 1, data.frameScaleH or 1)
end
end)
else
-- Numbered Textures
local texture = texturePath .. string.format("%03d", texture_data[texturePath].count)
textureWidget:SetTexture(texture, textureName)
textureWidget:SetTexCoord(0, 1, 0, 1)
textureWidget:SetOnUpdate(function(self, elapsed)
self.elapsed = (self.elapsed or 0) + elapsed
if(self.elapsed > 0.1) then
self.elapsed = self.elapsed - 0.1
textureWidget.frameNr = textureWidget.frameNr + 1
if (textureWidget.frameNr == data.count) then
textureWidget.frameNr = 1
end
local texture = texturePath .. string.format("%03d", textureWidget.frameNr)
textureWidget:SetTexture(texture, textureName)
end
end)
end
else
local texture = texturePath .. string.format("%03d", 1)
textureWidget:SetTexture(texture, textureName)
end
end
local function SetTextureViaAtlas(self, texture)
self.texture:SetTexture(texture)
end
local function SetFrameViaAtlas(self, texture, frame)
local frameScaleW = 1
local frameScaleH = 1
if self.fileWidth and self.frameWidth and self.fileWidth > 0 and self.frameWidth > 0 then
frameScaleW = (self.frameWidth * self.columns) / self.fileWidth
end
if self.fileHeight and self.frameHeight and self.fileHeight > 0 and self.frameHeight > 0 then
frameScaleH = (self.frameHeight * self.rows) / self.fileHeight
end
setTile(self.texture, frame, self.rows, self.columns, frameScaleW, frameScaleH)
end
local function SetTextureViaFrames(self, texture)
self.texture:SetTexture(texture .. string.format("%03d", 0))
self.texture:SetTexCoord(0, 1, 0, 1)
end
local function SetFrameViaFrames(self, texture, frame)
self.texture:SetTexture(texture .. string.format("%03d", frame))
end
local funcs = {
SetDesaturated = function(self, b)
self.texture:SetDesaturated(b)
end,
SetColor = function(self, r, g, b, a)
self.texture:SetVertexColor(r, g, b, a)
end,
GetColor = function(self)
return self.texture:GetVertexColor()
end,
SetStartTime = function(self, time)
self.startTime = time
end,
TimedUpdate = function(self)
local timeSinceStart = (GetTime() - self.startTime)
local newCurrentFrame = floor(timeSinceStart * (self.frameRate or 15))
if (newCurrentFrame == self.currentFrame) then
return
end
self.currentFrame = newCurrentFrame
local frames
local startFrame = self.startFrame
local endFrame = self.endFrame
local inverse = self.inverseDirection
if (endFrame >= startFrame) then
frames = endFrame - startFrame + 1
else
frames = startFrame - endFrame + 1
startFrame, endFrame = endFrame, startFrame
inverse = not inverse
end
local frame = 0
if (self.animationType == "loop") then
frame = (newCurrentFrame % frames) + startFrame
elseif (self.animationType == "bounce") then
local direction = floor(newCurrentFrame / frames) % 2
if (direction == 0) then
frame = (newCurrentFrame % frames) + startFrame
else
frame = endFrame - (newCurrentFrame % frames)
end
elseif (self.animationType == "once") then
frame = newCurrentFrame + startFrame
if (frame > endFrame) then
frame = endFrame
end
end
if (inverse) then
frame = endFrame - frame + startFrame
end
if (frame > endFrame) then
frame = endFrame
end
if (frame < startFrame) then
frame = startFrame
end
self:SetFrame(self.textureFile, frame)
end,
SetProgress = function(self, progress)
local frames
local startFrame = self.startFrame
local endFrame = self.endFrame
local inverse = self.inverseDirection
if (endFrame >= startFrame) then
frames = endFrame - startFrame + 1
else
frames = startFrame - endFrame + 1
startFrame, endFrame = endFrame, startFrame
inverse = not inverse
end
local frame = floor( (frames - 1) * progress) + startFrame
if (inverse) then
frame = endFrame - frame + startFrame
end
if (frame > endFrame) then
frame = endFrame
end
if (frame < startFrame) then
frame = startFrame
end
self:SetFrame(self.textureFile, frame)
end,
ClearAllPoints = function(self)
self.texture:ClearAllPoints()
end,
SetAllPoints = function(self, ...)
self.texture:SetAllPoints(...)
end,
SetPoint = function(self, ...)
self.texture:SetPoint(...)
end,
SetSize = function(self, w, h)
self.texture:SetSize(w, h)
end,
SetVisible = function(self, b)
if b then
self.texture:Show()
else
self.texture:Hide()
end
end
}
function Private.StopMotionBase.create(frame, drawLayer)
local stopMotion = {}
local texture = frame:CreateTexture(nil, "ARTWORK")
stopMotion.texture = texture
texture:SetAllPoints(frame)
for funcName, func in pairs(funcs) do
stopMotion[funcName] = func
end
return stopMotion
end
function Private.StopMotionBase.modify(stopMotion, options)
stopMotion.frameRate = options.frameRate
stopMotion.inverseDirection = options.inverseDirection
stopMotion.animationType = options.animationType
stopMotion.textureFile = options.texture
local pattern = "%.x(%d+)y(%d+)f(%d+)%.[tb][gl][ap]"
local pattern2 = "%.x(%d+)y(%d+)f(%d+)w(%d+)h(%d+)W(%d+)H(%d+)%.[tb][gl][ap]"
do -- setup texture
local tdata = texture_data[stopMotion.textureFile]
if (tdata) then
local lastFrame = tdata.count - 1
stopMotion.lastFrame = lastFrame
stopMotion.startFrame = floor( (options.startPercent or 0) * lastFrame) + 1
stopMotion.endFrame = floor( (options.endPercent or 1) * lastFrame) + 1
stopMotion.rows = tdata.rows
stopMotion.columns = tdata.columns
stopMotion.fileWidth = 0
stopMotion.fileHeight = 0
stopMotion.frameWidth = 0
stopMotion.frameHeight = 0
else
local rows, columns, frames = stopMotion.textureFile:lower():match(pattern)
if rows then
local lastFrame = tonumber(frames) - 1
stopMotion.lastFrame = lastFrame
stopMotion.startFrame = floor( (options.startPercent or 0) * lastFrame) + 1
stopMotion.endFrame = floor( (options.endPercent or 1) * lastFrame) + 1
stopMotion.rows = tonumber(rows)
stopMotion.columns = tonumber(columns)
stopMotion.fileWidth = 0
stopMotion.fileHeight = 0
stopMotion.frameWidth = 0
stopMotion.frameHeight = 0
else
local rows, columns, frames, frameWidth, frameHeight, fileWidth, fileHeight
= stopMotion.textureFile:match(pattern2)
if rows then
local lastFrame = tonumber(frames) - 1
stopMotion.lastFrame = lastFrame
stopMotion.startFrame = floor( (options.startPercent or 0) * lastFrame) + 1
stopMotion.endFrame = floor( (options.endPercent or 1) * lastFrame) + 1
stopMotion.rows = tonumber(rows)
stopMotion.columns = tonumber(columns)
stopMotion.fileWidth = tonumber(fileWidth)
stopMotion.fileHeight = tonumber(fileHeight)
stopMotion.frameWidth = tonumber(frameWidth)
stopMotion.frameHeight = tonumber(frameHeight)
else
local lastFrame = (options.customFrames or 256) - 1
stopMotion.lastFrame = lastFrame
stopMotion.startFrame = floor( (options.startPercent or 0) * lastFrame) + 1
stopMotion.endFrame = floor( (options.endPercent or 1) * lastFrame) + 1
stopMotion.rows = options.customRows
stopMotion.columns = options.customColumns
stopMotion.fileWidth = options.customFileWidth
stopMotion.fileHeight = options.customFileHeight
stopMotion.frameWidth = options.customFrameWidth
stopMotion.frameHeight = options.customFrameHeight
end
end
end
end
if (stopMotion.rows and stopMotion.columns) then
stopMotion.SetBaseTexture = SetTextureViaAtlas
stopMotion.SetFrame = SetFrameViaAtlas
else
stopMotion.SetBaseTexture = SetTextureViaFrames
stopMotion.SetFrame = SetFrameViaFrames
end
stopMotion:SetBaseTexture(options.texture)
if stopMotion.animationType == "background" then
stopMotion:SetFrame(options.texture, stopMotion.endFrame or 1)
else
stopMotion:SetFrame(options.texture, 1)
end
stopMotion.texture:SetBlendMode(options.blendMode)
end
+125
View File
@@ -0,0 +1,125 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L
Private.TextureBase = {}
local SQRT2 = sqrt(2)
local function GetRotatedPoints(degrees, scaleForFullRotate)
local angle = rad(135 - degrees)
local factor = scaleForFullRotate and 1 or SQRT2
local vx = math.cos(angle) / factor
local vy = math.sin(angle) / factor
return 0.5+vx,0.5-vy , 0.5-vy,0.5-vx , 0.5+vy,0.5+vx , 0.5-vx,0.5+vy
end
local funcs = {
ClearAllPoints = function(self)
self.texture:ClearAllPoints()
end,
SetAllPoints = function(self, ...)
self.texture:SetAllPoints(...)
end,
DoTexCoord = function(self)
local mirror_h, mirror_v = self.mirror_h, self.mirror_v
if(self.mirror) then
mirror_h = not mirror_h
end
local ulx,uly , llx,lly , urx,ury , lrx,lry
= GetRotatedPoints(self.effectiveRotation, self.canRotate)
if(mirror_h) then
if(mirror_v) then
self.texture:SetTexCoord(lrx,lry , urx,ury , llx,lly , ulx,uly)
else
self.texture:SetTexCoord(urx,ury , lrx,lry , ulx,uly , llx,lly)
end
else
if(mirror_v) then
self.texture:SetTexCoord(llx,lly , ulx,uly , lrx,lry , urx,ury)
else
self.texture:SetTexCoord(ulx,uly , llx,lly , urx,ury , lrx,lry)
end
end
end,
SetMirrorFromScale = function(self, h, v)
if self.mirror_h == h and self.mirror_v == v then
return
end
self.mirror_h = h
self.mirror_v = v
self:DoTexCoord()
end,
SetMirror = function(self, b)
if self.mirror == b then
return
end
self.mirror = b
self:DoTexCoord()
end,
SetTexture = function(self, file)
self.textureName = file
self.texture:SetTexture(file)
self:DoTexCoord()
end,
SetVertexColor = function(self, r, g, b, a)
self.texture:SetVertexColor(r, g, b,a)
end,
SetDesaturated = function(self, b)
self.texture:SetDesaturated(b)
end,
SetAnimRotation = function(self, degrees)
self.animRotation = degrees
self:UpdateEffectiveRotation()
end,
SetRotation = function(self, degrees)
self.rotation = degrees
self:UpdateEffectiveRotation()
end,
UpdateEffectiveRotation = function(self)
self.effectiveRotation = self.animRotation or self.rotation
self:DoTexCoord()
end,
GetBaseRotation = function(self)
return self.rotation
end
}
function Private.TextureBase.create(frame)
local base = {}
for funcName, func in pairs(funcs) do
base[funcName] = func
end
local texture = frame:CreateTexture()
base.texture = texture
return base
end
function Private.TextureBase.modify(base, options)
base.canRotate = options.canRotate
base.mirror = options.mirror
base.rotation = options.rotation
base.effectiveRotation = base.rotation
base.textureWrapMode = options.textureWrapMode
base.texture:SetDesaturated(options.desaturate)
base.texture:SetBlendMode(options.blendMode)
base:DoTexCoord()
end
File diff suppressed because it is too large Load Diff
-89
View File
@@ -1,89 +0,0 @@
--[[ BuffTrigger.lua
This used to contains the "aura" trigger for buffs and debuffs. Nowadays all functions do essentially nothing
]]--
if not WeakAuras.IsCorrectVersion() then return end
local AddonName, Private = ...
local L = WeakAuras.L
local BuffTrigger = {}
function BuffTrigger.UnloadAll() end
function BuffTrigger.LoadDisplays(toLoad) end
function BuffTrigger.UnloadDisplays(toUnload) end
function BuffTrigger.FinishLoadUnload() end
function BuffTrigger.Delete(id) end
function BuffTrigger.Rename(oldid, newid) end
function BuffTrigger.Add(data)
if data.triggers then
local hasLegacyAuraTrigger = false
for index, t in ipairs(data.triggers) do
if t.trigger.type == "aura" then
hasLegacyAuraTrigger = true
break
end
end
if hasLegacyAuraTrigger then
Private.AuraWarnings.UpdateWarning(data.uid, "legacy", "warning", L["This aura has legacy aura trigger(s), which are no longer supported."])
else
Private.AuraWarnings.UpdateWarning(data.uid, "legacy")
end
end
end
function BuffTrigger.CanHaveDuration(data, triggernum)
return false
end
function BuffTrigger.GetOverlayInfo(data, triggernum) return {} end
function BuffTrigger.CanHaveClones(data, triggernum) return false end
function BuffTrigger.CanHaveTooltip(data, triggernum) end
function BuffTrigger.SetToolTip(trigger, state) end
function BuffTrigger.GetNameAndIcon(data, triggernum) end
function BuffTrigger.GetAdditionalProperties(data, triggernum)
return ""
end
function BuffTrigger.GetTriggerConditions(data, triggernum)
return {}
end
function BuffTrigger.CreateFallbackState(data, triggernum, state)
state.show = true;
state.changed = true;
state.progressType = "timed";
state.duration = 0;
state.expirationTime = math.huge;
end
function BuffTrigger.GetName(triggerType)
if (triggerType == "aura") then
return L["Legacy Aura (disabled)"];
end
end
function BuffTrigger.GetTriggerDescription(data, triggernum, namestable)
tinsert(namestable, {L["Legacy Aura (disabled):"], L[""]});
end
function BuffTrigger.CreateFakeStates(id, triggernum)
local allStates = WeakAuras.GetTriggerStateForTrigger(id, triggernum);
local data = WeakAuras.GetData(id)
local state = {}
BuffTrigger.CreateFallbackState(data, triggernum, state)
allStates[""] = state
end
WeakAuras.RegisterTriggerSystem({"aura"}, BuffTrigger);
+536 -229
View File
File diff suppressed because it is too large Load Diff
-16
View File
@@ -1,16 +0,0 @@
# [2.17.4](https://github.com/WeakAuras/WeakAuras2/tree/2.17.4) (2020-04-22)
[Full Changelog](https://github.com/WeakAuras/WeakAuras2/compare/2.17.3...2.17.4)
## Highlights
- fix a buff tracking and nameplates regression
## Commits
InfusOnWoW (3):
- BT2 Fix Multi by adjusting it to recent changes (#2139)
- Clean up match data if a unit ceases to exists
- Fix nameplates auras sometimes not being applied if in a raid group
+159
View File
@@ -0,0 +1,159 @@
local ipairs = ipairs
local pairs = pairs
local abs, ceil, floor = math.abs, math.ceil, math.floor
local GetInstanceInfo = GetInstanceInfo
local GetNumPartyMembers = GetNumPartyMembers
local GetNumRaidMembers = GetNumRaidMembers
function noop()
end
function ipairs_reverse(table)
local function Enumerator(table, index)
index = index - 1;
local value = table[index];
if value ~= nil then
return index, value;
end
end
return Enumerator, table, #table + 1;
end
function tInvert(tbl)
local inverted = {};
for k, v in pairs(tbl) do
inverted[v] = k;
end
return inverted;
end
function Round(value)
if value < 0 then
return ceil(value - .5);
end
return floor(value + .5);
end
function tIndexOf(tbl, item)
for i, v in ipairs(tbl) do
if item == v then
return i;
end
end
end
function TableHasAnyEntries(tbl)
if tbl and type(tbl) == "table" then
for _ in pairs(tbl) do
return true
end
end
return false
end
function tAppendAll(table, addedArray)
for i, element in ipairs(addedArray) do
tinsert(table, element);
end
end
function MergeTable(t1, t2)
local merged = {}
for k, v in pairs(t1) do
merged[k] = v
end
for k, v in pairs(t2) do
merged[k] = v
end
return merged
end
function tCompare(t1, t2)
for k, v in pairs(t1) do
if type(v) == "table" and type(t2[k]) == "table" then
if not tCompare(v, t2[k]) then
return false
end
elseif t2[k] ~= v then
return false
end
end
for k in pairs(t2) do
if t1[k] == nil then
return false
end
end
return true
end
function IsInGroup()
return GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0
end
function IsInRaid()
return GetNumRaidMembers() > 0
end
function GetNumSubgroupMembers()
return GetNumPartyMembers()
end
function GetNumGroupMembers()
return IsInRaid() and GetNumRaidMembers() or GetNumPartyMembers()
end
RAID_CLASS_COLORS.HUNTER.colorStr = "ffabd473"
RAID_CLASS_COLORS.WARLOCK.colorStr = "ff8788ee"
RAID_CLASS_COLORS.PRIEST.colorStr = "ffffffff"
RAID_CLASS_COLORS.PALADIN.colorStr = "fff58cba"
RAID_CLASS_COLORS.MAGE.colorStr = "ff3fc7eb"
RAID_CLASS_COLORS.ROGUE.colorStr = "fffff569"
RAID_CLASS_COLORS.DRUID.colorStr = "ffff7d0a"
RAID_CLASS_COLORS.SHAMAN.colorStr = "ff0070de"
RAID_CLASS_COLORS.WARRIOR.colorStr = "ffc79c6e"
RAID_CLASS_COLORS.DEATHKNIGHT.colorStr = "ffc41f3b"
function CreateTextureMarkup(file, fileWidth, fileHeight, width, height, left, right, top, bottom, xOffset, yOffset)
return ("|T%s:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d|t"):format(
file
, height
, width
, xOffset or 0
, yOffset or 0
, fileWidth
, fileHeight
, left * fileWidth
, right * fileWidth
, top * fileHeight
, bottom * fileHeight
);
end
function Clamp(value, min, max)
if value > max then
return max;
elseif value < min then
return min;
end
return value;
end
-- This section is mostly used by Private.SmoothStatusBarMixin
function Lerp(startValue, endValue, amount)
return (1 - amount) * startValue + amount * endValue;
end
function Saturate(value)
return Clamp(value, 0, 1);
end
local TARGET_FRAME_PER_SEC = 60.0;
function DeltaLerp(startValue, endValue, amount, timeSec)
return Lerp(startValue, endValue, Saturate(amount * timeSec * TARGET_FRAME_PER_SEC));
end
function FrameDeltaLerp(startValue, endValue, amount, elapsed)
return DeltaLerp(startValue, endValue, amount, elapsed);
end
+295 -163
View File
@@ -1,4 +1,4 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L
@@ -17,7 +17,7 @@ local conditionChecksTimers = {};
conditionChecksTimers.recheckTime = {};
conditionChecksTimers.recheckHandle = {};
local function OnDelete(event, uid)
local function OnDelete(_, uid)
checkConditions[uid] = nil
conditionChecksTimers.recheckTime[uid] = nil
if (conditionChecksTimers.recheckHandle[uid]) then
@@ -27,14 +27,14 @@ local function OnDelete(event, uid)
end
conditionChecksTimers.recheckHandle[uid] = nil
for event, funcs in pairs(dynamicConditions) do
for _, funcs in pairs(dynamicConditions) do
funcs[uid] = nil
end
end
Private.callbacks:RegisterCallback("Delete", OnDelete)
local function formatValueForAssignment(vType, value, pathToCustomFunction, pathToFormatters)
local function formatValueForAssignment(vType, value, pathToCustomFunction, pathToFormatters, data)
if (value == nil) then
value = false;
end
@@ -42,13 +42,51 @@ local function formatValueForAssignment(vType, value, pathToCustomFunction, path
return value and tostring(value) or "false";
elseif(vType == "number") then
return value and tostring(value) or "0";
elseif (vType == "list") then
elseif (vType == "list" or vType == "textureLSM") then
if type(value) == "string" then
return string.format("%s", Private.QuotedString(value))
elseif type(value) == "number" then
return tostring(value)
end
return "nil"
elseif vType == "progressSource" then
if type(value) == "table" then
local progressSource = Private.AddProgressSourceMetaData(data, value)
if not progressSource then
return "{}"
end
local trigger = progressSource[1] or -1
local progressType = progressSource[2] or "auto"
local property = progressSource[3]
local totalProperty = progressSource[4]
local inverseProperty = progressSource[5]
local pausedProperty = progressSource[6]
local remainingProperty = progressSource[7]
if trigger == 0 then
-- Manual progress
local serialized = string.format("{%s, %s, %s, %s}",
trigger,
Private.QuotedString(progressType),
property or "0", -- Actually: value
totalProperty or "100" -- Actually: total
)
return serialized
else
local serialized = string.format("{%s, %s, %s, %s, %s, %s, %s, %s}",
trigger,
Private.QuotedString(progressType),
Private.QuotedString(property or "nil"),
totalProperty and Private.QuotedString(totalProperty) or "nil",
inverseProperty and Private.QuotedString(inverseProperty) or "nil",
pausedProperty and Private.QuotedString(pausedProperty) or "nil",
remainingProperty and Private.QuotedString(remainingProperty) or "nil"
)
return serialized
end
else
return "nil"
end
elseif (vType == "icon") then
if type(value) == "string" then
return string.format("%s", Private.QuotedString(value))
@@ -56,9 +94,16 @@ local function formatValueForAssignment(vType, value, pathToCustomFunction, path
return tostring(value)
end
return "nil"
elseif (vType == "string" or vType == "texture") then
if type(value) == "string" then
return string.format("%s", Private.QuotedString(value))
end
return "nil"
elseif(vType == "color") then
if (value and type(value) == "table") then
return string.format("{%s, %s, %s, %s}", tostring(value[1]), tostring(value[2]), tostring(value[3]), tostring(value[4]));
return string.format("{%s, %s, %s, %s}",
tostring(value[1]), tostring(value[2]),
tostring(value[3]), tostring(value[4]))
end
return "{1, 1, 1, 1}";
elseif(vType == "chat") then
@@ -114,7 +159,9 @@ local function formatValueForAssignment(vType, value, pathToCustomFunction, path
end
local function formatValueForCall(type, property)
if (type == "bool" or type == "number" or type == "list" or type == "icon") then
if type == "bool" or type == "number" or type == "list" or type == "icon" or type == "string" or type == "texture" or type == "textureLSM"
or type == "progressSource"
then
return "propertyChanges['" .. property .. "']";
elseif (type == "color") then
local pcp = "propertyChanges['" .. property .. "']";
@@ -124,8 +171,14 @@ local function formatValueForCall(type, property)
end
function Private.ExecEnv.CancelConditionCheck(uid, cloneId)
if conditionChecksTimers.recheckHandle[uid] and conditionChecksTimers.recheckHandle[uid][cloneId] then
timer:CancelTimer(conditionChecksTimers.recheckHandle[uid][cloneId])
conditionChecksTimers.recheckHandle[uid][cloneId] = nil
end
end
function WeakAuras.scheduleConditionCheck(time, uid, cloneId)
function Private.ExecEnv.ScheduleConditionCheck(time, uid, cloneId)
conditionChecksTimers.recheckTime[uid] = conditionChecksTimers.recheckTime[uid] or {}
conditionChecksTimers.recheckHandle[uid] = conditionChecksTimers.recheckHandle[uid] or {};
@@ -148,16 +201,17 @@ function WeakAuras.scheduleConditionCheck(time, uid, cloneId)
end
end
function WeakAuras.CallCustomConditionTest(uid, testFunctionNumber, ...)
local ok, result = pcall(WeakAuras.conditionHelpers[uid].customTestFunctions[testFunctionNumber], ...)
function Private.ExecEnv.CallCustomConditionTest(uid, testFunctionNumber, ...)
local ok, result = pcall(Private.ExecEnv.conditionHelpers[uid].customTestFunctions[testFunctionNumber], ...)
if not ok then
geterrorhandler()(result)
Private.GetErrorHandlerUid(uid, L["Condition Custom Test"])
elseif (ok) then
return result
end
end
local function CreateTestForCondition(uid, input, allConditionsTemplate, usedStates)
local function CreateTestForCondition(data, input, allConditionsTemplate, usedStates)
local uid = data.uid
local trigger = input and input.trigger;
local variable = input and input.variable;
local op = input and input.op;
@@ -170,7 +224,7 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta
local test = {};
if (input.checks) then
for i, subcheck in ipairs(input.checks) do
local subtest, subrecheckCode = CreateTestForCondition(uid, subcheck, allConditionsTemplate, usedStates);
local subtest, subrecheckCode = CreateTestForCondition(data, subcheck, allConditionsTemplate, usedStates);
if (subtest) then
tinsert(test, "(" .. subtest .. ")");
end
@@ -196,6 +250,14 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta
local cType = conditionTemplate and conditionTemplate.type;
local test = conditionTemplate and conditionTemplate.test;
local preamble = conditionTemplate and conditionTemplate.preamble;
local progressSource
local pausedProperty
local remainingProperty
if cType == "timer" then
progressSource = Private.GetProgressSourceFor(data, trigger, variable)
pausedProperty = progressSource and progressSource[6]
remainingProperty = progressSource[7]
end
local stateCheck = "state[" .. trigger .. "] and state[" .. trigger .. "].show and ";
local stateVariableCheck = string.format("state[" .. trigger .. "][%q]", variable) .. "~= nil and ";
@@ -203,34 +265,37 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta
local preambleString
if preamble then
WeakAuras.conditionHelpers[uid] = WeakAuras.conditionHelpers[uid] or {}
WeakAuras.conditionHelpers[uid].preambles = WeakAuras.conditionHelpers[uid].preambles or {}
tinsert(WeakAuras.conditionHelpers[uid].preambles, preamble(value) or "");
local preambleNumber = #WeakAuras.conditionHelpers[uid].preambles
preambleString = string.format("WeakAuras.conditionHelpers[%q].preambles[%s]", uid, preambleNumber)
Private.ExecEnv.conditionHelpers[uid] = Private.ExecEnv.conditionHelpers[uid] or {}
Private.ExecEnv.conditionHelpers[uid].preambles = Private.ExecEnv.conditionHelpers[uid].preambles or {}
tinsert(Private.ExecEnv.conditionHelpers[uid].preambles, preamble(value) or "");
local preambleNumber = #Private.ExecEnv.conditionHelpers[uid].preambles
preambleString = string.format("Private.ExecEnv.conditionHelpers[%q].preambles[%s]", uid, preambleNumber)
end
if (test) then
if (value) then
WeakAuras.conditionHelpers[uid] = WeakAuras.conditionHelpers[uid] or {}
WeakAuras.conditionHelpers[uid].customTestFunctions = WeakAuras.conditionHelpers[uid].customTestFunctions or {}
tinsert(WeakAuras.conditionHelpers[uid].customTestFunctions, test);
local testFunctionNumber = #(WeakAuras.conditionHelpers[uid].customTestFunctions);
Private.ExecEnv.conditionHelpers[uid] = Private.ExecEnv.conditionHelpers[uid] or {}
Private.ExecEnv.conditionHelpers[uid].customTestFunctions
= Private.ExecEnv.conditionHelpers[uid].customTestFunctions or {}
tinsert(Private.ExecEnv.conditionHelpers[uid].customTestFunctions, test);
local testFunctionNumber = #(Private.ExecEnv.conditionHelpers[uid].customTestFunctions);
local valueString = type(value) == "string" and string.format("%q", value) or value;
local opString = type(op) == "string" and string.format("%q", op) or op;
check = string.format("state and WeakAuras.CallCustomConditionTest(%q, %s, state[%s], %s, %s, %s)",
uid, testFunctionNumber, trigger, valueString, (opString or "nil"), preambleString or "nil");
check = string.format("state and Private.ExecEnv.CallCustomConditionTest(%q, %s, state[%s], %s, %s, %s)",
uid, testFunctionNumber, trigger, valueString, (opString or "nil"),
preambleString or "nil")
end
elseif (cType == "customcheck") then
if value then
local customCheck = WeakAuras.LoadFunction("return " .. value, Private.UIDtoID(uid), "conditions custom check")
local customCheck = WeakAuras.LoadFunction("return " .. value)
if customCheck then
WeakAuras.conditionHelpers[uid] = WeakAuras.conditionHelpers[uid] or {}
WeakAuras.conditionHelpers[uid].customTestFunctions = WeakAuras.conditionHelpers[uid].customTestFunctions or {}
tinsert(WeakAuras.conditionHelpers[uid].customTestFunctions, customCheck);
local testFunctionNumber = #(WeakAuras.conditionHelpers[uid].customTestFunctions);
Private.ExecEnv.conditionHelpers[uid] = Private.ExecEnv.conditionHelpers[uid] or {}
Private.ExecEnv.conditionHelpers[uid].customTestFunctions
= Private.ExecEnv.conditionHelpers[uid].customTestFunctions or {}
tinsert(Private.ExecEnv.conditionHelpers[uid].customTestFunctions, customCheck);
local testFunctionNumber = #(Private.ExecEnv.conditionHelpers[uid].customTestFunctions);
check = string.format("state and WeakAuras.CallCustomConditionTest(%q, %s, state)",
check = string.format("state and Private.ExecEnv.CallCustomConditionTest(%q, %s, state)",
uid, testFunctionNumber, trigger);
end
end
@@ -239,25 +304,39 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta
elseif (cType == "number" and value and op) then
local v = tonumber(value)
if (v) then
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable) .. op .. v;
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable)
.. op .. v;
end
elseif (cType == "timer" and value and op) then
local triggerState = "state[" .. trigger .. "]"
local varString = triggerState .. string.format("[%q]", variable)
local remainingTime = "(" .. varString .. " - now)"
if pausedProperty and remainingProperty then
local pausedString = "state[" .. trigger .. "]" .. string.format("[%q]", pausedProperty)
local remainingString = "(state[" .. trigger .. "]" .. string.format("[%q]", remainingProperty) .. " or 0)"
remainingTime = "((" .. pausedString .. " and " .. remainingString .. ") or " .. remainingTime .. ")"
end
if (op == "==") then
check = stateCheck .. stateVariableCheck .. "abs(state[" .. trigger .. "]" .. string.format("[%q]", variable) .. "- now -" .. value .. ") < 0.05";
check = stateCheck .. stateVariableCheck .. varString .. "~= 0 and " .. "abs((" .. remainingTime .. "-" .. value .. ")" .. ") < 0.05"
else
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable) .. "- now" .. op .. value;
check = stateCheck .. stateVariableCheck .. varString .. "~= 0 and " .. remainingTime .. op .. value
end
elseif (cType == "elapsedTimer" and value and op) then
if (op == "==") then
check = stateCheck .. stateVariableCheck .. "abs(state[" .. trigger .. "]" .. string.format("[%q]", variable) .. "- now +" .. value .. ") < 0.05";
check = stateCheck .. stateVariableCheck .. "abs(state[" .. trigger .. "]" .. string.format("[%q]", variable)
.. "- now +" .. value .. ") < 0.05";
else
check = stateCheck .. stateVariableCheck .. "now - state[" .. trigger .. "]" .. string.format("[%q]", variable) .. op .. value;
check = stateCheck .. stateVariableCheck .. "now - state[" .. trigger .. "]" .. string.format("[%q]", variable)
.. op .. value;
end
elseif (cType == "select" and value and op) then
if (tonumber(value)) then
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable) .. op .. tonumber(value);
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable)
.. op .. tonumber(value);
else
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]".. string.format("[%q]", variable) .. op .. "'" .. value .. "'";
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]".. string.format("[%q]", variable)
.. op .. "'" .. value .. "'";
end
elseif (cType == "range" and value and op and input.type and input.op_range and input.range) then
local fn
@@ -282,8 +361,7 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta
local found = 0
local op = %q
local range = %s
local max = C_NamePlate and C_NamePlate.GetNamePlates and #C_NamePlate.GetNamePlates() or 40
for i = 1, max do
for i = 1, 100 do
local unit = "nameplate" .. i
if UnitExists(unit) and UnitCanAttack("player", unit) and WeakAuras.CheckRange(unit, range, op) then
found = found + 1
@@ -295,33 +373,46 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta
fn = fn:format(input.op_range, input.range, op, value)
end
if fn then
local customCheck = WeakAuras.LoadFunction(fn, Private.UIDtoID(uid), "conditions range check")
local customCheck = WeakAuras.LoadFunction(fn)
if customCheck then
WeakAuras.conditionHelpers[uid] = WeakAuras.conditionHelpers[uid] or {}
WeakAuras.conditionHelpers[uid].customTestFunctions = WeakAuras.conditionHelpers[uid].customTestFunctions or {}
tinsert(WeakAuras.conditionHelpers[uid].customTestFunctions, customCheck);
local testFunctionNumber = #(WeakAuras.conditionHelpers[uid].customTestFunctions);
Private.ExecEnv.conditionHelpers[uid] = Private.ExecEnv.conditionHelpers[uid] or {}
Private.ExecEnv.conditionHelpers[uid].customTestFunctions
= Private.ExecEnv.conditionHelpers[uid].customTestFunctions or {}
tinsert(Private.ExecEnv.conditionHelpers[uid].customTestFunctions, customCheck);
local testFunctionNumber = #(Private.ExecEnv.conditionHelpers[uid].customTestFunctions);
check = string.format("state and WeakAuras.CallCustomConditionTest(%q, %s, state)",
check = string.format("state and Private.ExecEnv.CallCustomConditionTest(%q, %s, state)",
uid, testFunctionNumber, trigger);
end
end
elseif (cType == "bool" and value) then
local rightSide = value == 0 and "false" or "true";
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable) .. "==" .. rightSide
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable)
.. "==" .. rightSide
elseif (cType == "string" and value) then
if(op == "==") then
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable) .. " == [[" .. value .. "]]";
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable)
.. " == [[" .. value .. "]]";
elseif (op == "find('%s')") then
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable) .. ":find([[" .. value .. "]], 1, true)";
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable)
.. ":find([[" .. value .. "]], 1, true)";
elseif (op == "match('%s')") then
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable) .. ":match([[" .. value .. "]], 1, true)";
check = stateCheck .. stateVariableCheck .. "state[" .. trigger .. "]" .. string.format("[%q]", variable)
.. ":match([[" .. value .. "]], 1, true)";
end
end
-- If adding a new condition type, don't forget to adjust the validator in the options code
if (cType == "timer" and value) then
recheckCode = " nextTime = state[" .. trigger .. "] and state[" .. trigger .. "]" .. string.format("[%q]", variable) .. " and (state[" .. trigger .. "]" .. string.format("[%q]", variable) .. " -" .. value .. ")\n";
local variableString = "state[" .. trigger .. "]" .. string.format("[%q]", variable)
local andNotPaused = pausedProperty
and "and not " .. "state[" .. trigger .. "]" .. string.format("[%q]", pausedProperty)
or ""
recheckCode = " nextTime = state[" .. trigger .. "] " .. andNotPaused
.. " and " .. variableString
.. " and " .. "(" .. variableString .. " - " .. value .. ")\n"
recheckCode = recheckCode .. " if (nextTime and (not recheckTime or nextTime < recheckTime) and nextTime >= now) then\n"
recheckCode = recheckCode .. " recheckTime = nextTime\n";
recheckCode = recheckCode .. " end\n"
@@ -336,26 +427,26 @@ local function CreateTestForCondition(uid, input, allConditionsTemplate, usedSta
return check, recheckCode;
end
local function CreateCheckCondition(uid, ret, condition, conditionNumber, allConditionsTemplate, nextIsLinked, debug)
local function CreateCheckCondition(data, ret, condition, conditionNumber, allConditionsTemplate, nextIsLinked, debug)
local usedStates = {};
local check, recheckCode = CreateTestForCondition(uid, condition.check, allConditionsTemplate, usedStates);
local check, recheckCode = CreateTestForCondition(data, condition.check, allConditionsTemplate, usedStates);
if not check then
check = "false"
end
if condition.linked and conditionNumber > 1 then
ret = ret .. " elseif (" .. check .. ") then\n";
table.insert(ret, " elseif (" .. check .. ") then\n")
else
ret = ret .. " if (" .. check .. ") then\n";
table.insert(ret, " if (" .. check .. ") then\n")
end
ret = ret .. " newActiveConditions[" .. conditionNumber .. "] = true;\n";
table.insert(ret, " newActiveConditions[" .. conditionNumber .. "] = true;\n")
if not nextIsLinked then
ret = ret .. " end\n";
table.insert(ret, " end\n")
end
if (check) then
ret = ret .. "\n";
table.insert(ret, "\n")
end
return ret, recheckCode;
return recheckCode;
end
local function ParseProperty(property)
@@ -389,75 +480,99 @@ end
local function CreateDeactivateCondition(ret, condition, conditionNumber, data, properties, usedProperties, debug)
if (condition.changes) then
ret = ret .. " if (activatedConditions[".. conditionNumber .. "] and not newActiveConditions[" .. conditionNumber .. "]) then\n"
if (debug) then ret = ret .. " print('Deactivating condition " .. conditionNumber .. "' )\n"; end
table.insert(ret, " if (activatedConditions[".. conditionNumber .. "] and not newActiveConditions[" .. conditionNumber .. "]) then\n")
if (debug) then table.insert(ret, " print('Deactivating condition " .. conditionNumber .. "' )\n") end
for changeNum, change in ipairs(condition.changes) do
if (change.property) then
local propertyData = properties and properties[change.property]
if (propertyData and propertyData.type and propertyData.setter) then
usedProperties[change.property] = true;
ret = ret .. " propertyChanges['" .. change.property .. "'] = " .. formatValueForAssignment(propertyData.type, GetBaseProperty(data, change.property)) .. "\n";
if (debug) then ret = ret .. " print('- " .. change.property .. " " ..formatValueForAssignment(propertyData.type, GetBaseProperty(data, change.property)) .. "')\n"; end
table.insert(ret, " propertyChanges['" .. change.property .. "'] = "
.. formatValueForAssignment(propertyData.type, GetBaseProperty(data, change.property),
nil, nil, data)
.. "\n")
if (debug) then
table.insert(ret, " print('- " .. change.property .. " "
.. formatValueForAssignment(propertyData.type, GetBaseProperty(data, change.property),
nil, nil, data)
.. "')\n")
end
end
end
end
ret = ret .. " end\n"
table.insert(ret, " end\n")
end
return ret;
end
local function CreateActivateCondition(ret, id, condition, conditionNumber, properties, debug)
local function CreateActivateCondition(ret, id, condition, conditionNumber, data, properties, debug)
if (condition.changes) then
ret = ret .. " if (newActiveConditions[" .. conditionNumber .. "]) then\n"
ret = ret .. " if (not activatedConditions[".. conditionNumber .. "]) then\n"
if (debug) then ret = ret .. " print('Activating condition " .. conditionNumber .. "' )\n"; end
table.insert(ret, " if (newActiveConditions[" .. conditionNumber .. "]) then\n")
table.insert(ret, " if (not activatedConditions[".. conditionNumber .. "]) then\n")
if (debug) then table.insert(ret, " print('Activating condition " .. conditionNumber .. "' )\n") end
-- non active => active
for changeNum, change in ipairs(condition.changes) do
if (change.property) then
local propertyData = properties and properties[change.property]
if (propertyData and propertyData.type) then
if (propertyData.setter) then
ret = ret .. " propertyChanges['" .. change.property .. "'] = " .. formatValueForAssignment(propertyData.type, change.value) .. "\n";
if (debug) then ret = ret .. " print('- " .. change.property .. " " .. formatValueForAssignment(propertyData.type, change.value) .. "')\n"; end
table.insert(ret, " propertyChanges['" .. change.property .. "'] = "
.. formatValueForAssignment(propertyData.type, change.value, nil, nil, data) .. "\n")
if (debug) then
table.insert(ret, " print('- " .. change.property .. " "
.. formatValueForAssignment(propertyData.type, change.value, nil, nil, data) .. "')\n")
end
elseif (propertyData.action) then
local pathToCustomFunction = "nil";
local pathToFormatter = "nil"
if (WeakAuras.customConditionsFunctions[id]
and WeakAuras.customConditionsFunctions[id][conditionNumber]
and WeakAuras.customConditionsFunctions[id][conditionNumber].changes
and WeakAuras.customConditionsFunctions[id][conditionNumber].changes[changeNum]) then
pathToCustomFunction = string.format("WeakAuras.customConditionsFunctions[%q][%s].changes[%s]", id, conditionNumber, changeNum);
if (Private.ExecEnv.customConditionsFunctions[id]
and Private.ExecEnv.customConditionsFunctions[id][conditionNumber]
and Private.ExecEnv.customConditionsFunctions[id][conditionNumber].changes
and Private.ExecEnv.customConditionsFunctions[id][conditionNumber].changes[changeNum]) then
pathToCustomFunction = string.format("Private.ExecEnv.customConditionsFunctions[%q][%s].changes[%s]",
id, conditionNumber, changeNum);
end
if WeakAuras.conditionTextFormatters[id]
and WeakAuras.conditionTextFormatters[id][conditionNumber]
and WeakAuras.conditionTextFormatters[id][conditionNumber].changes
and WeakAuras.conditionTextFormatters[id][conditionNumber].changes[changeNum] then
pathToFormatter = string.format("WeakAuras.conditionTextFormatters[%q][%s].changes[%s]", id, conditionNumber, changeNum);
if Private.ExecEnv.conditionTextFormatters[id]
and Private.ExecEnv.conditionTextFormatters[id][conditionNumber]
and Private.ExecEnv.conditionTextFormatters[id][conditionNumber].changes
and Private.ExecEnv.conditionTextFormatters[id][conditionNumber].changes[changeNum] then
pathToFormatter = string.format("Private.ExecEnv.conditionTextFormatters[%q][%s].changes[%s]",
id, conditionNumber, changeNum);
end
table.insert(ret, " region:" .. propertyData.action .. "("
.. formatValueForAssignment(propertyData.type, change.value,
pathToCustomFunction, pathToFormatter, data)
.. ")" .. "\n")
if (debug) then
table.insert(ret, " print('# " .. propertyData.action .. "("
.. formatValueForAssignment(propertyData.type, change.value,
pathToCustomFunction, pathToFormatter, data)
.. "')\n")
end
ret = ret .. " region:" .. propertyData.action .. "(" .. formatValueForAssignment(propertyData.type, change.value, pathToCustomFunction, pathToFormatter) .. ")" .. "\n";
if (debug) then ret = ret .. " print('# " .. propertyData.action .. "(" .. formatValueForAssignment(propertyData.type, change.value, pathToCustomFunction, pathToFormatter) .. "')\n"; end
end
end
end
end
ret = ret .. " else\n"
table.insert(ret, " else\n")
-- active => active, only override properties
for changeNum, change in ipairs(condition.changes) do
if (change.property) then
local propertyData = properties and properties[change.property]
if (propertyData and propertyData.type and propertyData.setter) then
ret = ret .. " if(propertyChanges['" .. change.property .. "'] ~= nil) then\n"
ret = ret .. " propertyChanges['" .. change.property .. "'] = " .. formatValueForAssignment(propertyData.type, change.value) .. "\n";
if (debug) then ret = ret .. " print('- " .. change.property .. " " .. formatValueForAssignment(propertyData.type, change.value) .. "')\n"; end
ret = ret .. " end\n"
table.insert(ret, " if(propertyChanges['" .. change.property .. "'] ~= nil) then\n")
table.insert(ret, " propertyChanges['" .. change.property .. "'] = "
.. formatValueForAssignment(propertyData.type, change.value, nil, nil, data) .. "\n")
if (debug) then table.insert(ret, " print('- " .. change.property .. " "
.. formatValueForAssignment(propertyData.type, change.value, nil, nil, data) .. "')\n") end
table.insert(ret, " end\n")
end
end
end
ret = ret .. " end\n"
ret = ret .. " end\n"
ret = ret .. "\n";
ret = ret .. " activatedConditions[".. conditionNumber .. "] = newActiveConditions[" .. conditionNumber .. "]\n";
table.insert(ret, " end\n")
table.insert(ret, " end\n")
table.insert(ret, "\n")
table.insert(ret, " activatedConditions[".. conditionNumber .. "] = newActiveConditions[" .. conditionNumber .. "]\n")
end
return ret;
@@ -479,7 +594,9 @@ function Private.GetSubRegionProperties(data, properties)
if subProperties then
for key, property in pairs(subProperties) do
subIndex[key] = subIndex[key] and subIndex[key] + 1 or 1
property.display = { subIndex[key] .. ". " .. subRegionTypeData.displayName, property.display, property.defaultProperty }
property.display = { subRegionTypeData.displayName .. " " .. subIndex[key],
property.display,
property.defaultProperty }
properties["sub." .. index .. "." .. key ] = property;
end
end
@@ -489,7 +606,7 @@ end
function Private.GetProperties(data)
local properties;
local propertiesFunction = WeakAuras.regionTypes[data.regionType] and WeakAuras.regionTypes[data.regionType].properties;
local propertiesFunction = Private.regionTypes[data.regionType] and Private.regionTypes[data.regionType].properties;
if (type(propertiesFunction) == "function") then
properties = propertiesFunction(data);
elseif propertiesFunction then
@@ -505,7 +622,7 @@ end
function Private.LoadConditionPropertyFunctions(data)
local id = data.id;
if (data.conditions) then
WeakAuras.customConditionsFunctions[id] = {};
Private.ExecEnv.customConditionsFunctions[id] = {};
for conditionNumber, condition in ipairs(data.conditions) do
if (condition.changes) then
for changeIndex, change in ipairs(condition.changes) do
@@ -517,11 +634,11 @@ function Private.LoadConditionPropertyFunctions(data)
else
prefix, suffix = "return function()", "\nend";
end
local customFunc = WeakAuras.LoadFunction(prefix .. custom .. suffix, id, "condition");
local customFunc = WeakAuras.LoadFunction(prefix .. custom .. suffix);
if (customFunc) then
WeakAuras.customConditionsFunctions[id][conditionNumber] = WeakAuras.customConditionsFunctions[id][conditionNumber] or {};
WeakAuras.customConditionsFunctions[id][conditionNumber].changes = WeakAuras.customConditionsFunctions[id][conditionNumber].changes or {};
WeakAuras.customConditionsFunctions[id][conditionNumber].changes[changeIndex] = customFunc;
Private.ExecEnv.customConditionsFunctions[id][conditionNumber] = Private.ExecEnv.customConditionsFunctions[id][conditionNumber] or {};
Private.ExecEnv.customConditionsFunctions[id][conditionNumber].changes = Private.ExecEnv.customConditionsFunctions[id][conditionNumber].changes or {};
Private.ExecEnv.customConditionsFunctions[id][conditionNumber].changes[changeIndex] = customFunc;
end
end
if change.property == "chat" then
@@ -532,11 +649,11 @@ function Private.LoadConditionPropertyFunctions(data)
end
return change.value[fullKey]
end
local formatters = change.value and Private.CreateFormatters(change.value.message, getter, true)
WeakAuras.conditionTextFormatters[id] = WeakAuras.conditionTextFormatters[id] or {}
WeakAuras.conditionTextFormatters[id][conditionNumber] = WeakAuras.conditionTextFormatters[id][conditionNumber] or {};
WeakAuras.conditionTextFormatters[id][conditionNumber].changes = WeakAuras.conditionTextFormatters[id][conditionNumber].changes or {};
WeakAuras.conditionTextFormatters[id][conditionNumber].changes[changeIndex] = formatters;
local formatters = change.value and Private.CreateFormatters(change.value.message, getter, true, data)
Private.ExecEnv.conditionTextFormatters[id] = Private.ExecEnv.conditionTextFormatters[id] or {}
Private.ExecEnv.conditionTextFormatters[id][conditionNumber] = Private.ExecEnv.conditionTextFormatters[id][conditionNumber] or {};
Private.ExecEnv.conditionTextFormatters[id][conditionNumber].changes = Private.ExecEnv.conditionTextFormatters[id][conditionNumber].changes or {};
Private.ExecEnv.conditionTextFormatters[id][conditionNumber].changes[changeIndex] = formatters;
end
end
end
@@ -591,81 +708,81 @@ function Private.GetGlobalConditions()
end
local function ConstructConditionFunction(data)
local debug = false;
local debug = false
if (not data.conditions or #data.conditions == 0) then
return nil;
return nil
end
local usedProperties = {};
local usedProperties = {}
local allConditionsTemplate = Private.GetTriggerConditions(data);
allConditionsTemplate[-1] = Private.GetGlobalConditions();
local allConditionsTemplate = Private.GetTriggerConditions(data)
allConditionsTemplate[-1] = Private.GetGlobalConditions()
local ret = "";
ret = ret .. "local newActiveConditions = {};\n"
ret = ret .. "local propertyChanges = {};\n"
ret = ret .. "local nextTime;\n"
ret = ret .. string.format("local uid = %q\n", data.uid)
ret = ret .. "return function(region, hideRegion)\n";
if (debug) then ret = ret .. " print('check conditions for:', region.id, region.cloneId)\n"; end
ret = ret .. " local id = region.id\n";
ret = ret .. " local cloneId = region.cloneId or ''\n";
ret = ret .. " local state = region.states\n"
ret = ret .. " local activatedConditions = WeakAuras.GetActiveConditions(id, cloneId)\n";
ret = ret .. " wipe(newActiveConditions)\n";
ret = ret .. " local recheckTime;\n"
ret = ret .. " local now = GetTime();\n"
local ret = {""}
table.insert(ret, "local newActiveConditions = {};\n")
table.insert(ret, "local propertyChanges = {};\n")
table.insert(ret, "local nextTime;\n")
table.insert(ret, string.format("local uid = %q\n", data.uid))
table.insert(ret, "return function(region, hideRegion)\n")
if (debug) then table.insert(ret, " print('check conditions for:', region.id, region.cloneId)\n") end
table.insert(ret, " local id = region.id\n")
table.insert(ret, " local cloneId = region.cloneId or ''\n")
table.insert(ret, " local state = region.states\n")
table.insert(ret, " local activatedConditions = WeakAuras.GetActiveConditions(id, cloneId)\n")
table.insert(ret, " wipe(newActiveConditions)\n")
table.insert(ret, " local recheckTime;\n")
table.insert(ret, " local now = GetTime();\n")
local normalConditionCount = data.conditions and #data.conditions;
-- First Loop gather which conditions are active
ret = ret .. " if (not hideRegion) then\n"
local recheckCode = ""
table.insert(ret, " if (not hideRegion) then\n")
local recheckCode = {}
if (data.conditions) then
WeakAuras.conditionHelpers[data.uid] = nil
Private.ExecEnv.conditionHelpers[data.uid] = nil
for conditionNumber, condition in ipairs(data.conditions) do
local nextIsLinked = data.conditions[conditionNumber + 1] and data.conditions[conditionNumber + 1].linked
local additionalRecheckCode
ret, additionalRecheckCode = CreateCheckCondition(data.uid, ret, condition, conditionNumber, allConditionsTemplate, nextIsLinked, debug)
local additionalRecheckCode = CreateCheckCondition(data, ret, condition, conditionNumber, allConditionsTemplate, nextIsLinked, debug)
if additionalRecheckCode then
recheckCode = recheckCode .. "\n" .. additionalRecheckCode
table.insert(recheckCode, additionalRecheckCode)
end
end
end
ret = ret .. recheckCode
ret = ret .. " end\n";
table.insert(ret, table.concat(recheckCode))
table.insert(ret, " end\n")
ret = ret .. " if (recheckTime) then\n"
ret = ret .. " WeakAuras.scheduleConditionCheck(recheckTime, uid, cloneId);\n"
ret = ret .. " end\n"
table.insert(ret, " if (recheckTime) then\n")
table.insert(ret, " Private.ExecEnv.ScheduleConditionCheck(recheckTime, uid, cloneId);\n")
table.insert(ret, " else\n")
table.insert(ret, " Private.ExecEnv.CancelConditionCheck(uid, cloneId)")
table.insert(ret, " end\n")
local properties = Private.GetProperties(data);
local properties = Private.GetProperties(data)
-- Now build a property + change list
-- Second Loop deals with conditions that are no longer active
ret = ret .. " wipe(propertyChanges)\n"
table.insert(ret, " wipe(propertyChanges)\n")
if (data.conditions) then
for conditionNumber, condition in ipairs(data.conditions) do
ret = CreateDeactivateCondition(ret, condition, conditionNumber, data, properties, usedProperties, debug)
CreateDeactivateCondition(ret, condition, conditionNumber, data, properties, usedProperties, debug)
end
end
ret = ret .. "\n";
table.insert(ret, "\n")
-- Third Loop deals with conditions that are newly active
if (data.conditions) then
for conditionNumber, condition in ipairs(data.conditions) do
ret = CreateActivateCondition(ret, data.id, condition, conditionNumber, properties, debug)
CreateActivateCondition(ret, data.id, condition, conditionNumber, data, properties, debug)
end
end
-- Last apply changes to region
for property, _ in pairs(usedProperties) do
ret = ret .. " if(propertyChanges['" .. property .. "'] ~= nil) then\n"
local arg1 = "";
table.insert(ret, " if(propertyChanges['" .. property .. "'] ~= nil) then\n")
local arg1 = ""
if (properties[property].arg1) then
if (type(properties[property].arg1) == "number") then
arg1 = tostring(properties[property].arg1) .. ", ";
arg1 = tostring(properties[property].arg1) .. ", "
else
arg1 = "'" .. properties[property].arg1 .. "', ";
arg1 = "'" .. properties[property].arg1 .. "', "
end
end
@@ -675,13 +792,13 @@ local function ConstructConditionFunction(data)
base = "region.subRegions[" .. subIndex .. "]:"
end
ret = ret .. " " .. base .. properties[property].setter .. "(" .. arg1 .. formatValueForCall(properties[property].type, property) .. ")\n";
if (debug) then ret = ret .. " print('Calling " .. properties[property].setter .. " with', " .. arg1 .. formatValueForCall(properties[property].type, property) .. ")\n"; end
ret = ret .. " end\n";
table.insert(ret, " " .. base .. properties[property].setter .. "(" .. arg1 .. formatValueForCall(properties[property].type, property) .. ")\n")
if (debug) then table.insert(ret, " print('Calling " .. properties[property].setter .. " with', " .. arg1 .. formatValueForCall(properties[property].type, property) .. ")\n") end
table.insert(ret, " end\n")
end
ret = ret .. "end\n";
table.insert(ret, "end\n")
return ret;
return table.concat(ret)
end
local function CancelTimers(uid)
@@ -698,15 +815,18 @@ function Private.LoadConditionFunction(data)
CancelTimers(data.uid)
local checkConditionsFuncStr = ConstructConditionFunction(data);
local checkCondtionsFunc = checkConditionsFuncStr and WeakAuras.LoadFunction(checkConditionsFuncStr, data.id, "condition checks");
local checkConditionsFunc = checkConditionsFuncStr and Private.LoadFunction(checkConditionsFuncStr)
checkConditions[data.uid] = checkCondtionsFunc;
checkConditions[data.uid] = checkConditionsFunc;
end
function Private.RunConditions(region, uid, hideRegion)
if (checkConditions[uid]) then
Private.ActivateAuraEnvironmentForRegion(region)
checkConditions[uid](region, hideRegion);
local ok = pcall(checkConditions[uid], region, hideRegion);
if not ok then
Private.GetErrorHandlerUid(uid, L["Execute Conditions"])
end
Private.ActivateAuraEnvironment()
end
end
@@ -743,28 +863,39 @@ local function runDynamicConditionFunctions(funcs)
end
end
local function handleDynamicConditions(self, event)
Private.StartProfileSystem("dynamic conditions")
local function UpdateDynamicConditionsStates(self, event)
if (globalDynamicConditionFuncs[event]) then
for i, func in ipairs(globalDynamicConditionFuncs[event]) do
func(globalConditionState);
end
end
end
local function handleDynamicConditions(self, event)
Private.StartProfileSystem("dynamic conditions")
UpdateDynamicConditionsStates(self, event)
if (dynamicConditions[event]) then
runDynamicConditionFunctions(dynamicConditions[event]);
end
Private.StopProfileSystem("dynamic conditions")
end
local function handleDynamicConditionsPerUnit(self, event, unit)
Private.StartProfileSystem("dynamic conditions")
if unit and unit == self.unit then
local function UpdateDynamicConditionsPerUnitState(self, event, unit)
if unit then
local unitEvent = event..":"..unit
if globalDynamicConditionFuncs[unitEvent] then
for i, func in ipairs(globalDynamicConditionFuncs[unitEvent]) do
func(globalConditionState);
end
end
end
end
local function handleDynamicConditionsPerUnit(self, event, unit)
Private.StartProfileSystem("dynamic conditions")
if unit then
local unitEvent = event..":"..unit
UpdateDynamicConditionsPerUnitState(self, event, unit)
if (dynamicConditions[unitEvent]) then
runDynamicConditionFunctions(dynamicConditions[unitEvent]);
end
@@ -843,10 +974,10 @@ function Private.RegisterForGlobalConditions(uid)
end
if (next(register) and not dynamicConditionsFrame) then
dynamicConditionsFrame = CreateFrame("FRAME");
dynamicConditionsFrame = CreateFrame("Frame");
dynamicConditionsFrame:SetScript("OnEvent", handleDynamicConditions);
dynamicConditionsFrame.units = {}
WeakAuras.frames["Rerun Conditions Frame"] = dynamicConditionsFrame
Private.frames["Rerun Conditions Frame"] = dynamicConditionsFrame
end
for event in pairs(register) do
@@ -860,13 +991,14 @@ function Private.RegisterForGlobalConditions(uid)
if unitEvent and unit then
unit = unit:lower()
if not dynamicConditionsFrame.units[unit] then
dynamicConditionsFrame.units[unit] = CreateFrame("FRAME");
dynamicConditionsFrame.units[unit] = CreateFrame("Frame");
dynamicConditionsFrame.units[unit]:SetScript("OnEvent", handleDynamicConditionsPerUnit);
end
dynamicConditionsFrame.units[unit].unit = unit;
pcall(dynamicConditionsFrame.RegisterEvent, dynamicConditionsFrame.units[unit], unitEvent);
pcall(dynamicConditionsFrame.units[unit].RegisterUnitEvent, dynamicConditionsFrame.units[unit], unitEvent, unit);
UpdateDynamicConditionsPerUnitState(dynamicConditionsFrame, event, unit)
else
pcall(dynamicConditionsFrame.RegisterEvent, dynamicConditionsFrame, event);
UpdateDynamicConditionsStates(dynamicConditionsFrame, event)
end
end
end
@@ -879,7 +1011,7 @@ function Private.UnregisterForGlobalConditions(uid)
local unitEvent, unit = event:match("([^:]+):([^:]+)")
if unitEvent and unit then
unit = unit:lower()
dynamicConditionsFrame.units[unit]:UnregisterEvent(unitEvent)
pcall(dynamicConditionsFrame.units[unit].UnregisterEvent, dynamicConditionsFrame.units[unit], unitEvent);
elseif (event == "FRAME_UPDATE" or event == "WA_SPELL_RANGECHECK") then
if (event == "FRAME_UPDATE" and dynamicConditions["WA_SPELL_RANGECHECK"] == nil)
or (event == "WA_SPELL_RANGECHECK" and dynamicConditions["FRAME_UPDATE"] == nil)
@@ -888,7 +1020,7 @@ function Private.UnregisterForGlobalConditions(uid)
dynamicConditionsFrame.onUpdate = false
end
else
dynamicConditionsFrame:UnregisterEvent(event)
pcall(dynamicConditionsFrame.UnregisterEvent, dynamicConditionsFrame, event);
end
dynamicConditions[event] = nil
end
@@ -909,7 +1041,7 @@ function Private.UnloadAllConditions()
dynamicConditions = {}
if dynamicConditionsFrame then
dynamicConditionsFrame:UnregisterAllEvents()
for unit, frame in pairs(dynamicConditionsFrame.units) do
for _, frame in pairs(dynamicConditionsFrame.units) do
frame:UnregisterAllEvents()
end
dynamicConditionsFrame:SetScript("OnUpdate", nil)
+114
View File
@@ -0,0 +1,114 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local WeakAuras = WeakAuras
local L = WeakAuras.L
local debugLogs = {}
local enabled = {}
Private.DebugLog = {
Print = function(uid, text, ...) end,
Clear = function(uid) end,
SetEnabled = function(uid, enabled) end,
IsEnabled = function(uid) end,
GetLogs = function(uid) end
}
local function serialize(log, input)
if type(input) == "table" then
if log[#log] == "" then
log[#log] = L["Dumping table"]
else
tinsert(log, L["Dumping table"])
end
-- Use dump to create a table dump, because that already handles depth limitation
-- and cycles and looks nice
-- But this requires temporarily setting DEFAULT_CHAT_FRAME
-- Nothing can go wrong with that.
local defaultChatFrame = _G.DEFAULT_CHAT_FRAME
_G.DEFAULT_CHAT_FRAME = log
DevTools_Dump(input)
_G.DEFAULT_CHAT_FRAME = defaultChatFrame
tinsert(log, "")
else
if log[#log] == "" then
log[#log] = tostring(input)
else
log[#log] = log[#log] .. " " .. tostring(input)
end
end
end
function Private.DebugLog.Print(uid, text, ...)
if enabled[uid] then
local log = debugLogs[uid]
tinsert(log, "")
if select('#', ...) == 0 then
serialize(log, text)
else
serialize(log, text)
local texts = {...}
for i = 1, select('#', ...) do
local v = select(i, ...)
serialize(log, v)
end
end
if #log > 1000 then
Private.AuraWarnings.UpdateWarning(uid, "Debug Log", "warning",
L["Debug Log contains more than 1000 entries"],
true)
end
end
end
local function AddMessage(self, msg)
tinsert(self, msg)
end
function Private.DebugLog.Clear(uid)
if enabled[uid] then
debugLogs[uid] = {
AddMessage = AddMessage
}
-- Dance to clear a potential console message from the AuraWarnings
Private.AuraWarnings.UpdateWarning(uid, "Debug Log", "info")
Private.AuraWarnings.UpdateWarning(uid, "Debug Log", "info", L["Debug Logging enabled"])
end
end
function Private.DebugLog.SetEnabled(uid, enable)
if enabled[uid] == enable then
return
end
enabled[uid] = enable
if enable then
debugLogs[uid] = {
AddMessage = AddMessage
}
Private.AuraWarnings.UpdateWarning(uid, "Debug Log", "info", L["Debug Logging enabled"])
else
debugLogs[uid] = nil
Private.AuraWarnings.UpdateWarning(uid, "Debug Log", "info")
end
end
function Private.DebugLog.IsEnabled(uid)
return enabled[uid]
end
function Private.DebugLog.GetLogs(uid)
if debugLogs[uid] then
return table.concat(debugLogs[uid], "\n")
end
end
local function OnDelete(_, uid)
debugLogs[uid] = nil
enabled[uid] = nil
end
Private.callbacks:RegisterCallback("Delete", OnDelete)
+63
View File
@@ -0,0 +1,63 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
Private.DiscordList = {
[=[007bb]=],
[=[AcidWeb]=],
[=[aelen]=],
[=[Aishuu]=],
[=[Ariani Continuity]=],
[=[Azortharion]=],
[=[BadBrain]=],
[=[Bart]=],
[=[Boneshock]=],
[=[Boxthor]=],
[=[Burlis]=],
[=[Causese]=],
[=[Chab]=],
[=[cheswick]=],
[=[Darian]=],
[=[Desik]=],
[=[DjinnFish]=],
[=[exality]=],
[=[Fatpala]=],
[=[Fels]=],
[=[Fenchurch]=],
[=[Guffin]=],
[=[Ifor]=],
[=[Ipwnturkeys]=],
[=[Ironi]=],
[=[Jiberish]=],
[=[Jods]=],
[=[kanegasi]=],
[=[Koxy]=],
[=[Listefano]=],
[=[Luckyone]=],
[=[Luxthos]=],
[=[m33shoq]=],
[=[Marcelian]=],
[=[MetalMusicMan]=],
[=[Murph]=],
[=[Mynze]=],
[=[Nona]=],
[=[NostraDumAzz]=],
[=[Ocelots]=],
[=[Oi]=],
[=[Ora]=],
[=[phoenix7700]=],
[=[Pseiko]=],
[=[reggie]=],
[=[Reloe]=],
[=[Spaten]=],
[=[Tollo]=],
[=[Translit]=],
[=[update]=],
[=[vozochris]=],
[=[Wizeowel]=],
[=[Xepheris]=],
}
Private.DiscordListCJ = {
}
Private.DiscordListK = {
}
+1354 -1130
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local WeakAuras = WeakAuras
+70 -21
View File
@@ -1,28 +1,24 @@
local AddonName, Private = ...
WeakAuras = {}
WeakAuras.L = {}
WeakAuras.frames = {}
Private.frames = {}
WeakAuras.normalWidth = 1.3
WeakAuras.halfWidth = WeakAuras.normalWidth / 2
WeakAuras.doubleWidth = WeakAuras.normalWidth * 2
local versionStringFromToc = GetAddOnMetadata("WeakAuras", "Version")
local versionString = "4.1.2"
local buildTime = "20240701180000"
local isAwesomeEnabled = C_NamePlate and C_NamePlate.GetNamePlateForUnit or false
local versionString = "5.19.1 Beta"
local buildTime = "20250127040000"
local isAwesomeEnabled = C_NamePlate and C_NamePlate.GetNamePlateForUnit and true or false
WeakAuras.versionString = versionStringFromToc
WeakAuras.versionString = versionString
WeakAuras.buildTime = buildTime
WeakAuras.newFeatureString = "|TInterface\\OptionsFrame\\UI-OptionsFrame-NewFeatureIcon:0|t"
WeakAuras.BuildInfo = select(4, GetBuildInfo())
function WeakAuras.isAwesomeEnabled()
return isAwesomeEnabled
end
function WeakAuras.IsClassic()
return false
return isAwesomeEnabled or false
end
function WeakAuras.IsCorrectVersion()
@@ -33,31 +29,82 @@ WeakAuras.prettyPrint = function(...)
print("|cff9900ffWeakAuras:|r ", ...)
end
if versionString ~= versionStringFromToc and versionStringFromToc ~= "Dev" then
WeakAuras.prettyPrint("You need to restart your game client to complete the WeakAuras update!")
end
-- Force enable WeakAurasCompanion and Archive because some addon managers interfere with it
EnableAddOn("WeakAurasCompanion")
EnableAddOn("WeakAurasArchive")
local libsAreOk = true
do
local StandAloneLibs = {
"Archivist",
"LibStub"
}
local LibStubLibs = {
"CallbackHandler-1.0",
"AceTimer-3.0",
"AceSerializer-3.0",
"AceComm-3.0",
"LibSharedMedia-3.0",
"LibDataBroker-1.1",
"LibCompress",
"SpellRange-1.0",
"LibCustomGlow-1.0",
"LibDBIcon-1.0",
"LibGetFrame-1.0",
"LibSerialize",
"LibGroupTalents-1.0",
}
for _, lib in ipairs(StandAloneLibs) do
if not lib then
libsAreOk = false
WeakAuras.prettyPrint("Missing library:", lib)
end
end
if LibStub then
for _, lib in ipairs(LibStubLibs) do
if not LibStub:GetLibrary(lib, true) then
libsAreOk = false
WeakAuras.prettyPrint("Missing library:", lib)
end
end
else
libsAreOk = false
end
end
function WeakAuras.IsLibsOK()
return libsAreOk
end
if not libsAreOk then
WeakAuras.prettyPrint("WeakAuras is missing necessary libraries. Please reinstall a proper package.")
end
if versionString ~= versionStringFromToc and versionStringFromToc ~= "Dev" then
WeakAuras.prettyPrint("You need to restart your game client to complete the WeakAuras update!")
end
if not WeakAuras.IsLibsOK() then
WeakAuras.prettyPrint("WeakAuras is missing necessary libraries. Please reinstall a proper package.")
end
-- These function stubs are defined here to reduce the number of errors that occur if WeakAuras.lua fails to compile
function WeakAuras.RegisterRegionType()
function Private.RegisterRegionType(_, _, _ ,_)
end
function WeakAuras.RegisterRegionOptions()
function Private.RegisterRegionOptions(_, _ , _ ,_)
end
function Private.StartProfileSystem()
function Private.StartProfileSystem(_)
end
function Private.StartProfileAura()
function Private.StartProfileAura(_)
end
function Private.StopProfileSystem()
function Private.StopProfileSystem(_)
end
function Private.StopProfileAura()
function Private.StopProfileAura(_)
end
function Private.StartProfileUID()
@@ -66,8 +113,10 @@ end
function Private.StopProfileUID()
end
Private.ExecEnv = {}
-- If WeakAuras shuts down due to being installed on the wrong target, keep the bindings from erroring
function WeakAuras.StartProfile()
function WeakAuras.StartProfile(_)
end
function WeakAuras.StopProfile()
+159
View File
@@ -0,0 +1,159 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
-- Lua APIs
local unpack, wipe = unpack, wipe
-- WoW APIs
local UnitName, UnitIsUnit, UnitClass, GetNumGroupMembers = UnitName, UnitIsUnit, UnitClass, GetNumGroupMembers
local LibGroupTalents = LibStub("LibGroupTalents-1.0")
local nameToGlyphs = {}
local nameToSpecMap = {}
local nameToUnitRole = {}
local nameToUnitMap = {
[UnitName("player")] = "player"
}
local subscribers = {}
Private.LibGroupTalentsWrapper = {
Register = function(f) end,
SpecForUnit = function(unit) end,
GetUnitRole = function(unit) end,
SpecRolePositionForUnit = function(unit) end,
CheckTalentForUnit = function(unit) end,
CheckGlyphForUnit = function(unit) end,
}
if LibGroupTalents then
--- LibGroupTalents callback for talents and glyphs
function Private.LibGroupTalentsWrapper:LibGroupTalentsCallback(_, _, unit)
if not unit then
return
end
local unitName = UnitName(unit)
local ownName = UnitName("player")
local numMembers = GetNumGroupMembers()
local units = IsInRaid() and WeakAuras.raidUnits or WeakAuras.partyUnits
nameToUnitMap = { [ownName] = "player" }
for i = 1, numMembers do
local groupUnitName = UnitName(units[i])
if groupUnitName then
nameToUnitMap[groupUnitName] = groupUnit
end
end
for storedName in pairs(nameToSpecMap) do
if not nameToUnitMap[storedName] then
nameToSpecMap[storedName] = nil
nameToGlyphs[storedName] = nil
nameToUnitRole[storedName] = nil
end
end
local specInfo = { LibGroupTalents:GetUnitTalentSpec(unit) }
local class = select(2, UnitClass(unit))
if specInfo and #specInfo > 0 and class then
nameToSpecMap[unitName] = {
class .. specInfo[1], unpack(specInfo)
}
end
nameToUnitRole[unitName] = LibGroupTalents:GetUnitRole(unit)
nameToGlyphs[unitName] = {}
for _, glyphId in ipairs({ LibGroupTalents:GetUnitGlyphs(unit) }) do
if glyphId then
nameToGlyphs[unitName][glyphId] = true
end
end
if nameToUnitMap[unitName] then
for _, f in ipairs(subscribers) do
f(nameToUnitMap[unitName])
end
end
end
LibGroupTalents.RegisterCallback(Private.LibGroupTalentsWrapper, "LibGroupTalents_Update", "LibGroupTalentsCallback")
LibGroupTalents.RegisterCallback(Private.LibGroupTalentsWrapper, "LibGroupTalents_GlyphUpdate", "LibGroupTalentsCallback")
function Private.LibGroupTalentsWrapper.Register(f)
table.insert(subscribers, f)
end
function Private.LibGroupTalentsWrapper.SpecForUnit(unit)
local unitName = UnitName(unit)
local class = select(2, UnitClass(unit))
if nameToSpecMap[unitName] then
return nameToSpecMap[unitName]
end
if UnitIsUnit(unit, "player") and class then
local specInfo = { LibGroupTalents:GetUnitTalentSpec(unit) }
if specInfo and #specInfo > 0 then
return class .. specInfo[1], unpack(specInfo)
end
end
end
function Private.LibGroupTalentsWrapper.GetUnitRole(unit)
local unitName = UnitName(unit)
if nameToUnitRole[unitName] then
return nameToUnitRole[unitName]
end
if UnitIsUnit(unit, "player") then
local unitRole = LibGroupTalents:GetUnitRole(unit)
return unitRole
end
end
function Private.LibGroupTalentsWrapper.SpecRolePositionForUnit(unit)
local data = nameToSpecMap[UnitName(unit)]
if data then
return unpack(data, 2)
end
if UnitIsUnit(unit, "player") then
return LibGroupTalents:GetUnitTalentSpec(unit)
end
end
function Private.LibGroupTalentsWrapper.CheckTalentForUnit(unit, talentId)
return UnitIsUnit(unit, "player") and LibGroupTalents:UnitHasTalent(unit, talentId) and true or nil
end
function Private.LibGroupTalentsWrapper.CheckGlyphForUnit(unit, glyphId)
local unitName = UnitName(unit)
if nameToGlyphs[unitName] and nameToGlyphs[unitName][glyphId] then
return true
end
if UnitIsUnit(unit, "player") then
local glyphs = { LibGroupTalents:GetUnitGlyphs(unit) }
if glyphs then
for _, id in ipairs(glyphs) do
if id == glyphId then
return true
end
end
end
end
end
end
-- Export for GenericTrigger/Custom Code
WeakAuras.SpecForUnit = Private.LibGroupTalentsWrapper.SpecForUnit
WeakAuras.GetUnitRole = Private.LibGroupTalentsWrapper.GetUnitRole
WeakAuras.SpecRolePositionForUnit = Private.LibGroupTalentsWrapper.SpecRolePositionForUnit
WeakAuras.CheckTalentForUnit = Private.LibGroupTalentsWrapper.CheckTalentForUnit
WeakAuras.CheckGlyphForUnit = Private.LibGroupTalentsWrapper.CheckGlyphForUnit
@@ -0,0 +1,292 @@
-- LibBabble-3.0 is hereby placed in the Public Domain
-- Credits: ckknight
local LIBBABBLE_MAJOR, LIBBABBLE_MINOR = "LibBabble-3.0", 2
local LibBabble = LibStub:NewLibrary(LIBBABBLE_MAJOR, LIBBABBLE_MINOR)
if not LibBabble then
return
end
local data = LibBabble.data or {}
for k,v in pairs(LibBabble) do
LibBabble[k] = nil
end
LibBabble.data = data
local tablesToDB = {}
for namespace, db in pairs(data) do
for k,v in pairs(db) do
tablesToDB[v] = db
end
end
local function warn(message)
local _, ret = pcall(error, message, 3)
geterrorhandler()(ret)
end
local lookup_mt = { __index = function(self, key)
local db = tablesToDB[self]
local current_key = db.current[key]
if current_key then
self[key] = current_key
return current_key
end
local base_key = db.base[key]
local real_MAJOR_VERSION
for k,v in pairs(data) do
if v == db then
real_MAJOR_VERSION = k
break
end
end
if not real_MAJOR_VERSION then
real_MAJOR_VERSION = LIBBABBLE_MAJOR
end
if base_key then
warn(("%s: Translation %q not found for locale %q"):format(real_MAJOR_VERSION, key, GetLocale()))
rawset(self, key, base_key)
return base_key
end
warn(("%s: Translation %q not found."):format(real_MAJOR_VERSION, key))
rawset(self, key, key)
return key
end }
local function initLookup(module, lookup)
local db = tablesToDB[module]
for k in pairs(lookup) do
lookup[k] = nil
end
setmetatable(lookup, lookup_mt)
tablesToDB[lookup] = db
db.lookup = lookup
return lookup
end
local function initReverse(module, reverse)
local db = tablesToDB[module]
for k in pairs(reverse) do
reverse[k] = nil
end
for k,v in pairs(db.current) do
reverse[v] = k
end
tablesToDB[reverse] = db
db.reverse = reverse
db.reverseIterators = nil
return reverse
end
local prototype = {}
local prototype_mt = {__index = prototype}
--[[---------------------------------------------------------------------------
Notes:
* If you try to access a nonexistent key, it will warn but allow the code to pass through.
Returns:
A lookup table for english to localized words.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
local BL = B:GetLookupTable()
assert(BL["Some english word"] == "Some localized word")
DoSomething(BL["Some english word that doesn't exist"]) -- warning!
-----------------------------------------------------------------------------]]
function prototype:GetLookupTable()
local db = tablesToDB[self]
local lookup = db.lookup
if lookup then
return lookup
end
return initLookup(self, {})
end
--[[---------------------------------------------------------------------------
Notes:
* If you try to access a nonexistent key, it will return nil.
Returns:
A lookup table for english to localized words.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
local B_has = B:GetUnstrictLookupTable()
assert(B_has["Some english word"] == "Some localized word")
assert(B_has["Some english word that doesn't exist"] == nil)
-----------------------------------------------------------------------------]]
function prototype:GetUnstrictLookupTable()
local db = tablesToDB[self]
return db.current
end
--[[---------------------------------------------------------------------------
Notes:
* If you try to access a nonexistent key, it will return nil.
* This is useful for checking if the base (English) table has a key, even if the localized one does not have it registered.
Returns:
A lookup table for english to localized words.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
local B_hasBase = B:GetBaseLookupTable()
assert(B_hasBase["Some english word"] == "Some english word")
assert(B_hasBase["Some english word that doesn't exist"] == nil)
-----------------------------------------------------------------------------]]
function prototype:GetBaseLookupTable()
local db = tablesToDB[self]
return db.base
end
--[[---------------------------------------------------------------------------
Notes:
* If you try to access a nonexistent key, it will return nil.
* This will return only one English word that it maps to, if there are more than one to check, see :GetReverseIterator("word")
Returns:
A lookup table for localized to english words.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
local BR = B:GetReverseLookupTable()
assert(BR["Some localized word"] == "Some english word")
assert(BR["Some localized word that doesn't exist"] == nil)
-----------------------------------------------------------------------------]]
function prototype:GetReverseLookupTable()
local db = tablesToDB[self]
local reverse = db.reverse
if reverse then
return reverse
end
return initReverse(self, {})
end
local blank = {}
local weakVal = {__mode='v'}
--[[---------------------------------------------------------------------------
Arguments:
string - the localized word to chek for.
Returns:
An iterator to traverse all English words that map to the given key
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
for word in B:GetReverseIterator("Some localized word") do
DoSomething(word)
end
-----------------------------------------------------------------------------]]
function prototype:GetReverseIterator(key)
local db = tablesToDB[self]
local reverseIterators = db.reverseIterators
if not reverseIterators then
reverseIterators = setmetatable({}, weakVal)
db.reverseIterators = reverseIterators
elseif reverseIterators[key] then
return pairs(reverseIterators[key])
end
local t
for k,v in pairs(db.current) do
if v == key then
if not t then
t = {}
end
t[k] = true
end
end
reverseIterators[key] = t or blank
return pairs(reverseIterators[key])
end
--[[---------------------------------------------------------------------------
Returns:
An iterator to traverse all translations English to localized.
Example:
local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want.
for english, localized in B:Iterate() do
DoSomething(english, localized)
end
-----------------------------------------------------------------------------]]
function prototype:Iterate()
local db = tablesToDB[self]
return pairs(db.current)
end
-- #NODOC
-- modules need to call this to set the base table
function prototype:SetBaseTranslations(base)
local db = tablesToDB[self]
local oldBase = db.base
if oldBase then
for k in pairs(oldBase) do
oldBase[k] = nil
end
for k, v in pairs(base) do
oldBase[k] = v
end
base = oldBase
else
db.base = base
end
for k,v in pairs(base) do
if v == true then
base[k] = k
end
end
end
local function init(module)
local db = tablesToDB[module]
if db.lookup then
initLookup(module, db.lookup)
end
if db.reverse then
initReverse(module, db.reverse)
end
db.reverseIterators = nil
end
-- #NODOC
-- modules need to call this to set the current table. if current is true, use the base table.
function prototype:SetCurrentTranslations(current)
local db = tablesToDB[self]
if current == true then
db.current = db.base
else
local oldCurrent = db.current
if oldCurrent then
for k in pairs(oldCurrent) do
oldCurrent[k] = nil
end
for k, v in pairs(current) do
oldCurrent[k] = v
end
current = oldCurrent
else
db.current = current
end
end
init(self)
end
for namespace, db in pairs(data) do
setmetatable(db.module, prototype_mt)
init(db.module)
end
-- #NODOC
-- modules need to call this to create a new namespace.
function LibBabble:New(namespace, minor)
local module, oldminor = LibStub:NewLibrary(namespace, minor)
if not module then
return
end
if not oldminor then
local db = {
module = module,
}
data[namespace] = db
tablesToDB[module] = db
else
for k,v in pairs(module) do
module[k] = nil
end
end
setmetatable(module, prototype_mt)
return module
end
@@ -0,0 +1,295 @@
--[[
Name: LibBabble-TalentTree-3.0
Revision: $Rev: 26 $
Maintainers: ckknight, nevcairiel, Ackis
Website: http://www.wowace.com/projects/libbabble-talenttree-3-0/
Dependencies: None
License: MIT
]]
local MAJOR_VERSION = "LibBabble-TalentTree-3.0"
local MINOR_VERSION = 90000 + tonumber(("$Rev: 26 $"):match("%d+"))
if not LibStub then error(MAJOR_VERSION .. " requires LibStub.") end
local lib = LibStub("LibBabble-3.0"):New(MAJOR_VERSION, MINOR_VERSION)
if not lib then return end
local GAME_LOCALE = GetLocale()
lib:SetBaseTranslations {
Affliction = "Affliction",
Arcane = "Arcane",
Arms = "Arms",
Assassination = "Assassination",
Balance = "Balance",
["Beast Mastery"] = "Beast Mastery",
Blood = "Blood",
Combat = "Combat",
Demonology = "Demonology",
Destruction = "Destruction",
Discipline = "Discipline",
Elemental = "Elemental",
Enhancement = "Enhancement",
["Feral Combat"] = "Feral Combat",
Fire = "Fire",
Frost = "Frost",
Fury = "Fury",
Holy = "Holy",
Hybrid = "Hybrid",
Marksmanship = "Marksmanship",
Protection = "Protection",
Restoration = "Restoration",
Retribution = "Retribution",
Shadow = "Shadow",
Subtlety = "Subtlety",
Survival = "Survival",
Unholy = "Unholy",
}
if GAME_LOCALE == "enUS" then
lib:SetCurrentTranslations(true)
elseif GAME_LOCALE == "deDE" then
lib:SetCurrentTranslations {
Affliction = "Gebrechen",
Arcane = "Arkan",
Arms = "Waffen",
Assassination = "Meucheln",
Balance = "Gleichgewicht",
["Beast Mastery"] = "Tierherrschaft",
Blood = "Blut",
Combat = "Kampf",
Demonology = "Dämonologie",
Destruction = "Zerstörung",
Discipline = "Disziplin",
Elemental = "Elementar",
Enhancement = "Verstärkung",
["Feral Combat"] = "Wilder Kampf",
Fire = "Feuer",
Frost = "Frost",
Fury = "Furor",
Holy = "Heilig",
Hybrid = "Hybride",
Marksmanship = "Treffsicherheit",
Protection = "Schutz",
Restoration = "Wiederherstellung",
Retribution = "Vergeltung",
Shadow = "Schatten",
Subtlety = "Täuschung",
Survival = "Überleben",
Unholy = "Unheilig",
}
elseif GAME_LOCALE == "frFR" then
lib:SetCurrentTranslations {
Affliction = "Affliction",
Arcane = "Arcane",
Arms = "Armes",
Assassination = "Assassinat",
Balance = "Equilibre",
["Beast Mastery"] = "Maîtrise des bêtes",
Blood = "Sang",
Combat = "Combat",
Demonology = "Démonologie",
Destruction = "Destruction",
Discipline = "Discipline",
Elemental = "Elémentaire",
Enhancement = "Amélioration",
["Feral Combat"] = "Combat farouche",
Fire = "Feu",
Frost = "Givre",
Fury = "Fureur",
Holy = "Sacré",
Hybrid = "Hybride",
Marksmanship = "Précision",
Protection = "Protection",
Restoration = "Restauration",
Retribution = "Vindicte",
Shadow = "Ombre",
Subtlety = "Finesse",
Survival = "Survie",
Unholy = "Impie",
}
elseif GAME_LOCALE == "koKR" then
lib:SetCurrentTranslations {
Affliction = "고통",
Arcane = "비전",
Arms = "무기",
Assassination = "암살",
Balance = "조화",
["Beast Mastery"] = "야수",
Blood = "혈기",
Combat = "전투",
Demonology = "악마",
Destruction = "파괴",
Discipline = "수양",
Elemental = "정기",
Enhancement = "고양",
["Feral Combat"] = "야성",
Fire = "화염",
Frost = "냉기",
Fury = "분노",
Holy = "신성",
Hybrid = "하이브리드",
Marksmanship = "사격",
Protection = "방어",
Restoration = "복원",
Retribution = "징벌",
Shadow = "암흑",
Subtlety = "잠행",
Survival = "생존",
Unholy = "부정",
}
elseif GAME_LOCALE == "esES" then
lib:SetCurrentTranslations {
Affliction = "Aflicción",
Arcane = "Arcano",
Arms = "Armas",
Assassination = "Asesinato",
Balance = "Equilibrio",
["Beast Mastery"] = "Dominio de bestias",
Blood = "Sangre",
Combat = "Combate",
Demonology = "Demonología",
Destruction = "Destrucción",
Discipline = "Disciplina",
Elemental = "Elemental",
Enhancement = "Mejora",
["Feral Combat"] = "Combate Feral",
Fire = "Fuego",
Frost = "Escarcha",
Fury = "Furia",
Holy = "Sagrado",
Hybrid = "Híbrido",
Marksmanship = "Puntería",
Protection = "Protección",
Restoration = "Restauración",
Retribution = "Reprensión",
Shadow = "Sombras",
Subtlety = "Sutileza",
Survival = "Supervivencia",
Unholy = "Profano",
}
elseif GAME_LOCALE == "esMX" then
lib:SetCurrentTranslations {
Affliction = "Aflicción",
Arcane = "Arcano",
Arms = "Armas",
Assassination = "Asesinato",
Balance = "Balance",
["Beast Mastery"] = "Bestias",
Blood = "Sangre",
Combat = "Combate",
Demonology = "Demonología",
Destruction = "Destrucción",
Discipline = "Disciplina",
Elemental = "Elemental",
Enhancement = "Mejora",
["Feral Combat"] = "Combate feral",
Fire = "Fuego",
Frost = "Escarcha",
Fury = "Furia",
Holy = "Sagrado",
Hybrid = "Híbrido",
Marksmanship = "Puntería",
Protection = "Protección",
Restoration = "Restauración",
Retribution = "Reprensión",
Shadow = "Sombra",
Subtlety = "Sutileza",
Survival = "Supervivencia",
Unholy = "Profano",
}
elseif GAME_LOCALE == "ruRU" then
lib:SetCurrentTranslations {
Affliction = "Колдовство",
Arcane = "Тайная магия",
Arms = "Оружие",
Assassination = "Убийство",
Balance = "Баланс",
["Beast Mastery"] = "Чувство зверя",
Blood = "Кровь",
Combat = "Бой",
Demonology = "Демонология",
Destruction = "Разрушение",
Discipline = "Послушание",
Elemental = "Укрощение стихии",
Enhancement = "Совершенствование",
["Feral Combat"] = "Сила зверя",
Fire = "Огонь",
Frost = "Лед",
Fury = "Неистовство",
Holy = "Свет",
Hybrid = "Гибрид",
Marksmanship = "Стрельба",
Protection = "Защита",
Restoration = "Исцеление",
Retribution = "Возмездие",
Shadow = "Темная магия",
Subtlety = "Скрытность",
Survival = "Выживание",
Unholy = "Нечестивость",
}
elseif GAME_LOCALE == "zhCN" then
lib:SetCurrentTranslations {
Affliction = "痛苦",
Arcane = "奥术",
Arms = "武器",
Assassination = "刺杀",
Balance = "平衡",
["Beast Mastery"] = "野兽控制",
Blood = "鲜血",
Combat = "战斗",
Demonology = "恶魔学识",
Destruction = "毁灭",
Discipline = "戒律",
Elemental = "元素战斗",
Enhancement = "增强",
["Feral Combat"] = "野性战斗",
Fire = "火焰",
Frost = "冰霜",
Fury = "狂怒",
Holy = "神圣",
Hybrid = "混合",
Marksmanship = "射击",
Protection = "防护",
Restoration = "恢复",
Retribution = "惩戒",
Shadow = "暗影魔法",
Subtlety = "敏锐",
Survival = "生存技能",
Unholy = "邪恶",
}
elseif GAME_LOCALE == "zhTW" then
lib:SetCurrentTranslations {
Affliction = "痛苦",
Arcane = "秘法",
Arms = "武器",
Assassination = "刺殺",
Balance = "平衡",
["Beast Mastery"] = "野獸控制",
Blood = "血魄",
Combat = "戰鬥",
Demonology = "惡魔學識",
Destruction = "毀滅",
Discipline = "戒律",
Elemental = "元素",
Enhancement = "增強",
["Feral Combat"] = "野性戰鬥",
Fire = "火焰",
Frost = "冰霜",
Fury = "狂怒",
Holy = "神聖",
Hybrid = "混合",
Marksmanship = "射擊",
Protection = "防護",
Restoration = "恢復",
Retribution = "懲戒",
Shadow = "暗影",
Subtlety = "敏銳",
Survival = "生存",
Unholy = "穢邪",
}
else
error(("%s: Locale %q not supported"):format(MAJOR_VERSION, GAME_LOCALE))
end
@@ -0,0 +1,21 @@
## Interface: 30300
## LoadOnDemand: 1
## Title: Lib: Babble-TalentTree-3.0
## Notes: A library to help with localization of talent trees.
## Notes-deDE: BabbleLib ist eine Bibliothek, die bei der Lokalisierung helfen soll.
## Notes-esES: Una biblioteca para ayudar con las localizaciones.
## Notes-frFR: Une bibliothèque d'aide à la localisation.
## Notes-ruRU: Библиотека для локализации аддонов.
## Notes-zhCN: 为本地化服务的支持库[声望阵营]
## Notes-zhTW: 為本地化服務的函式庫[聲望陣營]
## Author: Pneumatus
## X-Category: Library
## X-License: MIT
## X-Curse-Packaged-Version: 3.3-release39
## X-Curse-Project-Name: LibBabble-TalentTree-3.0
## X-Curse-Project-ID: libbabble-talenttree-3-0
## X-Curse-Repository-ID: wow/libbabble-talenttree-3-0/mainline
LibStub\LibStub.lua
lib.xml
@@ -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="LibBabble-3.0.lua" />
<Script file="LibBabble-TalentTree-3.0.lua" />
</Ui>
@@ -1,5 +1,5 @@
local MAJOR_VERSION = "LibCustomGlow-1.0"
local MINOR_VERSION = 15
local MINOR_VERSION = 16
if not LibStub then error(MAJOR_VERSION .. " requires LibStub.") end
local lib, oldversion = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION)
if not lib then return end
@@ -219,6 +219,7 @@ function lib.PixelGlow_Start(r, color, N, frequency, length, th, xOffset, yOffse
pSizeChanged(f)
f:SetScript("OnSizeChanged", pSizeChanged)
pUpdate(f, 0)
f:SetScript("OnUpdate", pUpdate)
end
@@ -246,6 +247,7 @@ local function acSizeChanged(self, width, height)
end
if width ~= self.info.width or height ~= self.info.height then
if width*height == 0 then return end
self.info.width = width
self.info.height = height
self.info.perimeter = 2 * (width + height)
@@ -303,6 +305,7 @@ function lib.AutoCastGlow_Start(r, color, N, frequency, scale, xOffset, yOffset,
acSizeChanged(f)
f:SetScript("OnSizeChanged", acSizeChanged)
f:SetScript("OnUpdate", acUpdate)
acUpdate(f, 0)
end
function lib.AutoCastGlow_Stop(r, key)
@@ -715,6 +718,14 @@ end
local ButtonGlowTextures = {["spark"] = true, ["innerGlow"] = true, ["innerGlowOver"] = true, ["outerGlow"] = true, ["outerGlowOver"] = true, ["ants"] = true}
local function noZero(num)
if num == 0 then
return 0.001
else
return num
end
end
function lib.ButtonGlow_Start(r, color, frequency, frameLevel)
if not r then return end
frameLevel = frameLevel or 8;
@@ -738,14 +749,16 @@ function lib.ButtonGlow_Start(r, color, frequency, frameLevel)
if not color then
for texture in pairs(ButtonGlowTextures) do
f[texture]:SetVertexColor(1, 1, 1)
f[texture]:SetAlpha(f[texture]:GetAlpha() / (f.color and f.color[4] or 1))
local alpha = math.min(f[texture]:GetAlpha()/noZero(f.color and f.color[4] or 1), 1)
f[texture]:SetAlpha(alpha)
updateAlphaAnim(f, 1)
end
f.color = false
else
for texture in pairs(ButtonGlowTextures) do
f[texture]:SetVertexColor(color[1], color[2], color[3])
f[texture]:SetAlpha(f[texture]:GetAlpha() / (f.color and f.color[4] or 1) * color[4])
local alpha = math.min(f[texture]:GetAlpha()/noZero(f.color and f.color[4] or 1)*color[4], 1)
f[texture]:SetAlpha(alpha)
updateAlphaAnim(f,color and color[4] or 1)
end
f.color = color
@@ -0,0 +1,327 @@
--- **AceTimer-3.0** provides a central facility for registering timers.
-- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient
-- data structure that allows easy dispatching and fast rescheduling. Timers can be registered
-- or canceled at any time, even from within a running timer, without conflict or large overhead.\\
-- AceTimer is currently limited to firing timers at a frequency of 0.01s.
--
-- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you
-- need to cancel the timer you just registered.
--
-- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
-- and can be accessed directly, without having to explicitly call AceTimer itself.\\
-- It is recommended to embed AceTimer, otherwise you'll have to specify a custom `self` on all calls you
-- make into AceTimer.
-- @class file
-- @name AceTimer-3.0
-- @release $Id$
local MAJOR, MINOR = "AceTimer-3.0", 1017 -- Bump minor on changes
local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceTimer then return end -- No upgrade needed
AceTimer.frame = AceTimer.frame or CreateFrame("Frame", "AceTimer30Frame")
AceTimer.activeTimers = AceTimer.activeTimers or {} -- Active timer list
local activeTimers = AceTimer.activeTimers -- Upvalue our private data
-- Lua APIs
local assert, loadstring, rawset, tconcat = assert, loadstring, rawset, table.concat
local type, unpack, next, error, select = type, unpack, next, error, select
-- WoW APIs
local GetTime = GetTime
--[[
xpcall safecall implementation
]]
local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local xpcall, eh = ...
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = ...
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = code:gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
Dispatchers[0] = function(func)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
return Dispatchers[select("#", ...)](func, ...)
end
local function new(self, loop, func, delay, ...)
if delay < 0.01 then
delay = 0.01 -- Restrict to the lowest time
end
local timer = {
object = self,
func = func,
looping = loop,
argsCount = select("#", ...),
delay = delay,
timeleft = delay,
ends = GetTime() + delay,
...
}
activeTimers[timer] = timer
return timer
end
--- Schedule a new one-shot timer.
-- The timer will fire once in `delay` seconds, unless canceled before.
-- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds.
-- @param ... An optional, unlimited amount of arguments to pass to the callback function.
-- @usage
-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
--
-- function MyAddOn:OnEnable()
-- self:ScheduleTimer("TimerFeedback", 5)
-- end
--
-- function MyAddOn:TimerFeedback()
-- print("5 seconds passed")
-- end
function AceTimer:ScheduleTimer(func, delay, ...)
if not func or not delay then
error(MAJOR..": ScheduleTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
end
if type(func) == "string" then
if type(self) ~= "table" then
error(MAJOR..": ScheduleTimer(callback, delay, args...): 'self' - must be a table.", 2)
elseif not self[func] then
error(MAJOR..": ScheduleTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
end
end
return new(self, nil, func, delay, ...)
end
--- Schedule a repeating timer.
-- The timer will fire every `delay` seconds, until canceled.
-- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds.
-- @param ... An optional, unlimited amount of arguments to pass to the callback function.
-- @usage
-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
--
-- function MyAddOn:OnEnable()
-- self.timerCount = 0
-- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
-- end
--
-- function MyAddOn:TimerFeedback()
-- self.timerCount = self.timerCount + 1
-- print(("%d seconds passed"):format(5 * self.timerCount))
-- -- run 30 seconds in total
-- if self.timerCount == 6 then
-- self:CancelTimer(self.testTimer)
-- end
-- end
function AceTimer:ScheduleRepeatingTimer(func, delay, ...)
if not func or not delay then
error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
end
if type(func) == "string" then
if type(self) ~= "table" then
error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'self' - must be a table.", 2)
elseif not self[func] then
error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
end
end
return new(self, true, func, delay, ...)
end
--- Cancels a timer with the given id, registered by the same addon object as used for `:ScheduleTimer`
-- Both one-shot and repeating timers can be canceled with this function, as long as the `id` is valid
-- and the timer has not fired yet or was canceled before.
-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
function AceTimer:CancelTimer(id)
local timer = activeTimers[id]
if not timer then
return false
else
timer.cancelled = true
activeTimers[id] = nil
return true
end
end
--- Cancels all timers registered to the current addon object ('self')
function AceTimer:CancelAllTimers()
for k,v in next, activeTimers do
if v.object == self then
AceTimer.CancelTimer(self, k)
end
end
end
--- Returns the time left for a timer with the given id, registered by the current addon object ('self').
-- This function will return 0 when the id is invalid.
-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
-- @return The time left on the timer.
function AceTimer:TimeLeft(id)
local timer = activeTimers[id]
if not timer then
return
else
return timer.ends - GetTime()
end
end
-- ---------------------------------------------------------------------
-- Upgrading
-- Upgrade from old hash-bucket based timers to C_Timer.After timers.
if oldminor and oldminor < 10 then
-- disable old timer logic
AceTimer.frame:SetScript("OnUpdate", nil)
AceTimer.frame:SetScript("OnEvent", nil)
AceTimer.frame:UnregisterAllEvents()
-- convert timers
for object,timers in next, AceTimer.selfs do
for handle,timer in next, timers do
if type(timer) == "table" and timer.callback then
local newTimer
if timer.delay then
newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.callback, timer.delay, timer.arg)
else
newTimer = AceTimer.ScheduleTimer(timer.object, timer.callback, timer.when - GetTime(), timer.arg)
end
-- Use the old handle for old timers
activeTimers[newTimer] = nil
activeTimers[handle] = newTimer
newTimer.handle = handle
end
end
end
AceTimer.selfs = nil
AceTimer.hash = nil
AceTimer.debug = nil
elseif oldminor and oldminor < 17 then
-- Upgrade from old animation based timers to C_Timer.After timers.
AceTimer.inactiveTimers = nil
local oldTimers = AceTimer.activeTimers
-- Clear old timer table and update upvalue
AceTimer.activeTimers = {}
activeTimers = AceTimer.activeTimers
for handle, timer in next, oldTimers do
local newTimer
-- Stop the old timer animation
local duration, elapsed = timer:GetDuration(), timer:GetElapsed()
timer:GetParent():Stop()
if timer.looping then
newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.func, duration, unpack(timer.args, 1, timer.argsCount))
else
newTimer = AceTimer.ScheduleTimer(timer.object, timer.func, duration - elapsed, unpack(timer.args, 1, timer.argsCount))
end
-- Use the old handle for old timers
activeTimers[newTimer] = nil
activeTimers[handle] = newTimer
newTimer.handle = handle
end
-- Migrate transitional handles
if oldminor < 13 and AceTimer.hashCompatTable then
for handle, id in next, AceTimer.hashCompatTable do
local t = activeTimers[id]
if t then
activeTimers[id] = nil
activeTimers[handle] = t
t.handle = handle
end
end
AceTimer.hashCompatTable = nil
end
end
-- ---------------------------------------------------------------------
-- Embed handling
AceTimer.embeds = AceTimer.embeds or {}
local mixins = {
"ScheduleTimer", "ScheduleRepeatingTimer",
"CancelTimer", "CancelAllTimers",
"TimeLeft"
}
function AceTimer:Embed(target)
AceTimer.embeds[target] = true
for _,v in next, mixins do
target[v] = AceTimer[v]
end
return target
end
-- AceTimer:OnEmbedDisable(target)
-- target (object) - target object that AceTimer is embedded in.
--
-- cancel all timers registered for the object
function AceTimer:OnEmbedDisable(target)
target:CancelAllTimers()
end
for addon in next, AceTimer.embeds do
AceTimer:Embed(addon)
end
AceTimer.frame:SetScript("OnUpdate", function(self, elapsed)
for _, timer in next, activeTimers do
if not timer.cancelled then
if timer.timeleft > elapsed then
timer.timeleft = timer.timeleft - elapsed
else
if type(timer.func) == "string" then
-- We manually set the unpack count to prevent issues with an arg set that contains nil and ends with nil
-- e.g. local t = {1, 2, nil, 3, nil} print(#t) will result in 2, instead of 5. This fixes said issue.
safecall(timer.object[timer.func], timer.object, unpack(timer, 1, timer.argsCount))
else
safecall(timer.func, unpack(timer, 1, timer.argsCount))
end
if timer.looping and not timer.cancelled then
-- Compensate delay to get a perfect average delay, even if individual times don't match up perfectly
-- due to fps differences
local time = GetTime()
local delay = timer.delay - (time - timer.ends)
-- Ensure the delay doesn't go below the threshold
if delay < 0.01 then delay = 0.01 end
timer.ends = time + delay
timer.timeleft = timer.delay
else
activeTimers[timer.handle or timer] = nil
end
end
end
end
end)
@@ -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="AceTimer-3.0.lua"/>
</Ui>
+339
View File
@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
+653 -269
View File
@@ -1,342 +1,726 @@
local MAJOR_VERSION = "LibGetFrame-1.0"
local MINOR_VERSION = 26
if not LibStub then error(MAJOR_VERSION .. " requires LibStub.") end
local MINOR_VERSION = 63
if not LibStub then
error(MAJOR_VERSION .. " requires LibStub.")
end
local lib = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION)
if not lib then return end
if not lib then
return
end
lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib)
lib.timer = lib.timer or LibStub("AceTimer-3.0")
local callbacks = lib.callbacks
local GetPlayerInfoByGUID, UnitExists, IsAddOnLoaded, UnitIsUnit, SecureButton_GetUnit = GetPlayerInfoByGUID, UnitExists, IsAddOnLoaded, UnitIsUnit, SecureButton_GetUnit
local GetPlayerInfoByGUID, UnitExists, UnitIsUnit, SecureButton_GetUnit, IsAddOnLoaded =
GetPlayerInfoByGUID, UnitExists, UnitIsUnit, SecureButton_GetUnit, IsAddOnLoaded
local tinsert, CopyTable, wipe = tinsert, CopyTable, wipe
function lib.Mixin(object, ...)
for i = 1, select("#", ...) do
local mixin = select(i, ...);
for k, v in pairs(mixin) do
object[k] = v;
end
end
return object;
end
local maxDepth = 50
local defaultFramePriorities = {
-- raid frames
"^Vd1", -- vuhdo
"^Vd2", -- vuhdo
"^Vd3", -- vuhdo
"^Vd4", -- vuhdo
"^Vd5", -- vuhdo
"^Vd", -- vuhdo
"^HealBot", -- healbot
"^GridLayout", -- grid
"^Grid2Layout", -- grid2
"^PlexusLayout", -- plexus
"^ElvUF_RaidGroup", -- elv
"^oUF_bdGrid", -- bdgrid
"^oUF_.-Raid", -- generic oUF
"^LimeGroup", -- lime
"^SUFHeaderraid", -- suf
-- party frames
"^AleaUI_GroupHeader", -- Alea
"^SUFHeaderparty", --suf
"^ElvUF_PartyGroup", -- elv
"^oUF_.-Party", -- generic oUF
"^PitBull4_Groups_Party", -- pitbull4
"^CompactRaid", -- blizz
"^PartyMemberFrame", -- blizz
-- player frame
"^SUFUnitplayer",
"^PitBull4_Frames_Player",
"^ElvUF_Player",
"^oUF_.-Player",
"^PlayerFrame",
-- raid frames
"^Vd1", -- vuhdo
"^Vd2", -- vuhdo
"^Vd3", -- vuhdo
"^Vd4", -- vuhdo
"^Vd5", -- vuhdo
"^Vd", -- vuhdo
"^HealBot_HealUnit", -- healbot
"^hbPet_HealUnit", -- healbot
"^HealBot", -- healbot
"^GridLayout", -- grid
"^Grid2Layout", -- grid2
"^NugRaid%d+UnitButton%d+", -- Aptechka
"^PlexusLayout", -- plexus
"^ElvUF_Raid%d*Group", -- elv
"^ElvUF_RaidGroup", -- elv
"^oUF_bdGrid", -- bdgrid
"^oUF_.-Raid", -- generic oUF
"^LimeGroup", -- lime
"^InvenRaidFrames3Group%dUnitButton", -- InvenRaidFrames3
"^SUFHeaderraid", -- suf
"^LUFHeaderraid", -- luf
"^AshToAshUnit%d+Unit%d+", -- AshToAsh
"^Cell", -- Cell
-- party frames
"^AleaUI_GroupHeader", -- Alea
"^SUFHeaderparty", -- suf
"^LUFHeaderparty", -- luf
"^ElvUF_PartyGroup", -- elv
"^oUF_.-Party", -- generic oUF
"^PitBull4_Groups_Party", -- pitbull4
"^CompactRaid", -- blizz
"^CompactParty", -- blizz
"^PartyFrame", -- blizz
"^PartyMemberFrame", -- blizz
-- player frame
"^InvenUnitFrames_Player",
"^SUFUnitplayer",
"^LUFUnitplayer",
"^PitBull4_Frames_Player",
"^ElvUF_Player",
"^oUF_.-Player",
"^PlayerFrame",
}
local getDefaultFramePriorities = function()
return CopyTable(defaultFramePriorities)
end
lib.getDefaultFramePriorities = getDefaultFramePriorities
local defaultPlayerFrames = {
"SUFUnitplayer",
"PitBull4_Frames_Player",
"ElvUF_Player",
"oUF_.-Player",
"oUF_PlayerPlate",
"PlayerFrame",
}
local defaultTargetFrames = {
"SUFUnittarget",
"PitBull4_Frames_Target",
"ElvUF_Target",
"oUF_.-Target",
"TargetFrame",
}
local defaultTargettargetFrames = {
"SUFUnittargetarget",
"PitBull4_Frames_Target's target",
"ElvUF_TargetTarget",
"oUF_.-TargetTarget",
"oUF_ToT",
"TargetTargetFrame",
}
local defaultPartyFrames = {
"^AleaUI_GroupHeader",
"^SUFHeaderparty",
"^ElvUF_PartyGroup",
"^oUF_.-Party",
"^PitBull4_Groups_Party",
"^PartyMemberFrame",
}
local defaultPartyTargetFrames = {
"SUFChildpartytarget%d",
}
local defaultRaidFrames = {
"^Vd",
"^HealBot",
"^GridLayout",
"^Grid2Layout",
"^PlexusLayout",
"^ElvUF_RaidGroup",
"^oUF_.-Raid",
"^LimeGroup",
"^SUFHeaderraid",
"^RaidPullout",
"^InvenUnitFrames_Player",
"SUFUnitplayer",
"LUFUnitplayer",
"PitBull4_Frames_Player",
"ElvUF_Player",
"oUF_.-Player",
"oUF_PlayerPlate",
"PlayerFrame",
}
local getDefaultPlayerFrames = function()
return CopyTable(defaultPlayerFrames)
end
lib.getDefaultPlayerFrames = getDefaultPlayerFrames
local GetFramesCache = {}
local FrameToUnitFresh = {}
local FrameToUnit = {}
local UpdatedFrames = {}
local defaultTargetFrames = {
"^InvenUnitFrames_Target",
"SUFUnittarget",
"LUFUnittarget",
"PitBull4_Frames_Target",
"ElvUF_Target",
"oUF_.-Target",
"TargetFrame",
"^hbExtra_HealUnit",
}
local getDefaultTargetFrames = function()
return CopyTable(defaultTargetFrames)
end
lib.getDefaultTargetFrames = getDefaultTargetFrames
local defaultTargettargetFrames = {
"^InvenUnitFrames_TargetTarget",
"SUFUnittargetarget",
"LUFUnittargetarget",
"PitBull4_Frames_Target's target",
"ElvUF_TargetTarget",
"oUF_.-TargetTarget",
"oUF_ToT",
"TargetTargetFrame",
}
local getDefaultTargettargetFrames = function()
return CopyTable(defaultTargettargetFrames)
end
lib.getDefaultTargettargetFrames = getDefaultTargettargetFrames
local defaultPartyFrames = {
"^InvenUnitFrames_Party%d",
"^AleaUI_GroupHeader",
"^SUFHeaderparty",
"^LUFHeaderparty",
"^ElvUF_PartyGroup",
"^oUF_.-Party",
"^PitBull4_Groups_Party",
"^PartyFrame",
"^CompactParty",
"^PartyMemberFrame",
}
local getDefaultPartyFrames = function()
return CopyTable(defaultPartyFrames)
end
lib.getDefaultPartyFrames = getDefaultPartyFrames
local defaultPartyTargetFrames = {
"SUFChildpartytarget%d",
}
local getDefaultPartyTargetFrames = function()
return CopyTable(defaultPartyTargetFrames)
end
lib.getDefaultPartyTargetFrames = getDefaultPartyTargetFrames
local defaultFocusFrames = {
"^InvenUnitFrames_Focus",
"ElvUF_FocusTarget",
"LUFUnitfocus",
"FocusFrame",
"^hbExtra_HealUnit",
}
local getDefaultFocusFrames = function()
return CopyTable(defaultFocusFrames)
end
lib.getDefaultFocusFrames = getDefaultFocusFrames
local defaultRaidFrames = {
"^Vd",
"^HealBot_HealUnit",
"^hbPet_HealUnit",
"^HealBot",
"^GridLayout",
"^Grid2Layout",
"^PlexusLayout",
"^InvenRaidFrames3Group%dUnitButton",
"^ElvUF_Raid%d*Group",
"^ElvUF_RaidGroup",
"^oUF_.-Raid",
"^AshToAsh",
"^Cell",
"^LimeGroup",
"^SUFHeaderraid",
"^LUFHeaderraid",
"^CompactRaid",
"^RaidPullout",
}
local getDefaultRaidFrames = function()
return CopyTable(defaultRaidFrames)
end
lib.getDefaultRaidFrames = getDefaultRaidFrames
--
local CacheMonitorMixin = {}
function CacheMonitorMixin:Init(makeDiff)
self.data = {}
self.cache = {}
if makeDiff then
self.makeDiff = makeDiff
self.added = {}
self.updated = {}
self.removed = {}
end
end
-- fill cache, added, updated
function CacheMonitorMixin:Add(key, ...)
local args = select("#", ...)
if args > 1 then
if self.makeDiff then
if type(self.data[key]) == "table" then
for i = 1, args do
local arg = select(i, ...)
if self.data[key][i] ~= arg then
self.updated[key] = self.data[key]
break
end
end
else
self.added[key] = true
end
end
self.cache[key] = {...}
else
local value = ...
if self.makeDiff then
if self.data[key] ~= value then
if self.data[key] == nil then
self.added[key] = true
else
self.updated[key] = self.data[key]
end
end
end
self.cache[key] = value
end
end
function CacheMonitorMixin:CalcRemoved()
if not self.makeDiff then return end
for key, value in pairs(self.data) do
if self.cache[key] == nil then
self.removed[key] = value
end
end
end
function CacheMonitorMixin:WriteCache()
wipe(self.data)
self.data, self.cache = self.cache, {}
end
function CacheMonitorMixin:Reset()
if self.makeDiff then
wipe(self.updated)
wipe(self.removed)
wipe(self.added)
end
end
--
local FrameToFrameName = {} -- frame adress => frame name
local FrameToUnit = {} -- frame adress => unitToken
lib.Mixin(FrameToFrameName, CacheMonitorMixin)
lib.Mixin(FrameToUnit, CacheMonitorMixin)
FrameToFrameName:Init()
FrameToUnit:Init(true)
local profiling = false
local profileData
local function doNothing()
end
local StartProfiling = doNothing
local StopProfiling = doNothing
local function _StartProfiling(id)
if not profileData[id] then
profileData[id] = {}
profileData[id].count = 1
profileData[id].start = debugprofilestop()
profileData[id].elapsed = 0
profileData[id].spike = 0
return
end
if profileData[id].count == 0 then
profileData[id].count = 1
profileData[id].start = debugprofilestop()
else
profileData[id].count = profileData[id].count + 1
end
end
local function _StopProfiling(id)
profileData[id].count = profileData[id].count - 1
if profileData[id].count == 0 then
local elapsed = debugprofilestop() - profileData[id].start
profileData[id].elapsed = profileData[id].elapsed + elapsed
if elapsed > profileData[id].spike then
profileData[id].spike = elapsed
end
end
end
function lib.StartProfile()
if profiling then
print(MAJOR_VERSION, " (StartProfile) Profiling already started")
return false
end
profiling = true
profileData = {}
StartProfiling = _StartProfiling
StopProfiling = _StopProfiling
end
function lib.StopProfile()
if not profiling then
print(MAJOR_VERSION, " (StopProfile) Profiling not running")
return false
end
profiling = false
StartProfiling = doNothing
StopProfiling = doNothing
end
function lib.GetProfileData()
return profileData or {}
end
-- if frame doesn't have a name, try to use the key from it's parent
local function recurseGetName(frame)
local name = frame.GetName and frame:GetName() or nil
if name then
return name
end
local parent = frame.GetParent and frame:GetParent()
if parent then
local parentKey
for key, child in pairs(parent) do
if child == frame then
parentKey = key
break
end
end
if parentKey then
return (recurseGetName(parent) or "") .. "." .. parentKey
end
end
end
--local notAUnitFrameTypeAttribute = {
-- cancelaura = true
--}
local function ScanFrames(depth, frame, ...)
if not frame then return end
if depth < maxDepth then
local frameType = frame:GetObjectType()
if frameType == "Frame" or frameType == "Button" then
ScanFrames(depth + 1, frame:GetChildren())
end
if frameType == "Button" then
local unit = SecureButton_GetUnit(frame)
local name = frame:GetName()
if unit and frame:IsVisible() and name then
GetFramesCache[frame] = name
if unit ~= FrameToUnit[frame] then
FrameToUnit[frame] = unit
UpdatedFrames[frame] = unit
end
FrameToUnitFresh[frame] = unit
end
end
coroutine.yield()
if not frame then
return
end
if depth < maxDepth then
local frameType = frame:GetObjectType()
if frameType == "Frame" or frameType == "Button" then
ScanFrames(depth + 1, frame:GetChildren())
end
ScanFrames(depth, ...)
if frameType == "Button" then
local typeAttribute = frame:GetAttribute("type")
--if not notAUnitFrameTypeAttribute[typeAttribute] then
local unit = SecureButton_GetUnit(frame)
if unit and frame:IsVisible() then
local name = recurseGetName(frame)
if name then
FrameToFrameName:Add(frame, name)
FrameToUnit:Add(frame, unit)
end
end
--end
end
end
ScanFrames(depth, ...)
end
local wait = false
local status = "ready"
local co
local coroutineFrame = CreateFrame("Frame")
coroutineFrame:Hide()
local function doScanForUnitFrames()
wait = false
wipe(UpdatedFrames)
wipe(GetFramesCache)
wipe(FrameToUnitFresh)
ScanFrames(0, UIParent)
callbacks:Fire("GETFRAME_REFRESH")
for frame, unit in pairs(UpdatedFrames) do
callbacks:Fire("FRAME_UNIT_UPDATE", frame, unit)
end
for frame, unit in pairs(FrameToUnit) do
if FrameToUnitFresh[frame] ~= unit then
callbacks:Fire("FRAME_UNIT_REMOVED", frame, unit)
FrameToUnit[frame] = nil
end
end
if not coroutineFrame:IsShown() then
status = "scanning"
co = coroutine.create(ScanFrames)
coroutineFrame:Show()
end
end
local waitFrame = CreateFrame("Frame")
local function waitFrame_OnUpdate(self, elapsed)
self.delay = (self.delay or 1) - elapsed
if self.delay < 0 then
doScanForUnitFrames()
self:SetScript("OnUpdate", nil)
self.delay = nil
end
end
coroutineFrame:SetScript("OnUpdate", function()
local start = debugprofilestop()
-- Limit to 5ms per frame
StartProfiling("scan frames")
while debugprofilestop() - start < 5 and coroutine.status(co) ~= "dead" do
coroutine.resume(co, 0, UIParent)
end
StopProfiling("scan frames")
if coroutine.status(co) == "dead" then
StartProfiling("callbacks")
FrameToFrameName:WriteCache()
FrameToUnit:CalcRemoved()
FrameToUnit:WriteCache()
StartProfiling("callback GETFRAME_REFRESH")
callbacks:Fire("GETFRAME_REFRESH")
StopProfiling("callback GETFRAME_REFRESH")
-- FrameToUnit
if next(FrameToUnit.added) then
StartProfiling("callback FRAME_UNIT_ADDED")
for frame in pairs(FrameToUnit.added) do
callbacks:Fire("FRAME_UNIT_ADDED", frame, FrameToUnit.data[frame])
end
StopProfiling("callback FRAME_UNIT_ADDED")
end
if next(FrameToUnit.updated) then
StartProfiling("callback FRAME_UNIT_UPDATE")
for frame, previousUnit in pairs(FrameToUnit.updated) do
callbacks:Fire("FRAME_UNIT_UPDATE", frame, FrameToUnit.data[frame], previousUnit)
end
StopProfiling("callback FRAME_UNIT_UPDATE")
end
if next(FrameToUnit.removed) then
StartProfiling("callback FRAME_UNIT_REMOVED")
for frame, unit in pairs(FrameToUnit.removed) do
callbacks:Fire("FRAME_UNIT_REMOVED", frame, unit)
end
StopProfiling("callback FRAME_UNIT_REMOVED")
end
coroutineFrame:Hide()
FrameToFrameName:Reset()
FrameToUnit:Reset()
StopProfiling("callbacks")
if status == "scan_queued" then
doScanForUnitFrames("queued")
else
status = "ready"
end
end
end)
local function ScanForUnitFrames(noDelay)
if status == "ready" then
if noDelay then
doScanForUnitFrames()
else
status = "scan_delay"
lib.timer:ScheduleTimer(function()
doScanForUnitFrames()
elseif not wait then
wait = true
waitFrame.delay = 1
waitFrame:SetScript("OnUpdate", waitFrame_OnUpdate)
end, 1)
end
elseif status == "scanning" then
status = "scan_queued"
end
end
function lib.ScanForUnitFrames()
ScanForUnitFrames(true)
end
local function isFrameFiltered(name, ignoredFrames)
for _, filter in pairs(ignoredFrames) do
if name:find(filter) then
return true
end
for _, filter in pairs(ignoredFrames) do
if name:find(filter) then
return true
end
return false
end
return false
end
local function GetUnitFrames(target, ignoredFrames)
if not UnitExists(target) then
if type(target) ~= "string" then
return
end
local B = tonumber(target:sub(5, 5), 16)
if B and B % 8 == 0 then
target = select(6, GetPlayerInfoByGUID(target))
else
target = target:gsub(" .*", "")
end
if not UnitExists(target) then
if type(target) ~= "string" then return end
local B = tonumber(target:sub(5, 5), 16)
if B and B % 8 == 0 then
target = select(6, GetPlayerInfoByGUID(target))
else
target = target:gsub(" .*", "")
end
if not UnitExists(target) then
return
end
return
end
end
local frames
for frame, frameName in pairs(GetFramesCache) do
local unit = SecureButton_GetUnit(frame)
if unit and UnitIsUnit(unit, target)
and not isFrameFiltered(frameName, ignoredFrames)
then
frames = frames or {}
frames[frame] = frameName
end
local frames
for frame, frameName in pairs(FrameToFrameName.data) do
local unit = SecureButton_GetUnit(frame)
if unit and UnitIsUnit(unit, target) and not isFrameFiltered(frameName, ignoredFrames) then
frames = frames or {}
frames[frame] = frameName
end
return frames
end
return frames
end
local function ElvuiWorkaround(frame)
if IsAddOnLoaded("ElvUI") and frame and frame:GetName():find("^ElvUF_") and frame.Health then
return frame.Health
else
return frame
end
if IsAddOnLoaded("ElvUI") and frame and frame:GetName() and frame:GetName():find("^ElvUF_") and frame.Health then
return frame.Health
else
return frame
end
end
local function CellGetUnitFrames(target, frames, framePriorities)
if not IsAddOnLoaded("Cell") or not Cell.GetUnitFramesForLGF then
return frames
end
return Cell.GetUnitFramesForLGF(target, frames, framePriorities)
end
local defaultOptions = {
framePriorities = defaultFramePriorities,
ignorePlayerFrame = true,
ignoreTargetFrame = true,
ignoreTargettargetFrame = true,
ignorePartyFrame = false,
ignorePartyTargetFrame = true,
ignoreRaidFrame = false,
playerFrames = defaultPlayerFrames,
targetFrames = defaultTargetFrames,
targettargetFrames = defaultTargettargetFrames,
partyFrames = defaultPartyFrames,
partyTargetFrames = defaultPartyTargetFrames,
raidFrames = defaultRaidFrames,
ignoreFrames = {
"PitBull4_Frames_Target's target's target",
"ElvUF_PartyGroup%dUnitButton%dTarget",
"ElvUF_FocusTarget",
"RavenButton"
},
returnAll = false,
framePriorities = defaultFramePriorities,
ignorePlayerFrame = true,
ignoreTargetFrame = true,
ignoreTargettargetFrame = true,
ignorePartyFrame = false,
ignorePartyTargetFrame = true,
ignoreFocusFrame = true,
ignoreRaidFrame = false,
playerFrames = defaultPlayerFrames,
targetFrames = defaultTargetFrames,
targettargetFrames = defaultTargettargetFrames,
partyFrames = defaultPartyFrames,
partyTargetFrames = defaultPartyTargetFrames,
focusFrames = defaultFocusFrames,
raidFrames = defaultRaidFrames,
ignoreFrames = {
"PitBull4_Frames_Target's target's target",
"ElvUF_PartyGroup%dUnitButton%dTarget",
"RavenButton",
"RavenOverlay",
"AshToAshUnit%d+ShadowGroupHeaderUnitButton%d+",
"InvenUnitFrames_TargetTargetTarget",
"CellQuickCastButton",
},
skipCellOverrides = false,
returnAll = false,
}
local getDefaultOptions = function()
return CopyTable(defaultOptions)
end
lib.getDefaultOptions = getDefaultOptions
local IterateGroupMembers = function(reversed, forceParty)
local unit = (not forceParty and GetNumRaidMembers() > 0) and 'raid' or 'party'
local numGroupMembers = unit == 'party' and GetNumPartyMembers() or GetNumRaidMembers()
local i = reversed and numGroupMembers or (unit == 'party' and 0 or 1)
return function()
local ret
if i == 0 and unit == 'party' then
ret = 'player'
elseif i <= numGroupMembers and i > 0 then
ret = unit .. i
end
i = i + (reversed and -1 or 1)
return ret
end
end
local unitPetState = {} -- track if unit's pet exists
local saveGetUnitFrame
local function fixGetUnitFrameIntegrity()
lib.GetUnitFrame = saveGetUnitFrame
lib.GetFrame = saveGetUnitFrame
if WeakAuras and WeakAuras.GetUnitFrame then
WeakAuras.GetUnitFrame = saveGetUnitFrame
end
end
local GetFramesCacheListener
local function Init(noDelay)
GetFramesCacheListener = CreateFrame("Frame")
GetFramesCacheListener:RegisterEvent("PLAYER_REGEN_DISABLED")
GetFramesCacheListener:RegisterEvent("PLAYER_REGEN_ENABLED")
GetFramesCacheListener:RegisterEvent("PLAYER_ENTERING_WORLD")
GetFramesCacheListener:RegisterEvent("PARTY_MEMBERS_CHANGED")
GetFramesCacheListener:RegisterEvent("RAID_ROSTER_UPDATE")
GetFramesCacheListener:SetScript("OnEvent", function() ScanForUnitFrames(false) end)
ScanForUnitFrames(noDelay)
GetFramesCacheListener = CreateFrame("Frame")
GetFramesCacheListener:RegisterEvent("PLAYER_REGEN_DISABLED")
GetFramesCacheListener:RegisterEvent("PLAYER_REGEN_ENABLED")
GetFramesCacheListener:RegisterEvent("PLAYER_ENTERING_WORLD")
GetFramesCacheListener:RegisterEvent("RAID_ROSTER_UPDATE")
GetFramesCacheListener:RegisterEvent("PARTY_MEMBERS_CHANGED")
GetFramesCacheListener:RegisterEvent("UNIT_PET")
GetFramesCacheListener:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT")
GetFramesCacheListener:SetScript("OnEvent", function(self, event, unit, ...)
fixGetUnitFrameIntegrity()
if event == "RAID_ROSTER_UPDATE" or "PARTY_MEMBERS_CHANGED" then
wipe(unitPetState)
for member in IterateGroupMembers() do
unitPetState[member] = UnitExists(member .. "pet") and true or nil
end
end
if event == "UNIT_PET" then
if not (UnitIsUnit("player", unit) or UnitInParty(unit) or UnitInRaid(unit)) then
return
end
-- skip if unit's pet existance has not changed
local exists = UnitExists(unit .. "pet") and true or nil
if unitPetState[unit] == exists then
return
else
unitPetState[unit] = exists
end
end
ScanForUnitFrames(false)
end)
ScanForUnitFrames(noDelay)
end
function lib.GetUnitFrame(target, opt)
if type(GetFramesCacheListener) ~= "table" then Init(true) end
opt = opt or {}
setmetatable(opt, { __index = defaultOptions })
if type(GetFramesCacheListener) ~= "table" then
Init(true)
end
opt = opt or {}
setmetatable(opt, { __index = defaultOptions })
if not target then return end
if not target then
return
end
local ignoredFrames = CopyTable(opt.ignoreFrames)
if opt.ignorePlayerFrame then
for _,v in pairs(opt.playerFrames) do
tinsert(ignoredFrames, v)
end
local ignoredFrames = CopyTable(opt.ignoreFrames)
if opt.ignorePlayerFrame then
for _, v in pairs(opt.playerFrames) do
tinsert(ignoredFrames, v)
end
if opt.ignoreTargetFrame then
for _,v in pairs(opt.targetFrames) do
tinsert(ignoredFrames, v)
end
end
if opt.ignoreTargetFrame then
for _, v in pairs(opt.targetFrames) do
tinsert(ignoredFrames, v)
end
if opt.ignoreTargettargetFrame then
for _,v in pairs(opt.targettargetFrames) do
tinsert(ignoredFrames, v)
end
end
if opt.ignoreTargettargetFrame then
for _, v in pairs(opt.targettargetFrames) do
tinsert(ignoredFrames, v)
end
if opt.ignorePartyFrame then
for _,v in pairs(opt.partyFrames) do
tinsert(ignoredFrames, v)
end
end
if opt.ignorePartyFrame then
for _, v in pairs(opt.partyFrames) do
tinsert(ignoredFrames, v)
end
if opt.ignorePartyTargetFrame then
for _,v in pairs(opt.partyTargetFrames) do
tinsert(ignoredFrames, v)
end
end
if opt.ignorePartyTargetFrame then
for _, v in pairs(opt.partyTargetFrames) do
tinsert(ignoredFrames, v)
end
if opt.ignoreRaidFrame then
for _,v in pairs(opt.raidFrames) do
tinsert(ignoredFrames, v)
end
end
if opt.ignoreFocusFrame then
for _, v in pairs(opt.focusFrames) do
tinsert(ignoredFrames, v)
end
end
if opt.ignoreRaidFrame then
for _, v in pairs(opt.raidFrames) do
tinsert(ignoredFrames, v)
end
end
local frames = GetUnitFrames(target, ignoredFrames)
if not frames then return end
local frames = GetUnitFrames(target, ignoredFrames)
if not opt.returnAll then
for i = 1, #opt.framePriorities do
for frame, frameName in pairs(frames) do
if frameName:find(opt.framePriorities[i]) then
return ElvuiWorkaround(frame)
end
end
if not (opt.ignoreRaidFrame or opt.skipCellOverrides) then
frames = CellGetUnitFrames(target, frames, opt.framePriorities)
end
if not frames then
return
end
if not opt.returnAll then
for i = 1, #opt.framePriorities do
for frame, frameName in pairs(frames) do
if frameName:find(opt.framePriorities[i]) then
return ElvuiWorkaround(frame)
end
local next = next
return ElvuiWorkaround(next(frames))
else
for frame in pairs(frames) do
frames[frame] = ElvuiWorkaround(frame)
end
return frames
end
end
local next = next
return ElvuiWorkaround(next(frames))
else
for frame in pairs(frames) do
frames[frame] = ElvuiWorkaround(frame)
end
return frames
end
end
saveGetUnitFrame = lib.GetUnitFrame
lib.GetFrame = lib.GetUnitFrame -- compatibility
-- nameplates
function lib.GetUnitNameplate(unit)
if not unit then
return
end
local nameplate = C_NamePlate.GetNamePlateForUnit(unit)
if nameplate then
-- credit to Exality for https://wago.io/explosiveorbs
if nameplate.UnitFrame and nameplate.UnitFrame.Health then
-- elvui
return nameplate.UnitFrame.Health
elseif nameplate.unitFramePlater and nameplate.unitFramePlater.healthBar then
-- plater
return nameplate.unitFramePlater.healthBar
elseif nameplate.kui and nameplate.kui.HealthBar then
-- kui
return nameplate.kui.HealthBar
elseif nameplate.extended and nameplate.extended.visual and nameplate.extended.visual.healthbar then
-- tidyplates
return nameplate.extended.visual.healthbar
elseif nameplate.TPFrame and nameplate.TPFrame.visual and nameplate.TPFrame.visual.healthbar then
-- tidyplates: threat plates
return nameplate.TPFrame.visual.healthbar
elseif nameplate.unitFrame and nameplate.unitFrame.Health then
-- bdui nameplates
return nameplate.unitFrame.Health
elseif nameplate.ouf and nameplate.ouf.Health then
-- bdNameplates
return nameplate.ouf.Health
elseif nameplate.slab and nameplate.slab.components and nameplate.slab.components.healthBar and nameplate.slab.components.healthBar.frame then
-- Slab
return nameplate.slab.components.healthBar.frame
elseif nameplate.UnitFrame and nameplate.UnitFrame.healthBar then
-- default
return nameplate.UnitFrame.healthBar
else
return nameplate
end
if not unit then
return
end
local nameplate = C_NamePlate.GetNamePlateForUnit(unit)
if nameplate then
-- credit to Exality for https://wago.io/explosiveorbs
-- elvui bunny
if nameplate.UnitFrame and nameplate.UnitFrame.Health and nameplate.UnitFrame.Health:IsShown() then
return nameplate.UnitFrame.Health
elseif nameplate.UnitFrame and nameplate.UnitFrame.Name and nameplate.UnitFrame.Name:IsShown() then
return nameplate.UnitFrame.Name
-- elvui someday
elseif nameplate.unitFrame and nameplate.unitFrame.Health and nameplate.unitFrame.Health:IsShown() then
return nameplate.unitFrame.Health
elseif nameplate.unitFrame and nameplate.unitFrame.Name and nameplate.unitFrame.Name:IsShown() then
return nameplate.unitFrame.Name
elseif nameplate.unitFramePlater and nameplate.unitFramePlater.healthBar then
-- plater
-- fallback to default nameplate in case plater is not on screen and uses blizzard default (module disabled, force-blizzard functionality)
return nameplate.unitFramePlater.PlaterOnScreen and nameplate.unitFramePlater.healthBar or (nameplate.UnitFrame and nameplate.UnitFrame.healthBar) or nameplate
elseif nameplate.kui and nameplate.kui.HealthBar then
-- kui
return nameplate.kui.HealthBar
elseif nameplate.extended and nameplate.extended.visual and nameplate.extended.visual.healthbar then
-- tidyplates
return nameplate.extended.visual.healthbar
elseif nameplate.TPFrame and nameplate.TPFrame.visual and nameplate.TPFrame.visual.healthbar then
-- tidyplates: threat plates
return nameplate.TPFrame.visual.healthbar
elseif nameplate.unitFrame and nameplate.unitFrame.Health then
-- bdui nameplates
return nameplate.unitFrame.Health
elseif nameplate.ouf and nameplate.ouf.Health then
-- bdNameplates
return nameplate.ouf.Health
elseif nameplate.slab and nameplate.slab.components and nameplate.slab.components.healthBar and nameplate.slab.components.healthBar.frame then
-- Slab
return nameplate.slab.components.healthBar.frame
elseif nameplate.UnitFrame and nameplate.UnitFrame.healthBar then
-- default
return nameplate.UnitFrame.healthBar
else
return nameplate
end
end
end
@@ -1,10 +1,10 @@
## Interface: 80200
## Interface: 33000
## Title: Lib: GetFrame
## Notes: Get unit frame for a unit
## Author: Buds
## X-Category: Library
## X-License: BSD
## Version: 03cd52d
## Version: 1.6.3
## DefaultState: Enabled
## LoadOnDemand: 0
@@ -2,5 +2,6 @@
..\FrameXML\UI.xsd">
<Script file = "LibStub\LibStub.lua"/>
<Include file ="CallbackHandler-1.0\CallbackHandler-1.0.xml"/>
<Include file = "AceTimer-3.0\AceTimer-3.0.xml"/>
<Script file = "LibGetFrame-1.0.lua"/>
</Ui>
+130 -81
View File
@@ -7,92 +7,91 @@ Return unit frame for a given unit
```Lua
local LGF = LibStub("LibGetFrame-1.0")
local frame = LGF.GetUnitFrame(unit , options)
local callback = function(event, frame, unit)
if event == "GETFRAME_REFRESH" then
-- cache was refreshed
end
if event == "FRAME_UNIT_UPDATE" then
-- 'frame' was updated and is now a match for 'unit'
end
if event == "FRAME_UNIT_REMOVED" then
-- 'frame' was updated and is no longer a match for 'unit'
end
end
LGF.RegisterCallback("MyAddonName", "GETFRAME_REFRESH", callback)
LGF.RegisterCallback("MyAddonName", "FRAME_UNIT_UPDATE", callback)
LGF.RegisterCallback("MyAddonName", "FRAME_UNIT_REMOVED", callback)
```
## Options
- framePriorities : array, default :
## Public functions
```Lua
{
-- raid frames
[1] = "^Vd1", -- vuhdo
[2] = "^Vd2", -- vuhdo
[3] = "^Vd3", -- vuhdo
[4] = "^Vd4", -- vuhdo
[5] = "^Vd5", -- vuhdo
[6] = "^Vd", -- vuhdo
[7] = "^HealBot", -- healbot
[8] = "^GridLayout", -- grid
[9] = "^Grid2Layout", -- grid2
[10] = "^ElvUF_RaidGroup", -- elv
[11] = "^oUF_bdGrid", -- bdgrid
[12] = "^oUF.*raid", -- generic oUF
[13] = "^LimeGroup", -- lime
[14] = "^SUFHeaderraid", -- suf
[15] = "^CompactRaid", -- blizz
-- party frames
[16] = "^SUFHeaderparty", --suf
[17] = "^ElvUF_PartyGroup", -- elv
[18] = "^oUF.*party", -- generic oUF
[19] = "^PitBull4_Groups_Party", -- pitbull4
[20] = "^CompactParty", -- blizz
-- player frame
[21] = "^SUFUnitplayer",
[22] = "^PitBull4_Frames_Player",
[23] = "^ElvUF_Player",
[24] = "^oUF.*player",
[25] = "^PlayerFrame",
}
LGF:GetUnitFrame(unit, options)
```
Options:
- framePriorities : array
- ignorePlayerFrame : boolean (default true)
- ignoreTargetFrame : boolean (default true)
- ignoreTargettargetFrame : boolean (default true)
- playerFrames : array, default :
```Lua
{
"SUFUnitplayer",
"PitBull4_Frames_Player",
"ElvUF_Player",
"oUF_TukuiPlayer",
"PlayerFrame",
}
```
- targetFrames : array, default :
```Lua
{
"SUFUnittarget",
"PitBull4_Frames_Target",
"ElvUF_Target",
"TargetFrame",
"oUF_TukuiTarget",
}
```
- targettargetFrames : array, default :
```Lua
{
"SUFUnittargetarget",
"PitBull4_Frames_TargetTarget",
"ElvUF_TargetTarget",
"TargetTargetFrame",
"oUF_TukuiTargetTarget",
}
```
- ignoreFrames : array, default :
```Lua
{ }
```
- ignorePartyFrame : boolean (default false)
- ignorePartyTargetFrame : boolean (default true)
- ignoreRaidFrame : boolean (default false)
- playerFrames : array
- targetFrames : array
- targettargetFrames : array
- partyFrames : array
- partyTargetFrames : array
- raidFrames : array
- ignoreFrames : array
- returnAll : boolean (default false)
If returnAll is false, GetUnitFrame will return a single best match
For arrays check LibGetFrame-1.0.lua code for defaults
```Lua
LGF:ScanForUnitFrames()
```
Ask lib to do a new scan of frames.
This scan can take a few frames to be completed.
You should not expect the cache use by LGF:GetUnitFrame to be updated in the same frame as this ScanForUnitFrames call.
Use lib's callbacks to know when the cache is refresh.
```Lua
LGF:GetUnitNameplate(unit)
```
Return health bar for a nameplate unit, works with a variety of addons
## Callbacks
```Lua
-- Fired after a scan complete and cache refreshed
LGF.RegisterCallback("MyAddonName", "GETFRAME_REFRESH", function(event) end)
```
```Lua
-- Fired when a frame is a new match for a unit (it does not test if it is the BEST match!)
LGF.RegisterCallback("MyAddonName", "FRAME_UNIT_UPDATE", function(event, frame, unit) end)
```
```Lua
-- Fired when a frame is not a new match for a unit anymore
LGF.RegisterCallback("MyAddonName", "FRAME_UNIT_REMOVED", function(event, frame, unit) end)
```
## Examples
### Glow player frame
@@ -115,15 +114,15 @@ local LGF = LibStub("LibGetFrame-1.0")
local LCG = LibStub("LibCustomGlow-1.0")
local frames = LGF.GetUnitFrame("target", {
ignorePlayerFrame = false,
ignoreTargetFrame = false,
ignoreTargettargetFrame = false,
returnAll = true,
ignorePlayerFrame = false,
ignoreTargetFrame = false,
ignoreTargettargetFrame = false,
returnAll = true,
})
for _, frame in pairs(frames) do
LCG.ButtonGlow_Start(frame)
--LCG.ButtonGlow_Stop(frame)
LCG.ButtonGlow_Start(frame)
--LCG.ButtonGlow_Stop(frame)
end
```
@@ -131,8 +130,58 @@ end
```Lua
local frame = LGF.GetUnitFrame("player", {
ignoreFrames = { "Vd2.*", "Vd3.*" }
ignoreFrames = { "Vd2.*", "Vd3.*" }
})
```
### Glow specific units and update glow when frames changes
```Lua
local LGF = LibStub("LibGetFrame-1.0")
local LCG = LibStub("LibCustomGlow-1.0")
-- list of units i want glowing
local glow_units = {
player = true
}
-- track which frame is glowing per unit
local glow_unit_frames = {}
-- glow them using current cache
for unit in pairs(glow_units) do
local frame = LGF.GetUnitFrame("player")
if frame then
LCG.ButtonGlow_Start(frame)
glow_unit_frames[unit] = frame
end
end
local callback = function(event, frame, unit)
if not glow_units[unit] then
return
end
-- new match for GetUnitFrame(unit), check if it's different from previous "best match" returned
local new_best_match = LGF.GetUnitFrame(unit)
if new_best_match == nil then
-- didn't found a best match for this unit
if glow_unit_frames[unit] then
-- stop previous glow
LCG.ButtonGlow_Stop(glow_unit_frames[unit])
glow_unit_frames[unit] = nil
end
elseif new_best_match ~= glow_unit_frames[unit] then
-- best match found, but different from previous one
if glow_unit_frames[unit] then
-- stop previous glow
LCG.ButtonGlow_Stop(glow_unit_frames[unit])
end
LCG.ButtonGlow_Start(new_best_match)
glow_unit_frames[unit] = new_best_match
end
end
LGF.RegisterCallback("MyAddonName", "FRAME_UNIT_UPDATE", callback)
LGF.RegisterCallback("MyAddonName", "FRAME_UNIT_REMOVED", callback)
```
[GitHub Project](https://github.com/mrbuds/LibGetFrame)
@@ -0,0 +1,5 @@
indent_type = "Spaces"
indent_width = 2
column_width = 180
line_endings = "Unix"
quote_style = "ForceDouble"
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,358 @@
--[[
Name: LibTalentQuery-1.0
Revision: $Rev: 84 $
Author: Rich Martel (richmartel@gmail.com)
Documentation: http://wowace.com/wiki/LibTalentQuery-1.0
SVN: svn://svn.wowace.com/wow/libtalentquery-1-0/mainline/trunk
Description: Library to help with querying unit talents
Dependancies: LibStub, CallbackHandler-1.0
License: LGPL v2.1
Example Usage:
local TalentQuery = LibStub:GetLibrary("LibTalentQuery-1.0")
TalentQuery.RegisterCallback(self, "TalentQuery_Ready")
local raidTalents = {}
...
TalentQuery:Query(unit)
...
function MyAddon:TalentQuery_Ready(e, name, realm, unitid)
local isnotplayer = not UnitIsUnit(unitid, "player")
local spec = {}
for tab = 1, GetNumTalentTabs(isnotplayer) do
local treename, _, pointsspent = GetTalentTabInfo(tab, isnotplayer)
tinsert(spec, pointsspent)
end
raidTalents[UnitGUID(unitid)] = spec
end
]]
local MAJOR, MINOR = "LibTalentQuery-1.0", 90000 + tonumber(("$Rev: 84 $"):match("(%d+)"))
local lib = LibStub:NewLibrary(MAJOR, MINOR)
if not lib then return end
local INSPECTDELAY = 1
local INSPECTTIMEOUT = 5
if not lib.events then
lib.events = LibStub("CallbackHandler-1.0"):New(lib)
end
local validateTrees
local enteredWorld = IsLoggedIn()
local frame = lib.frame
if not frame then
frame = CreateFrame("Frame", MAJOR .. "_Frame")
lib.frame = frame
end
frame:UnregisterAllEvents()
frame:RegisterEvent("INSPECT_TALENT_READY")
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("PLAYER_LEAVING_WORLD")
frame:RegisterEvent("PLAYER_LOGIN")
frame:SetScript("OnEvent", function(this, event, ...)
return lib[event](lib, ...)
end)
do
local lastUpdateTime = 0
frame:SetScript("OnUpdate", function(this, elapsed)
lastUpdateTime = lastUpdateTime + elapsed
if lastUpdateTime > INSPECTDELAY then
lib:CheckInspectQueue()
lastUpdateTime = 0
end
end)
frame:Hide()
end
local inspectQueue = lib.inspectQueue or {}
lib.inspectQueue = inspectQueue
local garbageQueue = lib.garbageQueue or {} -- Added a second queue to things. Inspects that initially fail are now
lib.garbageQueue = garbageQueue -- thrown into second queue will will be processed once main queue is empty
if next(inspectQueue) then
frame:Show()
end
local UnitIsPlayer = _G.UnitIsPlayer
local UnitName = _G.UnitName
local UnitExists = _G.UnitExists
local UnitGUID = _G.UnitGUID
local GetNumRaidMembers = _G.GetNumRaidMembers
local GetNumPartyMembers = _G.GetNumPartyMembers
local UnitIsVisible = _G.UnitIsVisible
local UnitIsConnected = _G.UnitIsConnected
local UnitCanAttack = _G.UnitCanAttack
local CanInspect = _G.CanInspect
local function UnitFullName(unit)
local name, realm = UnitName(unit)
local namerealm = realm and realm ~= "" and name .. "-" .. realm or name
return namerealm
end
-- GuidToUnitID
local function GuidToUnitID(guid)
local prefix, min, max = "raid", 1, GetNumRaidMembers()
if max == 0 then
prefix, min, max = "party", 0, GetNumPartyMembers()
end
-- Prioritise getting direct units first because other players targets
-- can change between notify and event which can bugger things up
for i = min, max do
local unit = i == 0 and "player" or prefix .. i
if (UnitGUID(unit) == guid) then
return unit
end
end
-- This properly detects target units
if (UnitGUID("target") == guid) then
return "target"
elseif (UnitGUID("focus") == guid) then
return "focus"
elseif (UnitGUID("mouseover") == guid) then
return "mouseover"
end
for i = min, max + 3 do
local unit
if i == 0 then
unit = "player"
elseif i == max + 1 then
unit = "target"
elseif i == max + 2 then
unit = "focus"
elseif i == max + 3 then
unit = "mouseover"
else
unit = prefix .. i
end
if (UnitGUID(unit .. "target") == guid) then
return unit .. "target"
elseif (i <= max and UnitGUID(unit.."pettarget") == guid) then
return unit .. "pettarget"
end
end
return nil
end
-- Query
function lib:Query(unit)
if (UnitLevel(unit) < 10 or UnitName(unit) == UNKNOWN) then
return
end
self.lastQueuedInspectReceived = nil
if UnitIsUnit(unit, "player") then
self.events:Fire("TalentQuery_Ready", UnitName("player"), nil, "player")
else
if type(unit) ~= "string" then
error(("Bad argument #2 to 'Query'. Expected %q, received %q (%s)"):format("string", type(unit), tostring(unit)), 2)
elseif not UnitExists(unit) or not UnitIsPlayer(unit) then
error(("Bad argument #2 to 'Query'. %q is not a valid player unit"):format(tostring(unit)), 2)
elseif not UnitExists(unit) or not UnitIsPlayer(unit) then
error(("Bad argument #2 to 'Query'. %q does not require a server query before reading talents"):format("player"), 2)
else
local name = UnitFullName(unit)
if (not inspectQueue[name]) then
inspectQueue[name] = UnitGUID(unit)
garbageQueue[name] = nil
end
frame:Show()
end
end
end
-- CheckInspectQueue
-- Originally, it would wait until no pending NotifyInspect() were expected, and then do it's own.
-- It was also only bother looking at ready results if it had triggered the Notify for that occasion.
-- For the changes I've done, no assumption is made about which mod is performing NotifyInspect().
-- We note the name, unit, time of any inspects done whether from this queue or any other source,
-- we remove from our queue any we were expecting, and use a seperate event in case extra talent
-- info is any time wanted (opportunistic refreshes etc) - Zeksie, 20th May 2009
function lib:CheckInspectQueue()
if (_G.InspectFrame and _G.InspectFrame:IsShown()) then
return
end
if (not self.lastInspectTime or self.lastInspectTime < GetTime() - INSPECTTIMEOUT) then
self.lastInspectPending = 0
end
if (self.lastInspectPending > 0 or not enteredWorld) then
return
end
if (self.lastQueuedInspectReceived and self.lastQueuedInspectReceived < GetTime() - 60) then
-- No queued results received for a minute, so purge the queue as invalid and move on with our lives
self.lastQueuedInspectReceived = nil
inspectQueue = {}
lib.inspectQueue = inspectQueue
garbageQueue = {}
lib.garbageQueue = garbageQueue
frame:Hide()
return
end
for name,guid in pairs(inspectQueue) do
local unit = GuidToUnitID(guid)
if (not unit) then
inspectQueue[name] = nil
else
if (UnitIsVisible(unit) and UnitIsConnected(unit) and not UnitCanAttack("player", unit) and not UnitCanAttack(unit, "player") and CanInspect(unit) and UnitClass(unit)) then
NotifyInspect(unit)
break
else
garbageQueue[name] = guid -- Not available, throw into secondary queue and continue
inspectQueue[name] = nil
end
end
end
if (not next(inspectQueue)) then
if (next(garbageQueue)) then
-- Retry initially failed inspects
lib.inspectQueue = garbageQueue
inspectQueue = lib.inspectQueue
lib.garbageQueue = {}
garbageQueue = lib.garbageQueue
else
frame:Hide()
end
end
end
-- NotifyInspect
if not lib.NotifyInspect then -- don't hook twice
hooksecurefunc("NotifyInspect", function(...) return lib:NotifyInspect(...) end)
end
function lib:NotifyInspect(unit)
if (not (UnitExists(unit) and UnitIsVisible(unit) and UnitIsConnected(unit) and CheckInteractDistance(unit, 4))) then
return
end
self.lastInspectUnit = unit
self.lastInspectGUID = UnitGUID(unit)
self.lastInspectTime = GetTime()
self.lastInspectName = UnitFullName(unit)
self.lastInspectPending = self.lastInspectPending + 1
local isnotplayer = not UnitIsUnit("player", unit)
self.lastInspectTree = GetTalentTabInfo(1, isnotplayer) -- Talent tree names are available immediately
end
-- Reset
function lib:Reset()
self.lastInspectPending = 0
self.lastInspectUnit = nil
self.lastInspectTime = nil
self.lastInspectName = nil
self.lastInspectGUID = nil
self.lastInspectTree = nil
end
-- INSPECT_TALENT_READY
function lib:INSPECT_TALENT_READY()
self.lastInspectPending = self.lastInspectPending - 1
-- Results are valid only when we have received as many events as we have posted notifies
if (self.lastInspectName and self.lastInspectPending == 0) then
-- Check unit ID is still pointing to same actual unit
if (UnitGUID(self.lastInspectUnit) == self.lastInspectGUID) then
local guid = inspectQueue[self.lastInspectName]
inspectQueue[self.lastInspectName] = nil
local name, realm = strsplit("-", self.lastInspectName)
self.lastQueuedInspectReceived = GetTime()
-- Notify of expected talent results
local isnotplayer = not UnitIsUnit("player", self.lastInspectName)
local group = GetActiveTalentGroup(isnotplayer)
local tree1, _, spent1 = GetTalentTabInfo(1, isnotplayer, nil, group)
if (tree1 ~= self.lastInspectTree) then
-- Expected talent tree name to be the same as it was when we triggered the NotifyInspect()
garbageQueue[self.lastInspectName] = self.lastInspectGUID
self:Reset()
self:CheckInspectQueue()
return
elseif (validateTrees) then
-- Double checking here. Check the tree name matches what we expect for this class
local _, class = UnitClass(self.lastInspectUnit)
if (tree1 ~= validateTrees[class]) then
garbageQueue[self.lastInspectName] = self.lastInspectGUID
self:Reset()
self:CheckInspectQueue()
return
end
end
local tree2, _, spent2 = GetTalentTabInfo(2, isnotplayer, nil, group)
local tree3, _, spent3 = GetTalentTabInfo(3, isnotplayer, nil, group)
if ((spent1 or 0) + (spent2 or 0) + (spent3 or 0) > 0) then
if (guid) then
-- It was in our queue
self.events:Fire("TalentQuery_Ready", name, realm, self.lastInspectUnit)
else
-- Also notify of non-expected ones, as it's entirely useful to refresh them if they're there
-- It is up to the receiving applicating to determine whether they want to receive the information
self.events:Fire("TalentQuery_Ready_Outsider", name, realm, self.lastInspectUnit)
end
else
-- Tree came back with zero points spent, probably an issue while logging in
garbageQueue[self.lastInspectName] = guid
end
end
self:Reset()
self:CheckInspectQueue()
end
end
function lib:PLAYER_ENTERING_WORLD()
-- We can't inspect other's talents until now
-- We just get 0/0/0 back even though we get an INSPECT_TALENT_READY event
enteredWorld = true
end
function lib:PLAYER_LEAVING_WORLD()
enteredWorld = nil
end
function lib:PLAYER_LOGIN()
validateTrees = {
DRUID = "Balance",
PRIEST = "Discipline",
ROGUE = "Assassination",
HUNTER = "Beast Mastery",
WARLOCK = "Affliction",
WARRIOR = "Arms",
DEATHKNIGHT = "Blood",
PALADIN = "Holy",
SHAMAN = "Elemental",
MAGE = "Arcane",
}
if (GetLocale() ~= "enUS" and GetLocale() ~= "enGB") then
-- LibBabble-TalentTree-3.0 only loaded if present and not enUS
local LBT = LibStub("LibBabble-TalentTree-3.0", true)
if (not LBT) then
LoadAddOn("LibBabble-TalentTree-3.0")
LBT = LibStub("LibBabble-TalentTree-3.0", true)
end
LBT = LBT and LBT:GetLookupTable()
if (LBT) then
for class,tree1 in pairs(validateTrees) do
validateTrees[class] = LBT[tree1]
end
else
validateTrees = nil
end
end
self.PLAYER_LOGIN = nil
end
lib:Reset()
@@ -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="LibTalentQuery-1.0.lua"/>
<Script file="LibGroupTalents-1.0.lua"/>
</Ui>
+1025 -227
View File
File diff suppressed because it is too large Load Diff
+614 -138
View File
File diff suppressed because it is too large Load Diff
+1142 -1375
View File
File diff suppressed because it is too large Load Diff
+1237 -1402
View File
File diff suppressed because it is too large Load Diff
+1068 -337
View File
File diff suppressed because it is too large Load Diff
+976 -273
View File
File diff suppressed because it is too large Load Diff
+952 -641
View File
File diff suppressed because it is too large Load Diff
+1029 -217
View File
File diff suppressed because it is too large Load Diff
+586 -248
View File
File diff suppressed because it is too large Load Diff
+654 -175
View File
File diff suppressed because it is too large Load Diff
+648 -206
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
@@ -1,5 +1,4 @@
Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
with Reserved Font Name < Fira >,
Digitized data copyright 2012-2018: The Mozilla Foundation, Telefonica S.A., Carrois Corporate GbR and bBox Type GmbH.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
@@ -19,7 +18,7 @@ with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+95
View File
@@ -0,0 +1,95 @@
Copyright (c) 2018, Paratype Inc (https://paratype.com),
Copyright (c) 2018, Paratype Ltd,
with Reserved Font Name "PT Sans".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
+2 -1
View File
@@ -9,6 +9,7 @@ Creative Commons - Sampling Plus 1.0
Overview:
HeartbeatSingle - Creative Commons CC0 1.0 - original by: bart (https://opengameart.org/content/heartbeat-sounds), modified by: Jieiku (https://github.com/Jieiku)
BatmanPunch - Sampling Plus 1.0 - CGEffex (http://www.freesound.org/people/CGEffex/)
BikeHorn - Sampling Plus 1.0 - StickInTheMud
BoxingArenaSound - Attribution 3.0 - Samantha Enrico
@@ -31,4 +32,4 @@ Shotgun - Attribution 3.0 - Mike Koenig
SquishFart - Sampling Plus 1.0 - timtube
TempleBellHuge - Attribution 3.0 - Mike Koenig
Torch - Attribution 3.0 - Mike Koenig
WarningSiren - Attribution 3.0 - snottyboy
WarningSiren - Attribution 3.0 - snottyboy
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

+828 -140
View File
File diff suppressed because it is too large Load Diff
+232 -238
View File
@@ -1,9 +1,10 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local WeakAuras = WeakAuras
local L = WeakAuras.L
local prettyPrint = WeakAuras.prettyPrint
local LGF = LibStub("LibGetFrame-1.0")
local profileData = {}
profileData.systems = {}
@@ -11,8 +12,9 @@ profileData.auras = {}
local currentProfileState, ProfilingTimer
local RealTimeProfilingWindow = CreateFrame("Button", nil, UIParent)
WeakAuras.frames["RealTime Profiling Window"] = RealTimeProfilingWindow
local RealTimeProfilingWindow = CreateFrame("Frame", "WeakAurasRealTimeProfiling", UIParent, "WA_PortraitFrameTemplate")
RealTimeProfilingWindow:HidePortrait(RealTimeProfilingWindow)
Private.frames["RealTime Profiling Window"] = RealTimeProfilingWindow
RealTimeProfilingWindow.width = 500
RealTimeProfilingWindow.height = 300
RealTimeProfilingWindow.barHeight = 20
@@ -21,6 +23,7 @@ RealTimeProfilingWindow.statsHeight = 15
RealTimeProfilingWindow.buttonsHeight = 22
RealTimeProfilingWindow.bars = {}
RealTimeProfilingWindow:SetMovable(true)
RealTimeProfilingWindow:EnableMouse(true)
RealTimeProfilingWindow:Hide()
WeakAuras.RealTimeProfilingWindow = RealTimeProfilingWindow
@@ -44,174 +47,74 @@ table_to_string = function(tbl, depth)
k = '"' .. k ..'"'
end
str = (str and str .. "|cff999999,|r " or "|cff999999{|r ") .. "|cffffff99[" .. tostring(k) .. "]|r |cff999999=|r |cffffffff" .. tostring(v) .. "|r"
str = (str and str .. "|cff999999,|r " or "|cff999999{|r ") .. "|cffffff99["
.. tostring(k) .. "]|r |cff999999=|r |cffffffff" .. tostring(v) .. "|r"
end
end
return (str or "{ ") .. " }"
end
local function CreateDecoration(frame)
local deco = CreateFrame("Frame", nil, frame)
deco:SetSize(17, 40)
local bg1 = deco:CreateTexture(nil, "BACKGROUND")
bg1:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
bg1:SetTexCoord(0.31, 0.67, 0, 0.63)
bg1:SetAllPoints(deco)
local bg2 = deco:CreateTexture(nil, "BACKGROUND")
bg2:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
bg2:SetTexCoord(0.235, 0.275, 0, 0.63)
bg2:SetPoint("RIGHT", bg1, "LEFT")
bg2:SetSize(10, 40)
local bg3 = deco:CreateTexture(nil, "BACKGROUND")
bg3:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
bg3:SetTexCoord(0.72, 0.76, 0, 0.63)
bg3:SetPoint("LEFT", bg1, "RIGHT")
bg3:SetSize(10, 40)
return deco
end
local function CreateDecorationWide(frame)
local deco1 = frame:CreateTexture(nil, "OVERLAY")
deco1:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
deco1:SetTexCoord(0.31, 0.67, 0, 0.63)
deco1:SetSize(140, 40)
local deco2 = frame:CreateTexture(nil, "OVERLAY")
deco2:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
deco2:SetTexCoord(0.21, 0.31, 0, 0.63)
deco2:SetPoint("RIGHT", deco1, "LEFT")
deco2:SetSize(30, 40)
local deco3 = frame:CreateTexture(nil, "OVERLAY")
deco3:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
deco3:SetTexCoord(0.67, 0.77, 0, 0.63)
deco3:SetPoint("LEFT", deco1, "RIGHT")
deco3:SetSize(30, 40)
return deco1
end
local profilePopup
local function CreateProfilePopup()
local popupFrame = CreateFrame("EditBox", "WADebugEditBox", UIParent)
popupFrame:SetFrameStrata("DIALOG")
popupFrame:SetMultiLine(true)
popupFrame:SetAutoFocus(false)
popupFrame:SetFontObject(ChatFontNormal)
popupFrame:SetSize(450, 300)
popupFrame:SetScript("OnChar", function() popupFrame:SetText(popupFrame.originalText) end);
popupFrame:Hide()
local frame = CreateFrame("Frame", "WeakAurasProfilingReport", UIParent, "WA_PortraitFrameTemplate")
frame:HidePortrait(frame)
WeakAurasProfilingReportTitleText:SetText(L["WeakAuras Profiling Report"])
frame:SetMovable(true)
frame:SetSize(450, 300)
popupFrame.orig_Hide = popupFrame.Hide
function popupFrame:Hide()
self:SetText("")
self.ScrollFrame:Hide()
self.Background:Hide()
self:orig_Hide()
end
frame:SetScript("OnMouseDown", function(self, button)
if button == "LeftButton" and not self.is_moving then
self:StartMoving()
self.is_moving = true
elseif button == "RightButton" then
self:Stop()
end
end)
popupFrame.orig_Show = popupFrame.Show
function popupFrame:Show()
self.ScrollFrame:Show()
self.Background:Show()
self:orig_Show()
end
frame:SetScript("OnMouseUp", function(self, button)
if button == "LeftButton" and self.is_moving then
self:StopMovingOrSizing()
local xOffset = self:GetLeft()
local yOffset = self:GetTop() - GetScreenHeight()
WeakAurasSaved.ProfilingWindow = WeakAurasSaved.ProfilingWindow or {}
WeakAurasSaved.ProfilingWindow.xOffset = xOffset
WeakAurasSaved.ProfilingWindow.yOffset = yOffset
self.is_moving = nil
end
end)
function popupFrame:AddText(v)
local scrollFrame = CreateFrame("ScrollFrame", "WeakAurasProfilingReportScrollFrame", frame, "UIPanelScrollFrameTemplate")
scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 10, -28)
scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -27, 15)
local messageFrame = CreateFrame("EditBox", nil, scrollFrame)
frame.messageFrame = messageFrame
messageFrame:SetMultiLine(true)
messageFrame:SetAutoFocus(false)
messageFrame:SetFontObject(ChatFontNormal)
messageFrame:SetSize(440, 260)
messageFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, -5)
messageFrame:SetPoint("BOTTOMRIGHT", scrollFrame, "BOTTOMRIGHT")
messageFrame:Show()
messageFrame:SetScript("OnChar", function() messageFrame:SetText(messageFrame.originalText) end)
function frame:AddText(v)
if not v then return end
local m = popupFrame:GetText()
local m = self.messageFrame:GetText()
if m ~= "" then
m = m .. "|n"
end
if type(v) == "table" then
v = table_to_string(v)
end
popupFrame.originalText = m .. v
popupFrame:SetText(popupFrame.originalText)
self.messageFrame.originalText = m .. v
self.messageFrame:SetText(self.messageFrame.originalText)
end
popupFrame:SetScript("OnEscapePressed", function(self)
self:ClearFocus()
if IsModifierKeyDown() then
popupFrame:Hide()
end
end)
local scrollFrame = CreateFrame("ScrollFrame", "WADebugEditBoxScrollFrame", UIParent, "UIPanelScrollFrameTemplate")
scrollFrame:SetMovable(true)
scrollFrame:SetFrameStrata("DIALOG")
scrollFrame:SetSize(450, 300)
if WeakAurasSaved.ProfilingWindow then
scrollFrame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", WeakAurasSaved.ProfilingWindow.xOffset or 0, WeakAurasSaved.ProfilingWindow.yOffset or 0)
else
scrollFrame:SetPoint("CENTER")
end
scrollFrame:SetHitRectInsets(-8, -8, -8, -8)
scrollFrame:SetScrollChild(popupFrame)
scrollFrame:Hide()
scrollFrame:SetScrollChild(messageFrame)
local bg = CreateFrame("Frame", nil, UIParent)
bg:SetFrameStrata("DIALOG")
bg:SetBackdrop({
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
tile = true,
tileSize = 32,
edgeSize = 32,
insets = { left = 4, right = 4, top = 4, bottom = 4 }
})
bg:SetPoint("TOPLEFT", scrollFrame, -20, 20)
bg:SetPoint("BOTTOMRIGHT", scrollFrame, 35, -25)
bg:Hide()
local title = CreateFrame("Frame", nil, bg)
title:SetSize(200, 40)
title:SetPoint("TOP", 0, 12)
title:EnableMouse(true)
local titlebg = CreateDecorationWide(bg)
titlebg:SetPoint("TOP", 0, 12)
local titletext = title:CreateFontString(nil, "OVERLAY", "GameFontNormal")
titletext:SetPoint("TOP", titlebg, "TOP", 0, -14)
titletext:SetText(L["WeakAuras Profiling Report"])
local close = CreateDecoration(bg)
close:SetPoint("RIGHT", titlebg, 50, 0)
local closeButton = CreateFrame("Button", nil, close, "UIPanelCloseButton")
closeButton:SetPoint("CENTER", close, "CENTER", 1, -1)
closeButton:SetScript("OnClick", function()
popupFrame:Hide()
end)
popupFrame.ScrollFrame = scrollFrame
popupFrame.Background = bg
title:SetScript("OnMouseDown", function(self, button)
if button == "LeftButton" and not scrollFrame.is_moving then
scrollFrame:StartMoving()
scrollFrame.is_moving = true
end
end)
title:SetScript("OnMouseUp", function(self, button)
if button == "LeftButton" and scrollFrame.is_moving then
scrollFrame:StopMovingOrSizing()
local xOffset = scrollFrame:GetLeft()
local yOffset = scrollFrame:GetTop() - GetScreenHeight()
WeakAurasSaved.ProfilingWindow = WeakAurasSaved.ProfilingWindow or {}
WeakAurasSaved.ProfilingWindow.xOffset = xOffset
WeakAurasSaved.ProfilingWindow.yOffset = yOffset
scrollFrame.is_moving = nil
end
end)
profilePopup = popupFrame
profilePopup = frame
end
local function ProfilePopup()
@@ -285,9 +188,16 @@ function Private.ProfileRenameAura(oldid, id)
end
local RegisterProfile = function(startType)
if startType == "boss" then startType = "combat" end
if startType == "boss" then startType = "encounter" end
local delayedStart
if startType == "combat" then
if startType == "encounter" then
RealTimeProfilingWindow:UnregisterAllEvents()
prettyPrint(L["Your next instance of combat will automatically be profiled."])
RealTimeProfilingWindow:RegisterEvent("PLAYER_REGEN_DISABLED")
RealTimeProfilingWindow:RegisterEvent("PLAYER_REGEN_ENABLED")
currentProfileState = startType
delayedStart = true
elseif startType == "combat" then
RealTimeProfilingWindow:UnregisterAllEvents()
prettyPrint(L["Your next instance of combat will automatically be profiled."])
RealTimeProfilingWindow:RegisterEvent("PLAYER_REGEN_DISABLED")
@@ -335,6 +245,7 @@ function WeakAuras.StartProfile(startType)
Private.StopProfileSystem = StopProfileSystem
Private.StopProfileAura = StopProfileAura
Private.StopProfileUID = StopProfileUID
LGF.StartProfile()
end
local function doNothing()
@@ -357,6 +268,7 @@ function WeakAuras.StopProfile()
Private.StopProfileSystem = doNothing
Private.StopProfileAura = doNothing
Private.StopProfileUID = doNothing
LGF.StopProfile()
currentProfileState = nil
RealTimeProfilingWindow:UnregisterAllEvents()
@@ -399,13 +311,25 @@ local function PrintOneProfile(popup, name, map, total)
end
local percent = ""
if total then
percent = ", " .. string.format("%.2f", 100 * map.elapsed / total) .. "%"
percent = (", %.2f%%"):format(100 * map.elapsed / total)
end
local spikeInfo = ""
if map.spike then
spikeInfo = string.format("(%.2fms)", map.spike)
local r, g, b
if map.spike < 2 then
r, g, b = WeakAuras.GetHSVTransition(map.spike / 2, 0, 1, 0, 1, 1, 1, 0, 1)
elseif map.spike < 2.5 then
r, g, b = WeakAuras.GetHSVTransition((map.spike - 2) * 2, 1, 1, 0, 1, 1, 0.65, 0, 1)
elseif map.spike < 3 then
r, g, b = WeakAuras.GetHSVTransition((map.spike - 2.5) * 2, 1, 0.65, 0, 1, 1, 0, 0, 1)
else
r, g, b = 1, 0, 0
end
spikeInfo = ("|cff%02x%02x%02x(%.2fms)|r"):format(r * 255, g * 255, b * 255, map.spike)
end
popup:AddText(string.format("%s |cff999999%.2fms%s %s|r", name, map.elapsed, percent, spikeInfo))
popup:AddText(("%s |cff999999%.2fms%s %s|r"):format(name, map.elapsed, percent, spikeInfo))
end
local function SortProfileMap(map)
@@ -415,6 +339,9 @@ local function SortProfileMap(map)
end
sort(result, function(a, b)
if map[a].spike and map[b].spike then
return map[a].spike > map[b].spike
end
return map[a].elapsed > map[b].elapsed
end)
@@ -429,6 +356,24 @@ local function TotalProfileTime(map)
return total
end
local function unitEventToMultiUnit(event)
local count
event, count = event:gsub("nameplate%d+$", "nameplate")
if count == 1 then return event end
event, count = event:gsub("boss%d$", "boss")
if count == 1 then return event end
event, count = event:gsub("arena%d$", "arena")
if count == 1 then return event end
event, count = event:gsub("raid%d+$", "group")
if count == 1 then return event end
event, count = event:gsub("raidpet%d+$", "group")
if count == 1 then return event end
event, count = event:gsub("party%d$", "party")
if count == 1 then return event end
event, count = event:gsub("partypet%d$", "party")
return event
end
function WeakAuras.PrintProfile()
local popup = ProfilePopup()
if not profileData.systems.time then
@@ -441,19 +386,28 @@ function WeakAuras.PrintProfile()
return
end
popup:SetText("")
if WeakAurasRealTimeProfiling and WeakAurasRealTimeProfiling:IsShown() then
popup:ClearAllPoints()
popup:SetPoint("TOPLEFT", WeakAurasRealTimeProfiling, "TOPRIGHT", 5, 0)
else
if WeakAurasSaved.ProfilingWindow then
popup:SetPoint("TOPLEFT", UIParent, "TOPLEFT", WeakAurasSaved.ProfilingWindow.xOffset or 0,
WeakAurasSaved.ProfilingWindow.yOffset or 0)
else
popup:SetPoint("CENTER")
end
end
popup.messageFrame:SetText("")
PrintOneProfile(popup, "|cff9900ffTotal time:|r", profileData.systems.time)
PrintOneProfile(popup, "|cff9900ffTime inside WA:|r", profileData.systems.wa)
popup:AddText(string.format("|cff9900ffTime spent inside WA:|r %.2f%%", 100 * profileData.systems.wa.elapsed / profileData.systems.time.elapsed))
popup:AddText("")
popup:AddText("|cff9900ffSystems:|r")
popup:AddText(string.format("|cff9900ffTime spent inside WA:|r %.2f%%",
100 * profileData.systems.wa.elapsed / profileData.systems.time.elapsed))
for i, k in ipairs(SortProfileMap(profileData.systems)) do
if (k ~= "time" and k ~= "wa") then
PrintOneProfile(popup, k, profileData.systems[k], profileData.systems.wa.elapsed)
end
end
popup:AddText("")
popup:AddText("Note: Not every aspect of each aura can be tracked.")
popup:AddText("You can ask on our discord https://discord.gg/weakauras for help interpreting this output.")
popup:AddText("")
popup:AddText("|cff9900ffAuras:|r")
@@ -462,6 +416,38 @@ function WeakAuras.PrintProfile()
for i, k in ipairs(SortProfileMap(profileData.auras)) do
PrintOneProfile(popup, k, profileData.auras[k], total)
end
popup:AddText("")
popup:AddText("|cff9900ffSystems:|r")
-- make a new table for system data with multiUnits grouped
local systemRegrouped = {}
for k, v in pairs(profileData.systems) do
local event = unitEventToMultiUnit(k)
if systemRegrouped[event] == nil then
systemRegrouped[event] = CopyTable(v)
else
if v.elapsed then
systemRegrouped[event].elapsed = (systemRegrouped[event].elapsed or 0) + v.elapsed
end
if v.spike then
systemRegrouped[event].spike = (systemRegrouped[event].spike or 0) + v.spike
end
end
end
for i, k in ipairs(SortProfileMap(systemRegrouped)) do
if (k ~= "time" and k ~= "wa") then
PrintOneProfile(popup, k, systemRegrouped[k], profileData.systems.wa.elapsed)
end
end
popup:AddText("")
popup:AddText("|cff9900ffLibGetFrame:|r")
for id, map in pairs(LGF.GetProfileData()) do
PrintOneProfile(popup, id, map)
end
popup:Show()
end
@@ -471,23 +457,25 @@ function RealTimeProfilingWindow:GetBar(name)
if self.bars[name] then
return self.bars[name]
else
local bar = CreateFrame("FRAME", nil, self.barsFrame)
local bar = CreateFrame("Frame", nil, self.barsFrame)
self.bars[name] = bar
WeakAuras.Mixin(bar, SmoothStatusBarMixin)
WeakAuras.Mixin(bar, Private.SmoothStatusBarMixin)
bar.name = name
bar.parent = self
bar:SetSize(self.width, self.barHeight)
bar:SetHeight(self.barHeight)
local fg = bar:CreateTexture(nil, "ARTWORK")
fg:SetTexture(texture)
fg:SetDrawLayer("ARTWORK", 0)
fg:ClearAllPoints()
fg:SetPoint("TOPLEFT", bar)
fg:SetHeight(self.barHeight)
fg:Show()
bar.fg = fg
local bg = bar:CreateTexture(nil, "BORDER")
local bg = bar:CreateTexture(nil, "ARTWORK")
bg:SetTexture(texture)
bg:SetDrawLayer("ARTWORK", -1)
bg:SetAllPoints()
bg:Show()
bar.bg = bg
@@ -527,11 +515,14 @@ function RealTimeProfilingWindow:GetBar(name)
end
function bar:SetPosition(pos)
if self.parent.barHeight * pos > self.parent.height - self.parent.titleHeight - self.parent.statsHeight - self.parent.buttonsHeight then
if self.parent.barHeight * pos >
self.parent.height - self.parent.titleHeight - self.parent.statsHeight - self.parent.buttonsHeight
then
self:Hide()
else
self:ClearAllPoints()
self:SetPoint("TOPLEFT", self.parent.barsFrame, "TOPLEFT", 0, - (pos - 1) * self.parent.barHeight)
self:SetPoint("RIGHT", self.parent.barsFrame, "RIGHT")
if pos % 2 == 0 then
bar.fg:SetTexture(0.7, 0.7, 0.7, 0.7)
bar.bg:SetTexture(0, 0, 0, 0.2)
@@ -586,88 +577,67 @@ function RealTimeProfilingWindow:Init()
self:SetClampedToScreen(true)
if WeakAurasSaved.RealTimeProfilingWindow then
self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", WeakAurasSaved.RealTimeProfilingWindow.xOffset or 0, WeakAurasSaved.RealTimeProfilingWindow.yOffset or 0)
self:SetPoint("TOPLEFT", UIParent, "TOPLEFT",
WeakAurasSaved.RealTimeProfilingWindow.xOffset or 0,
WeakAurasSaved.RealTimeProfilingWindow.yOffset or 0)
else
self:SetPoint("TOPLEFT", UIParent, "TOPLEFT")
end
self:Show()
local bg = self:CreateTexture(nil, "BACKGROUND")
self.bg = bg
bg:SetTexture(texture)
bg:SetAllPoints()
bg:Show()
local titleFrame = CreateFrame("Frame", nil, self)
self.titleFrame = titleFrame
titleFrame:SetSize(self.width, self.titleHeight)
titleFrame:SetPoint("TOPLEFT", self)
titleFrame:Show()
local titleText = self.titleFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
self.titleFrameText = titleText
titleText:SetText(L["WeakAuras Profiling"])
titleText:SetPoint("CENTER", self.titleFrame)
WeakAurasRealTimeProfilingTitleText:SetText(L["WeakAuras Profiling"])
local barsFrame = CreateFrame("Frame", nil, self)
self.barsFrame = barsFrame
barsFrame:SetSize(self.width, self.height - self.titleHeight - self.statsHeight - self.buttonsHeight)
barsFrame:SetPoint("TOPLEFT", self.titleFrame, "BOTTOMLEFT")
barsFrame:SetPoint("TOPLEFT", 7, -20)
barsFrame:SetPoint("BOTTOMRIGHT", -3, 30)
barsFrame:Show()
local statsFrame = CreateFrame("Frame", nil, self)
self.statsFrame = statsFrame
statsFrame:SetSize(self.width, self.statsHeight)
statsFrame:SetPoint("TOPLEFT", self.barsFrame, "BOTTOMLEFT")
statsFrame:Show()
local statsFrameText = self.statsFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
local statsFrameText = self:CreateFontString(nil, "OVERLAY", "GameFontNormal")
self.statsFrameText = statsFrameText
statsFrameText:SetPoint("LEFT", self.statsFrame, "LEFT", margin, 2)
statsFrameText:SetPoint("BOTTOMLEFT", 15, 25)
local closeButton = CreateFrame("Button", nil, self.titleFrame, "UIPanelCloseButton")
closeButton:SetPoint("TOPRIGHT", self.titleFrame, "TOPRIGHT", 1, 5)
closeButton:SetScript("OnClick", function(self)
self:GetParent():GetParent():Stop()
local minimizeButton = CreateFrame("Button", nil, self, "WA_MaximizeMinimizeButtonFrameTemplate")
minimizeButton:SetPoint("RIGHT", self.CloseButton, "LEFT")
minimizeButton:SetOnMaximizedCallback(function()
self.minimized = false
self.barsFrame:Show()
self.toggleButton:Show()
self.reportButton:Show()
self.combatButton:Show()
self.encounterButton:Show()
self.statsFrameText:Show()
self:ClearAllPoints()
self:SetPoint("TOPRIGHT", UIParent, "BOTTOMLEFT", self.right, self.top)
self:SetHeight(self.prevHeight)
end)
local minimizeButton = CreateFrame("Button", nil, self.titleFrame)
minimizeButton:SetSize(30, 30)
minimizeButton:SetPoint("TOPRIGHT", self.titleFrame, "TOPRIGHT", -25, 5)
minimizeButton:SetNormalTexture("Interface\\BUTTONS\\UI-Panel-CollapseButton-Up.blp")
minimizeButton:SetPushedTexture("Interface\\BUTTONS\\UI-Panel-CollapseButton-Down.blp")
minimizeButton:SetHighlightTexture("Interface\\BUTTONS\\UI-Panel-MinimizeButton-Highlight.blp")
minimizeButton:SetScript("OnClick", function(self)
local parent = self:GetParent():GetParent()
if parent.minimized then
parent.minimized = nil
parent.barsFrame:Show()
parent.statsFrame:Show()
parent:SetHeight(parent.height)
self:SetNormalTexture("Interface\\BUTTONS\\UI-Panel-CollapseButton-Up.blp")
self:SetPushedTexture("Interface\\BUTTONS\\UI-Panel-CollapseButton-Down.blp")
else
parent.minimized = true
parent.barsFrame:Hide()
parent.statsFrame:Hide()
parent:SetHeight(parent.titleHeight)
self:SetNormalTexture("Interface\\BUTTONS\\UI-Panel-ExpandButton-Up.blp")
self:SetPushedTexture("Interface\\BUTTONS\\UI-Panel-ExpandButton-Down.blp")
end
minimizeButton:SetOnMinimizedCallback(function()
self.minimized = true
self.barsFrame:Hide()
self.toggleButton:Hide()
self.reportButton:Hide()
self.combatButton:Hide()
self.encounterButton:Hide()
self.statsFrameText:Hide()
self.right, self.top = self:GetRight(), self:GetTop()
self:ClearAllPoints()
self:SetPoint("TOPRIGHT", UIParent, "BOTTOMLEFT", self.right, self.top)
self.prevHeight = self:GetHeight()
self:SetHeight(60)
end)
local width = 120
local spacing = 2
local toggleButton = CreateFrame("Button", nil, statsFrame, "UIPanelButtonTemplate")
local toggleButton = CreateFrame("Button", nil, self, "UIPanelButtonTemplate")
self.toggleButton = toggleButton
toggleButton:SetPoint("TOPRIGHT", statsFrame, "BOTTOMRIGHT", -spacing, spacing)
toggleButton:SetFrameLevel(statsFrame:GetFrameLevel() + 1)
toggleButton:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -spacing, spacing)
toggleButton:SetFrameLevel(self:GetFrameLevel() + 1)
toggleButton:SetHeight(20)
toggleButton:SetWidth(width)
toggleButton:SetText(L["Start Now"])
toggleButton:SetScript("OnClick", function(self)
local parent = self:GetParent():GetParent()
local parent = self:GetParent()
if (not profileData.systems.time or profileData.systems.time.count ~= 1) then
parent:ResetBars()
WeakAuras.StartProfile()
@@ -676,10 +646,11 @@ function RealTimeProfilingWindow:Init()
end
end)
local reportButton = CreateFrame("Button", nil, statsFrame, "UIPanelButtonTemplate")
local reportButton = CreateFrame("Button", nil, self, "UIPanelButtonTemplate")
self.reportButton = reportButton
reportButton:SetPoint("TOPLEFT", statsFrame, "BOTTOMLEFT", spacing, spacing)
reportButton:SetFrameLevel(statsFrame:GetFrameLevel() + 1)
reportButton:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", spacing, spacing)
reportButton:SetFrameLevel(self:GetFrameLevel() + 1)
reportButton:SetHeight(20)
reportButton:SetWidth(width)
reportButton:SetText(L["Report Summary"])
@@ -688,14 +659,14 @@ function RealTimeProfilingWindow:Init()
end)
reportButton:Hide()
local combatButton = CreateFrame("Button", nil, statsFrame, "UIPanelButtonTemplate")
local combatButton = CreateFrame("Button", nil, self, "UIPanelButtonTemplate")
self.combatButton = combatButton
combatButton:SetPoint("TOPRIGHT", statsFrame, "BOTTOMRIGHT", -spacing - width , spacing)
combatButton:SetFrameLevel(statsFrame:GetFrameLevel() + 1)
combatButton:SetPoint("BOTTOMRIGHT", -spacing - width , spacing)
combatButton:SetFrameLevel(self:GetFrameLevel() + 1)
combatButton:SetHeight(20)
combatButton:SetWidth(width)
combatButton:SetScript("OnClick", function(self)
local parent = self:GetParent():GetParent()
local parent = self:GetParent()
parent:ResetBars()
if currentProfileState ~= "combat" then
WeakAuras.StartProfile("combat")
@@ -704,6 +675,22 @@ function RealTimeProfilingWindow:Init()
end
end)
local encounterButton = CreateFrame("Button", nil, self, "UIPanelButtonTemplate")
self.encounterButton = encounterButton
encounterButton:SetPoint("BOTTOMRIGHT", -spacing - 2 * width, spacing)
encounterButton:SetFrameLevel(self:GetFrameLevel() + 1)
encounterButton:SetHeight(20)
encounterButton:SetWidth(width)
encounterButton:SetScript("OnClick", function(self)
local parent = self:GetParent()
parent:ResetBars()
if currentProfileState ~= "encounter" then
WeakAuras.StartProfile("encounter")
else
CancelScheduledProfile()
end
end)
self:SetScript("OnMouseDown", function(self, button)
if button == "LeftButton" and not self.is_moving then
self:StartMoving()
@@ -726,12 +713,12 @@ function RealTimeProfilingWindow:Init()
end)
self:SetScript("OnUpdate", self.RefreshBars)
self.init = true
self.initt = true
self:UpdateButtons()
end
function RealTimeProfilingWindow:UpdateButtons()
if not self.init then
if not self.initt then
return
end
if currentProfileState == "combat" then
@@ -739,13 +726,20 @@ function RealTimeProfilingWindow:UpdateButtons()
else
self.combatButton:SetText(L["Next Combat"])
end
if currentProfileState == "encounter" then
self.encounterButton:SetText(L["Cancel"])
else
self.encounterButton:SetText(L["Next Encounter"])
end
if currentProfileState == "profiling" then
self.toggleButton:SetText(L["Stop"])
self.combatButton:Hide()
self.encounterButton:Hide()
self.reportButton:Hide()
else
self.toggleButton:SetText(L["Start Now"])
self.combatButton:Show()
self.encounterButton:Show()
if profileData.systems.time then
self.reportButton:Show()
end
@@ -753,7 +747,7 @@ function RealTimeProfilingWindow:UpdateButtons()
end
function RealTimeProfilingWindow:Start()
if not self.init then
if not self.initt then
self:Init()
end
self:Show()
+2210 -1231
View File
File diff suppressed because it is too large Load Diff
+139 -154
View File
@@ -1,4 +1,4 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
@@ -9,7 +9,11 @@ local default = {
icon = false,
desaturate = false,
iconSource = -1,
progressSource = {-1, "" },
adjustedMax = "",
adjustedMin = "",
texture = "Blizzard",
textureSource = "LSM",
width = 200,
height = 15,
orientation = "HORIZONTAL",
@@ -38,12 +42,31 @@ local default = {
zoom = 0
};
WeakAuras.regionPrototype.AddAdjustedDurationToDefault(default);
WeakAuras.regionPrototype.AddAlphaToDefault(default);
Private.regionPrototype.AddProgressSourceToDefault(default)
Private.regionPrototype.AddAlphaToDefault(default);
local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20;
local properties = {
textureSource = {
display = {L["Bar Texture"], L["Selection Mode"]},
setter = "SetStatusBarTextureMode",
type = "list",
values = {
LSM = L["LibSharedMedia"],
Picker = L["Texture Picker"]
}
},
textureInput = {
display = {L["Bar Texture"], L["Texture Picker"]},
setter = "SetStatusBarTextureInput",
type = "texture",
},
texture = {
display = {L["Bar Texture"], L["LibSharedMedia"]},
setter = "SetStatusBarTextureLSM",
type = "textureLSM",
},
barColor = {
display = L["Bar Color"],
setter = "Color",
@@ -66,7 +89,7 @@ local properties = {
values = {}
},
displayIcon = {
display = {L["Icon"], L["Fallback"]},
display = {L["Icon"], L["Manual"]},
setter = "SetIcon",
type = "icon",
},
@@ -132,7 +155,7 @@ local properties = {
},
};
WeakAuras.regionPrototype.AddProperties(properties, default);
Private.regionPrototype.AddProperties(properties, default);
local function GetProperties(data)
local overlayInfo = Private.GetOverlayInfo(data);
@@ -149,6 +172,7 @@ local function GetProperties(data)
end
auraProperties.iconSource.values = Private.IconSources(data)
auraProperties.progressSource.values = Private.GetProgressSourcesForUi(data)
return auraProperties;
end
@@ -338,7 +362,7 @@ local barPrototype = {
local width = additionalBar.width or 0;
local offset = additionalBar.offset or 0;
if (width ~= 0) then
if (width ~= 0 and valueWidth ~= 0) then
if (forwardDirection) then
startProgress = self.value + offset / valueWidth;
endProgress = self.value + (width + offset) / valueWidth;
@@ -725,17 +749,33 @@ local function GetTexCoordZoom(texWidth)
return unpack(texCoord)
end
local function FrameTick(self)
local expirationTime = self.expirationTime
local remaining = expirationTime - GetTime()
local duration = self.duration
local progress = duration ~= 0 and remaining / duration or 0;
if self.inverse then
progress = 1 - progress;
end
self:SetProgress(progress)
end
local funcs = {
AnchorSubRegion = function(self, subRegion, anchorType, selfPoint, anchorPoint, anchorXOffset, anchorYOffset)
AnchorSubRegion = function(self, subRegion, anchorType, anchorPoint, selfPoint, anchorXOffset, anchorYOffset)
if anchorPoint:sub(1, 4) == "sub." then
Private.regionPrototype.AnchorSubRegion(self, subRegion, anchorType, anchorPoint, selfPoint, anchorXOffset, anchorYOffset)
return
end
if anchorType == "area" then
local anchor = self
if selfPoint == "bar" then
if anchorPoint == "bar" then
anchor = self
elseif selfPoint == "icon" then
elseif anchorPoint == "icon" then
anchor = self.icon
elseif selfPoint == "fg" then
elseif anchorPoint == "fg" then
anchor = self.bar.fgFrame
elseif selfPoint == "bg" then
elseif anchorPoint == "bg" then
anchor = self.bar.bg
end
@@ -816,12 +856,7 @@ local funcs = {
self.height = height;
self:Scale(self.scalex, self.scaley);
end,
SetValue = function(self, value, total)
local progress = 0;
if (total ~= 0) then
progress = value / total;
end
SetProgress = function(self, progress)
if self.inverseDirection then
progress = 1 - progress;
end
@@ -833,22 +868,34 @@ local funcs = {
self.bar:SetValue(progress);
end
end,
SetTime = function(self, duration, expirationTime, inverse)
local remaining = expirationTime - GetTime();
local progress = duration ~= 0 and remaining / duration or 0;
-- Need to invert?
if (
(self.inverseDirection and not inverse)
or (inverse and not self.inverseDirection)
)
then
UpdateValue = function(self)
local progress = 0;
if (self.total ~= 0) then
progress = self.value / self.total;
end
self:SetProgress(progress)
if self.FrameTick then
self.FrameTick = nil
self.subRegionEvents:RemoveSubscriber("FrameTick", self)
end
end,
UpdateTime = function(self)
local remaining = self.expirationTime - GetTime();
local progress = self.duration ~= 0 and remaining / self.duration or 0;
if self.inverse then
progress = 1 - progress;
end
if (self.smoothProgress) then
self.bar.targetValue = progress
self.bar:SetSmoothedValue(progress);
else
self.bar:SetValue(progress);
self:SetProgress(progress)
if self.paused and self.FrameTick then
self.FrameTick = nil
self.subRegionEvents:RemoveSubscriber("FrameTick", self)
end
if not self.paused and not self.FrameTick then
self.FrameTick = FrameTick
self.subRegionEvents:AddSubscriber("FrameTick", self)
end
end,
SetInverse = function(self, inverse)
@@ -879,6 +926,40 @@ local funcs = {
end
end,
SetStatusBarTextureMode = function(self, mode)
if self.textureSource == mode then
return
end
self.textureSource = mode
self:UpdateStatusBarTexture()
end,
SetStatusBarTextureInput = function(self, texture)
if self.textureInput == texture then
return
end
self.textureInput = texture
self:UpdateStatusBarTexture()
end,
SetStatusBarTextureLSM = function(self, texture)
if self.texture == texture then
return
end
self.texture = texture
self:UpdateStatusBarTexture()
end,
UpdateStatusBarTexture = function(self)
local texturePath
if self.textureSource == "Picker" then
texturePath = self.textureInput or ""
else
texturePath = SharedMedia:Fetch("statusbar", self.texture) or ""
end
self.bar:SetStatusBarTexture(texturePath)
end,
SetIconVisible = function(self, iconVisible)
if (self.iconVisible == iconVisible) then
return
@@ -939,7 +1020,7 @@ local funcs = {
end
iconPath = iconPath or self.displayIcon or "Interface\\Icons\\INV_Misc_QuestionMark"
self.icon:SetTexture(iconPath)
Private.SetTextureOrSpellTexture(self.icon, iconPath)
end,
SetOverlayColor = function(self, id, r, g, b, a)
self.bar:SetAdditionalBarColor(id, { r, g, b, a});
@@ -961,7 +1042,7 @@ local funcs = {
orientVertical(self);
end
end,
UpdateEffectiveOrientation = function(self)
UpdateEffectiveOrientation = function(self, force)
local orientation = self.orientation
if self.flipX then
@@ -979,7 +1060,7 @@ local funcs = {
end
end
if orientation ~= self.effectiveOrientation then
if orientation ~= self.effectiveOrientation or force then
self.effectiveOrientation = orientation
self:ReOrient()
end
@@ -1004,19 +1085,19 @@ end
-- Called when first creating a new region/display
local function create(parent)
-- Create overall region (containing everything else)
local region = CreateFrame("FRAME", nil, parent);
local region = CreateFrame("Frame", nil, parent);
region.regionType = "aurabar"
region:SetMovable(true);
region:SetResizable(true);
region:SetMinResize(1, 1);
-- Create statusbar (inherit prototype)
local bar = CreateFrame("FRAME", nil, region);
WeakAuras.Mixin(bar, SmoothStatusBarMixin);
local bar = CreateFrame("Frame", nil, region);
WeakAuras.Mixin(bar, Private.SmoothStatusBarMixin);
local fg = bar:CreateTexture(nil, "BORDER");
local bg = bar:CreateTexture(nil, "BACKGROUND");
bg:SetAllPoints();
local fgFrame = CreateFrame("FRAME", nil, bar)
local bg = region:CreateTexture(nil, "BACKGROUND");
bg:SetAllPoints(bar);
local fgFrame = CreateFrame("Frame", nil, bar)
local spark = bar:CreateTexture(nil, "ARTWORK");
bar.fg = fg;
bar.fgFrame = fgFrame
@@ -1031,7 +1112,7 @@ local function create(parent)
region.bar = bar;
-- Create icon
local iconFrame = CreateFrame("FRAME", nil, region);
local iconFrame = CreateFrame("Frame", nil, region);
region.iconFrame = iconFrame;
local icon = iconFrame:CreateTexture(nil, "OVERLAY");
region.icon = icon;
@@ -1051,7 +1132,7 @@ local function create(parent)
end
end
WeakAuras.regionPrototype.create(region);
Private.regionPrototype.create(region);
for k, f in pairs(funcs) do
region[k] = f
@@ -1061,21 +1142,13 @@ local function create(parent)
return region;
end
local function TimerTick(self)
local state = self.state
local duration = state.duration or 0
local adjustMin = self.adjustedMin or self.adjustedMinRel or 0;
local expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge;
self:SetTime((duration ~= 0 and (self.adjustedMax or self.adjustedMaxRel) or duration) - adjustMin, expirationTime - adjustMin, state.inverse);
end
-- Modify a given region/display
local function modify(parent, region, data)
region.timer = nil
region.text = nil
region.stacks = nil
WeakAuras.regionPrototype.modify(parent, region, data);
Private.regionPrototype.modify(parent, region, data);
-- Localize
local bar, iconFrame, icon = region.bar, region.iconFrame, region.icon;
@@ -1116,8 +1189,11 @@ local function modify(parent, region, data)
end
-- Update texture settings
local texturePath = SharedMedia:Fetch("statusbar", data.texture) or "";
bar:SetStatusBarTexture(texturePath);
region.textureSource = data.textureSource
region.texture = data.texture
region.textureInput = data.textureInput
region:UpdateStatusBarTexture();
bar:SetBackgroundColor(data.backgroundColor[1], data.backgroundColor[2], data.backgroundColor[3], data.backgroundColor[4]);
-- Update spark settings
bar.spark:SetTexture(data.sparkTexture);
@@ -1187,7 +1263,7 @@ local function modify(parent, region, data)
if tooltipType and data.useTooltip then
-- Create and enable tooltip-hover frame
if not region.tooltipFrame then
region.tooltipFrame = CreateFrame("frame", nil, region);
region.tooltipFrame = CreateFrame("Frame", nil, region);
region.tooltipFrame:SetAllPoints(icon);
region.tooltipFrame:SetScript("OnEnter", function()
Private.ShowMouseoverTooltip(region, region.tooltipFrame);
@@ -1201,106 +1277,15 @@ local function modify(parent, region, data)
region.tooltipFrame:EnableMouse(false);
end
function region:UpdateMinMax()
local state = region.state
local min
local max
if state.progressType == "timed" then
local duration = state.duration or 0
if region.adjustedMinRelPercent then
region.adjustedMinRel = region.adjustedMinRelPercent * duration
end
min = region.adjustedMin or region.adjustedMinRel or 0;
if duration == 0 then
max = 0
elseif region.adjustedMax then
max = region.adjustedMax
elseif region.adjustedMaxRelPercent then
region.adjustedMaxRel = region.adjustedMaxRelPercent * duration
max = region.adjustedMaxRel
else
max = duration
end
elseif state.progressType == "static" then
local total = state.total or 0;
if region.adjustedMinRelPercent then
region.adjustedMinRel = region.adjustedMinRelPercent * total
end
min = region.adjustedMin or region.adjustedMinRel or 0;
if region.adjustedMax then
max = region.adjustedMax
elseif region.adjustedMaxRelPercent then
region.adjustedMaxRel = region.adjustedMaxRelPercent * total
max = region.adjustedMaxRel
else
max = total
end
end
region.currentMin, region.currentMax = min, max
end
function region:GetMinMax()
return region.currentMin or 0, region.currentMax or 0
end
region.FrameTick = nil
function region:Update()
local state = region.state
region:UpdateMinMax()
if state.progressType == "timed" then
local expirationTime
if state.paused == true then
if not region.paused then
region:Pause()
end
if region.TimerTick then
region.TimerTick = nil
region:UpdateRegionHasTimerTick()
end
expirationTime = GetTime() + (state.remaining or 0)
else
if region.paused then
region:Resume()
end
if not region.TimerTick then
region.TimerTick = TimerTick
region:UpdateRegionHasTimerTick()
end
expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge;
end
local duration = state.duration or 0
region:SetTime(region.currentMax - region.currentMin, expirationTime - region.currentMin, state.inverse);
elseif state.progressType == "static" then
if region.paused then
region:Resume()
end
local value = state.value or 0;
local total = state.total or 0;
region:SetValue(value - region.currentMin, region.currentMax - region.currentMin);
if region.TimerTick then
region.TimerTick = nil
region:UpdateRegionHasTimerTick()
end
else
if region.paused then
region:Resume()
end
region:SetTime(0, math.huge)
if region.TimerTick then
region.TimerTick = nil
region:UpdateRegionHasTimerTick()
end
end
region:UpdateProgress()
region:UpdateIcon()
end
local duration = state.duration or 0
local effectiveInverse = (state.inverse and not region.inverseDirection) or (not state.inverse and region.inverseDirection);
region.bar:SetAdditionalBars(state.additionalProgress, region.overlays, region.overlaysTexture, region.currentMin, region.currentMax, effectiveInverse, region.overlayclip);
function region:SetAdditionalProgress(additionalProgress, currentMin, currentMax, inverse)
local effectiveInverse = (inverse and not region.inverseDirection) or (not inverse and region.inverseDirection);
region.bar:SetAdditionalBars(additionalProgress, region.overlays, region.overlaysTexture, currentMin, currentMax, effectiveInverse, region.overlayclip);
end
-- Scale update function
@@ -1339,7 +1324,7 @@ local function modify(parent, region, data)
self:SetHeight(self.bar.totalHeight);
icon:SetHeight(self.bar.iconHeight);
region:UpdateEffectiveOrientation()
region:UpdateEffectiveOrientation(true)
end
-- region:Scale(1.0, 1.0);
if data.smoothProgress then
@@ -1354,7 +1339,7 @@ local function modify(parent, region, data)
--- Update internal bar alignment
region.bar:Update();
WeakAuras.regionPrototype.modifyFinish(parent, region, data);
Private.regionPrototype.modifyFinish(parent, region, data);
end
local function validate(data)
@@ -1371,4 +1356,4 @@ local function validate(data)
end
-- Register new region type with WeakAuras
WeakAuras.RegisterRegionType("aurabar", create, modify, default, GetProperties, validate);
Private.RegisterRegionType("aurabar", create, modify, default, GetProperties, validate);
+405 -85
View File
@@ -1,7 +1,8 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local WeakAuras = WeakAuras
local L = WeakAuras.L
local SharedMedia = LibStub("LibSharedMedia-3.0")
local default = {
@@ -27,6 +28,7 @@ local default = {
yOffset = 0,
radius = 200,
rotation = 0,
stepAngle = 15,
fullCircle = true,
arcLength = 360,
constantFactor = "RADIUS",
@@ -35,15 +37,19 @@ local default = {
useLimit = false,
limit = 5,
gridType = "RD",
centerType = "LR",
gridWidth = 5,
rowSpace = 1,
columnSpace = 1
}
Private.regionPrototype.AddAlphaToDefault(default);
local controlPointFunctions = {
["SetAnchorPoint"] = function(self, point, relativeFrame, relativePoint, offsetX, offsetY)
self:ClearAllPoints();
self.point, self.relativeFrame, self.relativePoint, self.offsetX, self.offsetY = point, relativeFrame, relativePoint, offsetX, offsetY
self.point, self.relativeFrame, self.relativePoint, self.offsetX, self.offsetY
= point, relativeFrame, relativePoint, offsetX, offsetY
self.totalOffsetX = (self.animOffsetX or 0) + (self.offsetX or 0)
self.totalOffsetY = (self.animOffsetY or 0) + (self.offsetY or 0)
if self.relativeFrame and self.relativePoint then
@@ -79,7 +85,7 @@ local controlPointFunctions = {
}
local function createControlPoint(self)
local controlPoint = CreateFrame("FRAME", nil, self.parent)
local controlPoint = CreateFrame("Frame", nil, self.parent)
WeakAuras.Mixin(controlPoint, controlPointFunctions)
controlPoint:SetWidth(16)
@@ -103,19 +109,21 @@ local function releaseControlPoint(self, controlPoint)
end
local function create(parent)
local region = CreateFrame("FRAME", nil, parent)
local region = CreateFrame("Frame", nil, parent)
region.regionType = "dynamicgroup"
region:SetSize(16, 16)
region:SetMovable(true)
region.sortedChildren = {}
region.controlledChildren = {}
region.updatedChildren = {}
local background = CreateFrame("frame", nil, region)
region.sortStates = {}
region.growStates = {}
local background = CreateFrame("Frame", nil, region)
region.background = background
region.selfPoint = "TOPLEFT"
region.controlPoints = CreateObjectPool(createControlPoint, releaseControlPoint)
region.controlPoints.parent = region
WeakAuras.regionPrototype.create(region)
Private.regionPrototype.create(region)
region.suspended = 0
local oldSetFrameLevel = region.SetFrameLevel
@@ -270,7 +278,7 @@ local sorters = {
return WeakAuras.ComposeSorts(
WeakAuras.SortAscending({"dataIndex"}),
WeakAuras.SortAscending({"region", "state", "index"})
)
), { index = true }
end,
hybrid = function(data)
local sortHybridTable = data.sortHybridTable or {}
@@ -301,33 +309,41 @@ local sorters = {
sortHybridStatus,
sortExpirationTime,
WeakAuras.SortAscending({"dataIndex"})
)
), {expirationTime = true}
end,
ascending = function(data)
return WeakAuras.ComposeSorts(
WeakAuras.SortAscending({"region", "state", "expirationTime"}),
WeakAuras.SortAscending({"dataIndex"})
)
), {expirationTime = true}
end,
descending = function(data)
return WeakAuras.ComposeSorts(
WeakAuras.SortDescending({"region", "state", "expirationTime"}),
WeakAuras.SortAscending({"dataIndex"})
)
), {expirationTime = true}
end,
custom = function(data)
local sortStr = data.customSort or ""
local sortFunc = WeakAuras.LoadFunction("return " .. sortStr, data.id, "custom sort") or noop
local sortFunc = WeakAuras.LoadFunction("return " .. sortStr) or noop
local sortOn = nil
local events = WeakAuras.split(data.sortOn or "")
if #events > 0 then
sortOn = {}
for _, event in ipairs(events) do
sortOn[event] = true
end
end
return function(a, b)
Private.ActivateAuraEnvironment(data.id)
local ok, result = pcall(sortFunc, a, b)
Private.ActivateAuraEnvironment()
if not ok then
geterrorhandler()(result)
Private.GetErrorHandlerId(data.id, L["Custom Sort"])
else
return result
end
end
end, sortOn
end
}
WeakAuras.SortFunctions = sorters
@@ -380,7 +396,7 @@ local anchorers = {
tinsert(frames[Private.personalRessourceDisplayFrame], regionData)
end
end
end
end, {unit = true }
end,
["UNITFRAME"] = function(data)
return function(frames, activeRegions)
@@ -394,24 +410,104 @@ local anchorers = {
end
end
end
end
end, {unit = true }
end,
["CUSTOM"] = function(data)
local anchorStr = data.customAnchorPerUnit or ""
local anchorFunc = WeakAuras.LoadFunction("return " .. anchorStr, data.id, "custom frame anchor") or noop
local anchorFunc = WeakAuras.LoadFunction("return " .. anchorStr) or noop
local anchorOn = nil
local events = WeakAuras.split(data.anchorOn or "")
if #events > 0 then
anchorOn = {}
for _, event in ipairs(events) do
anchorOn[event] = true
end
end
return function(frames, activeRegions)
Private.ActivateAuraEnvironment(data.id)
local ok, ret = pcall(anchorFunc, frames, activeRegions)
if not ok then
geterrorhandler()(ret)
Private.GetErrorHandlerUid(data.uid, L["Custom Anchor"])
end
Private.ActivateAuraEnvironment()
end, anchorOn
end
}
-- Names are based on the Left->Right layout,
local centeredIndexerStart = {
-- Left to right, e.g: 1 2 3 4
["LR"] = function(maxIndex)
return maxIndex > 0 and 1 or nil
end,
["RL"] = function(maxIndex)
return maxIndex > 0 and maxIndex or nil
end,
-- Center -> Left -> Right, e.g: 4 2 1 3
["CLR"] = function(maxIndex)
if maxIndex >= 3 then
return maxIndex - maxIndex % 2
else
return maxIndex > 0 and maxIndex or nil
end
end,
-- Center -> Right -> Left, e.g: 3 1 2 4
["CRL"] = function(maxIndex)
if maxIndex % 2 == 1 then
return maxIndex
else
return maxIndex > 0 and maxIndex - 1 or nil
end
end
}
local centeredIndexerNext = {
["LR"] = function(index, maxIndex)
index = index + 1
return index <= maxIndex and index or nil
end,
["RL"] = function(index, maxIndex)
index = index - 1
return index > 0 and index or nil
end,
["CLR"] = function(index, maxIndex)
-- Center -> Left -> Right
-- So even -> odd
if index % 2 == 0 then
index = index - 2
if index == 0 then
index = 1
end
else
index = index + 2
end
if index > maxIndex then
return nil
end
return index
end,
["CRL"] = function(index, maxIndex)
-- Center -> Right -> Left
-- So odd -> even
if index % 2 == 1 then
index = index - 2
if index == -1 then
index = 2
end
else
index = index + 2
end
if index > maxIndex then
return nil
end
return index
end,
}
local function createAnchorPerUnitFunc(data)
local anchorer = anchorers[data.anchorPerUnit] or anchorers.NAMEPLATE or anchorers.UNITFRAME
local anchorer = anchorers[data.anchorPerUnit] or anchorers.NAMEPLATE
return anchorer(data)
end
@@ -426,7 +522,10 @@ local growers = {
local limit = data.useLimit and data.limit or math.huge
local startX, startY = 0, 0
local coeff = staggerCoefficient(data.align, data.stagger)
local anchorPerUnitFunc = data.useAnchorPerUnit and createAnchorPerUnitFunc(data)
local anchorPerUnitFunc, anchorOn
if data.useAnchorPerUnit then
anchorPerUnitFunc, anchorOn = createAnchorPerUnitFunc(data)
end
return function(newPositions, activeRegions)
local frames = {}
if anchorPerUnitFunc then
@@ -446,7 +545,7 @@ local growers = {
end
end
end
end
end, anchorOn
end,
RIGHT = function(data)
local stagger = data.stagger or 0
@@ -454,7 +553,10 @@ local growers = {
local limit = data.useLimit and data.limit or math.huge
local startX, startY = 0, 0
local coeff = 1 - staggerCoefficient(data.align, stagger)
local anchorPerUnitFunc = data.useAnchorPerUnit and createAnchorPerUnitFunc(data)
local anchorPerUnitFunc, anchorOn
if data.useAnchorPerUnit then
anchorPerUnitFunc, anchorOn = createAnchorPerUnitFunc(data)
end
return function(newPositions, activeRegions)
local frames = {}
if anchorPerUnitFunc then
@@ -474,7 +576,7 @@ local growers = {
end
end
end
end
end, anchorOn
end,
UP = function(data)
local stagger = data.stagger or 0
@@ -482,7 +584,10 @@ local growers = {
local limit = data.useLimit and data.limit or math.huge
local startX, startY = 0, 0
local coeff = 1 - staggerCoefficient(data.align, stagger)
local anchorPerUnitFunc = data.useAnchorPerUnit and createAnchorPerUnitFunc(data)
local anchorPerUnitFunc, anchorOn
if data.useAnchorPerUnit then
anchorPerUnitFunc, anchorOn = createAnchorPerUnitFunc(data)
end
return function(newPositions, activeRegions)
local frames = {}
if anchorPerUnitFunc then
@@ -502,7 +607,7 @@ local growers = {
end
end
end
end
end, anchorOn
end,
DOWN = function(data)
local stagger = data.stagger or 0
@@ -510,7 +615,10 @@ local growers = {
local limit = data.useLimit and data.limit or math.huge
local startX, startY = 0, 0
local coeff = staggerCoefficient(data.align, stagger)
local anchorPerUnitFunc = data.useAnchorPerUnit and createAnchorPerUnitFunc(data)
local anchorPerUnitFunc, anchorOn
if data.useAnchorPerUnit then
anchorPerUnitFunc, anchorOn = createAnchorPerUnitFunc(data)
end
return function(newPositions, activeRegions)
local frames = {}
if anchorPerUnitFunc then
@@ -530,14 +638,19 @@ local growers = {
end
end
end
end
end, anchorOn
end,
HORIZONTAL = function(data)
local stagger = data.stagger or 0
local space = data.space or 0
local limit = data.useLimit and data.limit or math.huge
local midX, midY = 0, 0
local anchorPerUnitFunc = data.useAnchorPerUnit and createAnchorPerUnitFunc(data)
local anchorPerUnitFunc, anchorOn
if data.useAnchorPerUnit then
anchorPerUnitFunc, anchorOn = createAnchorPerUnitFunc(data)
end
local FirstIndex = centeredIndexerStart[data.centerType]
local NextIndex = centeredIndexerNext[data.centerType]
return function(newPositions, activeRegions)
local frames = {}
if anchorPerUnitFunc then
@@ -554,23 +667,29 @@ local growers = {
end
local x, y = midX - totalWidth/2, midY - (stagger * (numVisible - 1)/2)
newPositions[frame] = {}
for i, regionData in ipairs(regionDatas) do
if i <= numVisible then
x = x + (regionData.dimensions.width) / 2
newPositions[frame][regionData] = { x, y, true }
x = x + (regionData.dimensions.width) / 2 + space
y = y + stagger
end
local i = FirstIndex(numVisible)
while i do
local regionData = regionDatas[i]
x = x + (regionData.dimensions.width) / 2
newPositions[frame][regionData] = { x, y, true }
x = x + (regionData.dimensions.width) / 2 + space
y = y + stagger
i = NextIndex(i, numVisible)
end
end
end
end, anchorOn
end,
VERTICAL = function(data)
local stagger = -(data.stagger or 0)
local space = data.space or 0
local limit = data.useLimit and data.limit or math.huge
local midX, midY = 0, 0
local anchorPerUnitFunc = data.useAnchorPerUnit and createAnchorPerUnitFunc(data)
local anchorPerUnitFunc, anchorOn
if data.useAnchorPerUnit then
anchorPerUnitFunc, anchorOn = createAnchorPerUnitFunc(data)
end
local FirstIndex = centeredIndexerStart[data.centerType]
local NextIndex = centeredIndexerNext[data.centerType]
return function(newPositions, activeRegions)
local frames = {}
if anchorPerUnitFunc then
@@ -587,26 +706,31 @@ local growers = {
end
local x, y = midX - (stagger * (numVisible - 1)/2), midY - totalHeight/2
newPositions[frame] = {}
for i, regionData in ipairs(regionDatas) do
if i <= numVisible then
y = y + (regionData.dimensions.height) / 2
newPositions[frame][regionData] = { x, y, true }
x = x + stagger
y = y + (regionData.dimensions.height) / 2 + space
end
local i = FirstIndex(numVisible)
while i do
local regionData = regionDatas[i]
y = y + (regionData.dimensions.height) / 2
newPositions[frame][regionData] = { x, y, true }
x = x + stagger
y = y + (regionData.dimensions.height) / 2 + space
i = NextIndex(i, numVisible)
end
end
end
end, anchorOn
end,
CIRCLE = function(data)
local oX, oY = 0, 0
local constantFactor = data.constantFactor
local space = data.space or 0
local radius = data.radius or 0
local stepAngle = (data.stepAngle or 0) * math.pi / 180
local limit = data.useLimit and data.limit or math.huge
local sAngle = (data.rotation or 0) * math.pi / 180
local arc = (data.fullCircle and 360 or data.arcLength or 0) * math.pi / 180
local anchorPerUnitFunc = data.useAnchorPerUnit and createAnchorPerUnitFunc(data)
local anchorPerUnitFunc, anchorOn
if data.useAnchorPerUnit then
anchorPerUnitFunc, anchorOn = createAnchorPerUnitFunc(data)
end
return function(newPositions, activeRegions)
local frames = {}
if anchorPerUnitFunc then
@@ -617,7 +741,7 @@ local growers = {
for frame, regionDatas in pairs(frames) do
local numVisible = min(limit, #regionDatas)
local r
if constantFactor == "RADIUS" then
if constantFactor == "RADIUS" or constantFactor == "ANGLE" then
r = radius
else
if numVisible <= 1 then
@@ -630,6 +754,8 @@ local growers = {
local dAngle
if numVisible == 1 then
dAngle = 0
elseif constantFactor == "ANGLE" then
dAngle = stepAngle
elseif not data.fullCircle then
dAngle = arc / (numVisible - 1)
else
@@ -644,17 +770,21 @@ local growers = {
end
end
end
end
end, anchorOn
end,
COUNTERCIRCLE = function(data)
local oX, oY = 0, 0
local constantFactor = data.constantFactor
local space = data.space or 0
local radius = data.radius or 0
local stepAngle = (data.stepAngle or 0) * math.pi / 180
local limit = data.useLimit and data.limit or math.huge
local sAngle = (data.rotation or 0) * math.pi / 180
local arc = (data.fullCircle and 360 or data.arcLength or 0) * math.pi / 180
local anchorPerUnitFunc = data.useAnchorPerUnit and createAnchorPerUnitFunc(data)
local anchorPerUnitFunc, anchorOn
if data.useAnchorPerUnit then
anchorPerUnitFunc, anchorOn = createAnchorPerUnitFunc(data)
end
return function(newPositions, activeRegions)
local frames = {}
if anchorPerUnitFunc then
@@ -665,7 +795,7 @@ local growers = {
for frame, regionDatas in pairs(frames) do
local numVisible = min(limit, #regionDatas)
local r
if constantFactor == "RADIUS" then
if constantFactor == "RADIUS" or constantFactor == "ANGLE" then
r = radius
else
if numVisible <= 1 then
@@ -678,6 +808,8 @@ local growers = {
local dAngle
if numVisible == 1 then
dAngle = 0
elseif constantFactor == "ANGLE" then
dAngle = -stepAngle
elseif not data.fullCircle then
dAngle = arc / (1 - numVisible)
else
@@ -692,16 +824,16 @@ local growers = {
end
end
end
end
end, anchorOn
end,
GRID = function(data)
local gridType = data.gridType
local gridWidth = data.gridWidth
local rowSpace = data.rowSpace
local colSpace = data.columnSpace
local rowFirst = (gridType:find("^[RL]")) ~= nil
local rowFirst = (gridType:find("^[RLH]")) ~= nil
local limit = data.useLimit and data.limit or math.huge
local rowMul, colMul
local rowMul, colMul, primary_horizontal, secondary_horizontal, primary_vertical, secondary_vertical
if gridType:find("D") then
rowMul = -1
else
@@ -712,6 +844,16 @@ local growers = {
else
colMul = 1
end
if gridType:sub(1, 1) == "H" then
primary_horizontal = true
elseif gridType:sub(2, 2) == "H" then
secondary_horizontal = true
end
if gridType:sub(1, 1) == "V" then
primary_vertical = true
elseif gridType:sub(2, 2) == "V" then
secondary_vertical = true
end
local primary = {
-- x direction
dim = "width",
@@ -731,7 +873,10 @@ local growers = {
if not rowFirst then
primary, secondary = secondary, primary
end
local anchorPerUnitFunc = data.useAnchorPerUnit and createAnchorPerUnitFunc(data)
local anchorPerUnitFunc, anchorOn
if data.useAnchorPerUnit then
anchorPerUnitFunc, anchorOn = createAnchorPerUnitFunc(data)
end
return function(newPositions, activeRegions)
local frames = {}
if anchorPerUnitFunc then
@@ -745,34 +890,104 @@ local growers = {
secondary.current = 0
secondary.max = 0
newPositions[frame] = {}
local minX, maxX, minY, maxY, totalMinX, totalMaxX, totalMinY, totalMaxY
local start
for i, regionData in ipairs(regionDatas) do
if i <= numVisible then
newPositions[frame][regionData] = { [primary.coord] = primary.current, [secondary.coord] = secondary.current, [3] = true }
newPositions[frame][regionData] = {
[primary.coord] = primary.current,
[secondary.coord] = secondary.current,
[3] = true
}
local x, y = newPositions[frame][regionData][1], newPositions[frame][regionData][2]
if minX == nil then
minX, maxX, minY, maxY = x, x, y, y
start = i
else
minX, maxX = math.min(minX, x), math.max(maxX, x)
minY, maxY = math.min(minY, y), math.max(maxY, y)
end
if totalMinX == nil then
totalMinX, totalMaxX, totalMinY, totalMaxY = x, x, y, y
else
totalMinX, totalMaxX = math.min(totalMinX, x), math.max(totalMaxX, x)
totalMinY, totalMaxY = math.min(totalMinY, y), math.max(totalMaxY, y)
end
secondary.max = max(secondary.max, getDimension(regionData, secondary.dim))
if i % gridWidth == 0 then
if primary_horizontal then
local offsetX = (maxX - minX) / 2
for j = start, i do
newPositions[frame][regionDatas[j]][1] = newPositions[frame][regionDatas[j]][1] - offsetX
end
end
if primary_vertical then
local offsetY = (maxY - minY) / 2
for j = start, i do
newPositions[frame][regionDatas[j]][2] = newPositions[frame][regionDatas[j]][2] - offsetY
end
end
primary.current = 0
secondary.current = secondary.current + (secondary.space + secondary.max) * secondary.mul
secondary.max = 0
minX, maxX = nil, nil
minY, maxY = nil, nil
else
primary.current = primary.current + (primary.space + getDimension(regionData, primary.dim)) * primary.mul
end
end
end
if (primary_horizontal or primary_vertical) and minX then
local offsetX = (maxX - minX) / 2
local offsetY = (maxY - minY) / 2
for j = start, #regionDatas do
if j <= numVisible then
if primary_horizontal then
newPositions[frame][regionDatas[j]][1] = newPositions[frame][regionDatas[j]][1] - offsetX
end
if primary_vertical then
newPositions[frame][regionDatas[j]][2] = newPositions[frame][regionDatas[j]][2] - offsetY
end
end
end
end
if (secondary_horizontal or secondary_vertical) and totalMinX then
local offsetX = (totalMaxX - totalMinX) / 2
local offsetY = (totalMaxY - totalMinY) / 2
for j = 1, #regionDatas do
if j <= numVisible then
if secondary_horizontal then
newPositions[frame][regionDatas[j]][1] = newPositions[frame][regionDatas[j]][1] - offsetX
end
if secondary_vertical then
newPositions[frame][regionDatas[j]][2] = newPositions[frame][regionDatas[j]][2] - offsetY
end
end
end
end
end
end
end, anchorOn
end,
CUSTOM = function(data)
local growStr = data.customGrow or ""
local growFunc = WeakAuras.LoadFunction("return " .. growStr, data.id, "custom grow") or noop
local growFunc = WeakAuras.LoadFunction("return " .. growStr) or noop
local growOn = nil
local events = WeakAuras.split(data.growOn or "")
if #events > 0 then
growOn = {}
for _, event in ipairs(events) do
growOn[event] = true
end
end
return function(newPositions, activeRegions)
Private.ActivateAuraEnvironment(data.id)
local ok, ret = pcall(growFunc, newPositions, activeRegions)
Private.ActivateAuraEnvironment()
if not ok then
geterrorhandler()(ret)
Private.GetErrorHandlerId(data.id, L["Custom Grow"])
wipe(newPositions)
end
end
end, growOn
end
}
WeakAuras.GrowFunctions = growers
@@ -789,12 +1004,56 @@ local function SafeGetPos(region, func)
end
end
local function isDifferent(regionData, cache, events)
local id = regionData.id
local cloneId = regionData.cloneId or ""
local state = regionData.region.state
if not events then
return false
elseif events.changed then
return true -- escape hatch, not super recommended
else
local isDifferent = false
if not cache[id] then
isDifferent = true
local cachedState = {}
cache[id] = {[cloneId] = cachedState}
for event in pairs(events) do
cachedState[event] = state[event]
end
elseif not cache[id][cloneId] then
isDifferent = true
local cachedState = {}
cache[id][cloneId] = cachedState
for event in pairs(events) do
cachedState[event] = state[event]
end
else
local cachedState = cache[id][cloneId]
for event in pairs(events) do
if regionData.region.state[event] ~= cachedState[event] then
cachedState[event] = state[event]
isDifferent = true
end
end
end
return isDifferent
end
end
local function clearCache(cache, id, cloneId)
cloneId = cloneId or ""
if cache[id] then
cache[id][cloneId] = nil
end
end
local function modify(parent, region, data)
Private.FixGroupChildrenOrderForGroup(data)
region:SetScale(data.scale and data.scale > 0 and data.scale <= 10 and data.scale or 1)
WeakAuras.regionPrototype.modify(parent, region, data)
Private.regionPrototype.modify(parent, region, data)
if data.border and (data.grow ~= "CUSTOM" and not data.useAnchorPerUnit) then
if data.border and not data.useAnchorPerUnit then
local background = region.background
background:SetBackdrop({
edgeFile = data.borderEdge ~= "None" and SharedMedia:Fetch("border", data.borderEdge) or "",
@@ -807,8 +1066,10 @@ local function modify(parent, region, data)
bottom = data.borderInset,
},
});
background:SetBackdropBorderColor(data.borderColor[1], data.borderColor[2], data.borderColor[3], data.borderColor[4]);
background:SetBackdropColor(data.backdropColor[1], data.backdropColor[2], data.backdropColor[3], data.backdropColor[4]);
background:SetBackdropBorderColor(data.borderColor[1], data.borderColor[2],
data.borderColor[3], data.borderColor[4]);
background:SetBackdropColor(data.backdropColor[1], data.backdropColor[2],
data.backdropColor[3], data.backdropColor[4]);
background:ClearAllPoints();
background:SetPoint("bottomleft", region, "bottomleft", -1 * data.borderOffset, -1 * data.borderOffset)
@@ -832,7 +1093,7 @@ local function modify(parent, region, data)
end
function region:Resume()
-- Allows group to reindex and reposition.
-- Allows group to re-index and reposition.
-- TriggersSortUpdatedChildren and PositionChildren to happen
if self.suspended > 0 then
self.suspended = self.suspended - 1
@@ -883,13 +1144,6 @@ local function modify(parent, region, data)
region.controlledChildren[childID] = region.controlledChildren[childID] or {}
region.controlledChildren[childID][cloneID] = controlPoint
childRegion:SetAnchor(data.selfPoint, controlPoint, data.selfPoint)
if(childData.frameStrata == 1) then
local frameStrata = region:GetFrameStrata()
childRegion:SetFrameStrata(frameStrata ~= "UNKNOWN" and frameStrata or "BACKGROUND");
else
childRegion:SetFrameStrata(Private.frame_strata_types[childData.frameStrata]);
end
Private.ApplyFrameLevel(childRegion)
return regionData
end
@@ -915,6 +1169,8 @@ local function modify(parent, region, data)
Private.StartProfileAura(data.id)
self.needToReload = false
self.sortedChildren = {}
self.sortStates = {}
self.growStates = {}
self.controlledChildren = {}
self.updatedChildren = {}
self.controlPoints:ReleaseAll()
@@ -927,8 +1183,8 @@ local function modify(parent, region, data)
self.updatedChildren[regionData] = true
end
end
if childData and WeakAuras.clones[childID] then
for cloneID, cloneRegion in pairs(WeakAuras.clones[childID]) do
if childData and Private.clones[childID] then
for cloneID, cloneRegion in pairs(Private.clones[childID]) do
local regionData = createRegionData(childData, cloneRegion, childID, cloneID, dataIndex)
if cloneRegion.toShow then
tinsert(self.sortedChildren, regionData)
@@ -978,9 +1234,14 @@ local function modify(parent, region, data)
-- if it has been, then don't insert it again
if not regionData.active and self.updatedChildren[regionData] == nil then
tinsert(self.sortedChildren, regionData)
self.updatedChildren[regionData] = true
self:SortUpdatedChildren()
elseif isDifferent(regionData, self.sortStates, self.sortOn) then
self.updatedChildren[regionData] = true
self:SortUpdatedChildren()
elseif isDifferent(regionData, self.growStates, self.growOn) then
self:PositionChildren()
end
self.updatedChildren[regionData] = true
self:SortUpdatedChildren()
end
function region:RemoveChild(childID, cloneID)
@@ -990,6 +1251,8 @@ local function modify(parent, region, data)
if not regionData then return end
releaseRegionData(regionData)
self.updatedChildren[regionData] = false
clearCache(self.sortStates, childID, cloneID)
clearCache(self.growStates, childID, cloneID)
self:SortUpdatedChildren()
end
@@ -1000,10 +1263,12 @@ local function modify(parent, region, data)
if regionData and not regionData.region.toShow then
self.updatedChildren[regionData] = false
end
clearCache(self.sortStates, childID, cloneID)
clearCache(self.growStates, childID, cloneID)
self:SortUpdatedChildren()
end
region.sortFunc = createSortFunc(data)
region.sortFunc, region.sortOn = createSortFunc(data)
function region:SortUpdatedChildren()
-- iterates through cache to insert all updated children in the right spot
@@ -1048,7 +1313,7 @@ local function modify(parent, region, data)
end
end
region.growFunc = createGrowFunc(data)
region.growFunc, region.growOn = createGrowFunc(data)
region.anchorPerUnit = data.useAnchorPerUnit and data.anchorPerUnit
local animate = data.animate
@@ -1083,12 +1348,21 @@ local function modify(parent, region, data)
local controlPoint = regionData.controlPoint
controlPoint:ClearAnchorPoint()
controlPoint:SetAnchorPoint(
data.selfPoint,
frame == "" and self.relativeTo or frame,
data.anchorPoint,
x + data.xOffset, y + data.yOffset
)
if frame == "" then
controlPoint:SetAnchorPoint(
data.selfPoint,
self,
data.selfPoint,
x, y
)
else
controlPoint:SetAnchorPoint(
data.selfPoint,
frame,
data.anchorPoint,
x + data.xOffset, y + data.yOffset
)
end
if show and frame ~= WeakAuras.HiddenFrames then
controlPoint:Show()
else
@@ -1096,6 +1370,42 @@ local function modify(parent, region, data)
end
controlPoint:SetWidth(regionData.dimensions.width)
controlPoint:SetHeight(regionData.dimensions.height)
if (data.anchorFrameParent or data.anchorFrameParent == nil)
and (
data.useAnchorPerUnit
or (
not data.useAnchorPerUnit
and not (data.anchorFrameType == "SCREEN" or data.anchorFrameType == "UIPARENT" or data.anchorFrameType == "MOUSE")
)
)
then
local parent
if frame == "" then
parent = self.relativeTo
else
if type(frame) == "string" then
parent = _G[frame]
else
parent = frame
end
end
if parent and parent.IsObjectType and parent:IsObjectType("Frame") then
controlPoint:SetParent(parent)
end
else
controlPoint:SetParent(self)
end
local childData = controlPoint.regionData.data
local childRegion = controlPoint.regionData.region
if(childData.frameStrata == 1) then
local frameStrata = region:GetFrameStrata()
childRegion:SetFrameStrata(frameStrata ~= "UNKNOWN" and frameStrata or "BACKGROUND");
else
childRegion:SetFrameStrata(Private.frame_strata_types[childData.frameStrata]);
end
Private.ApplyFrameLevel(childRegion)
if self.anchorPerUnit == "UNITFRAME" then
Private.dyngroup_unitframe_monitor[regionData] = frame
end
@@ -1256,11 +1566,21 @@ local function modify(parent, region, data)
self:SetHeight(height)
self.currentWidth = width
self.currentHeight = height
if data.border and not data.useAnchorPerUnit then
local regionLeft = SafeGetPos(region, region.GetLeft) or minX
local regionBottom = SafeGetPos(region, region.GetBottom) or minY
if regionLeft and regionBottom then
self.background:ClearAllPoints()
self.background:SetPoint("BOTTOMLEFT", region, "BOTTOMLEFT", minX + -1 * data.borderOffset - regionLeft, minY + -1 * data.borderOffset - regionBottom)
self.background:SetPoint("TOPRIGHT", region, "BOTTOMLEFT", maxX + data.borderOffset - regionLeft, maxY + data.borderOffset - regionBottom)
end
end
else
self:Hide()
end
if WeakAuras.IsOptionsOpen() then
WeakAuras.OptionsFrame().moversizer:ReAnchor()
Private.OptionsFrame().moversizer:ReAnchor()
end
Private.StopProfileSystem("dynamicgroup")
Private.StopProfileAura(data.id)
@@ -1271,7 +1591,7 @@ local function modify(parent, region, data)
region:ReloadControlledChildren()
WeakAuras.regionPrototype.modifyFinish(parent, region, data)
Private.regionPrototype.modifyFinish(parent, region, data)
end
WeakAuras.RegisterRegionType("dynamicgroup", create, modify, default)
Private.RegisterRegionType("dynamicgroup", create, modify, default)
+50
View File
@@ -0,0 +1,50 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L
local default = {
width = 200,
height = 200,
selfPoint = "CENTER",
anchorPoint = "CENTER",
anchorFrameType = "SCREEN",
xOffset = 0,
yOffset = 0,
frameStrata = 1
}
Private.regionPrototype.AddAlphaToDefault(default)
local properties = {
}
Private.regionPrototype.AddProperties(properties, default);
local function create(parent)
local region = CreateFrame("Frame", nil, UIParent)
region.regionType = "empty"
region:SetMovable(true)
region:SetResizable(true)
region:SetMinResize(1, 1)
region.Update = function() end
Private.regionPrototype.create(region)
return region
end
local function modify(parent, region, data)
Private.regionPrototype.modify(parent, region, data)
region:SetWidth(data.width)
region:SetHeight(data.height)
region.width = data.width
region.height = data.height
region.scalex = 1
region.scaley = 1
Private.regionPrototype.modifyFinish(parent, region, data)
end
Private.RegisterRegionType("empty", create, modify, default, properties)
+10 -8
View File
@@ -1,4 +1,4 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
@@ -22,20 +22,22 @@ local default = {
scale = 1,
};
Private.regionPrototype.AddAlphaToDefault(default);
-- Called when first creating a new region/display
local function create(parent)
-- Main region
local region = CreateFrame("FRAME", nil, parent);
local region = CreateFrame("Frame", nil, parent);
region.regionType = "group"
region:SetMovable(true);
region:SetWidth(2);
region:SetHeight(2);
-- Border region
local border = CreateFrame("frame", nil, region);
local border = CreateFrame("Frame", nil, region);
region.border = border;
WeakAuras.regionPrototype.create(region);
Private.regionPrototype.create(region);
local oldSetFrameLevel = region.SetFrameLevel
region.SetFrameLevel = function(self, level)
@@ -90,7 +92,7 @@ local function modify(parent, region, data)
else
data.selfPoint = "CENTER";
end
WeakAuras.regionPrototype.modify(parent, region, data);
Private.regionPrototype.modify(parent, region, data);
-- Localize
local border = region.border;
@@ -138,7 +140,7 @@ local function modify(parent, region, data)
-- Scan children for visibility
if not childVisible then
for child in Private.TraverseLeafs(data) do
local childRegion = WeakAuras.regions[child.id] and WeakAuras.regions[child.id].region;
local childRegion = Private.regions[child.id] and Private.regions[child.id].region;
if childRegion and childRegion.toShow then
childVisible = true;
break;
@@ -179,8 +181,8 @@ local function modify(parent, region, data)
region.border:Hide()
end
WeakAuras.regionPrototype.modifyFinish(parent, region, data);
Private.regionPrototype.modifyFinish(parent, region, data);
end
-- Register new region type with WeakAuras
WeakAuras.RegisterRegionType("group", create, modify, default);
Private.RegisterRegionType("group", create, modify, default);
+104 -105
View File
@@ -1,7 +1,6 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
local L = WeakAuras.L
local MSQ, MSQ_Version = LibStub("Masque", true);
if MSQ then
@@ -20,6 +19,9 @@ local default = {
icon = true,
desaturate = false,
iconSource = -1,
progressSource = {-1, "" },
adjustedMax = "",
adjustedMin = "",
inverse = false,
width = 64,
height = 64,
@@ -32,11 +34,12 @@ local default = {
zoom = 0,
keepAspectRatio = false,
frameStrata = 1,
cooldown = false,
cooldown = true,
cooldownEdge = false
};
WeakAuras.regionPrototype.AddAlphaToDefault(default);
Private.regionPrototype.AddProgressSourceToDefault(default)
Private.regionPrototype.AddAlphaToDefault(default);
local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20;
@@ -96,54 +99,68 @@ local properties = {
values = {}
},
displayIcon = {
display = {L["Icon"], L["Fallback"]},
display = {L["Icon"], L["Manual"]},
setter = "SetIcon",
type = "icon",
}
};
WeakAuras.regionPrototype.AddProperties(properties, default);
Private.regionPrototype.AddProperties(properties, default);
local function GetProperties(data)
local result = CopyTable(properties)
result.iconSource.values = Private.IconSources(data)
result.progressSource.values = Private.GetProgressSourcesForUi(data)
return result
end
local function GetTexCoord(region, texWidth, aspectRatio)
local function GetTexCoord(region, texWidth, aspectRatio, xOffset, yOffset)
region.currentCoord = region.currentCoord or {}
local usesMasque = false
if region.MSQGroup then
local db = region.MSQGroup.db
if db and not db.Disabled then
usesMasque = true
region.currentCoord[1], region.currentCoord[2], region.currentCoord[3], region.currentCoord[4], region.currentCoord[5], region.currentCoord[6], region.currentCoord[7], region.currentCoord[8] = region.icon:GetTexCoord()
region.currentCoord[1], region.currentCoord[2], region.currentCoord[3], region.currentCoord[4],
region.currentCoord[5], region.currentCoord[6], region.currentCoord[7], region.currentCoord[8]
= region.icon:GetTexCoord()
end
end
if (not usesMasque) then
region.currentCoord[1], region.currentCoord[2], region.currentCoord[3], region.currentCoord[4], region.currentCoord[5], region.currentCoord[6], region.currentCoord[7], region.currentCoord[8] = 0, 0, 0, 1, 1, 0, 1, 1;
region.currentCoord[1], region.currentCoord[2], region.currentCoord[3], region.currentCoord[4],
region.currentCoord[5], region.currentCoord[6], region.currentCoord[7], region.currentCoord[8]
= 0, 0, 0, 1, 1, 0, 1, 1;
end
local xRatio = aspectRatio < 1 and aspectRatio or 1;
local yRatio = aspectRatio > 1 and 1 / aspectRatio or 1;
for i, coord in ipairs(region.currentCoord) do
local aspectRatio = (i % 2 == 1) and xRatio or yRatio;
region.currentCoord[i] = (coord - 0.5) * texWidth * aspectRatio + 0.5;
if(i % 2 == 1) then
region.currentCoord[i] = (coord - 0.5) * texWidth * xRatio + 0.5 - xOffset;
else
region.currentCoord[i] = (coord - 0.5) * texWidth * yRatio + 0.5 - yOffset;
end
end
return unpack(region.currentCoord)
end
local function AnchorSubRegion(self, subRegion, anchorType, selfPoint, anchorPoint, anchorXOffset, anchorYOffset)
local function AnchorSubRegion(self, subRegion, anchorType, anchorPoint, selfPoint, anchorXOffset, anchorYOffset)
if type(anchorPoint) == "string" and anchorPoint:sub(1, 4) == "sub." then
Private.regionPrototype.AnchorSubRegion(self, subRegion, anchorType, anchorPoint, selfPoint, anchorXOffset, anchorYOffset)
return
end
if anchorType == "area" then
WeakAuras.regionPrototype.AnchorSubRegion(selfPoint == "region" and self or self.icon, subRegion, anchorType, selfPoint, anchorPoint, anchorXOffset, anchorYOffset)
Private.regionPrototype.AnchorSubRegion(selfPoint == "region" and self or self.icon,
subRegion, anchorType, anchorPoint, selfPoint, anchorXOffset, anchorYOffset)
else
subRegion:ClearAllPoints()
anchorPoint = anchorPoint or "CENTER"
local anchorRegion = self.icon
if anchorPoint:sub(1, 6) == "INNER_" then
if not self.inner then
self.inner = CreateFrame("FRAME", nil, self)
self.inner = CreateFrame("Frame", nil, self)
self.inner:SetPoint("CENTER")
self.UpdateInnerOuterSize()
end
@@ -151,7 +168,7 @@ local function AnchorSubRegion(self, subRegion, anchorType, selfPoint, anchorPoi
anchorPoint = anchorPoint:sub(7)
elseif anchorPoint:sub(1, 6) == "OUTER_" then
if not self.outer then
self.outer = CreateFrame("FRAME", nil, self)
self.outer = CreateFrame("Frame", nil, self)
self.outer:SetPoint("CENTER")
self.UpdateInnerOuterSize()
end
@@ -243,7 +260,7 @@ end
local function create(parent, data)
local font = "GameFontHighlight";
local region = CreateFrame("FRAME", nil, parent);
local region = CreateFrame("Frame", nil, parent);
region.regionType = "icon"
region:SetMovable(true);
region:SetResizable(true);
@@ -299,7 +316,8 @@ local function create(parent, data)
icon.SetTexture = setTexture
--This section creates a unique frame id for the cooldown frame so that it can be created with a global reference
--The reason is so that WeakAuras cooldown frames can interact properly with OmniCC (i.e., put on its ignore list for timer overlays)
--The reason is so that WeakAuras cooldown frames can interact properly with OmniCC
-- (i.e., put on its ignore list for timer overlays)
local id = data.id;
local frameId = id:lower():gsub(" ", "_");
if(_G["WeakAurasCooldown"..frameId]) then
@@ -312,7 +330,7 @@ local function create(parent, data)
end
region.frameId = frameId;
local cooldown = CreateFrame("COOLDOWN", "WeakAurasCooldown"..frameId, region, "CooldownFrameTemplate");
local cooldown = CreateFrame("Cooldown", "WeakAurasCooldown"..frameId, region, "CooldownFrameTemplate");
region.cooldown = cooldown;
cooldown:SetAllPoints(icon);
@@ -331,7 +349,7 @@ local function create(parent, data)
end
end
WeakAuras.regionPrototype.create(region);
Private.regionPrototype.create(region);
region.AnchorSubRegion = AnchorSubRegion
@@ -343,7 +361,7 @@ local function modify(parent, region, data)
region.stacks = nil
region.text2 = nil
WeakAuras.regionPrototype.modify(parent, region, data);
Private.regionPrototype.modify(parent, region, data);
local button, icon, cooldown = region.button, region.icon, region.cooldown;
@@ -394,11 +412,16 @@ local function modify(parent, region, data)
end
if region.MSQGroup then
region.MSQGroup:RemoveButton(button)
region.MSQGroup:AddButton(button, {Icon = icon, Cooldown = cooldown}, "WA_Aura", true)
if region.MSQGroup.ReSkin then
region.MSQGroup:ReSkin(button)
else
region.MSQGroup:RemoveButton(button)
region.MSQGroup:AddButton(button, {Icon = icon, Cooldown = cooldown}, "WA_Aura", true)
end
end
local ulx, uly, llx, lly, urx, ury, lrx, lry = GetTexCoord(region, texWidth, aspectRatio)
local ulx, uly, llx, lly, urx, ury, lrx, lry
= GetTexCoord(region, texWidth, aspectRatio, region.texXOffset, region.texYOffset and -region.texYOffset)
if(mirror_h) then
if(mirror_v) then
@@ -421,6 +444,8 @@ local function modify(parent, region, data)
region.scaley = 1;
region.keepAspectRatio = data.keepAspectRatio;
region.zoom = data.zoom;
region.texXOffset = data.texXOffset or 0
region.texYOffset = data.texYOffset or 0
region:UpdateSize()
icon:SetDesaturated(data.desaturate);
@@ -428,7 +453,7 @@ local function modify(parent, region, data)
local tooltipType = Private.CanHaveTooltip(data);
if(tooltipType and data.useTooltip) then
if not region.tooltipFrame then
region.tooltipFrame = CreateFrame("frame", nil, region);
region.tooltipFrame = CreateFrame("Frame", nil, region);
region.tooltipFrame:SetAllPoints(region);
region.tooltipFrame:SetScript("OnEnter", function()
Private.ShowMouseoverTooltip(region, region);
@@ -440,7 +465,30 @@ local function modify(parent, region, data)
region.tooltipFrame:EnableMouse(false);
end
cooldown:SetReverse(not data.inverse);
function region:SetInverse(inverse)
if region.inverseDirection == inverse then
return
end
region.inverseDirection = inverse
region:UpdateEffectiveInverse()
end
function region:UpdateEffectiveInverse()
-- If cooldown.inverse == false then effectiveReverse = not inverse
-- If cooldown.inverse == true then effectiveReverse = inverse
local effectiveReverse = not region.inverseDirection == not cooldown.inverse
cooldown:SetReverse(effectiveReverse)
if (cooldown.expirationTime and cooldown.duration and cooldown:IsShown()) then
-- WORKAROUND SetReverse not applying until next frame
cooldown:SetCooldown(0, 0)
cooldown:SetCooldown(cooldown.expirationTime - cooldown.duration,
cooldown.duration,
cooldown.useCooldownModRate and cooldown.modRate or nil)
end
end
region:SetInverse(data.inverse)
function region:Color(r, g, b, a)
region.color_r = r;
@@ -450,7 +498,8 @@ local function modify(parent, region, data)
if (r or g or b) then
a = a or 1;
end
icon:SetVertexColor(region.color_anim_r or r, region.color_anim_g or g, region.color_anim_b or b, region.color_anim_a or a);
icon:SetVertexColor(region.color_anim_r or r, region.color_anim_g or g,
region.color_anim_b or b, region.color_anim_a or a)
if region.button then
region.button:SetAlpha(region.color_anim_a or a or 1);
end
@@ -508,7 +557,7 @@ local function modify(parent, region, data)
end
iconPath = iconPath or self.displayIcon or "Interface\\Icons\\INV_Misc_QuestionMark"
icon:SetTexture(iconPath)
Private.SetTextureOrSpellTexture(icon, iconPath)
end
function region:Scale(scalex, scaley)
@@ -534,15 +583,6 @@ local function modify(parent, region, data)
region:UpdateSize();
end
function region:SetInverse(inverse)
cooldown:SetReverse(not inverse);
if (cooldown.expirationTime and cooldown.duration and cooldown:IsShown()) then
-- WORKAROUND SetReverse not applying until next frame
cooldown:SetCooldown(0, 0);
cooldown:SetCooldown(cooldown.expirationTime - cooldown.duration, cooldown.duration);
end
end
function region:SetCooldownEdge(cooldownEdge)
region.cooldownEdge = cooldownEdge;
cooldown:SetDrawEdge(cooldownEdge);
@@ -559,32 +599,40 @@ local function modify(parent, region, data)
cooldown.duration = nil;
cooldown:Hide()
if(data.cooldown) then
function region:SetValue(value, total)
cooldown.value = value
cooldown.total = total
if (value >= 0 and value <= total) then
function region:UpdateValue()
cooldown.value = self.value
cooldown.total = self.total
if (self.value >= 0 and self.value <= self.total) then
cooldown:Show()
cooldown:SetCooldown(GetTime() - (total - value), total)
cooldown:SetCooldown(GetTime() - (self.total - self.value), self.total)
cooldown:Pause()
else
cooldown:Hide();
end
end
function region:SetTime(duration, expirationTime)
if (duration > 0 and expirationTime > GetTime()) then
cooldown:Show();
cooldown.expirationTime = expirationTime;
cooldown.duration = duration;
cooldown:SetCooldown(expirationTime - duration, duration);
function region:UpdateTime()
if self.paused then
cooldown:Pause()
else
cooldown.expirationTime = expirationTime;
cooldown.duration = duration;
cooldown:Resume()
end
if (self.duration > 0 and self.expirationTime > GetTime() and self.expirationTime ~= math.huge) then
cooldown:Show();
cooldown.expirationTime = self.expirationTime
cooldown.duration = self.duration
cooldown.inverse = self.inverse
region:UpdateEffectiveInverse()
cooldown:SetCooldown(self.expirationTime - self.duration, self.duration)
else
cooldown.expirationTime = self.expirationTime
cooldown.duration = self.duration
cooldown:Hide();
end
end
function region:PreShow()
if (cooldown.duration and cooldown.duration > 0.01) then
if (cooldown.duration and cooldown.duration > 0.01 and cooldown.duration ~= math.huge and cooldown.expirationTime ~= math.huge) then
cooldown:Show();
cooldown:SetCooldown(cooldown.expirationTime - cooldown.duration, cooldown.duration);
cooldown:Resume()
@@ -592,64 +640,15 @@ local function modify(parent, region, data)
end
function region:Update()
local state = region.state
if state.progressType == "timed" then
local expirationTime
if state.paused == true then
if not region.paused then
region:Pause()
end
cooldown:Pause()
expirationTime = GetTime() + (state.remaining or 0)
else
if region.paused then
region:Resume()
end
cooldown:Resume()
expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge;
end
local duration = state.duration or 0
if region.adjustedMinRelPercent then
region.adjustedMinRel = region.adjustedMinRelPercent * duration
end
local adjustMin = region.adjustedMin or region.adjustedMinRel or 0;
local max
if duration == 0 then
max = 0
elseif region.adjustedMax then
max = region.adjustedMax
elseif region.adjustedMaxRelPercent then
region.adjustedMaxRel = region.adjustedMaxRelPercent * duration
max = region.adjustedMaxRel
else
max = duration
end
region:SetTime(max - adjustMin, expirationTime - adjustMin, state.inverse);
elseif state.progressType == "static" then
local value = state.value or 0;
local total = state.total or 0;
if region.adjustedMinRelPercent then
region.adjustedMinRel = region.adjustedMinRelPercent * total
end
local adjustMin = region.adjustedMin or region.adjustedMinRel or 0;
local max = region.adjustedMax or region.adjustedMaxRel or total;
region:SetValue(value - adjustMin, max - adjustMin);
cooldown:Pause()
else
region:SetTime(0, math.huge)
end
region:UpdateProgress()
region:UpdateIcon()
end
else
region.SetValue = nil
region.SetTime = nil
region.UpdateValue = nil
region.UpdateTime = nil
function region:Update()
local state = region.state
region:UpdateProgress()
region:UpdateIcon()
end
end
@@ -663,7 +662,7 @@ local function modify(parent, region, data)
end
end
WeakAuras.regionPrototype.modifyFinish(parent, region, data);
Private.regionPrototype.modifyFinish(parent, region, data);
--- WORKAROUND
-- This fixes a issue with barmodels not appearing on icons if the
@@ -676,4 +675,4 @@ local function validate(data)
Private.EnforceSubregionExists(data, "subbackground")
end
WeakAuras.RegisterRegionType("icon", create, modify, default, GetProperties, validate)
Private.RegisterRegionType("icon", create, modify, default, GetProperties, validate)
+29 -21
View File
@@ -1,4 +1,4 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
@@ -56,7 +56,7 @@ local properties = {
},
}
WeakAuras.regionPrototype.AddProperties(properties, default);
Private.regionPrototype.AddProperties(properties, default);
local function GetProperties(data)
return properties;
@@ -69,24 +69,22 @@ local regionFunctions = {
-- Called when first creating a new region/display
local function create(parent)
-- Main region
local region = CreateFrame("FRAME", nil, UIParent);
local region = CreateFrame("Frame", nil, UIParent);
region.regionType = "model"
region:SetMovable(true);
region:SetResizable(true);
region:SetMinResize(1, 1);
-- Border region
local border = CreateFrame("frame", nil, region);
local border = CreateFrame("Frame", nil, region);
region.border = border;
WeakAuras.regionPrototype.create(region);
Private.regionPrototype.create(region);
for k, v in pairs (regionFunctions) do
region[k] = v
end
region.AnchorSubRegion = WeakAuras.regionPrototype.AnchorSubRegion
-- Return complete region
return region;
end
@@ -175,7 +173,7 @@ end
-- Modify a given region/display
local function modify(parent, region, data)
WeakAuras.regionPrototype.modify(parent, region, data);
Private.regionPrototype.modify(parent, region, data);
-- Localize
local border = region.border;
@@ -200,9 +198,9 @@ local function modify(parent, region, data)
bgFile = SharedMedia:Fetch("background", data.borderBackdrop),
insets = {
left = data.borderInset,
right = data.borderInset,
top = data.borderInset,
bottom = data.borderInset,
right = data.borderInset,
top = data.borderInset,
bottom = data.borderInset,
},
});
border:SetBackdropBorderColor(data.borderColor[1], data.borderColor[2], data.borderColor[3], data.borderColor[4]);
@@ -244,18 +242,28 @@ local function modify(parent, region, data)
end
-- Rotate model
function region:Rotate(degrees)
region.rotation = degrees;
function region:SetAnimRotation(degrees)
region.animRotation = degrees
region:UpdateEffectiveRotation()
end
function region:SetRotation(degrees)
region.rotation = degrees
region:UpdateEffectiveRotation()
end
function region:UpdateEffectiveRotation()
region.effectiveRotation = region.animRotation or region.rotation
if region.model then
region.model:SetFacing(rad(region.rotation));
region.model:SetFacing(rad(region.effectiveRotation))
end
end
region:Rotate(data.rotation);
region:SetRotation(data.rotation)
-- Get model rotation
function region:GetRotation()
return region.rotation;
function region:GetBaseRotation()
return region.rotation
end
function region:PreShow()
@@ -273,16 +281,16 @@ local function modify(parent, region, data)
end
end
WeakAuras.regionPrototype.modifyFinish(parent, region, data);
Private.regionPrototype.modifyFinish(parent, region, data);
end
-- Work around for movies and world map hiding all models
do
function Private.PreShowModels(self, event)
Private.StartProfileSystem("model");
for id, data in pairs(WeakAuras.regions) do
for id, data in pairs(Private.regions) do
Private.StartProfileAura(id);
if data.region.toShow then
if data.region and data.region.toShow then
if (data.regionType == "model") then
data.region:PreShow();
end
@@ -301,4 +309,4 @@ local function validate(data)
end
-- Register new region type with WeakAuras
WeakAuras.RegisterRegionType("model", create, modify, default, GetProperties, validate);
Private.RegisterRegionType("model", create, modify, default, GetProperties, validate);
+75 -108
View File
@@ -1,4 +1,4 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L;
@@ -80,6 +80,9 @@ local function Transform(tx, x, y, angle, aspect) -- Translates texture to x, y
end
local default = {
progressSource = {-1, "" },
adjustedMax = "",
adjustedMin = "",
foregroundTexture = "Interface\\Addons\\WeakAuras\\PowerAurasMedia\\Auras\\Aura3",
backgroundTexture = "Interface\\Addons\\WeakAuras\\PowerAurasMedia\\Auras\\Aura3",
desaturateBackground = false,
@@ -113,9 +116,9 @@ local default = {
slantMode = "INSIDE"
};
WeakAuras.regionPrototype.AddAlphaToDefault(default);
Private.regionPrototype.AddAlphaToDefault(default);
WeakAuras.regionPrototype.AddAdjustedDurationToDefault(default);
Private.regionPrototype.AddProgressSourceToDefault(default)
local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20;
@@ -176,13 +179,13 @@ local properties = {
}
}
WeakAuras.regionPrototype.AddProperties(properties, default);
Private.regionPrototype.AddProperties(properties, default);
local function GetProperties(data)
local overlayInfo = Private.GetOverlayInfo(data);
local auraProperties = CopyTable(properties)
auraProperties.progressSource.values = Private.GetProgressSourcesForUi(data)
if (overlayInfo and next(overlayInfo)) then
local auraProperties = CopyTable(properties);
for id, display in ipairs(overlayInfo) do
auraProperties["overlays." .. id] = {
display = string.format(L["%s Overlay Color"], display),
@@ -191,10 +194,9 @@ local function GetProperties(data)
type = "color",
}
end
return auraProperties;
return auraProperties
else
return CopyTable(properties);
return auraProperties
end
end
@@ -424,7 +426,7 @@ WeakAuras.createSpinner = createSpinner;
local function create(parent)
local font = "GameFontHighlight";
local region = CreateFrame("FRAME", nil, parent);
local region = CreateFrame("Frame", nil, parent);
region.regionType = "progresstexture"
region:SetMovable(true);
region:SetResizable(true);
@@ -446,7 +448,7 @@ local function create(parent)
-- Use a dummy object for the SmoothStatusBarMixin, because our SetValue
-- is used for a different purpose
region.smoothProgress = {};
WeakAuras.Mixin(region.smoothProgress, SmoothStatusBarMixin);
WeakAuras.Mixin(region.smoothProgress, Private.SmoothStatusBarMixin);
region.smoothProgress.SetValue = function(self, progress)
region:SetValueOnTexture(progress);
end
@@ -462,19 +464,37 @@ local function create(parent)
region.duration = 0;
region.expirationTime = math.huge;
WeakAuras.regionPrototype.create(region);
Private.regionPrototype.create(region);
return region;
end
local function TimerTick(self)
local adjustMin = self.adjustedMin or self.adjustedMinRel or 0;
local duration = self.state.duration
self:SetTime( (duration ~= 0 and (self.adjustedMax or self.adjustedMaxRel) or duration) - adjustMin, self.state.expirationTime - adjustMin, self.state.inverse);
local function FrameTick(self)
local duration = self.duration
local expirationTime = self.expirationTime
local inverse = self.inverse
local progress = 1;
if (duration ~= 0) then
local remaining = expirationTime - GetTime();
progress = remaining / duration;
local inversed = not inverse ~= not self.inverseDirection
if(inversed) then
progress = 1 - progress;
end
end
progress = progress > 0.0001 and progress or 0.0001;
if (self.useSmoothProgress) then
self.smoothProgress:SetSmoothedValue(progress);
else
self:SetValueOnTexture(progress);
end
end
local function modify(parent, region, data)
WeakAuras.regionPrototype.modify(parent, region, data);
Private.regionPrototype.modify(parent, region, data);
local background, foreground = region.background, region.foreground;
local foregroundSpinner, backgroundSpinner = region.foregroundSpinner, region.backgroundSpinner;
@@ -486,6 +506,7 @@ local function modify(parent, region, data)
region.scalex = 1;
region.scaley = 1;
region.aspect = data.width / data.height;
region.useSmoothProgress = data.smoothProgress
foreground:SetWidth(data.width);
foreground:SetHeight(data.height);
local scaleWedge = 1 / 1.4142 * (1 + (data.crop or 0.41));
@@ -843,122 +864,68 @@ local function modify(parent, region, data)
region:Color(data.foregroundColor[1], data.foregroundColor[2], data.foregroundColor[3], data.foregroundColor[4]);
function region:SetTime(duration, expirationTime, inverse)
function region:UpdateTime()
local progress = 1;
if (duration ~= 0) then
local remaining = expirationTime - GetTime();
progress = remaining / duration;
local inversed = (not inverse and region.inverseDirection) or (inverse and not region.inverseDirection);
if (self.duration ~= 0) then
local remaining = self.expirationTime - GetTime()
progress = remaining / self.duration
local inversed = not self.inverse ~= not region.inverseDirection
if(inversed) then
progress = 1 - progress;
end
end
progress = progress > 0.0001 and progress or 0.0001;
if (data.smoothProgress) then
if (region.useSmoothProgress) then
region.smoothProgress:SetSmoothedValue(progress);
else
region:SetValueOnTexture(progress);
end
if self.paused and self.FrameTick then
self.FrameTick = nil
self.subRegionEvents:RemoveSubscriber("FrameTick", region)
end
if not self.paused and not self.FrameTick then
self.FrameTick = FrameTick
self.subRegionEvents:AddSubscriber("FrameTick", region)
end
end
function region:SetValue(value, total)
function region:UpdateValue()
local progress = 1
if(total > 0) then
progress = value / total;
if(self.total > 0) then
progress = self.value / self.total;
if(region.inverseDirection) then
progress = 1 - progress;
end
end
progress = progress > 0.0001 and progress or 0.0001;
if (data.smoothProgress) then
if (region.useSmoothProgress) then
region.smoothProgress:SetSmoothedValue(progress);
else
region:SetValueOnTexture(progress);
end
if self.FrameTick then
self.FrameTick = nil
self.subRegionEvents:RemoveSubscriber("FrameTick", region)
end
end
function region:Update()
local state = region.state
local max
if state.progressType == "timed" then
local expirationTime
if state.paused == true then
if not region.paused then
region:Pause()
end
if region.TimerTick then
region.TimerTick = nil
region:UpdateRegionHasTimerTick()
end
expirationTime = GetTime() + (state.remaining or 0)
else
if region.paused then
region:Resume()
end
if not region.TimerTick then
region.TimerTick = TimerTick
region:UpdateRegionHasTimerTick()
end
expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge;
end
local duration = state.duration or 0
if region.adjustedMinRelPercent then
region.adjustedMinRel = region.adjustedMinRelPercent * duration
end
local adjustMin = region.adjustedMin or region.adjustedMinRel or 0;
if duration == 0 then
max = 0
elseif region.adjustedMax then
max = region.adjustedMax
elseif region.adjustedMaxRelPercent then
region.adjustedMaxRel = region.adjustedMaxRelPercent * duration
max = region.adjustedMaxRel
else
max = duration
end
region:SetTime(max - adjustMin, expirationTime - adjustMin, state.inverse);
elseif state.progressType == "static" then
if region.paused then
region:Resume()
end
local value = state.value or 0;
local total = state.total or 0;
if region.adjustedMinRelPercent then
region.adjustedMinRel = region.adjustedMinRelPercent * total
end
local adjustMin = region.adjustedMin or region.adjustedMinRel or 0;
if region.adjustedMax then
max = region.adjustedMax
elseif region.adjustedMaxRelPercent then
region.adjustedMaxRel = region.adjustedMaxRelPercent * total
max = region.adjustedMaxRel
else
max = total
end
region:SetValue(value - adjustMin, max - adjustMin);
if region.TimerTick then
region.TimerTick = nil
region:UpdateRegionHasTimerTick()
end
else
if region.paused then
region:Resume()
end
region:SetTime(0, math.huge)
if region.TimerTick then
region.TimerTick = nil
region:UpdateRegionHasTimerTick()
end
if region.useSmoothProgress then
region.PreShow = function()
region.smoothProgress:ResetSmoothedValue();
end
else
region.PreShow = nil
end
max = max or 0
region.FrameTick = nil
function region:Update()
region:UpdateProgress()
local state = region.state
if state.texture then
region:SetTexture(state.texture)
@@ -1028,11 +995,11 @@ local function modify(parent, region, data)
end
end
WeakAuras.regionPrototype.modifyFinish(parent, region, data);
Private.regionPrototype.modifyFinish(parent, region, data);
end
local function validate(data)
Private.EnforceSubregionExists(data, "subbackground")
end
WeakAuras.RegisterRegionType("progresstexture", create, modify, default, GetProperties, validate);
Private.RegisterRegionType("progresstexture", create, modify, default, GetProperties, validate);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,65 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
-- This is a more or less 1:1 copy of SmoothStatusBarMixin except that it
-- doesn't clamp the targetValue in ProcessSmoothStatusBars, because that's incorrect for us
local g_updatingBars = {};
local function IsCloseEnough(bar, newValue, targetValue)
local min, max = bar:GetMinMaxValues();
local range = max - min;
if range > 0.0 then
return math.abs((newValue - targetValue) / range) < 0.00001;
end
return true;
end
local function ProcessSmoothStatusBars(self, elapsed)
for bar, targetValue in pairs(g_updatingBars) do
local newValue = FrameDeltaLerp(bar:GetValue(), targetValue, 0.25, elapsed);
if IsCloseEnough(bar, newValue, targetValue) then
g_updatingBars[bar] = nil;
bar:SetValue(targetValue);
else
bar:SetValue(newValue);
end
end
end
CreateFrame("Frame"):SetScript("OnUpdate", ProcessSmoothStatusBars);
Private.SmoothStatusBarMixin = {};
function Private.SmoothStatusBarMixin:ResetSmoothedValue(value) --If nil, tries to set to the last target value
local targetValue = g_updatingBars[self];
if targetValue then
g_updatingBars[self] = nil;
self:SetValue(value or targetValue);
elseif value then
self:SetValue(value);
end
end
function Private.SmoothStatusBarMixin:SetSmoothedValue(value)
g_updatingBars[self] = value;
end
function Private.SmoothStatusBarMixin:SetMinMaxSmoothedValue(min, max)
self:SetMinMaxValues(min, max);
local targetValue = g_updatingBars[self];
if targetValue then
local ratio = 1;
if max ~= 0 and self.lastSmoothedMax and self.lastSmoothedMax ~= 0 then
ratio = max / self.lastSmoothedMax;
end
g_updatingBars[self] = targetValue * ratio;
end
self.lastSmoothedMin = min;
self.lastSmoothedMax = max;
end
+178 -330
View File
@@ -1,14 +1,14 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local texture_types = WeakAuras.StopMotion.texture_types;
local texture_data = WeakAuras.StopMotion.texture_data;
local animation_types = WeakAuras.StopMotion.animation_types;
local L = WeakAuras.L;
local default = {
foregroundTexture = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\StopMotion",
backgroundTexture = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\StopMotion",
progressSource = {-1, "" },
adjustedMax = "",
adjustedMin = "",
foregroundTexture = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\stopmotion",
backgroundTexture = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\stopmotion",
desaturateBackground = false,
desaturateForeground = false,
sameTexture = true,
@@ -17,10 +17,7 @@ local default = {
foregroundColor = {1, 1, 1, 1},
backgroundColor = {0.5, 0.5, 0.5, 0.5},
blendMode = "BLEND",
rotation = 0,
discrete_rotation = 0,
mirror = false,
rotate = true,
selfPoint = "CENTER",
anchorPoint = "CENTER",
anchorFrameType = "SCREEN",
@@ -46,6 +43,8 @@ local default = {
hideBackground = true
};
Private.regionPrototype.AddProgressSourceToDefault(default)
local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20;
local properties = {
@@ -87,227 +86,114 @@ local properties = {
},
}
WeakAuras.regionPrototype.AddProperties(properties, default);
Private.regionPrototype.AddProperties(properties, default);
local function GetProperties(data)
local result = CopyTable(properties)
result.progressSource.values = Private.GetProgressSourcesForUi(data)
return result
end
local function create(parent)
local frame = CreateFrame("FRAME", nil, UIParent);
frame.regionType = "stopmotion"
frame:SetMovable(true);
frame:SetResizable(true);
frame:SetMinResize(1, 1);
local frame = CreateFrame("Frame", nil, UIParent)
frame:SetMovable(true)
frame:SetResizable(true)
frame:SetMinResize(1, 1)
local background = frame:CreateTexture(nil, "BACKGROUND");
frame.background = background;
background:SetAllPoints(frame);
frame.background = Private.StopMotionBase.create(frame, "BACKGROUND")
frame.foreground = Private.StopMotionBase.create(frame, "ARTWORK")
local foreground = frame:CreateTexture(nil, "ART");
frame.foreground = foreground;
foreground:SetAllPoints(frame);
frame.regionType = "stopmotion"
Private.regionPrototype.create(frame)
WeakAuras.regionPrototype.create(frame);
return frame;
return frame
end
local function SetTextureViaAtlas(self, texture)
self:SetTexture(texture);
end
local FrameTickFunctions = {
progressTimer = function(self)
Private.StartProfileSystem("stopmotion")
Private.StartProfileAura(self.id)
local function setTile(texture, frame, rows, columns, frameScaleW, frameScaleH)
frame = frame - 1;
local row = floor(frame / columns);
local column = frame % columns;
local remaining = self.expirationTime - GetTime()
local progress = 1 - (remaining / self.duration)
local deltaX = frameScaleW / columns
local deltaY = frameScaleH / rows
self.foreground:SetProgress(progress)
local left = deltaX * column;
local right = left + deltaX;
Private.StopProfileAura(self.id)
Private.StopProfileSystem("stopmotion")
end,
timed = function(self)
if (not self.foreground.startTime) then return end
local top = deltaY * row;
local bottom = top + deltaY;
pcall(function() texture:SetTexCoord(left, right, top, bottom) end)
end
Private.StartProfileSystem("stopmotion")
Private.StartProfileAura(self.id)
WeakAuras.setTile = setTile;
self.foreground:TimedUpdate()
local function SetFrameViaAtlas(self, texture, frame)
local frameScaleW = 1
local frameScaleH = 1
if self.fileWidth and self.frameWidth and self.fileWidth > 0 and self.frameWidth > 0 then
frameScaleW = (self.frameWidth * self.columns) / self.fileWidth
end
if self.fileHeight and self.frameHeight and self.fileHeight > 0 and self.frameHeight > 0 then
frameScaleH = (self.frameHeight * self.rows) / self.fileHeight
end
setTile(self, frame, self.rows, self.columns, frameScaleW, frameScaleH);
end
local function SetTextureViaFrames(self, texture)
self:SetTexture(texture .. format("%03d", 0));
self:SetTexCoord(0, 1, 0, 1);
end
local function SetFrameViaFrames(self, texture, frame)
self:SetTexture(texture .. format("%03d", frame));
end
Private.StopProfileAura(self.id)
Private.StopProfileSystem("stopmotion")
end,
}
local function modify(parent, region, data)
WeakAuras.regionPrototype.modify(parent, region, data);
region.foreground = region.foreground or {}
region.background = region.background or {}
local pattern = "%.x(%d+)y(%d+)f(%d+)%.[tb][gl][ap]"
local pattern2 = "%.x(%d+)y(%d+)f(%d+)w(%d+)h(%d+)W(%d+)H(%d+)%.[tb][gl][ap]"
Private.regionPrototype.modify(parent, region, data)
do
local tdata = texture_data[data.foregroundTexture];
if (tdata) then
local lastFrame = tdata.count - 1;
region.foreground.lastFrame = lastFrame
region.startFrame = floor( (data.startPercent or 0) * lastFrame) + 1;
region.endFrame = floor( (data.endPercent or 1) * lastFrame) + 1;
region.foreground.rows = tdata.rows;
region.foreground.columns = tdata.columns;
region.foreground.fileWidth = 0
region.foreground.fileHeight = 0
region.foreground.frameWidth = 0
region.foreground.frameHeight = 0
else
local rows, columns, frames = data.foregroundTexture:lower():match(pattern)
if rows then
local lastFrame = tonumber(frames) - 1;
region.foreground.lastFrame = lastFrame
region.startFrame = floor( (data.startPercent or 0) * lastFrame) + 1;
region.endFrame = floor( (data.endPercent or 1) * lastFrame) + 1;
region.foreground.rows = tonumber(rows)
region.foreground.columns = tonumber(columns)
region.foreground.fileWidth = 0
region.foreground.fileHeight = 0
region.foreground.frameWidth = 0
region.foreground.frameHeight = 0
else
local rows, columns, frames, frameWidth, frameHeight, fileWidth, fileHeight = data.foregroundTexture:match(pattern2)
if rows then
local lastFrame = tonumber(frames) - 1;
region.foreground.lastFrame = lastFrame
region.startFrame = floor( (data.startPercent or 0) * lastFrame) + 1;
region.endFrame = floor( (data.endPercent or 1) * lastFrame) + 1;
region.foreground.rows = tonumber(rows)
region.foreground.columns = tonumber(columns)
region.foreground.fileWidth = tonumber(fileWidth)
region.foreground.fileHeight = tonumber(fileHeight)
region.foreground.frameWidth = tonumber(frameWidth)
region.foreground.frameHeight = tonumber(frameHeight)
else
local lastFrame = (data.customForegroundFrames or 256) - 1;
region.foreground.lastFrame = lastFrame
region.startFrame = floor( (data.startPercent or 0) * lastFrame) + 1;
region.endFrame = floor( (data.endPercent or 1) * lastFrame) + 1;
region.foreground.rows = data.customForegroundRows;
region.foreground.columns = data.customForegroundColumns;
region.foreground.fileWidth = data.customForegroundFileWidth
region.foreground.fileHeight = data.customForegroundFileHeight
region.foreground.frameWidth = data.customForegroundFrameWidth
region.foreground.frameHeight = data.customForegroundFrameHeight
end
end
end
end
Private.StopMotionBase.modify(region.foreground, {
blendMode = data.blendMode,
-- Foreground Data
frameRate = data.frameRate,
inverseDirection = data.inverse,
animationType = data.animationType,
texture = data.foregroundTexture,
startPercent = data.startPercent,
endPercent = data.endPercent,
customFrames = data.customForegroundFrames,
customRows = data.customForegroundRows,
customColumns = data.customForegroundColumns,
customFileWidth = data.customForegroundFileWidth,
customFileHeight = data.customForegroundFileHeight,
customFrameWidth = data.customForegroundFrameWidth,
customFrameHeight = data.customForegroundFrameHeight,
})
local backgroundTexture = data.sameTexture
and data.foregroundTexture
or data.backgroundTexture;
do
if data.sameTexture then
region.backgroundFrame = floor( (data.backgroundPercent or 1) * region.foreground.lastFrame + 1);
region.background.rows = region.foreground.rows
region.background.columns = region.foreground.columns
region.background.fileWidth = region.foreground.fileWidth
region.background.fileHeight = region.foreground.fileHeight
region.background.frameWidth = region.foreground.frameWidth
region.background.frameHeight = region.foreground.frameHeight
else
local tdata = texture_data[data.backgroundTexture];
if (tdata) then
local lastFrame = tdata.count - 1;
region.backgroundFrame = floor( (data.backgroundPercent or 1) * lastFrame + 1);
region.background.rows = tdata.rows;
region.background.columns = tdata.columns;
region.background.fileWidth = 0
region.background.fileHeight = 0
region.background.frameWidth = 0
region.background.frameHeight = 0
else
local rows, columns, frames = data.backgroundTexture:lower():match(pattern)
if rows then
local lastFrame = frames - 1;
region.backgroundFrame = floor( (data.backgroundPercent or 1) * lastFrame + 1);
region.background.rows = tonumber(rows)
region.background.columns = tonumber(columns)
region.background.fileWidth = 0
region.background.fileHeight = 0
region.background.frameWidth = 0
region.background.frameHeight = 0
else
local rows, columns, frames, frameWidth, frameHeight, fileWidth, fileHeight = data.backgroundTexture:match(pattern2)
if rows then
local lastFrame = frames - 1;
region.backgroundFrame = floor( (data.backgroundPercent or 1) * lastFrame + 1);
region.background.rows = tonumber(rows)
region.background.columns = tonumber(columns)
region.background.fileWidth = tonumber(fileWidth)
region.background.fileHeight = tonumber(fileHeight)
region.background.frameWidth = tonumber(frameWidth)
region.background.frameHeight = tonumber(frameHeight)
else
local lastFrame = (data.customBackgroundFrames or 256) - 1;
region.backgroundFrame = floor( (data.backgroundPercent or 1) * lastFrame + 1);
region.background.rows = data.customBackgroundRows;
region.background.columns = data.customBackgroundColumns;
region.background.fileWidth = data.customBackgroundFileWidth
region.background.fileHeight = data.customBackgroundFileHeight
region.background.frameWidth = data.customBackgroundFrameWidth
region.background.frameHeight = data.customBackgroundFrameHeight
end
end
end
end
end
if (region.foreground.rows and region.foreground.columns) then
region.foreground.SetBaseTexture = SetTextureViaAtlas;
region.foreground.SetFrame = SetFrameViaAtlas;
if data.sameTexture then
Private.StopMotionBase.modify(region.background, {
blendMode = data.blendMode,
animationType = "background",
-- Background Data
texture = data.foregroundTexture,
startPercent = data.backgroundPercent,
endPercent = data.backgroundPercent,
customFrames = data.customForegroundFrames,
customRows = data.customForegroundRows,
customColumns = data.customForegroundColumns,
customFileWidth = data.customForegroundFileWidth,
customFileHeight = data.customForegroundFileHeight,
customFrameWidth = data.customForegroundFrameWidth,
customFrameHeight = data.customForegroundFrameHeight,
})
else
region.foreground.SetBaseTexture = SetTextureViaFrames;
region.foreground.SetFrame = SetFrameViaFrames;
Private.StopMotionBase.modify(region.background, {
blendMode = data.blendMode,
animationType = "background",
-- Background Data
texture = data.backgroundTexture,
startPercent = data.backgroundPercent,
endPercent = data.backgroundPercent,
customFrames = data.customBackgroundFrames,
customRows = data.customBackgroundRows,
customColumns = data.customBackgroundColumns,
customFileWidth = data.customBackgroundFileWidth,
customFileHeight = data.customBackgroundFileHeight,
customFrameWidth = data.customBackgroundFrameWidth,
customFrameHeight = data.customBackgroundFrameHeight,
})
end
if (region.background.rows and region.background.columns) then
region.background.SetBaseTexture = SetTextureViaAtlas;
region.background.SetFrame = SetFrameViaAtlas;
else
region.background.SetBaseTexture = SetTextureViaFrames;
region.background.SetFrame = SetFrameViaFrames;
end
region.background:SetVisible(not data.hideBackground)
region.background:SetBaseTexture(backgroundTexture);
region.background:SetFrame(backgroundTexture, region.backgroundFrame or 1);
region.background:SetDesaturated(data.desaturateBackground)
region.background:SetVertexColor(data.backgroundColor[1], data.backgroundColor[2], data.backgroundColor[3], data.backgroundColor[4]);
region.background:SetBlendMode(data.blendMode);
if (data.hideBackground) then
region.background:Hide();
else
region.background:Show();
end
region.foreground:SetBaseTexture(data.foregroundTexture);
region.foreground:SetFrame(data.foregroundTexture, 1);
region.foreground:SetDesaturated(data.desaturateForeground);
region.foreground:SetBlendMode(data.blendMode);
region.foreground:SetDesaturated(data.desaturateForeground)
region:SetWidth(data.width);
region:SetHeight(data.height);
@@ -317,22 +203,34 @@ local function modify(parent, region, data)
region.scaley = 1;
function region:Scale(scalex, scaley)
region.scalex = scalex;
region.scaley = scaley;
if(scalex < 0) then
region.mirror_h = true;
scalex = scalex * -1;
else
region.mirror_h = nil;
end
region:SetWidth(region.width * scalex);
if(scaley < 0) then
scaley = scaley * -1;
region.mirror_v = true;
else
region.mirror_v = nil;
end
region:SetHeight(region.height * scaley);
self.scalex = scalex
self.scaley = scaley
if(scalex < 0) then
self.mirror_h = true
scalex = scalex * -1
else
self.mirror_h = nil
end
self:SetWidth(self.width * scalex)
if(scaley < 0) then
scaley = scaley * -1
self.mirror_v = true
else
self.mirror_v = nil
end
self:SetHeight(self.height * scaley)
end
-- Set colors
region.background:SetColor(data.backgroundColor[1], data.backgroundColor[2],
data.backgroundColor[3], data.backgroundColor[4])
function region:SetBackgroundColor(r, g, b, a)
self.background:SetColor(r, g, b, a)
end
function region:GetColor()
return region.color_r, region.color_g, region.color_b, region.color_a
end
function region:Color(r, g, b, a)
@@ -343,7 +241,7 @@ local function modify(parent, region, data)
if (r or g or b) then
a = a or 1;
end
region.foreground:SetVertexColor(region.color_anim_r or r, region.color_anim_g or g, region.color_anim_b or b, region.color_anim_a or a);
region.foreground:SetColor(region.color_anim_r or r, region.color_anim_g or g, region.color_anim_b or b, region.color_anim_a or a);
end
function region:ColorAnim(r, g, b, a)
@@ -354,137 +252,87 @@ local function modify(parent, region, data)
if (r or g or b) then
a = a or 1;
end
region.foreground:SetVertexColor(r or region.color_r, g or region.color_g, b or region.color_b, a or region.color_a);
end
function region:GetColor()
return region.color_r or data.color[1], region.color_g or data.color[2],
region.color_b or data.color[3], region.color_a or data.color[4];
region.foreground:SetColor(r or region.color_r, g or region.color_g, b or region.color_b, a or region.color_a);
end
region:Color(data.foregroundColor[1], data.foregroundColor[2], data.foregroundColor[3], data.foregroundColor[4]);
function region:PreShow()
region.startTime = GetTime();
region.foreground:SetStartTime(GetTime())
if region.FrameTick then
region:FrameTick()
end
end
local function onUpdate()
if (not region.startTime) then return end
Private.StartProfileAura(region.id);
Private.StartProfileSystem("stopmotion")
local timeSinceStart = (GetTime() - region.startTime);
local newCurrentFrame = floor(timeSinceStart * (data.frameRate or 15));
if (newCurrentFrame == region.currentFrame) then
Private.StopProfileAura(region.id);
Private.StopProfileSystem("stopmotion")
return;
region.FrameTick = nil
if data.animationType == "loop" or data.animationType == "bounce" or data.animationType == "once" then
region.FrameTick = FrameTickFunctions.timed
region.subRegionEvents:AddSubscriber("FrameTick", region, true)
region.UpdateValue = nil
region.UpdateTime = nil
function region:Update()
region:UpdateProgress()
end
elseif data.animationType == "progress" then
function region:Update()
region:UpdateProgress()
end
region.currentFrame = newCurrentFrame;
local frames;
local startFrame = region.startFrame;
local endFrame = region.endFrame;
local inverse = data.inverse;
if (endFrame >= startFrame) then
frames = endFrame - startFrame + 1;
else
frames = startFrame - endFrame + 1;
startFrame, endFrame = endFrame, startFrame;
inverse = not inverse;
function region:UpdateValue()
local progress = 0;
if (self.total ~= 0) then
progress = self.value / self.total
end
self.foreground:SetProgress(progress)
if self.FrameTick then
self.FrameTick = nil
self.subRegionEvents:RemoveSubscriber("FrameTick", self)
end
end
local frame = 0;
if (data.animationType == "loop") then
frame = (newCurrentFrame % frames) + startFrame;
elseif (data.animationType == "bounce") then
local direction = floor(newCurrentFrame / frames) % 2;
if (direction == 0) then
frame = (newCurrentFrame % frames) + startFrame;
else
frame = endFrame - (newCurrentFrame % frames);
function region:UpdateTime()
if self.paused then
if self.FrameTick then
self.FrameTick = nil
self.subRegionEvents:RemoveSubscriber("FrameTick", self)
end
elseif (data.animationType == "once") then
frame = newCurrentFrame + startFrame
if (frame > endFrame) then
frame = endFrame;
end
elseif (data.animationType == "progress") then
if (not region.state) then
-- Do nothing
elseif (region.state.progressType == "static") then
local value = region.state.value or 0
local total = region.state.total ~= 0 and region.state.total or 1
frame = floor((frames - 1) * value / total) + startFrame;
local remaining = self.remaining
local progress = 1 - (remaining / self.duration)
self.foreground:SetProgress(progress)
else
local remaining
if region.state.paused then
remaining = region.state.remaining or 0;
else
remaining = region.state.expirationTime and (region.state.expirationTime - GetTime()) or 0;
if not self.FrameTick then
self.FrameTick = FrameTickFunctions.progressTimer
self.subRegionEvents:AddSubscriber("FrameTick", self)
end
local progress = region.state.duration and region.state.duration > 0 and (1 - (remaining / region.state.duration)) or 0;
frame = floor( (frames - 1) * progress) + startFrame;
self:FrameTick()
end
end
if (inverse) then
frame = endFrame - frame + startFrame;
end
if (frame > endFrame) then
frame = endFrame
end
if (frame < startFrame) then
frame = startFrame
end
region.foreground:SetFrame(data.foregroundTexture, frame);
Private.StopProfileAura(region.id);
Private.StopProfileSystem("stopmotion")
end;
region.FrameTick = onUpdate;
function region:Update()
if region.state.paused then
if not region.paused then
region:Pause()
end
else
if region.paused then
region:Resume()
end
end
onUpdate();
end
function region:SetForegroundDesaturated(b)
region.foreground:SetDesaturated(b);
end
function region:SetBackgroundDesaturated(b)
region.background:SetDesaturated(b);
end
function region:SetBackgroundColor(r, g, b, a)
region.background:SetVertexColor(r, g, b, a);
end
function region:SetRegionWidth(width)
region.width = width;
region:Scale(region.scalex, region.scaley);
self.width = width
self:Scale(self.scalex, self.scaley)
end
function region:SetRegionHeight(height)
region.height = height;
region:Scale(region.scalex, region.scaley);
self.height = height
self:Scale(self.scalex, self.scaley)
end
function region:SetForegroundDesaturated(b)
self.foreground:SetDesaturated(b)
end
function region:SetBackgroundDesaturated(b)
self.background:SetDesaturated(b)
end
Private.regionPrototype.modifyFinish(parent, region, data)
end
local function validate(data)
Private.EnforceSubregionExists(data, "subbackground")
end
WeakAuras.RegisterRegionType("stopmotion", create, modify, default, properties, validate);
Private.RegisterRegionType("stopmotion", create, modify, default, GetProperties, validate);
+144 -84
View File
@@ -1,4 +1,4 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
@@ -44,17 +44,18 @@ local properties = {
softMax = 72,
step = 1,
default = 12
}
},
displayText = {
display = L["Text"],
setter = "ChangeText",
type = "string"
},
}
WeakAuras.regionPrototype.AddProperties(properties, default);
local function GetProperties(data)
return properties;
end
Private.regionPrototype.AddProperties(properties, default);
local function create(parent)
local region = CreateFrame("FRAME", nil, parent);
local region = CreateFrame("Frame", nil, parent);
region.regionType = "text"
region:SetMovable(true);
@@ -63,29 +64,29 @@ local function create(parent)
text:SetWordWrap(true);
text:SetNonSpaceWrap(true);
region.duration = 0;
region.expirationTime = math.huge;
WeakAuras.regionPrototype.create(region);
Private.regionPrototype.create(region);
return region;
end
local function modify(parent, region, data)
WeakAuras.regionPrototype.modify(parent, region, data);
Private.regionPrototype.modify(parent, region, data);
local text = region.text;
local fontPath = SharedMedia:Fetch("font", data.font);
text:SetFont(fontPath, data.fontSize < 33 and data.fontSize or 33, data.outline);
text:SetFont(fontPath, data.fontSize < 33 and data.fontSize or 33, data.outline == "None" and "" or data.outline);
if not text:GetFont() and fontPath then -- workaround font not loading correctly
local objectName = "WeakAuras-Font-" .. data.font
local fontObject = _G[objectName] or CreateFont(objectName)
fontObject:SetFont(fontPath, data.fontSize < 33 and data.fontSize or 33, data.outline == "None" and "" or data.outline)
text:SetFontObject(fontObject)
end
if not text:GetFont() then -- Font invalid, set the font but keep the setting
text:SetFont(STANDARD_TEXT_FONT, data.fontSize <= 33 and data.fontSize or 33, data.outline);
end
text:SetTextHeight(data.fontSize);
if text:GetFont() then
text:SetText("")
text:SetText(WeakAuras.ReplaceRaidMarkerSymbols(data.displayText));
text:SetFont(STANDARD_TEXT_FONT, data.fontSize < 33 and data.fontSize or 33, data.outline == "None" and "" or data.outline);
end
text:SetJustifyH(data.justify);
text:SetText("")
text:ClearAllPoints();
text:SetPoint("CENTER", UIParent, "CENTER");
@@ -98,7 +99,7 @@ local function modify(parent, region, data)
local tooltipType = Private.CanHaveTooltip(data);
if(tooltipType and data.useTooltip) then
if not region.tooltipFrame then
region.tooltipFrame = CreateFrame("frame", nil, region);
region.tooltipFrame = CreateFrame("Frame", nil, region);
region.tooltipFrame:SetAllPoints(region);
region.tooltipFrame:SetScript("OnEnter", function()
Private.ShowMouseoverTooltip(region, region);
@@ -110,6 +111,7 @@ local function modify(parent, region, data)
region.tooltipFrame:EnableMouse(false);
end
text:SetTextHeight(data.fontSize);
text:SetShadowColor(unpack(data.shadowColor))
text:SetShadowOffset(data.shadowXOffset, data.shadowYOffset)
@@ -142,8 +144,8 @@ local function modify(parent, region, data)
region:SetHeight(height)
if data.parent then
Private.EnsureRegion(data.parent)
if WeakAuras.regions[data.parent].region.PositionChildren then
WeakAuras.regions[data.parent].region:PositionChildren()
if Private.regions[data.parent].region.PositionChildren then
Private.regions[data.parent].region:PositionChildren()
end
end
end
@@ -157,23 +159,33 @@ local function modify(parent, region, data)
if text:GetFont() then
text:SetText(WeakAuras.ReplaceRaidMarkerSymbols(textStr));
end
end
local width = text:GetWidth();
local height = text:GetStringHeight();
if(width ~= region.width or height ~= region.height ) then
region.width = width;
region.height = height;
region:SetWidth(region.width);
region:SetHeight(region.height);
if(data.parent and WeakAuras.regions[data.parent].region.PositionChildren) then
WeakAuras.regions[data.parent].region:PositionChildren();
-- If the text changes we need to figure out the text size
-- To unset scaling we need to temporarily detach the text from
-- the region
text:SetParent(UIParent)
local width = text:GetWidth();
local height = text:GetStringHeight();
if(width ~= region.width or height ~= region.height ) then
region.width = width
region.height = height
region:SetWidth(region.width);
region:SetHeight(region.height);
if(data.parent and Private.regions[data.parent].region.PositionChildren) then
Private.regions[data.parent].region:PositionChildren();
end
end
text:SetParent(region)
end
end
end
local UpdateText
if Private.ContainsAnyPlaceHolders(data.displayText) then
local containsCustomText = false
if Private.ContainsCustomPlaceHolder(data.displayText) then
containsCustomText = true
end
local formatters, everyFrameFormatters
do
local getter = function(key, default)
local fullKey = "displayText_format_" .. key
if (data[fullKey] == nil) then
@@ -181,58 +193,98 @@ local function modify(parent, region, data)
end
return data[fullKey]
end
local formatters = Private.CreateFormatters(data.displayText, getter)
UpdateText = function()
local textStr = data.displayText;
textStr = Private.ReplacePlaceHolders(textStr, region, nil, false, formatters);
if (textStr == nil or textStr == "") then
textStr = " ";
end
local texts = {}
tinsert(texts, data.displayText)
if type(data.conditions) == "table" then
for _, condition in ipairs(data.conditions) do
if type(condition.changes) == "table" then
for _, change in ipairs(condition.changes) do
if type(change.property) == "string"
and change.property == "displayText"
and type(change.value) == "string"
and Private.ContainsAnyPlaceHolders(change.value)
then
if not containsCustomText and Private.ContainsCustomPlaceHolder(change.value) then
containsCustomText = true
end
tinsert(texts, change.value)
end
end
end
end
end
formatters, everyFrameFormatters = Private.CreateFormatters(texts, getter, false, data)
end
local customTextFunc = nil
if containsCustomText and data.customText and data.customText ~= "" then
customTextFunc = WeakAuras.LoadFunction("return "..data.customText)
end
function region:ConfigureTextUpdate()
local UpdateText
if self.displayText and Private.ContainsAnyPlaceHolders(self.displayText) then
UpdateText = function()
local textStr = Private.ReplacePlaceHolders(self.displayText, self, nil, false, formatters);
if textStr == "" then
textStr = " "
end
SetText(textStr)
end
end
local Update
if customTextFunc and self.displayText and Private.ContainsCustomPlaceHolder(self.displayText) then
Update = function()
self.values.custom = Private.RunCustomTextFunc(self, customTextFunc)
UpdateText()
end
else
Update = UpdateText or function() end
end
local FrameTick
if Private.ContainsPlaceHolders(self.displayText, "p")
or Private.AnyEveryFrameFormatters(self.displayText, everyFrameFormatters)
then
FrameTick = UpdateText
end
if customTextFunc and data.customTextUpdate == "update" then
if Private.ContainsCustomPlaceHolder(self.displayText) then
FrameTick = function()
self.values.custom = Private.RunCustomTextFunc(self, customTextFunc)
UpdateText()
end
end
end
self.Update = Update
self.FrameTick = FrameTick
if not UpdateText then
local textStr = self.displayText
textStr = textStr:gsub("\\n", "\n");
SetText(textStr)
end
end
local customTextFunc = nil
if(Private.ContainsCustomPlaceHolder(data.displayText) and data.customText) then
customTextFunc = WeakAuras.LoadFunction("return "..data.customText, region.id, "custom text")
end
local Update
if customTextFunc then
if UpdateText then
Update = function()
region.values.custom = Private.RunCustomTextFunc(region, customTextFunc)
UpdateText()
end
function region:ConfigureSubscribers()
if self.FrameTick then
self.subRegionEvents:AddSubscriber("FrameTick", self)
else
self.subRegionEvents:RemoveSubscriber("FrameTick", self)
end
else
Update = UpdateText or function() end
end
local TimerTick
if Private.ContainsPlaceHolders(data.displayText, "p") then
TimerTick = UpdateText
end
local FrameTick
if customTextFunc and data.customTextUpdate == "update" then
FrameTick = function()
region.values.custom = Private.RunCustomTextFunc(region, customTextFunc)
UpdateText()
if self.Update and self.state then
self:Update()
end
end
region.Update = Update
region.FrameTick = FrameTick
region.TimerTick = TimerTick
if not UpdateText then
local textStr = data.displayText
textStr = textStr:gsub("\\n", "\n");
SetText(textStr)
end
function region:Color(r, g, b, a)
region.color_r = r;
region.color_g = g;
@@ -268,23 +320,31 @@ local function modify(parent, region, data)
region.text:SetTextHeight(size)
end
WeakAuras.regionPrototype.modifyFinish(parent, region, data);
function region:ChangeText(msg)
self.displayText = msg
self:ConfigureTextUpdate()
self:ConfigureSubscribers()
end
region.displayText = data.displayText
region:ConfigureTextUpdate()
region:ConfigureSubscribers()
Private.regionPrototype.modifyFinish(parent, region, data);
end
local function validate(data)
Private.EnforceSubregionExists(data, "subbackground")
end
WeakAuras.RegisterRegionType("text", create, modify, default, GetProperties, validate);
Private.RegisterRegionType("text", create, modify, default, properties, validate);
-- Fallback region type
local function fallbackmodify(parent, region, data)
WeakAuras.regionPrototype.modify(parent, region, data);
Private.regionPrototype.modify(parent, region, data);
local text = region.text;
text:SetFont(STANDARD_TEXT_FONT, data.fontSize < 33 and data.fontSize or 33, data.outline and "OUTLINE" or nil);
text:SetTextHeight(data.fontSize);
text:SetFont(STANDARD_TEXT_FONT, data.fontSize, data.outline and "OUTLINE" or nil);
if text:GetFont() then
text:SetText(WeakAuras.L["Region type %s not supported"]:format(data.regionType));
end
@@ -297,7 +357,7 @@ local function fallbackmodify(parent, region, data)
region.Update = function() end
WeakAuras.regionPrototype.modifyFinish(parent, region, data);
Private.regionPrototype.modifyFinish(parent, region, data);
end
WeakAuras.RegisterRegionType("fallback", create, fallbackmodify, default);
Private.RegisterRegionType("fallback", create, fallbackmodify, default);
+58 -88
View File
@@ -1,11 +1,8 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L;
local root2 = math.sqrt(2);
local halfroot2 = root2/2;
local default = {
texture = "Interface\\Addons\\WeakAuras\\PowerAurasMedia\\Auras\\Aura3",
desaturate = false,
@@ -14,9 +11,8 @@ local default = {
color = {1, 1, 1, 1},
blendMode = "BLEND",
rotation = 0,
discrete_rotation = 0,
mirror = false,
rotate = true,
rotate = false,
selfPoint = "CENTER",
anchorPoint = "CENTER",
anchorFrameType = "SCREEN",
@@ -25,11 +21,16 @@ local default = {
frameStrata = 1
};
WeakAuras.regionPrototype.AddAlphaToDefault(default);
Private.regionPrototype.AddAlphaToDefault(default);
local screenWidth, screenHeight = math.ceil(GetScreenWidth() / 20) * 20, math.ceil(GetScreenHeight() / 20) * 20;
local properties = {
texture = {
display = L["Texture"],
setter = "SetTexture",
type = "texture",
},
color = {
display = L["Color"],
setter = "Color",
@@ -62,106 +63,70 @@ local properties = {
display = L["Mirror"],
setter = "SetMirror",
type = "bool"
},
rotation = {
display = L["Rotation"],
setter = "SetRotation",
type = "number",
min = 0,
max = 360,
bigStep = 1,
default = 0
}
}
WeakAuras.regionPrototype.AddProperties(properties, default);
Private.regionPrototype.AddProperties(properties, default);
local function create(parent)
local region = CreateFrame("FRAME", nil, UIParent);
local region = CreateFrame("Frame", nil, UIParent);
region.regionType = "texture"
region:SetMovable(true);
region:SetResizable(true);
region:SetMinResize(1, 1);
local texture = region:CreateTexture();
local texture = Private.TextureBase.create(region)
region.texture = texture;
texture:SetAllPoints(region);
WeakAuras.regionPrototype.create(region);
Private.regionPrototype.create(region);
return region;
end
local function modify(parent, region, data)
WeakAuras.regionPrototype.modify(parent, region, data);
region.texture:SetTexture(data.texture);
region.texture:SetDesaturated(data.desaturate)
Private.regionPrototype.modify(parent, region, data);
region:SetWidth(data.width);
region:SetHeight(data.height);
region.width = data.width;
region.height = data.height;
region.scalex = 1;
region.scaley = 1;
region.texture:SetBlendMode(data.blendMode);
--region.texture:SetRotation((data.rotation / 180) * math.pi);
local function GetRotatedPoints(degrees)
local angle = rad(135 - degrees);
local vx = math.cos(angle);
local vy = math.sin(angle);
return 0.5+vx,0.5-vy , 0.5-vy,0.5-vx , 0.5+vy,0.5+vx , 0.5-vx,0.5+vy
end
region.mirror = data.mirror
local function DoTexCoord()
local mirror_h, mirror_v = region.mirror_h, region.mirror_v;
if(region.mirror) then
mirror_h = not mirror_h;
end
local ulx,uly , llx,lly , urx,ury , lrx,lry;
if(data.rotate) then
ulx,uly , llx,lly , urx,ury , lrx,lry = GetRotatedPoints(region.rotation);
else
if(data.discrete_rotation == 0 or data.discrete_rotation == 360) then
ulx,uly , llx,lly , urx,ury , lrx,lry = 0,0 , 0,1 , 1,0 , 1,1;
elseif(data.discrete_rotation == 90) then
ulx,uly , llx,lly , urx,ury , lrx,lry = 1,0 , 0,0 , 1,1 , 0,1;
elseif(data.discrete_rotation == 180) then
ulx,uly , llx,lly , urx,ury , lrx,lry = 1,1 , 1,0 , 0,1 , 0,0;
elseif(data.discrete_rotation == 270) then
ulx,uly , llx,lly , urx,ury , lrx,lry = 0,1 , 1,1 , 0,0 , 1,0;
end
end
if(mirror_h) then
if(mirror_v) then
region.texture:SetTexCoord(lrx,lry , urx,ury , llx,lly , ulx,uly);
else
region.texture:SetTexCoord(urx,ury , lrx,lry , ulx,uly , llx,lly);
end
else
if(mirror_v) then
region.texture:SetTexCoord(llx,lly , ulx,uly , lrx,lry , urx,ury);
else
region.texture:SetTexCoord(ulx,uly , llx,lly , urx,ury , lrx,lry);
end
end
end
region.rotation = data.rotation;
DoTexCoord();
Private.TextureBase.modify(region.texture, {
canRotate = data.rotate,
desaturate = data.desaturate,
blendMode = data.blendMode,
mirror = data.mirror,
rotation = data.rotation,
textureWrapMode = data.textureWrapMode
})
function region:Scale(scalex, scaley)
region.scalex = scalex;
region.scaley = scaley;
local mirror_h, mirror_v
if(scalex < 0) then
region.mirror_h = true;
mirror_h = true
scalex = scalex * -1;
else
region.mirror_h = nil;
end
region:SetWidth(region.width * scalex);
if(scaley < 0) then
scaley = scaley * -1;
region.mirror_v = true;
else
region.mirror_v = nil;
mirror_v = true
end
region:SetHeight(region.height * scaley);
DoTexCoord();
region.texture:SetMirrorFromScale(mirror_h, mirror_v)
end
function region:SetRegionWidth(width)
@@ -175,16 +140,22 @@ local function modify(parent, region, data)
end
function region:SetMirror(mirror)
region.mirror = mirror
DoTexCoord()
self.texture:SetMirror(mirror)
end
function region:Update()
if region.state.texture then
region.texture:SetTexture(region.state.texture);
if self.state.texture then
self.texture:SetTexture(self.state.texture)
end
self:UpdateProgress()
end
function region:SetTexture(texture)
self.texture:SetTexture(texture)
end
region.texture:SetTexture(data.texture)
function region:Color(r, g, b, a)
region.color_r = r;
region.color_g = g;
@@ -215,28 +186,27 @@ local function modify(parent, region, data)
region:Color(data.color[1], data.color[2], data.color[3], data.color[4]);
function region:SetDesaturated(b)
region.texture:SetDesaturated(b);
self.texture:SetDesaturated(b)
end
if(data.rotate) then
function region:Rotate(degrees)
region.rotation = degrees;
DoTexCoord();
end
function region:GetRotation()
return region.rotation;
end
else
region.Rotate = nil;
region.GetRotation = nil;
function region:SetAnimRotation(degrees)
self.texture:SetAnimRotation(degrees)
end
WeakAuras.regionPrototype.modifyFinish(parent, region, data);
function region:SetRotation(degrees)
self.texture:SetRotation(degrees)
end
function region:GetBaseRotation()
return self.texture:GetBaseRotation()
end
region:SetRotation(data.rotation)
Private.regionPrototype.modifyFinish(parent, region, data);
end
local function validate(data)
Private.EnforceSubregionExists(data, "subbackground")
end
WeakAuras.RegisterRegionType("texture", create, modify, default, properties, validate);
Private.RegisterRegionType("texture", create, modify, default, properties, validate);
+37 -35
View File
@@ -1,56 +1,58 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L;
do
local function subSupports(regionType)
return regionType ~= "group" and regionType ~= "dynamicgroup"
end
local function subSupports(regionType)
return regionType ~= "group" and regionType ~= "dynamicgroup"
end
local function noop()
end
local function noop()
end
local function subSetFrameLevel(self, level)
self.parent:SetFrameLevel(level)
end
local function subSetFrameLevel(self, level)
self.parent:SetFrameLevel(level)
end
local function subCreate()
return { Update = noop, SetFrameLevel = subSetFrameLevel}
end
local function subCreate()
return { Update = noop, SetFrameLevel = subSetFrameLevel}
end
local function subModify(parent, region)
region.parent = parent
end
local function subModify(parent, region)
region.parent = parent
end
WeakAuras.RegisterSubRegionType("subbackground", L["Background"], subSupports, subCreate, subModify, noop, noop, {}, nil, {}, false);
WeakAuras.RegisterSubRegionType("subbackground", L["Background"], subSupports, subCreate, subModify,
noop, noop, {}, nil, {}, false)
end
-- Foreground for aurabar
do
local function subSupports(regionType)
return regionType == "aurabar"
end
local function subSupports(regionType)
return regionType == "aurabar"
end
local function noop()
end
local function noop()
end
local function subSetFrameLevel(self, level)
if self.parent.bar then
self.parent.bar:SetFrameLevel(level)
end
if self.parent.iconFrame then
self.parent.iconFrame:SetFrameLevel(level)
end
local function subSetFrameLevel(self, level)
if self.parent.bar then
self.parent.bar:SetFrameLevel(level)
end
local function subCreate()
return { Update = noop, SetFrameLevel = subSetFrameLevel}
if self.parent.iconFrame then
self.parent.iconFrame:SetFrameLevel(level)
end
end
local function subModify(parent, region)
region.parent = parent
end
local function subCreate()
return { Update = noop, SetFrameLevel = subSetFrameLevel}
end
WeakAuras.RegisterSubRegionType("subforeground", L["Foreground"], subSupports, subCreate, subModify, noop, noop, {}, nil, {}, false);
local function subModify(parent, region)
region.parent = parent
end
WeakAuras.RegisterSubRegionType("subforeground", L["Foreground"], subSupports, subCreate, subModify,
noop, noop, {}, nil, {}, false)
end
+14 -7
View File
@@ -1,4 +1,4 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
@@ -13,7 +13,7 @@ local default = function(parentType)
border_size = 2,
}
if parentType == "aurabar" then
options["border_anchor"] = "bar"
options["anchor_area"] = "bar"
end
return options
end
@@ -34,7 +34,8 @@ local properties = {
local function create()
return CreateFrame("FRAME", nil, UIParent)
local region = CreateFrame("Frame", nil, UIParent)
return region
end
local function onAcquire(subRegion)
@@ -48,8 +49,6 @@ end
local function modify(parent, region, parentData, data, first)
region:SetParent(parent)
parent:AnchorSubRegion(region, "area", parentData.regionType == "aurabar" and data.border_anchor, nil, data.border_offset, data.border_offset)
local edgeFile = SharedMedia:Fetch("border", data.border_edge)
if edgeFile and edgeFile ~= "" then
region:SetBackdrop({
@@ -57,7 +56,8 @@ local function modify(parent, region, parentData, data, first)
edgeSize = data.border_size,
bgFile = nil,
})
region:SetBackdropBorderColor(data.border_color[1], data.border_color[2], data.border_color[3], data.border_color[4])
region:SetBackdropBorderColor(data.border_color[1], data.border_color[2],
data.border_color[3], data.border_color[4])
region:SetBackdropColor(0, 0, 0, 0)
end
@@ -76,6 +76,11 @@ local function modify(parent, region, parentData, data, first)
end
region:SetVisible(data.border_visible)
region.Anchor = function()
parent:AnchorSubRegion(region, "area", parentData.regionType == "aurabar" and data.anchor_area or nil,
nil, data.border_offset, data.border_offset)
end
end
local function supports(regionType)
@@ -83,6 +88,8 @@ local function supports(regionType)
or regionType == "progresstexture"
or regionType == "icon"
or regionType == "aurabar"
or regionType == "empty"
end
WeakAuras.RegisterSubRegionType("subborder", L["Border"], supports, create, modify, onAcquire, onRelease, default, nil, properties);
WeakAuras.RegisterSubRegionType("subborder", L["Border"], supports, create, modify, onAcquire, onRelease,
default, nil, properties)
+31 -27
View File
@@ -1,15 +1,10 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
local LCG = LibStub("LibCustomGlow-1.0")
local MSQ, MSQ_Version = LibStub("Masque", true);
if MSQ then
if MSQ_Version <= 80100 then
MSQ = nil
end
end
local L = WeakAuras.L;
local MSQ = LibStub("Masque", true)
local L = WeakAuras.L
local default = function(parentType)
local options = {
@@ -28,7 +23,7 @@ local default = function(parentType)
}
if parentType == "aurabar" then
options["glowType"] = "Pixel"
options["glow_anchor"] = "bar"
options["anchor_area"] = "bar"
end
return options
end
@@ -178,16 +173,16 @@ local funcs = {
if (visible) then
self.__MSQ_Shape = self:GetParent().button.__MSQ_Shape
self:Show()
glowStart(self, self, color);
glowStart(self, self, color)
else
self.glowStop(self);
self.glowStop(self)
self:Hide()
end
elseif (visible) then
self:Show()
glowStart(self, self, color);
glowStart(self, self, color)
else
self.glowStop(self);
self.glowStop(self)
self:Hide()
end
end,
@@ -297,7 +292,7 @@ local funcs = {
}
local function create()
local region = CreateFrame("FRAME", nil, UIParent)
local region = CreateFrame("Frame", nil, UIParent)
for name, func in pairs(funcs) do
region[name] = func
@@ -320,12 +315,6 @@ end
local function modify(parent, region, parentData, data, first)
region:SetParent(parent)
region.parentRegionType = parentData.regionType
if parentData.regionType == "aurabar" then
parent:AnchorSubRegion(region, "area", data.glow_anchor)
else
parent:AnchorSubRegion(region, "area", data.glowType == "buttonOverlay" and "region")
end
region.parent = parent
region.parentType = parentData.regionType
@@ -344,10 +333,18 @@ local function modify(parent, region, parentData, data, first)
region:SetVisible(data.glow)
region:SetScript("OnSizeChanged", region.UpdateSize)
region.Anchor = function()
if parentData.regionType == "aurabar" then
parent:AnchorSubRegion(region, "area", data.anchor_area)
else
parent:AnchorSubRegion(region, "area", (data.glowType == "buttonOverlay" or data.glowType == "Proc") and "region")
end
end
end
-- This is used by the templates to add glow
function WeakAuras.getDefaultGlow(regionType)
function Private.getDefaultGlow(regionType)
if regionType == "aurabar" then
return {
["type"] = "subglow",
@@ -363,9 +360,9 @@ function WeakAuras.getDefaultGlow(regionType)
glowBorder = false,
glowXOffset = 0,
glowYOffset = 0,
glow_anchor = "bar"
anchor_area = "bar"
}
elseif regionType == "icon" then
else
return {
["type"] = "subglow",
glow = false,
@@ -384,9 +381,15 @@ function WeakAuras.getDefaultGlow(regionType)
end
end
local supportedRegion = {
icon = true,
aurabar = true,
texture = true,
progresstexture = true,
empty = true,
}
local function supports(regionType)
return regionType == "icon"
or regionType == "aurabar"
return supportedRegion[regionType]
end
local function addDefaultsForNewAura(data)
@@ -409,4 +412,5 @@ local function addDefaultsForNewAura(data)
end
end
WeakAuras.RegisterSubRegionType("subglow", L["Glow"], supports, create, modify, onAcquire, onRelease, default, addDefaultsForNewAura, properties);
WeakAuras.RegisterSubRegionType("subglow", L["Glow"], supports, create, modify, onAcquire, onRelease,
default, addDefaultsForNewAura, properties)
+4 -5
View File
@@ -1,7 +1,6 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
local L = WeakAuras.L;
Private.barmodels = {}
@@ -155,7 +154,7 @@ local funcs = {
}
local function create()
local subRegion = CreateFrame("FRAME", nil, UIParent)
local subRegion = CreateFrame("Frame", nil, UIParent)
--subRegion:SetClipsChildren(true)
for k, v in pairs(funcs) do
@@ -174,8 +173,6 @@ local function onRelease(subRegion)
subRegion:Hide()
end
local function modify(parent, region, parentData, data, first)
if region.model then
ReleaseModel(region.model)
@@ -205,6 +202,7 @@ local function modify(parent, region, parentData, data, first)
extra_height = data.extra_height or 0
end
region:ClearAllPoints()
region:SetPoint("TOPLEFT", anchor ,"TOPLEFT", -extra_width/2, extra_height/2)
region:SetPoint("BOTTOMRIGHT", anchor ,"BOTTOMRIGHT", extra_width/2, -extra_height/2)
@@ -222,6 +220,7 @@ local function supports(regionType)
or regionType == "icon"
or regionType == "aurabar"
or regionType == "text"
or regionType == "empty"
end
WeakAuras.RegisterSubRegionType("submodel", L["Model"], supports, create, modify, onAcquire, onRelease, default, nil, properties);
+280
View File
@@ -0,0 +1,280 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L
local default = function(parentType)
local defaults = {
stopmotionVisible = true,
barModelClip = true,
stopmotionTexture = "Interface\\AddOns\\WeakAuras\\Media\\Textures\\stopmotion",
stopmotionDesaturate = false,
stopmotionColor = {1, 1, 1, 1},
stopmotionBlendMode = "BLEND",
startPercent = 0,
endPercent = 1,
frameRate = 15,
animationType = "loop",
inverse = false,
customFrames = 0,
customRows = 16,
customColumns = 16,
customFileWidth = 0,
customFileHeight = 0,
customFrameWidth = 0,
customFrameHeight = 0,
anchor_mode = "area",
self_point = "CENTER",
anchor_point = "CENTER",
width = 32,
height = 32,
scale = 1,
progressSource = {-2, ""},
}
if IsAddOnLoaded("WeakAurasStopMotion") then
defaults.stopmotionTexture = "Interface\\AddOns\\WeakAurasStopMotion\\Textures\\IconOverlays\\ArcReactor"
defaults.frameRate = 30
defaults.scale = 3
end
if parentType == "aurabar" then
defaults.anchor_area = "bar"
else
defaults.anchor_area = "ALL"
end
return defaults
end
local properties = {
stopmotionVisible = {
display = L["Visibility"],
setter = "SetVisible",
type = "bool",
defaultProperty = true
},
stopmotionDesaturate = {
display = L["Desaturate"],
setter = "SetDesaturated",
type = "bool",
},
stopmotionColor = {
display = L["Color"],
setter = "SetColor",
type = "color"
},
}
local funcs = {
OnSizeChanged = function(self)
local w, h = self:GetSize()
self.stopMotion:SetSize(w * self.scale, h * self.scale)
end,
SetDesaturated = function(self, b)
self.stopMotion:SetDesaturated(b)
end,
SetColor = function(self, ...)
self.stopMotion:SetColor(...)
end,
}
local TimedFuncs = {
SetVisible = function(self, visible)
self.visible = visible
if visible then
self:Show()
self.stopMotion:SetStartTime(GetTime())
self.FrameTick = function()
self.stopMotion:TimedUpdate()
end
self.parent.subRegionEvents:AddSubscriber("FrameTick", self)
else
self:Hide()
self.FrameTick = nil
self.parent.subRegionEvents:RemoveSubscriber("FrameTick", self)
end
end,
Update = function(self) end,
}
local ProgressFuncs = {
UpdateFrameTick = function(self)
if self.visible and self.progressData.progressType == "timed" and not self.progressData.paused then
if not self.FrameTick then
self.FrameTick = self.UpdateFrame
self.parent.subRegionEvents:AddSubscriber("FrameTick", self)
end
else
if self.FrameTick then
self.FrameTick = nil
self.parent.subRegionEvents:RemoveSubscriber("FrameTick", self)
end
end
end,
SetVisible = function(self, visible)
self.visible = visible
if visible then
self:Show()
else
self:Hide()
end
self:UpdateFrame()
self:UpdateFrameTick()
end,
UpdateFrame = function(self)
if self.visible then
local progressData = self.progressData
if progressData.progressType == "static" then
local progress = 0
if progressData.total ~= 0 then
progress = progressData.value / progressData.total
end
self.stopMotion:SetProgress(progress)
elseif progressData.progressType == "timed" then
if progressData.paused then
local remaining = self.progressData.remaining
local progress = 1 - (remaining / self.progressData.duration)
self.stopMotion:SetProgress(progress)
else
local remaining = self.progressData.expirationTime - GetTime()
local progress = 1 - (remaining / self.progressData.duration)
self.stopMotion:SetProgress(progress)
end
end
end
end,
Update = function(self, state, states)
Private.UpdateProgressFrom(self.progressData, self.progressSource, self, state, states, self.parent)
self:UpdateFrame()
self:UpdateFrameTick()
end,
}
local function create()
local region = CreateFrame("Frame", nil, UIParent)
--region:SetFlattensRenderLayers(true)
for k, v in pairs(funcs) do
region[k] = v
end
region.stopMotion = Private.StopMotionBase.create(region, "ARTWORK")
region.progressData = {}
return region
end
local function onAcquire(subRegion)
subRegion:Show()
end
local function onRelease(subRegion)
subRegion:Hide()
end
local function modify(parent, region, parentData, data, first)
region.parent = parent
region:SetParent(parent)
region.scale = data.scale or 1
region.Anchor = nil
if parentData.regionType == "aurabar"
and data.anchor_mode == "area"
and data.anchor_area == "fg"
and data.barModelClip
then
-- Special anchoring for clipping !
region:SetScript("OnSizeChanged", nil)
region:ClearAllPoints()
region:SetAllPoints(parent.bar.fgFrame)
region.stopMotion:ClearAllPoints()
region.stopMotion:SetAllPoints(region.parent.bar)
else
local arg1 = data.anchor_mode == "point" and data.anchor_point or data.anchor_area
local arg2 = data.anchor_mode == "point" and data.self_point or nil
if data.anchor_mode == "area" and data.scale ~= 1 then
-- Extra Scale mode
region.stopMotion:ClearAllPoints()
region.stopMotion:SetPoint("CENTER", region, "CENTER")
region:SetScript("OnSizeChanged", region.OnSizeChanged)
region:OnSizeChanged()
else
if data.anchor_mode == "point" then
region:SetSize(data.width or 0, data.height or 0)
end
region.stopMotion:ClearAllPoints()
region.stopMotion:SetAllPoints(region)
region:SetScript("OnSizeChanged", nil)
end
region.Anchor = function()
region:ClearAllPoints()
parent:AnchorSubRegion(region, data.anchor_mode, arg1, arg2, data.xOffset, data.yOffset)
if data.anchor_mode == "area" and data.scale ~= 1 then
region:OnSizeChanged()
end
end
end
Private.StopMotionBase.modify(region.stopMotion, {
blendMode = data.stopmotionBlendMode,
frameRate = data.frameRate,
inverseDirection = data.inverse,
animationType = data.animationType,
texture = data.stopmotionTexture,
startPercent = data.startPercent,
endPercent = data.endPercent,
customFrames = data.customFrames,
customRows = data.customRows,
customColumns = data.customColumns,
customFileWidth = data.customFileWidth,
customFileHeight = data.customFileHeight,
customFrameWidth = data.customFrameWidth,
customFrameHeight = data.customFrameHeight,
})
region.stopMotion:SetColor(unpack(data.stopmotionColor))
Private.regionPrototype.AddMinMaxProgressSource(true, region, parentData, data)
region.FrameTick = nil
if data.animationType == "loop" or data.animationType == "bounce" or data.animationType == "once" then
region.Update = TimedFuncs.Update
region.SetVisible = TimedFuncs.SetVisible
region.UpdateFrameTick = nil
region.UpdateFrame = nil
parent.subRegionEvents:RemoveSubscriber("Update", region)
else
region.Update = ProgressFuncs.Update
region.SetVisible = ProgressFuncs.SetVisible
region.UpdateFrameTick = ProgressFuncs.UpdateFrameTick
region.UpdateFrame = ProgressFuncs.UpdateFrame
parent.subRegionEvents:AddSubscriber("Update", region)
end
region:SetVisible(data.stopmotionVisible)
region:SetDesaturated(data.stopmotionDesaturate)
end
local function supports(regionType)
return regionType == "texture"
or regionType == "progresstexture"
or regionType == "icon"
or regionType == "aurabar"
or regionType == "text"
or regionType == "empty"
end
WeakAuras.RegisterSubRegionType("substopmotion", L["Stop Motion"], supports, create, modify, onAcquire, onRelease, default, nil, properties)
+178 -121
View File
@@ -1,4 +1,4 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
@@ -22,7 +22,7 @@ local default = function(parentType)
text_justify = "CENTER",
text_selfPoint = "AUTO",
text_anchorPoint = "CENTER",
anchor_point = "CENTER",
anchorXOffset = 0,
anchorYOffset = 0,
@@ -46,7 +46,7 @@ local default = function(parentType)
text_justify = "CENTER",
text_selfPoint = "AUTO",
text_anchorPoint = parentType == "aurabar" and "INNER_RIGHT" or "BOTTOMLEFT",
anchor_point = parentType == "aurabar" and "INNER_RIGHT" or "BOTTOMLEFT",
anchorXOffset = 0,
anchorYOffset = 0,
@@ -68,6 +68,11 @@ local properties = {
type = "bool",
defaultProperty = true
},
text_text = {
display = L["Text"],
setter = "ChangeText",
type = "string"
},
text_color = {
display = L["Color"],
setter = "Color",
@@ -101,7 +106,7 @@ local properties = {
}
local function create()
local region = CreateFrame("FRAME", nil, UIParent);
local region = CreateFrame("Frame", nil, UIParent);
local text = region:CreateFontString(nil, "OVERLAY");
region.text = text;
@@ -132,34 +137,23 @@ local function modify(parent, region, parentData, data, first)
region:SetParent(parent)
local text = region.text;
-- Legacy members in icon
-- Can we remove them with 9.0 ?
if parentData.regionType == "icon" then
if not parent.stacks then
parent.stacks = text
elseif not parent.text2 then
parent.text2 = text
end
elseif parentData.regionType == "aurabar" then
if not parent.timer then
parent.timer = text
elseif not parent.text then
parent.text = text
elseif not parent.stacks then
parent.stacks = text
end
end
local fontPath = SharedMedia:Fetch("font", data.text_font);
text:SetFont(fontPath, data.text_fontSize < 33 and data.text_fontSize or 33, data.text_fontType);
if not text:GetFont() and fontPath then -- workaround font not loading correctly
local objectName = "WeakAuras-Font-" .. data.text_font
local fontObject = _G[objectName] or CreateFont(objectName)
fontObject:SetFont(fontPath, data.text_fontSize < 33 and data.text_fontSize or 33, data.text_fontType == "None" and "" or data.text_fontType)
text:SetFontObject(fontObject)
end
if not text:GetFont() then -- Font invalid, set the font but keep the setting
text:SetFont(STANDARD_TEXT_FONT, data.text_fontSize < 33 and data.text_fontSize or 33, data.text_fontType);
end
text:SetTextHeight(data.text_fontSize);
if text:GetFont() then
text:SetText(WeakAuras.ReplaceRaidMarkerSymbols(data.text_text));
end
text:SetTextHeight(data.text_fontSize);
text:SetShadowColor(unpack(data.text_shadowColor))
text:SetShadowOffset(data.text_shadowXOffset, data.text_shadowYOffset)
text:SetJustifyH(data.text_justify or "CENTER")
@@ -190,98 +184,174 @@ local function modify(parent, region, parentData, data, first)
break
end
end
if not containsCustomText then
if type(parentData.conditions) == "table" then
for _, condition in ipairs(parentData.conditions) do
if type(condition.changes) == "table" then
for _, change in ipairs(condition.changes) do
if type(change.property) == "string"
and change.property:match("sub%.%d+%.text_text")
then
containsCustomText = true
break
end
end
end
end
end
end
if containsCustomText and parentData.customText and parentData.customText ~= "" then
parent.customTextFunc = WeakAuras.LoadFunction("return "..parentData.customText, parentData.id, "custom text")
parent.customTextFunc = WeakAuras.LoadFunction("return "..parentData.customText)
else
parent.customTextFunc = nil
end
parent.values.custom = nil
parent.values.lastCustomTextUpdate = nil
end
local UpdateText
if data.text_text and Private.ContainsAnyPlaceHolders(data.text_text) then
local getter = function(key, default)
local fullKey = "text_text_format_" .. key
if data[fullKey] == nil then
data[fullKey] = default
end
return data[fullKey]
end
local formatters = Private.CreateFormatters(data.text_text, getter)
UpdateText = function()
local textStr = data.text_text or ""
textStr = Private.ReplacePlaceHolders(textStr, parent, nil, false, formatters)
local texts = {}
local textStr = data.text_text or ""
if textStr ~= "" then
tinsert(texts, textStr)
end
local subRegionIndex = 1
for index, subRegion in ipairs(parentData.subRegions) do
if subRegion == data then
subRegionIndex = index
break;
end
end
if type(parentData.conditions) == "table" then
local conditionName = "sub."..subRegionIndex..".text_text"
for _, condition in ipairs(parentData.conditions) do
if type(condition.changes) == "table" then
for _, change in ipairs(condition.changes) do
if type(change.property) == "string" and change.property == conditionName then
if type(change.value ) == "string" and change.value ~= "" then
tinsert(texts, change.value)
end
end
end
end
end
end
local getter = function(key, default)
local fullKey = "text_text_format_" .. key
if (data[fullKey] == nil) then
data[fullKey] = default
end
return data[fullKey]
end
region.subTextFormatters, region.everyFrameFormatters = Private.CreateFormatters(texts, getter, false, parentData)
function region:ConfigureTextUpdate()
local UpdateText
if region.text_text and Private.ContainsAnyPlaceHolders(region.text_text) then
UpdateText = function()
local textStr = region.text_text or ""
textStr = Private.ReplacePlaceHolders(textStr, parent, nil, false, self.subTextFormatters)
if text:GetFont() then
text:SetText(WeakAuras.ReplaceRaidMarkerSymbols(textStr))
end
region:Anchor()
end
end
local Update
if parent.customTextFunc and UpdateText then
Update = function()
if parent.values.lastCustomTextUpdate ~= GetTime() then
parent.values.custom = Private.RunCustomTextFunc(parent, parent.customTextFunc)
parent.values.lastCustomTextUpdate = GetTime()
end
UpdateText()
end
else
Update = UpdateText
end
local FrameTick
if Private.ContainsPlaceHolders(region.text_text, "p")
or Private.AnyEveryFrameFormatters(region.text_text, region.everyFrameFormatters)
then
FrameTick = UpdateText
end
if parent.customTextFunc and parentData.customTextUpdate == "update" then
if Private.ContainsCustomPlaceHolder(region.text_text) then
FrameTick = function()
if parent.values.lastCustomTextUpdate ~= GetTime() then
parent.values.custom = Private.RunCustomTextFunc(parent, parent.customTextFunc)
parent.values.lastCustomTextUpdate = GetTime()
end
UpdateText()
end
end
end
region.Update = Update
region.FrameTick = FrameTick
if not UpdateText then
if text:GetFont() then
local textStr = region.text_text
textStr = textStr:gsub("\\n", "\n");
text:SetText(WeakAuras.ReplaceRaidMarkerSymbols(textStr))
end
end
end
local Update
if first and parent.customTextFunc then
if UpdateText then
Update = function()
parent.values.custom = Private.RunCustomTextFunc(parent, parent.customTextFunc)
UpdateText()
function region:ConfigureSubscribers()
local visible = self:IsShown()
if self.Update then
if visible then
parent.subRegionEvents:AddSubscriber("Update", region)
end
else
Update = function()
parent.values.custom = Private.RunCustomTextFunc(parent, parent.customTextFunc)
end
parent.subRegionEvents:RemoveSubscriber("Update", region)
end
else
Update = UpdateText
end
local TimerTick
if Private.ContainsPlaceHolders(data.text_text, "p") then
TimerTick = UpdateText
end
local FrameTick
if parent.customTextFunc and parentData.customTextUpdate == "update" then
if first then
if Private.ContainsCustomPlaceHolder(data.text_text) then
FrameTick = function()
parent.values.custom = Private.RunCustomTextFunc(parent, parent.customTextFunc)
UpdateText()
end
else
FrameTick = function()
parent.values.custom = Private.RunCustomTextFunc(parent, parent.customTextFunc)
end
if self.FrameTick then
if visible then
parent.subRegionEvents:AddSubscriber("FrameTick", region)
end
else
if Private.ContainsCustomPlaceHolder(data.text_text) then
FrameTick = UpdateText
end
parent.subRegionEvents:RemoveSubscriber("FrameTick", region)
end
if self.Update and parent.state and visible then
self:Update()
end
end
region.Update = Update
region.FrameTick = FrameTick
region.TimerTick = TimerTick
if Update then
parent.subRegionEvents:AddSubscriber("Update", region)
function region:ChangeText(msg)
region.text_text = msg
region:ConfigureTextUpdate()
region:ConfigureSubscribers()
end
if FrameTick then
parent.subRegionEvents:AddSubscriber("FrameTick", region)
end
region.text_text = data.text_text
region:ConfigureTextUpdate()
if TimerTick then
parent.subRegionEvents:AddSubscriber("TimerTick", region)
end
if not UpdateText then
if text:GetFont() then
local textStr = data.text_text
textStr = textStr:gsub("\\n", "\n");
text:SetText(WeakAuras.ReplaceRaidMarkerSymbols(textStr))
function region:SetTextHeight(size)
local fontPath = SharedMedia:Fetch("font", data.text_font);
if not text:GetFont() then -- Font invalid, set the font but keep the setting
text:SetFont(STANDARD_TEXT_FONT, size < 33 and size or 33, data.text_fontType);
else
region.text:SetFont(fontPath, size < 33 and size or 33, data.text_fontType);
end
region.text:SetTextHeight(size)
region:Anchor();
end
function region:SetVisible(visible)
if visible then
self:Show()
else
self:Hide()
end
region:ConfigureSubscribers()
end
function region:Color(r, g, b, a)
@@ -292,31 +362,14 @@ local function modify(parent, region, parentData, data, first)
if (r or g or b) then
a = a or 1;
end
text:SetTextColor(region.color_anim_r or r, region.color_anim_g or g, region.color_anim_b or b, region.color_anim_a or a);
text:SetTextColor(region.color_anim_r or r, region.color_anim_g or g,
region.color_anim_b or b, region.color_anim_a or a)
end
region:Color(data.text_color[1], data.text_color[2], data.text_color[3], data.text_color[4]);
function region:SetTextHeight(size)
local fontPath = SharedMedia:Fetch("font", data.text_font);
region.text:SetFont(fontPath, size < 33 and size or 33, data.text_fontType);
region.text:SetTextHeight(size)
end
function region:SetVisible(visible)
if visible then
self:Show()
else
self:Hide()
end
end
region:SetVisible(data.text_visible)
local selfPoint = data.text_selfPoint
if selfPoint == "AUTO" then
if parentData.regionType == "icon" then
local anchorPoint = data.text_anchorPoint or "CENTER"
local anchorPoint = data.anchor_point or "CENTER"
if anchorPoint:sub(1, 6) == "INNER_" then
selfPoint = anchorPoint:sub(7)
elseif anchorPoint:sub(1, 6) == "OUTER_" then
@@ -326,7 +379,7 @@ local function modify(parent, region, parentData, data, first)
selfPoint = "CENTER"
end
elseif parentData.regionType == "aurabar" then
selfPoint = data.text_anchorPoint or "CENTER"
selfPoint = data.anchor_point or "CENTER"
if selfPoint:sub(1, 5) == "ICON_" then
selfPoint = selfPoint:sub(6)
elseif selfPoint:sub(1, 6) == "INNER_" then
@@ -334,25 +387,24 @@ local function modify(parent, region, parentData, data, first)
end
selfPoint = Private.point_types[selfPoint] and selfPoint or "CENTER"
else
selfPoint = Private.inverse_point_types[data.text_anchorPoint or "CENTER"] or "CENTER"
selfPoint = Private.inverse_point_types[data.anchor_point or "CENTER"] or "CENTER"
end
end
region.text_anchorXOffset = data.text_anchorXOffset
region.text_anchorYOffset = data.text_anchorYOffset
region.UpdateAnchor = function(self)
parent:AnchorSubRegion(text, "point", selfPoint, data.text_anchorPoint, self.text_anchorXOffset or 0, self.text_anchorYOffset or 0)
region.Anchor = function(self)
parent:AnchorSubRegion(text, "point", data.anchor_point, selfPoint,
self.text_anchorXOffset or 0, self.text_anchorYOffset or 0)
end
region:UpdateAnchor()
region.SetXOffset = function(self, xOffset)
if self.text_anchorXOffset == xOffset then
return
end
self.text_anchorXOffset = xOffset
self:UpdateAnchor()
self:Anchor()
end
region.SetYOffset = function(self, yOffset)
@@ -360,8 +412,11 @@ local function modify(parent, region, parentData, data, first)
return
end
self.text_anchorYOffset = yOffset
self:UpdateAnchor()
self:Anchor()
end
region:Color(data.text_color[1], data.text_color[2], data.text_color[3], data.text_color[4]);
region:SetVisible(data.text_visible)
end
local function addDefaultsForNewAura(data)
@@ -377,7 +432,7 @@ local function addDefaultsForNewAura(data)
text_visible = true,
text_selfPoint = "AUTO",
text_anchorPoint = "INNER_LEFT",
anchor_point = "INNER_LEFT",
anchorXOffset = 0,
anchorYOffset = 0,
@@ -397,7 +452,7 @@ local function addDefaultsForNewAura(data)
text_visible = true,
text_selfPoint = "AUTO",
text_anchorPoint = "INNER_RIGHT",
anchor_point = "INNER_RIGHT",
anchorXOffset = 0,
anchorYOffset = 0,
@@ -417,7 +472,7 @@ local function addDefaultsForNewAura(data)
text_visible = true,
text_selfPoint = "AUTO",
text_anchorPoint = "INNER_BOTTOMRIGHT",
anchor_point = "INNER_BOTTOMRIGHT",
anchorXOffset = 0,
anchorYOffset = 0,
@@ -433,6 +488,8 @@ local function supports(regionType)
or regionType == "progresstexture"
or regionType == "icon"
or regionType == "aurabar"
or regionType == "empty"
end
WeakAuras.RegisterSubRegionType("subtext", L["Text"], supports, create, modify, onAcquire, onRelease, default, addDefaultsForNewAura, properties);
WeakAuras.RegisterSubRegionType("subtext", L["Text"], supports, create, modify, onAcquire, onRelease,
default, addDefaultsForNewAura, properties)
+158
View File
@@ -0,0 +1,158 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local L = WeakAuras.L
local default = function(parentType)
local defaults = {
textureVisible = true,
textureTexture = "Interface\\Addons\\WeakAuras\\PowerAurasMedia\\Auras\\Aura3",
textureDesaturate = false,
textureColor = {1, 1, 1, 1},
textureBlendMode = "BLEND",
textureMirror = false,
textureRotate = false,
textureRotation = 0,
anchor_mode = "area",
self_point = "CENTER",
anchor_point = "CENTER",
width = 32,
height = 32,
scale = 1,
mirror = false,
rotate = false,
}
if parentType == "aurabar" then
defaults.anchor_area = "bar"
else
defaults.anchor_area = "ALL"
end
return defaults
end
local properties = {
textureVisible = {
display = L["Visibility"],
setter = "SetVisible",
type = "bool",
defaultProperty = true
},
textureDesaturate = {
display = L["Desaturate"],
setter = "SetDesaturated",
type = "bool",
},
textureColor = {
display = L["Color"],
setter = "SetColor",
type = "color"
},
textureMirror = {
display = L["Mirror"],
setter = "SetMirror",
type = "bool"
},
textureRotation = {
display = L["Rotation"],
setter = "SetRotation",
type = "number",
min = 0,
max = 360,
bigStep = 1,
default = 0
}
}
local funcs = {
SetDesaturated = function(self, b)
self.texture:SetDesaturated(b)
end,
SetColor = function(self, ...)
self.texture:SetVertexColor(...)
end,
SetMirror = function(self, b)
self.texture:SetMirror(b)
end,
SetRotation = function(self, rotation)
self.texture:SetRotation(rotation)
end,
SetVisible = function(self, visible)
self.visible = visible
if visible then
self:Show()
else
self:Hide()
end
end
}
local function create()
local region = CreateFrame("Frame", nil, UIParent)
--region:SetFlattensRenderLayers(true)
for k, v in pairs(funcs) do
region[k] = v
end
region.texture = Private.TextureBase.create(region)
region.texture:ClearAllPoints()
region.texture:SetAllPoints(region)
return region
end
local function onAcquire(subRegion)
subRegion:Show()
end
local function onRelease(subRegion)
subRegion:Hide()
end
local function modify(parent, region, parentData, data, first)
region.parent = parent
region:SetParent(parent)
region.scale = data.scale or 1
local arg1 = data.anchor_mode == "point" and data.anchor_point or data.anchor_area
local arg2 = data.anchor_mode == "point" and data.self_point or nil
if data.anchor_mode == "point" then
region:SetSize(data.width or 0, data.height or 0)
end
region.Anchor = function()
region:ClearAllPoints()
parent:AnchorSubRegion(region, data.anchor_mode, arg1, arg2, data.xOffset, data.yOffset)
end
Private.TextureBase.modify(region.texture, {
canRotate = data.textureRotate,
desaturate = data.textureDesaturate,
blendMode = data.textureBlendMode,
mirror = data.textureMirror,
rotation = data.textureRotation,
textureWrapMode = "CLAMPTOBLACKADDITIVE"
})
region:SetVisible(data.textureVisible)
region:SetDesaturated(data.textureDesaturate)
region:SetColor(data.textureColor[1], data.textureColor[2], data.textureColor[3], data.textureColor[4])
region.texture:SetTexture(data.textureTexture)
end
local function supports(regionType)
return regionType == "texture"
or regionType == "progresstexture"
or regionType == "icon"
or regionType == "aurabar"
or regionType == "text"
or regionType == "empty"
end
WeakAuras.RegisterSubRegionType("subtexture", L["Texture"], supports, create, modify, onAcquire, onRelease, default, nil, properties)
+259 -114
View File
@@ -1,15 +1,15 @@
if not WeakAuras.IsCorrectVersion() then return end
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local SharedMedia = LibStub("LibSharedMedia-3.0");
local L = WeakAuras.L;
local default = function(parentType)
local default = function()
return {
tick_visible = true,
tick_color = {1, 1, 1, 1},
tick_placement_mode = "AtValue",
tick_placement = "50",
tick_placements = {"50"},
progressSources = {{-2, ""}},
automatic_length = true,
tick_thickness = 2,
tick_length = 30,
@@ -42,12 +42,6 @@ local properties = {
type = "list",
values = Private.tick_placement_modes,
},
tick_placement = {
display = L["Placement"],
setter = "SetTickPlacement",
type = "number",
validate = WeakAuras.ValidateNumeric,
},
automatic_length = {
display = L["Automatic Length"],
setter = "SetAutomaticLength",
@@ -90,8 +84,35 @@ local properties = {
type = "bool",
default = true,
},
tick_use_texture = {
display = L["Use Texture"],
setter = "SetUseTexture",
type = "bool",
default = true,
},
tick_texture = {
display = L["Texture"],
setter = "SetTexture",
type = "texture"
}
}
local function GetProperties(parentData, data)
local result = CopyTable(properties)
for i in ipairs(data.tick_placements) do
result["tick_placements." .. i] = {
display = #data.tick_placements > 1 and L["Placement %i"]:format(i) or L["Placement"],
setter = "SetTickPlacementAt",
type = "number",
arg1 = i,
validate = WeakAuras.ValidateNumeric,
}
end
return result
end
local auraBarAnchor = {
["HORIZONTAL"] = "LEFT",
["HORIZONTAL_INVERSE"] = "RIGHT",
@@ -107,10 +128,8 @@ local auraBarAnchorInverse = {
}
local function create()
local subRegion = CreateFrame("FRAME", nil, UIParent)
subRegion.texture = subRegion:CreateTexture()
subRegion.texture:SetDrawLayer("ARTWORK", 3)
subRegion.texture:SetAllPoints(subRegion)
local subRegion = CreateFrame("Frame", nil, UIParent)
subRegion.ticks = {}
return subRegion
end
@@ -130,19 +149,14 @@ local function getRotatedPoints(degrees)
end
local funcs = {
Update = function(self, state)
self.trigger_inverse = state.inverse
self.state = state
if state.progressType == "timed" then
self.trigger_total = state.duration
elseif state.progressType == "static" then
self.trigger_total = state.total
else
self.trigger_total = nil
Update = function(self, state, states)
for i, progressSource in ipairs(self.progressSources) do
self.progressData[i] = {}
Private.UpdateProgressFrom(self.progressData[i], progressSource, {}, state, states, self.parent)
end
self:UpdateVisible()
self:UpdateTickPlacement();
self:UpdateTimerTick()
self:UpdateFrameTick()
end,
OrientationChanged = function(self)
self.orientation = self.parent:GetEffectiveOrientation()
@@ -162,7 +176,7 @@ local funcs = {
self:UpdateTickSize()
end,
InverseChanged = function(self)
self.inverse = self.parent:GetInverse()
self.inverse_direction = self.parent:GetInverse()
self:UpdateTickPlacement()
end,
SetVisible = function(self, visible)
@@ -171,21 +185,29 @@ local funcs = {
self:UpdateVisible()
end
end,
UpdateVisible = function(self)
local missingProgress = self.tick_placement_mode ~= "AtPercent" and not self.trigger_total
if self.tick_visible and not missingProgress then
self:Show()
UpdateVisibleOne = function(self, i)
if self.tick_visible and self.hasProgress[i] then
self.ticks[i]:Show()
else
self:Hide()
self.ticks[i]:Hide()
end
end,
UpdateVisible = function(self)
for i in ipairs(self.ticks) do
self:UpdateVisibleOne(i)
end
end,
SetTickColor = function(self, r, g, b, a)
self.tick_color[1], self.tick_color[2], self.tick_color[3], self.tick_color[4] = r, g, b, a or 1
if self.use_texture then
self.texture:SetVertexColor(r, g, b, a or 1)
for _, tick in ipairs(self.ticks) do
tick:SetVertexColor(r, g, b, a or 1)
end
self:UpdateTickDesaturated()
else
self.texture:SetTexture(r, g, b, a or 1)
for _, tick in ipairs(self.ticks) do
tick:SetTexture(r, g, b, a or 1)
end
end
end,
SetTickPlacementMode = function(self, placement_mode)
@@ -193,77 +215,96 @@ local funcs = {
self.tick_placement_mode = placement_mode
self:UpdateTickPlacement()
self:UpdateVisible()
self:UpdateTimerTick()
self:UpdateFrameTick()
end
end,
UpdateTimerTick = function(self)
if self.tick_placement_mode == "ValueOffset" and self.state and self.state.progressType == "timed" and not self.paused then
if not self.TimerTick then
self.TimerTick = self.UpdateTickPlacement
self.parent:UpdateRegionHasTimerTick()
self.parent.subRegionEvents:AddSubscriber("TimerTick", self)
end
else
if self.TimerTick then
self.TimerTick = nil
self.parent:UpdateRegionHasTimerTick()
self.parent.subRegionEvents:RemoveSubscriber("TimerTick", self)
end
end
end,
SetTickPlacement = function(self, placement)
placement = tonumber(placement)
if self.tick_placement ~= placement then
self.tick_placement = placement
self:UpdateTickPlacement()
end
end,
UpdateTickPlacement = function(self)
local offset, offsetx, offsety = self.tick_placement, 0, 0
local width = self.parentMajorSize
local minValue, maxValue = self.parent:GetMinMax()
local valueRange = maxValue - minValue
local tick_placement
if self.tick_placement_mode == "AtValue" then
tick_placement = self.tick_placement
elseif self.tick_placement_mode == "AtMissingValue" then
tick_placement = self.trigger_total and self.trigger_total - self.tick_placement
elseif self.tick_placement_mode == "AtPercent" then
if self.tick_placement >= 0 and self.tick_placement <= 100 and self.trigger_total then
tick_placement = self.tick_placement * self.trigger_total / 100
end
elseif self.tick_placement_mode == "ValueOffset" then
if self.trigger_total and self.trigger_total ~= 0 then
if self.state.progressType == "timed" then
if self.state.paused then
if self.state.remaining then
tick_placement = self.state.remaining + self.tick_placement
end
else
tick_placement = self.state.expirationTime - GetTime() + self.tick_placement
end
else
tick_placement = self.state.value + self.tick_placement
UpdateFrameTick = function(self)
local requiresFrameTick = false
if self.tick_placement_mode == "ValueOffset" then
for i, progress in ipairs(self.progressData) do
if progress.progressType == "timed" and not progress.paused then
requiresFrameTick = true
break
end
end
end
local percent = valueRange ~= 0 and tick_placement and (tick_placement - minValue) / valueRange
if not percent or (percent and percent < 0 or percent > 1) then
self.texture:Hide()
offset = 0
if requiresFrameTick then
if not self.FrameTick then
self.FrameTick = self.UpdateTickPlacement
self.parent.subRegionEvents:AddSubscriber("FrameTick", self)
end
else
self.texture:Show()
offset = percent * width
if self.FrameTick then
self.FrameTick = nil
self.parent.subRegionEvents:RemoveSubscriber("FrameTick", self)
end
end
end,
SetTickPlacementAt = function(self, tick, placement)
placement = tonumber(placement)
if self.tick_placements[tick] ~= placement then
self.tick_placements[tick] = placement
self:UpdateTickPlacementOne(tick)
end
end,
-- For backwards compability
SetTickPlacement = function(self, placement)
self:SetTickPlacementAt(1, placement)
end,
UpdateTickPlacement = function(self)
for i in ipairs(self.tick_placements) do
self:UpdateTickPlacementOne(i)
end
end,
UpdateTickPlacementOne = function(self, i)
local offsetx, offsety = 0, 0
local width = self.parentMajorSize
local inverse = self.inverse
if self.trigger_inverse then
local minValue, maxValue = self.parent:GetMinMaxProgress()
local valueRange = maxValue - minValue
local inverse = self.inverse_direction
if self.parent.inverse then
inverse = not inverse
end
local tick_placement
if self.tick_placement_mode == "AtValue" then
tick_placement = self.tick_placements[i]
elseif self.tick_placement_mode == "AtMissingValue" then
tick_placement = maxValue - self.tick_placements[i]
elseif self.tick_placement_mode == "AtPercent" then
if self.tick_placements[i] >= 0 and self.tick_placements[i] <= 100 and maxValue then
tick_placement = minValue + self.tick_placements[i] * valueRange / 100
end
elseif self.tick_placement_mode == "ValueOffset" then
if maxValue ~= 0 and self.progressData[i] then
if self.progressData[i].progressType == "timed" then
if self.progressData[i].paused then
if self.progressData[i].remaining then
tick_placement = self.progressData[i].remaining + self.tick_placements[i]
end
else
tick_placement = self.progressData[i].expirationTime - GetTime() + self.tick_placements[i]
end
elseif self.progressData[i].progressType == "static" then
tick_placement = self.progressData[i].value + self.tick_placements[i]
end
end
end
local offset
local percent = valueRange ~= 0 and tick_placement and (tick_placement - minValue) / valueRange
if not percent or (percent and percent < 0 or percent > 1) then
offset = 0
self.hasProgress[i] = false
else
offset = percent * width
self.hasProgress[i] = true
end
self:UpdateVisible(i)
if (self.orientation == "HORIZONTAL_INVERSE") or (self.orientation == "VERTICAL") then
offset = -offset
end
@@ -278,8 +319,10 @@ local funcs = {
offsetx = offset
end
local side = inverse and auraBarAnchorInverse or auraBarAnchor
self:ClearAllPoints()
self:SetPoint("CENTER", self.parent.bar, side[self.orientation], offsetx + self.tick_xOffset, offsety + self.tick_yOffset)
self.ticks[i]:ClearAllPoints()
self.ticks[i]:SetPoint("CENTER", self.parent.bar, side[self.orientation],
offsetx + self.tick_xOffset,
offsety + self.tick_yOffset)
end,
SetAutomaticLength = function(self, automatic_length)
if self.automatic_length ~= automatic_length then
@@ -301,16 +344,24 @@ local funcs = {
end,
UpdateTickSize = function(self)
if self.vertical then
self:SetHeight(self.tick_thickness)
for i, tick in ipairs(self.ticks) do
tick:SetHeight(self.tick_thickness)
end
else
self:SetWidth(self.tick_thickness)
for i, tick in ipairs(self.ticks) do
tick:SetWidth(self.tick_thickness)
end
end
local length = self.automatic_length and self.parentMinorSize or self.tick_length
if self.vertical then
self:SetWidth(length)
for i, tick in ipairs(self.ticks) do
tick:SetWidth(length)
end
else
self:SetHeight(length)
for i, tick in ipairs(self.ticks) do
tick:SetHeight(length)
end
end
end,
SetTickDesaturated = function(self, desaturate)
@@ -320,7 +371,9 @@ local funcs = {
end
end,
UpdateTickDesaturated = function(self)
self.texture:SetDesaturated(self.tick_desaturate)
for i, tick in ipairs(self.ticks) do
tick:SetDesaturated(self.tick_desaturate)
end
end,
SetTickRotation = function(self, degrees)
if self.tick_rotation ~= degrees then
@@ -329,7 +382,10 @@ local funcs = {
end
end,
UpdateTickRotation = function(self)
self:UpdateTexCoord()
local rad = math.rad(self.tick_rotation)
for _, tick in ipairs(self.ticks) do
tick:SetRotation(rad)
end
end,
SetTickMirror = function(self, mirror)
if self.mirror ~= mirror then
@@ -338,7 +394,15 @@ local funcs = {
end
end,
UpdateTickMirror = function(self)
self:UpdateTexCoord()
if self.mirror then
for _, tick in ipairs(self.ticks) do
tick:SetTexCoord(0, 1, 1, 1, 0, 0, 1, 0)
end
else
for _, tick in ipairs(self.ticks) do
tick:SetTexCoord(0, 0, 1, 0, 0, 1, 1, 1)
end
end
end,
SetTickBlendMode = function(self, mode)
if self.tick_blend_mode ~= mode then
@@ -348,27 +412,72 @@ local funcs = {
end,
UpdateTickBlendMode = function(self)
if self.use_texture then
self.texture:SetBlendMode(self.tick_blend_mode)
for _, tick in ipairs(self.ticks) do
tick:SetBlendMode(self.tick_blend_mode)
end
else
self.texture:SetBlendMode("BLEND")
for _, tick in ipairs(self.ticks) do
tick:SetBlendMode("BLEND")
end
end
end,
UpdateTexCoord = function(self)
local ulx, uly, llx, lly, urx, ury, lrx, lry = getRotatedPoints(self.tick_rotation);
if self.mirror then
self.texture:SetTexCoord(urx, ury, lrx, lry, ulx, uly, llx, lly);
UpdateTexture = function(self)
if self.use_texture then
for _, tick in ipairs(self.ticks) do
tick:SetTexture(tick, self.tick_texture)
end
else
self.texture:SetTexCoord(ulx, uly, llx, lly, urx, ury, lrx, lry);
for _, tick in ipairs(self.ticks) do
tick:SetTexture(self.tick_color[1], self.tick_color[2], self.tick_color[3], self.tick_color[4])
end
end
end,
SetTexture = function(self, texture)
if self.tick_texture == texture then
return
end
self.tick_texture = texture
self:UpdateTexture()
end,
SetUseTexture = function(self, use)
if self.use_texture == use then
return
end
self.use_texture = use
self:UpdateTexture()
end,
AnchorSubRegion = function(self, subRegion, anchorType, anchorPoint, subRegionPoint, anchorXOffset, anchorYOffset)
subRegion:ClearAllPoints()
if anchorType == "point" then
local xOffset = anchorXOffset or 0
local yOffset = anchorYOffset or 0
subRegionPoint = Private.point_types[subRegionPoint] and subRegionPoint or "CENTER"
local tickIndex = tonumber(anchorPoint:sub(6))
local anchorTo = tickIndex and self.ticks[tickIndex] or nil
if anchorTo then
subRegion:SetPoint(subRegionPoint, anchorTo, "CENTER", xOffset, yOffset)
end
else
local tickIndex = tonumber(anchorPoint:sub(10))
local anchorTo = tickIndex and self.ticks[tickIndex] or nil
local xOffset = anchorXOffset or 0
local yOffset = anchorYOffset or 0
if anchorTo then
subRegion:SetPoint("BOTTOMLEFT", anchorTo, "BOTTOMLEFT", -xOffset, -yOffset)
subRegion:SetPoint("TOPRIGHT", anchorTo, "TOPRIGHT", xOffset, yOffset)
end
end
end
}
local function modify(parent, region, parentData, data, first)
region:SetParent(parent)
region.orientation = parent.effectiveOrientation
region.inverse = parentData.inverse
region.trigger_inverse = false
region.inverse_direction = parentData.inverse
region.inverse = false
region.vertical = region.orientation == "VERTICAL" or region.orientation == "VERTICAL_INVERSE"
if (region.vertical) then
region.parentMinorSize, region.parentMajorSize = parent.bar:GetRealSize()
@@ -381,7 +490,35 @@ local function modify(parent, region, parentData, data, first)
region.tick_visible = data.tick_visible
region.tick_color = CopyTable(data.tick_color)
region.tick_placement_mode = data.tick_placement_mode
region.tick_placement = tonumber(data.tick_placement)
region.tick_placements = {}
region.progressSources = {}
region.progressData = {}
for i, tick_placement in ipairs(data.tick_placements) do
local value = tonumber(tick_placement)
if region.tick_placement_mode == "ValueOffset" then
local progressSource = Private.AddProgressSourceMetaData(parentData, data.progressSources[i] or {-2, ""})
if value and progressSource then
tinsert(region.tick_placements, value)
tinsert(region.progressSources, progressSource or {})
end
else
if value then
tinsert(region.tick_placements, value)
end
end
if region.ticks[i] == nil then
local texture = region:CreateTexture()
texture:SetDrawLayer("ARTWORK", 3)
texture:SetAllPoints()
region.ticks[i] = texture
end
end
for i = #data.tick_placements + 1, #region.ticks do
region.ticks[i]:Hide()
end
region.automatic_length = data.automatic_length
region.tick_thickness = data.tick_thickness
region.tick_length = data.tick_length
@@ -391,12 +528,16 @@ local function modify(parent, region, parentData, data, first)
region.tick_xOffset = data.tick_xOffset
region.tick_yOffset = data.tick_yOffset
region.hasProgress = {}
for k, v in pairs(funcs) do
region[k] = v
end
if data.use_texture then
region.texture:SetTexture(data.tick_texture)
for _, tick in ipairs(region.ticks) do
tick:SetTexture(data.tick_texture)
end
end
region:SetVisible(data.tick_visible)
@@ -406,6 +547,7 @@ local function modify(parent, region, parentData, data, first)
region:SetTickRotation(data.tick_rotation)
region:SetTickMirror(data.tick_mirror)
region:UpdateTickPlacement()
region:UpdateTickSize()
parent.subRegionEvents:AddSubscriber("Update", region)
@@ -413,11 +555,14 @@ local function modify(parent, region, parentData, data, first)
parent.subRegionEvents:AddSubscriber("InverseChanged", region)
parent.subRegionEvents:AddSubscriber("OnRegionSizeChanged", region)
region.TimerTick = nil
region.FrameTick = nil
region:ClearAllPoints()
region:SetAllPoints(parent.bar)
end
local function supports(regionType)
return regionType == "aurabar"
end
WeakAuras.RegisterSubRegionType("subtick", L["Tick"], supports, create, modify, onAcquire, onRelease, default, nil, properties);
WeakAuras.RegisterSubRegionType("subtick", L["Tick"], supports, create, modify, onAcquire, onRelease,
default, nil, GetProperties);
+85
View File
@@ -0,0 +1,85 @@
if not WeakAuras.IsLibsOK() then return end
local AddonName, Private = ...
local WeakAuras = WeakAuras
local L = WeakAuras.L
local SubscribableObject =
{
events = {},
subscribers = {},
callbacks = {},
ClearSubscribers = function(self)
self.events = {}
self.subscribers = {}
end,
ClearCallbacks = function(self)
self.callbacks = {}
end,
AddSubscriber = function(self, event, subscriber, highPriority)
if not subscriber[event] then
print("Can't register for ", event, " ", subscriber, subscriber.type)
return
end
self.events[event] = self.events[event] or {}
self.subscribers[event] = self.subscribers[event] or {}
if self.subscribers[event][subscriber] then
-- Already subscribed, just return
return
end
self.subscribers[event][subscriber] = true
local pos = highPriority and 1 or (#self.events[event] + 1)
if TableHasAnyEntries(self.events[event]) then
tinsert(self.events[event], pos, subscriber)
else
tinsert(self.events[event], pos, subscriber)
if self.callbacks[event] then
self.callbacks[event]()
end
end
end,
RemoveSubscriber = function(self, event, subscriber)
if self.events[event] then
if not self.subscribers[event][subscriber] then
-- Not subscribed
return
end
self.subscribers[event][subscriber] = nil
local index = tIndexOf(self.events[event], subscriber)
if index then
tremove(self.events[event], index)
if not TableHasAnyEntries(self.events[event]) then
if self.callbacks[event] then
self.callbacks[event]()
end
end
end
end
end,
SetOnSubscriptionStatusChanged = function(self, event, cb)
self.callbacks[event] = cb
end,
Notify = function(self, event, ...)
if self.events[event] then
for _, subscriber in ipairs(self.events[event]) do
subscriber[event](subscriber, ...)
end
end
end,
HasSubscribers = function(self, event)
return self.events[event] and TableHasAnyEntries(self.events[event])
end
}
function Private.CreateSubscribableObject()
return CopyTable(SubscribableObject)
end

Some files were not shown because too many files have changed in this diff Show More